1 /*
2 * Percepio Trace Recorder for Tracealyzer v4.8.1
3 * Copyright 2023 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * The implementation for print.
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 #if (TRC_CFG_INCLUDE_USER_EVENTS == 1)
18 
19 #include <stdarg.h>
20 
21 static traceResult prvTraceVPrintF(const TraceStringHandle_t xChannel, const char* szFormat, uint32_t uiLength, uint32_t uiArgs, va_list* pxVariableList);
22 
23 static TracePrintData_t *pxPrintData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
24 
xTracePrintInitialize(TracePrintData_t * pxBuffer)25 traceResult xTracePrintInitialize(TracePrintData_t *pxBuffer)
26 {
27 	/* This should never fail */
28 	TRC_ASSERT(pxBuffer != (void*)0);
29 
30 	pxPrintData = pxBuffer;
31 
32 	pxPrintData->defaultChannel = 0;
33 	pxPrintData->consoleChannel = 0;
34 
35 	xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_PRINT);
36 
37 	return TRC_SUCCESS;
38 }
39 
40 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/
xTracePrint(TraceStringHandle_t xChannel,const char * szString)41 traceResult xTracePrint(TraceStringHandle_t xChannel, const char* szString)
42 {
43 	uint32_t uiLength;
44 	uint32_t i;
45 
46 	/* We need to check this */
47 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
48 	{
49 		return TRC_FAIL;
50 	}
51 
52 	if (szString == (void*)0)
53 	{
54 		szString = ""; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
55 	}
56 
57 	for (i = 0u; (szString[i] != (char)0) && (i < 128u); i++) {} /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress char base type usage checks*/ /*cstat !MISRAC2004-17.4_b We need to access every character in the string*/
58 
59 	uiLength = i + 1u; /* Null termination */
60 
61 	return prvTraceVPrintF(xChannel, szString, uiLength, 0u, (va_list*)0);  /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 Suppress conversion of pointer to integer check*/ /*cstat !MISRAC2012-Rule-11.9 Suppress NULL recommendation*/
62 }
63 
64 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-16.1 Suppress variable parameter count check*/
xTraceConsoleChannelPrintF(const char * szFormat,...)65 traceResult xTraceConsoleChannelPrintF(const char* szFormat, ...)
66 {
67 	traceResult xResult;
68 	va_list xVariableList; /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
69 
70 	/* We need to check this */
71 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
72 	{
73 		return TRC_FAIL;
74 	}
75 
76 	if (pxPrintData->consoleChannel == 0)
77 	{
78 		if (xTraceStringRegister("Debug Console", &pxPrintData->consoleChannel) == TRC_FAIL)
79 		{
80 			return TRC_FAIL;
81 		}
82 	}
83 
84 	va_start(xVariableList, szFormat);
85 	xResult = xTraceVPrintF(pxPrintData->consoleChannel, szFormat, &xVariableList);
86 	va_end(xVariableList);
87 
88 	return xResult;
89 }
90 
91 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-16.1 Suppress variable parameter count check*/
xTracePrintCompactF(const char * szChannel,const char * szFormat,...)92 traceResult xTracePrintCompactF(const char* szChannel, const char* szFormat, ...)
93 {
94 	uint32_t i;
95 	uint32_t uiArgs = 0u;
96 	traceResult xResult;
97 	va_list xVariableList; /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
98 	TraceUnsignedBaseType_t uxArg1, uxArg2, uxArg3, uxArg4;
99 
100 	/* We need to check this */
101 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
102 	{
103 		return TRC_FAIL;
104 	}
105 
106 	if (szFormat == (void*)0)
107 	{
108 		szFormat = ""; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
109 	}
110 
111 	/* Count the number of arguments in the format string (e.g., %d) */
112 	for (i = 0u; (szFormat[i] != (char)0) && (i < 128u); i++) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress char base type usage checks*/ /*cstat !MISRAC2012-Rule-14.2 Suppress malformed for loop due to i being incremented inside*/ /*cstat !MISRAC2004-17.4_b We need to access every character in the string*/
113 	{
114 		if (szFormat[i] == '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
115 		{
116 			if (szFormat[i + 1u] == (char)0) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
117 			{
118 				/* Found end of string, let for loop detect it */
119 				continue; /*cstat !MISRAC2004-14.5 Suppress continue usage check*/
120 			}
121 
122 			if (szFormat[i + 1u] != '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
123 			{
124 				uiArgs++;        /* Found an argument */
125 			}
126 
127 			/* Move past format specifier or non-argument '%' */
128 			i++; /*cstat !MISRAC2004-13.6 Suppress i increment inside for loop check*/
129 		}
130 	}
131 
132 	va_start(xVariableList, szFormat);
133 	switch(uiArgs)
134 	{
135 	case 0:
136 		xResult = xTraceEventCreate2(PSF_EVENT_USER_EVENT_FIXED, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
137 		break;
138 	case 1:
139 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
140 		xResult = xTraceEventCreate3(PSF_EVENT_USER_EVENT_FIXED + 1UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
141 		break;
142 	case 2:
143 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
144 		uxArg2 = va_arg(xVariableList, TraceUnsignedBaseType_t);
145 		xResult = xTraceEventCreate4(PSF_EVENT_USER_EVENT_FIXED + 2UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1, uxArg2); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
146 		break;
147 	case 3:
148 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
149 		uxArg2 = va_arg(xVariableList, TraceUnsignedBaseType_t);
150 		uxArg3 = va_arg(xVariableList, TraceUnsignedBaseType_t);
151 		xResult = xTraceEventCreate5(PSF_EVENT_USER_EVENT_FIXED + 3UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1, uxArg2, uxArg3); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
152 		break;
153 	case 4:
154 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
155 		uxArg2 = va_arg(xVariableList, TraceUnsignedBaseType_t);
156 		uxArg3 = va_arg(xVariableList, TraceUnsignedBaseType_t);
157 		uxArg4 = va_arg(xVariableList, TraceUnsignedBaseType_t);
158 		xResult = xTraceEventCreate6(PSF_EVENT_USER_EVENT_FIXED + 4UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1, uxArg2, uxArg3, uxArg4); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
159 		break;
160 	default:
161 		xResult = TRC_FAIL;
162 		break;
163 	}
164 	va_end(xVariableList);
165 
166 	return xResult;
167 }
168 
169 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-16.1 Suppress variable parameter count check*/
xTracePrintF(TraceStringHandle_t xChannel,const char * szFormat,...)170 traceResult xTracePrintF(TraceStringHandle_t xChannel, const char* szFormat, ...)
171 {
172 	traceResult xResult;
173 	va_list xVariableList; /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
174 
175 	/* We need to check this */
176 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
177 	{
178 		return TRC_FAIL;
179 	}
180 
181 	va_start(xVariableList, szFormat);
182 	xResult = xTraceVPrintF(xChannel, szFormat, &xVariableList);
183 	va_end(xVariableList);
184 
185 	return xResult;
186 }
187 
188 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
xTraceVPrintF(TraceStringHandle_t xChannel,const char * szFormat,va_list * pxVariableList)189 traceResult xTraceVPrintF(TraceStringHandle_t xChannel, const char* szFormat, va_list* pxVariableList)
190 {
191 	uint32_t i;
192 	uint32_t uiArgs = 0u;
193 	uint32_t uiLength;
194 
195 	/* We need to check this */
196 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
197 	{
198 		return TRC_FAIL;
199 	}
200 
201 	if (szFormat == (void*)0)
202 	{
203 		szFormat = ""; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
204 	}
205 
206 	/* Count the number of arguments in the format string (e.g., %d) */
207 	for (i = 0u; (szFormat[i] != (char)0) && (i < 128u); i++) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress char base type usage checks*/ /*cstat !MISRAC2012-Rule-14.2 Suppress malformed for loop due to i being incremented inside*/ /*cstat !MISRAC2004-17.4_b We need to access every character in the string*/
208 	{
209 		if (szFormat[i] == '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
210 		{
211 			if (szFormat[i + 1u] == (char)0) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
212 			{
213 				/* Found end of string, let for loop detect it */
214 				continue; /*cstat !MISRAC2004-14.5 Suppress continue usage check*/
215 			}
216 
217 			if (szFormat[i + 1u] != '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
218 			{
219 				uiArgs++;        /* Found an argument */
220 			}
221 
222 			/* Move past format specifier or non-argument '%' */
223 			i++; /*cstat !MISRAC2004-13.6 Suppress i increment inside for loop check*/
224 		}
225 	}
226 
227 	uiLength = i + 1u; /* Null termination */
228 
229 	return prvTraceVPrintF(xChannel, szFormat, uiLength, uiArgs, pxVariableList);
230 }
231 
232 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
prvTraceVPrintF(TraceStringHandle_t xChannel,const char * szFormat,uint32_t uiLength,uint32_t uiArgs,va_list * pxVariableList)233 static traceResult prvTraceVPrintF(TraceStringHandle_t xChannel, const char* szFormat, uint32_t uiLength, uint32_t uiArgs, va_list* pxVariableList)
234 {
235 	TraceEventHandle_t xEventHandle = 0;
236 	uint32_t i, uiRemaining = 0u;
237 	uint32_t uiValue = 0u;
238 	const uint32_t uiEventCode = PSF_EVENT_USER_EVENT + 1u + uiArgs; /* Add channel (1) */
239 	const uint32_t uiSize = sizeof(void*) + (uiArgs * sizeof(TraceUnsignedBaseType_t)) + uiLength; /* Add channel (sizeof(void*)) */
240 
241 	if (xChannel == 0)
242 	{
243 		if (pxPrintData->defaultChannel == 0)
244 		{
245 			/* Channel is not present */
246 			if (xTraceStringRegister("Default", &pxPrintData->defaultChannel) == TRC_FAIL)
247 			{
248 				return TRC_FAIL;
249 			}
250 		}
251 
252 		xChannel = pxPrintData->defaultChannel; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
253 	}
254 
255 	/* Added channel to uiEventCode and uiSize */
256 	if (xTraceEventBegin(uiEventCode, uiSize , &xEventHandle) == TRC_FAIL)
257 	{
258 		return TRC_FAIL;
259 	}
260 
261 	/* Add xChannel */
262 	(void)xTraceEventAddPointer(xEventHandle, (void*)xChannel);
263 
264 	/* Add all arguments */
265 	for (i = 0u; i < uiArgs; i++)
266 	{
267 		(void)xTraceEventAddUnsignedBaseType(xEventHandle, va_arg(*pxVariableList, TraceUnsignedBaseType_t));
268 	}
269 
270 	(void)xTraceEventPayloadRemaining(xEventHandle, &uiRemaining);
271 	if (uiRemaining < uiLength)
272 	{
273 		uiLength = uiRemaining - 1u; /* Make room for null termination */ /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
274 	}
275 
276 	/* Add format string */
277 	(void)xTraceEventAddString(xEventHandle, szFormat, uiLength);
278 
279 	/* Check if we can truncate */
280 	(void)xTraceEventPayloadRemaining(xEventHandle, &uiValue);
281 	if (uiValue > 0u)
282 	{
283 		(void)xTraceEventAdd8(xEventHandle, 0u);
284 	}
285 
286 	(void)xTraceEventEnd(xEventHandle); /*cstat !MISRAC2012-Rule-17.7 Suppress ignored return value check (inside macro)*/
287 
288 	return TRC_SUCCESS;
289 }
290 
291 #endif
292 
293 #endif
294 
295 #endif
296