xref: /optee_os/lib/libutils/ext/trace.c (revision d1d226a5264ce5654695edc656ef759fc48f675f)
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 <stdio.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <trace.h>
32 #include <util.h>
33 
34 #if (CFG_TRACE_LEVEL != 0)
35 
36 #if (CFG_TRACE_LEVEL < TRACE_MIN) || (CFG_TRACE_LEVEL > TRACE_MAX)
37 #error "Invalid value of CFG_TRACE_LEVEL"
38 #endif
39 static int trace_level = CFG_TRACE_LEVEL;
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)
55 {
56 	static const char lvl_strs[][4] = {
57 		"UKN", "ERR", "INF", "DBG", "FLW" };
58 	int l = 0;
59 
60 	if (l >= TRACE_MIN || l <= TRACE_MAX)
61 		l = level;
62 
63 	return lvl_strs[l];
64 }
65 
66 /* Format trace of user ta. Inline with kernel ta */
67 void trace_printf(const char *function, int line, int level, bool sync,
68 		const char *fmt, ...)
69 {
70 	va_list ap;
71 	char buf[MAX_PRINT_SIZE];
72 	size_t boffs = 0;
73 	int res;
74 
75 	if (level > trace_level)
76 		return;
77 
78 	if (function) {
79 		int thread_id = trace_ext_get_thread_id();
80 
81 		if (thread_id >= 0)
82 			res = snprintf(buf, sizeof(buf), "%s [0x%x] %s:%s:%d: ",
83 				       trace_level_to_string(level), thread_id,
84 				       trace_ext_prefix, function, line);
85 		else
86 			res = snprintf(buf, sizeof(buf), "%s %s:%s:%d: ",
87 				       trace_level_to_string(level),
88 				       trace_ext_prefix, function, line);
89 		if (res < 0)
90 			return; /* "Can't happen" */
91 		boffs = res;
92 	}
93 
94 	va_start(ap, fmt);
95 	res = vsnprintf(buf + boffs, sizeof(buf) - boffs, fmt, ap);
96 	va_end(ap);
97 	if (res > 0)
98 		boffs += res;
99 
100 	if (boffs >= sizeof(buf)) {
101 		boffs = sizeof(buf) - 2;
102 		/* Make there's a newline at the end */
103 		buf[boffs] = '\n';
104 	} else if (buf[boffs - 1] != '\n') {
105 		/* Append a newline */
106 		buf[boffs] = '\n';
107 		buf[boffs + 1] = '\0';
108 	}
109 
110 	trace_ext_puts(sync, buf);
111 }
112 #endif
113 
114 #if (CFG_TRACE_LEVEL >= TRACE_DEBUG)
115 struct strbuf {
116 	char buf[MAX_PRINT_SIZE];
117 	char *ptr;
118 };
119 
120 static int __printf(2, 3) append(struct strbuf *sbuf, const char *fmt, ...)
121 {
122 	int left;
123 	int len;
124 	va_list ap;
125 
126 	if (sbuf->ptr == NULL)
127 		sbuf->ptr = sbuf->buf;
128 	left = sizeof(sbuf->buf) - (sbuf->ptr - sbuf->buf);
129 	va_start(ap, fmt);
130 	len = vsnprintf(sbuf->ptr, left, fmt, ap);
131 	va_end(ap);
132 	if (len < 0) {
133 		/* Format error */
134 		return 0;
135 	}
136 	if (len >= left) {
137 		/* Output was truncated */
138 		return 0;
139 	}
140 	sbuf->ptr += MIN(left, len);
141 	return 1;
142 }
143 
144 void dhex_dump(const char *function, int line, int level,
145 	       const void *buf, int len)
146 {
147 	int i;
148 	int ok;
149 	struct strbuf sbuf;
150 	char *in = (char *)buf;
151 
152 	if (level <= trace_level) {
153 		sbuf.ptr = NULL;
154 		for (i = 0; i < len; i++) {
155 			ok = append(&sbuf, "%02x ", in[i]);
156 			if (!ok)
157 				goto err;
158 			if ((i % 16) == 7) {
159 				ok = append(&sbuf, " ");
160 				if (!ok)
161 					goto err;
162 			} else if ((i % 16) == 15) {
163 				trace_printf(function, line, level, false,
164 					      "%s", sbuf.buf);
165 				sbuf.ptr = NULL;
166 			}
167 		}
168 		if (sbuf.ptr) {
169 			/* Buffer is not empty: flush it */
170 			trace_printf(function, line, level, false, "%s",
171 				      sbuf.buf);
172 
173 		}
174 	}
175 	return;
176 err:
177 	DMSG("Hex dump error");
178 }
179 #endif
180