xref: /optee_os/lib/libutils/ext/trace.c (revision a50cb361d9e5735f197ccc87beb0d24af8315369)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <printk.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <trace.h>
32 #include <util.h>
33 #include <types_ext.h>
34 
35 #if (TRACE_LEVEL > 0)
36 
37 #if (TRACE_LEVEL < TRACE_MIN) || (TRACE_LEVEL > TRACE_MAX)
38 #error "Invalid value of TRACE_LEVEL"
39 #endif
40 
41 void trace_set_level(int level)
42 {
43 	if (((int)level >= TRACE_MIN) && (level <= TRACE_MAX))
44 		trace_level = level;
45 	else
46 		trace_level = TRACE_MAX;
47 }
48 
49 int trace_get_level(void)
50 {
51 	return trace_level;
52 }
53 
54 static const char *trace_level_to_string(int level, bool level_ok)
55 {
56 	static const char lvl_strs[][9] = {
57 		"UNKNOWN:", "ERROR:  ", "INFO:   ", "DEBUG:  ",
58 		"FLOW:   " };
59 	int l = 0;
60 
61 	if (!level_ok)
62 		return "MESSAGE:";
63 
64 	if ((level >= TRACE_MIN) && (level <= TRACE_MAX))
65 		l = level;
66 
67 	return lvl_strs[l];
68 }
69 
70 /* Format trace of user ta. Inline with kernel ta */
71 void trace_printf(const char *function, int line, int level, bool level_ok,
72 		  const char *fmt, ...)
73 {
74 	va_list ap;
75 	char buf[MAX_PRINT_SIZE];
76 	size_t boffs = 0;
77 	int res;
78 	int thread_id;
79 
80 	if (level_ok && level > trace_level)
81 		return;
82 
83 	res = snprintk(buf, sizeof(buf), "%s ",
84 		       trace_level_to_string(level, level_ok));
85 	if (res < 0)
86 		return;
87 	boffs += res;
88 
89 	if (level_ok && level < CFG_MSG_LONG_PREFIX_THRESHOLD)
90 		thread_id = -1;
91 	else
92 		thread_id = trace_ext_get_thread_id();
93 
94 	if (thread_id >= 0) {
95 		res = snprintk(buf + boffs, sizeof(buf) - boffs, "[0x%x] ",
96 			       thread_id);
97 		if (res < 0)
98 			return;
99 		boffs += res;
100 	}
101 
102 	res = snprintk(buf + boffs, sizeof(buf) - boffs, "%s:",
103 		       trace_ext_prefix);
104 	if (res < 0)
105 		return;
106 	boffs += res;
107 
108 	if (level_ok && level < CFG_MSG_LONG_PREFIX_THRESHOLD)
109 		function = NULL;
110 
111 	if (function) {
112 		res = snprintk(buf + boffs, sizeof(buf) - boffs, "%s:%d:",
113 			       function, line);
114 		if (res < 0)
115 			return;
116 		boffs += res;
117 	}
118 
119 	res = snprintk(buf + boffs, sizeof(buf) - boffs, " ");
120 	if (res < 0)
121 		return;
122 	boffs += res;
123 
124 	va_start(ap, fmt);
125 	res = vsnprintk(buf + boffs, sizeof(buf) - boffs, fmt, ap);
126 	va_end(ap);
127 	if (res > 0)
128 		boffs += res;
129 
130 	if (boffs >= (sizeof(buf) - 1))
131 		boffs = sizeof(buf) - 2;
132 
133 	buf[boffs] = '\n';
134 	while (boffs && buf[boffs] == '\n')
135 		boffs--;
136 	boffs++;
137 	buf[boffs + 1] = '\0';
138 
139 	trace_ext_puts(buf);
140 }
141 
142 #else
143 
144 /*
145  * In case we have a zero or negative trace level when compiling optee_os, we
146  * have to add stubs to trace functions in case they are used with TA having a
147  * non-zero trace level
148  */
149 
150 void trace_set_level(int level __unused)
151 {
152 }
153 
154 int trace_get_level(void)
155 {
156 	return 0;
157 }
158 
159 void trace_printf(const char *function __unused, int line __unused,
160 		  int level __unused, bool level_ok __unused,
161 		  const char *fmt __unused, ...)
162 {
163 }
164 
165 #endif
166 
167 #if (TRACE_LEVEL >= TRACE_DEBUG)
168 struct strbuf {
169 	char buf[MAX_PRINT_SIZE];
170 	char *ptr;
171 };
172 
173 static int __printf(2, 3) append(struct strbuf *sbuf, const char *fmt, ...)
174 {
175 	int left;
176 	int len;
177 	va_list ap;
178 
179 	if (sbuf->ptr == NULL)
180 		sbuf->ptr = sbuf->buf;
181 	left = sizeof(sbuf->buf) - (sbuf->ptr - sbuf->buf);
182 	va_start(ap, fmt);
183 	len = vsnprintk(sbuf->ptr, left, fmt, ap);
184 	va_end(ap);
185 	if (len < 0) {
186 		/* Format error */
187 		return 0;
188 	}
189 	if (len >= left) {
190 		/* Output was truncated */
191 		return 0;
192 	}
193 	sbuf->ptr += MIN(left, len);
194 	return 1;
195 }
196 
197 #define PRIxVA_WIDTH ((int)(sizeof(vaddr_t)*2))
198 
199 void dhex_dump(const char *function, int line, int level,
200 	       const void *buf, int len)
201 {
202 	int i;
203 	int ok;
204 	struct strbuf sbuf;
205 	char *in = (char *)buf;
206 
207 	if (level <= trace_level) {
208 		sbuf.ptr = NULL;
209 		for (i = 0; i < len; i++) {
210 			if ((i % 16) == 0) {
211 				ok = append(&sbuf, "%0*" PRIxVA "  ",
212 					    PRIxVA_WIDTH, (vaddr_t)(in + i));
213 				if (!ok)
214 					goto err;
215 			}
216 			ok = append(&sbuf, "%02x ", in[i]);
217 			if (!ok)
218 				goto err;
219 			if ((i % 16) == 7) {
220 				ok = append(&sbuf, " ");
221 				if (!ok)
222 					goto err;
223 			} else if ((i % 16) == 15) {
224 				trace_printf(function, line, level, true, "%s",
225 					     sbuf.buf);
226 				sbuf.ptr = NULL;
227 			}
228 		}
229 		if (sbuf.ptr) {
230 			/* Buffer is not empty: flush it */
231 			trace_printf(function, line, level, true, "%s",
232 				     sbuf.buf);
233 
234 		}
235 	}
236 	return;
237 err:
238 	DMSG("Hex dump error");
239 }
240 #else
241 
242 /*
243  * In case we have trace level less than debug when compiling optee_os, we have
244  * to add stubs to trace functions in case they are used with TA having a
245  * a higher trace level
246  */
247 
248 void dhex_dump(const char *function __unused, int line __unused,
249 	       int level __unused,
250 	       const void *buf __unused, int len __unused)
251 {
252 }
253 
254 #endif
255