printing available memory fails on win + mac. Disable for now until a robust way...
[openocd.git] / src / helper / log.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "log.h"
25 #include "configuration.h"
26 #include "time_support.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32
33 #define PRINT_MEM() 0
34 #if PRINT_MEM()
35 #include <malloc.h>
36 #endif
37
38 int debug_level = -1;
39
40 static FILE* log_output;
41 static log_callback_t *log_callbacks = NULL;
42
43 static long long start;
44
45 static char *log_strings[5] =
46 {
47 "User: ",
48 "Error: ",
49 "Warning:",
50 "Info: ",
51 "Debug: "
52 };
53
54 static int count = 0;
55
56 /* The log_puts() serves to somewhat different goals:
57 *
58 * - logging
59 * - feeding low-level info to the user in GDB or Telnet
60 *
61 * The latter dictates that strings without newline are not logged, lest there
62 * will be *MANY log lines when sending one char at the time(e.g.
63 * target_request.c).
64 *
65 */
66 static void log_puts(enum log_levels level, const char *file, int line, const char *function, const char *string)
67 {
68 char *f;
69 if (level == LOG_LVL_OUTPUT)
70 {
71 /* do not prepend any headers, just print out what we were given and return */
72 fputs(string, log_output);
73 fflush(log_output);
74 return;
75 }
76
77 f = strrchr(file, '/');
78 if (f != NULL)
79 file = f + 1;
80
81 if (strchr(string, '\n')!=NULL)
82 {
83 if (debug_level >= LOG_LVL_DEBUG)
84 {
85 /* print with count and time information */
86 int t=(int)(timeval_ms()-start);
87 #if PRINT_MEM()
88 struct mallinfo info;
89 info = mallinfo();
90 #endif
91 fprintf(log_output, "%s %d %d %s:%d %s()"
92 #if PRINT_MEM()
93 " %d"
94 #endif
95 ": %s", log_strings[level+1], count, t, file, line, function,
96 #if PRINT_MEM()
97 info.fordblks,
98 #endif
99 string);
100 }
101 else
102 {
103 /* do not print count and time */
104 fprintf(log_output, "%s %s:%d %s(): %s", log_strings[level+1], file, line, function, string);
105 }
106 } else
107 {
108 /* only entire lines are logged. Otherwise it's
109 * single chars intended for the log callbacks. */
110 }
111
112 fflush(log_output);
113
114 /* Never forward LOG_LVL_DEBUG, too verbose and they can be found in the log if need be */
115 if (level <= LOG_LVL_INFO)
116 {
117 log_callback_t *cb, *next;
118 cb = log_callbacks;
119 /* DANGER!!!! the log callback can remove itself!!!! */
120 while (cb)
121 {
122 next=cb->next;
123 cb->fn(cb->priv, file, line, function, string);
124 cb=next;
125 }
126 }
127 }
128
129 void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
130 {
131 char *string;
132 va_list ap;
133
134 count++;
135 if (level > debug_level)
136 return;
137
138 va_start(ap, format);
139
140 string = alloc_vprintf(format, ap);
141 if (string != NULL)
142 {
143 log_puts(level, file, line, function, string);
144 free(string);
145 }
146
147 va_end(ap);
148 }
149
150 void log_printf_lf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
151 {
152 char *string;
153 va_list ap;
154
155 count++;
156 if (level > debug_level)
157 return;
158
159 va_start(ap, format);
160
161 string = alloc_vprintf(format, ap);
162 if (string != NULL)
163 {
164 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
165 log_puts(level, file, line, function, string);
166 free(string);
167 }
168
169 va_end(ap);
170 }
171
172 /* change the current debug level on the fly
173 * 0: only ERRORS
174 * 1: + WARNINGS
175 * 2: + INFORMATIONAL MSGS
176 * 3: + DEBUG MSGS
177 */
178 int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
179 {
180 if (argc == 0)
181 command_print(cmd_ctx, "debug_level: %i", debug_level);
182
183 if (argc > 0)
184 debug_level = strtoul(args[0], NULL, 0);
185
186 if (debug_level < 0)
187 debug_level = 0;
188
189 if (debug_level > 3)
190 debug_level = 3;
191
192 return ERROR_OK;
193 }
194
195 int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
196 {
197 if (argc == 1)
198 {
199 FILE* file = fopen(args[0], "w");
200
201 if (file)
202 {
203 log_output = file;
204 }
205 }
206
207 return ERROR_OK;
208 }
209
210 int log_register_commands(struct command_context_s *cmd_ctx)
211 {
212 start = timeval_ms();
213 register_command(cmd_ctx, NULL, "log_output", handle_log_output_command,
214 COMMAND_ANY, "redirect logging to <file> (default: stderr)");
215 register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command,
216 COMMAND_ANY, "adjust debug level <0-3>");
217
218 return ERROR_OK;
219 }
220
221 int log_init(struct command_context_s *cmd_ctx)
222 {
223 /* set defaults for daemon configuration, if not set by cmdline or cfgfile */
224 if (debug_level == -1)
225 debug_level = LOG_LVL_INFO;
226
227 if (log_output == NULL)
228 {
229 log_output = stderr;
230 }
231
232 return ERROR_OK;
233 }
234
235 int set_log_output(struct command_context_s *cmd_ctx, FILE *output)
236 {
237 log_output = output;
238 return ERROR_OK;
239 }
240
241 /* add/remove log callback handler */
242 int log_add_callback(log_callback_fn fn, void *priv)
243 {
244 log_callback_t *cb;
245
246 /* prevent the same callback to be registered more than once, just for sure */
247 for (cb = log_callbacks; cb; cb = cb->next)
248 {
249 if (cb->fn == fn && cb->priv == priv)
250 return ERROR_INVALID_ARGUMENTS;
251 }
252
253 /* alloc memory, it is safe just to return in case of an error, no need for the caller to check this */
254 if ((cb = malloc(sizeof(log_callback_t))) == NULL)
255 return ERROR_BUF_TOO_SMALL;
256
257 /* add item to the beginning of the linked list */
258 cb->fn = fn;
259 cb->priv = priv;
260 cb->next = log_callbacks;
261 log_callbacks = cb;
262
263 return ERROR_OK;
264 }
265
266 int log_remove_callback(log_callback_fn fn, void *priv)
267 {
268 log_callback_t *cb, **p;
269
270 for (p = &log_callbacks; (cb = *p); p = &(*p)->next)
271 {
272 if (cb->fn == fn && cb->priv == priv)
273 {
274 *p = cb->next;
275 free(cb);
276 return ERROR_OK;
277 }
278 }
279
280 /* no such item */
281 return ERROR_INVALID_ARGUMENTS;
282 }
283
284 /* return allocated string w/printf() result */
285 char *alloc_vprintf(const char *fmt, va_list ap)
286 {
287 /* no buffer at the beginning, force realloc to do the job */
288 char *string = NULL;
289
290 /* start with buffer size suitable for typical messages */
291 int size = 128;
292
293 for (;;)
294 {
295 char *t = string;
296 va_list ap_copy;
297 int ret;
298 string = realloc(string, size);
299 if (string == NULL)
300 {
301 if (t != NULL)
302 free(t);
303 return NULL;
304 }
305
306 va_copy(ap_copy, ap);
307
308 ret = vsnprintf(string, size, fmt, ap_copy);
309 /* NB! The result of the vsnprintf() might be an *EMPTY* string! */
310 if ((ret >= 0) && ((ret + 1) < size))
311 break;
312
313 /* there was just enough or not enough space, allocate more in the next round */
314 size *= 2; /* double the buffer size */
315 }
316
317 /* the returned buffer is by principle guaranteed to be at least one character longer */
318 return string;
319 }
320
321 char *alloc_printf(const char *format, ...)
322 {
323 char *string;
324 va_list ap;
325 va_start(ap, format);
326 string = alloc_vprintf(format, ap);
327 va_end(ap);
328 return string;
329 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)