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