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