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

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)