1 /*
2 * Percepio Trace Recorder for Tracealyzer v4.6.6
3 * Copyright 2021 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * The implementation for errors.
9 */
10 
11 #include <trcRecorder.h>
12 
13 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
14 
15 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
16 
17 /* We skip the slot for TRC_ERROR_NONE so error code 1 is the first bit */
18 #define GET_ERROR_WARNING_FLAG(errorCode) (pxErrorInfo->uiErrorAndWarningFlags & (1 << ((errorCode) - 1)))
19 #define SET_ERROR_WARNING_FLAG(errorCode) (pxErrorInfo->uiErrorAndWarningFlags |= (1 << ((errorCode) - 1)))
20 
21 traceResult prvTraceErrorPrint(uint32_t uiErrorCode);
22 traceResult prvTraceErrorGetDescription(uint32_t uiErrorCode, const char** pszDesc);
23 
24 typedef struct TraceErrorInfo
25 {
26 	uint32_t uiErrorAndWarningFlags;
27 	uint32_t uiErrorCode;
28 	TraceStringHandle_t xWarningChannel;
29 } TraceErrorInfo_t;
30 
31 static TraceErrorInfo_t* pxErrorInfo;
32 
xTraceErrorInitialize(TraceErrorBuffer_t * pxBuffer)33 traceResult xTraceErrorInitialize(TraceErrorBuffer_t* pxBuffer)
34 {
35 	TRC_ASSERT_EQUAL_SIZE(TraceErrorBuffer_t, TraceErrorInfo_t);
36 
37 	/* This should never fail */
38 	TRC_ASSERT(pxBuffer != 0);
39 
40 	pxErrorInfo = (TraceErrorInfo_t*)pxBuffer;
41 
42 	pxErrorInfo->uiErrorAndWarningFlags = 0;
43 	pxErrorInfo->uiErrorCode = 0;
44 	pxErrorInfo->xWarningChannel = 0;
45 
46 	xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_ERROR);
47 
48 	return TRC_SUCCESS;
49 }
50 
51 /* Called on warnings, when the recording can continue. */
xTraceWarning(uint32_t uiErrorCode)52 traceResult xTraceWarning(uint32_t uiErrorCode)
53 {
54 	/* Probably good to verify this */
55 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_ERROR))
56 	{
57 		/* If not initialized */
58 		return TRC_FAIL;
59 	}
60 
61 	if (GET_ERROR_WARNING_FLAG(uiErrorCode) == 0)
62 	{
63 		/* Will never reach this point more than once per warning type, since we verify if uiErrorAndWarningFlags[uiErrorCode] has already been set */
64 		SET_ERROR_WARNING_FLAG(uiErrorCode);
65 
66 		prvTraceErrorPrint(uiErrorCode);
67 	}
68 
69 	return TRC_SUCCESS;
70 }
71 
72 /* Called on critical errors in the recorder. Stops the recorder! */
xTraceError(uint32_t uiErrorCode)73 traceResult xTraceError(uint32_t uiErrorCode)
74 {
75 	/* Probably good to verify this */
76 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_ERROR))
77 	{
78 		return TRC_FAIL;
79 	}
80 
81 	if (pxErrorInfo->uiErrorCode == TRC_ERROR_NONE)
82 	{
83 		/* Will never reach this point more than once, since we verify if uiErrorCode has already been set */
84 		SET_ERROR_WARNING_FLAG(uiErrorCode);
85 		pxErrorInfo->uiErrorCode = uiErrorCode;
86 
87 		if (prvTraceErrorPrint(uiErrorCode) == TRC_FAIL)
88 		{
89 			xTraceDisable();
90 
91 			return TRC_FAIL;
92 		}
93 
94 		xTracePrint(pxErrorInfo->xWarningChannel, "Recorder stopped in xTraceError(...)!");
95 		xTraceDisable();
96 	}
97 
98 	return TRC_SUCCESS;
99 }
100 
101 /*******************************************************************************
102  * xTraceErrorGetLast
103  *
104  * Returns the last error or warning, as a string, or NULL if none.
105  *****************************************************************************/
xTraceErrorGetLast(const char ** pszError)106 traceResult xTraceErrorGetLast(const char **pszError)
107 {
108 	/* Probably good to verify this */
109 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_ERROR))
110 	{
111 		return TRC_FAIL;
112 	}
113 
114 	/* This should never fail */
115 	TRC_ASSERT(pszError != 0);
116 
117 	return prvTraceErrorGetDescription(pxErrorInfo->uiErrorCode, pszError);
118 }
119 
120 /*******************************************************************************
121  * xTraceErrorClear
122  *
123  * Clears any errors.
124  *****************************************************************************/
xTraceErrorClear(void)125 traceResult xTraceErrorClear(void)
126 {
127 	/* Probably good to verify this */
128 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_ERROR))
129 	{
130 		/* If not initialized */
131 		return TRC_FAIL;
132 	}
133 
134 	pxErrorInfo->uiErrorCode = TRC_ERROR_NONE;
135 
136 	return TRC_SUCCESS;
137 }
138 
139 /* Returns the error or warning, as a string, or NULL if none. */
prvTraceErrorPrint(uint32_t uiErrorCode)140 traceResult prvTraceErrorPrint(uint32_t uiErrorCode)
141 {
142 	const char* szDesc;
143 	/* Note: the error messages are short, in order to fit in a User Event.
144 	Instead, the users can read more in the below comments.*/
145 
146 	if (pxErrorInfo->xWarningChannel == 0)
147 	{
148 		/* The #WFR channel means "Warnings from Recorder" and
149 		* is used to store warnings and errors from the recorder.
150 		* The abbreviation #WFR is used instead of the longer full name,
151 		* to avoid truncation by small slots in the symbol table.
152 		* This is translated in Tracealyzer and shown as the full name,
153 		* "Warnings from Recorder".
154 		 */
155 		if (xTraceStringRegister("#WFR", &pxErrorInfo->xWarningChannel) == TRC_FAIL)
156 		{
157 			return TRC_FAIL;
158 		}
159 	}
160 
161 	prvTraceErrorGetDescription(uiErrorCode, &szDesc);
162 
163 	switch (uiErrorCode)
164 	{
165 	case TRC_WARNING_ENTRY_TABLE_SLOTS:
166 	case TRC_WARNING_ENTRY_SYMBOL_MAX_LENGTH:
167 	case TRC_WARNING_EVENT_SIZE_TRUNCATED:
168 	case TRC_WARNING_STREAM_PORT_READ:
169 	case TRC_WARNING_STREAM_PORT_WRITE:
170 	case TRC_WARNING_STREAM_PORT_INITIAL_BLOCKING:
171 	case TRC_WARNING_STACKMON_NO_SLOTS:
172 	case TRC_ERROR_STREAM_PORT_WRITE:
173 	case TRC_ERROR_EVENT_CODE_TOO_LARGE:
174 	case TRC_ERROR_ISR_NESTING_OVERFLOW:
175 	case TRC_ERROR_DWT_NOT_SUPPORTED:
176 	case TRC_ERROR_DWT_CYCCNT_NOT_SUPPORTED:
177 	case TRC_ERROR_TZCTRLTASK_NOT_CREATED:
178 		xTracePrint(pxErrorInfo->xWarningChannel, szDesc);
179 		break;
180 
181 	case TRC_ERROR_ASSERT:
182 		/* A TRC_ASSERT has triggered */
183 		{
184 			TraceUnsignedBaseType_t uxLineNumber;
185 			TraceStringHandle_t xFileName;
186 
187 			if (xTraceAssertGet(&xFileName, &uxLineNumber) == TRC_FAIL)
188 			{
189 				return TRC_FAIL;
190 			}
191 
192 			xTracePrintF(pxErrorInfo->xWarningChannel, szDesc, xFileName, (uint32_t)uxLineNumber);
193 
194 			return TRC_SUCCESS;
195 		}
196 
197 	default:
198 		/* No error, or an unknown error occurred */
199 		xTracePrintF(pxErrorInfo->xWarningChannel, "Unknown error code: 0x%08X", uiErrorCode);
200 
201 		return TRC_FAIL;
202 	}
203 
204 	return TRC_SUCCESS;
205 }
206 
207 /* Returns the error or warning, as a string, or NULL if none. */
prvTraceErrorGetDescription(uint32_t uiErrorCode,const char ** pszDesc)208 traceResult prvTraceErrorGetDescription(uint32_t uiErrorCode, const char** pszDesc)
209 {
210 	/* Note: the error messages are short, in order to fit in a User Event.
211 	Instead, the users can read more in the below comments.*/
212 
213 	switch (uiErrorCode)
214 	{
215 	case TRC_ERROR_NONE:
216 		return TRC_FAIL;
217 
218 	case TRC_WARNING_ENTRY_TABLE_SLOTS:
219 		/* There was not enough symbol table slots for storing symbol names.
220 		The number of missing slots is counted by NoRoomForSymbol. Inspect this
221 		variable and increase TRC_CFG_ENTRY_TABLE_SLOTS by at least that value. */
222 
223 		*pszDesc = "Exceeded TRC_CFG_ENTRY_TABLE_SLOTS";
224 		break;
225 
226 	case TRC_WARNING_ENTRY_SYMBOL_MAX_LENGTH:
227 		/* A symbol name exceeded TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH in length.
228 		Make sure the symbol names are at most TRC_CFG_SYMBOL_MAX_LENGTH,
229 		or inspect uiLongestSymbolName in trcEntryTable and increase
230 		TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH to at least this value. */
231 
232 		*pszDesc = "Exceeded TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH";
233 		break;
234 
235 	case TRC_WARNING_EVENT_SIZE_TRUNCATED:
236 		/* Some arguments was longer than the maximum payload size
237 		and has been truncated by "uiMaxBytesTruncated" bytes.
238 
239 		This usually happens for the following functions:
240 		- xTracePrint
241 		- xTracePrintF
242 		- xTraceStringRegister
243 
244 		A trace event may store a maximum of 56 bytes payload, including
245 		data arguments and string characters. */
246 
247 		*pszDesc = "Event size exceeded";
248 		break;
249 
250 	case TRC_WARNING_STREAM_PORT_READ:
251 		/* TRC_STREAM_PORT_READ_DATA is expected to return 0 when completed successfully.
252 		This means there is an error in the communication with host/Tracealyzer. */
253 
254 		*pszDesc = "TRC_STREAM_PORT_READ_DATA returned error";
255 		break;
256 
257 	case TRC_WARNING_STREAM_PORT_WRITE:
258 		/* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully.
259 		This means there is an error in the communication with host/Tracealyzer. */
260 
261 		*pszDesc = "TRC_STREAM_PORT_WRITE_DATA returned error";
262 		break;
263 
264 	case TRC_WARNING_STREAM_PORT_INITIAL_BLOCKING:
265 		/* Blocking occurred during xTraceEnable. This happens if the trace buffer is
266 		smaller than the initial transmission (trace header, object table, and symbol table). */
267 
268 		*pszDesc = "Blocking in xTraceEnable";
269 		break;
270 
271 	case TRC_WARNING_STACKMON_NO_SLOTS:
272 		/* Some tasks did not fit in the stack monitor. Increase the slot count. */
273 
274 		*pszDesc = "No slots left in Stack Monitor";
275 		break;
276 
277 	case TRC_ERROR_STREAM_PORT_WRITE:
278 		/* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully.
279 		This means there is an error in the communication with host/Tracealyzer. */
280 
281 		*pszDesc = "TRC_STREAM_PORT_WRITE_DATA returned error";
282 		break;
283 
284 	case TRC_ERROR_EVENT_CODE_TOO_LARGE:
285 		/* The highest allowed event code is 4095, anything higher is an unexpected error.
286 		Please contact support@percepio.com for assistance.*/
287 
288 		*pszDesc = "Invalid event code";
289 		break;
290 
291 	case TRC_ERROR_ISR_NESTING_OVERFLOW:
292 		/* Nesting of ISR trace calls exceeded the limit (TRC_CFG_MAX_ISR_NESTING).
293 		If this is unlikely, make sure that you call vTraceStoreISRExit in the end
294 		of all ISR handlers. Or increase TRC_CFG_MAX_ISR_NESTING. */
295 
296 		*pszDesc = "Exceeded ISR nesting";
297 		break;
298 
299 	case TRC_ERROR_DWT_NOT_SUPPORTED:
300 		/* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
301 		DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
302 		macro normally set by ARM's CMSIS library, since typically available. You can however select
303 		SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
304 
305 		*pszDesc = "DWT not supported";
306 		break;
307 
308 	case TRC_ERROR_DWT_CYCCNT_NOT_SUPPORTED:
309 		/* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
310 		DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
311 		macro normally set by ARM's CMSIS library, since typically available. You can however select
312 		SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
313 
314 		*pszDesc = "DWT_CYCCNT not supported";
315 		break;
316 
317 	case TRC_ERROR_TZCTRLTASK_NOT_CREATED:
318 		/* xTraceEnable failed creating the trace control task (TzCtrl) - incorrect parameters (priority?)
319 		or insufficient heap size? */
320 		*pszDesc = "Could not create TzCtrl";
321 		break;
322 
323 	case TRC_ERROR_ASSERT:
324 		/* A TRC_ASSERT has triggered */
325 		*pszDesc = "ASSERT: %s (%d)";
326 		break;
327 
328 	default:
329 		/* An unknown error occurred */
330 		*pszDesc = "Unknown error code: 0x%08X";
331 		break;
332 	}
333 
334 	return TRC_SUCCESS;
335 }
336 
337 #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */
338 
339 #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
340