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