1
2
3
13
14
15
16
17
18
27
28
33
34
35
36
37
38
39
40
41
42
43
44
52
53
54
55
56
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
92
93
99
100
101
102
103
104
105
106
107
108
110
111
112
113
114
115
116
117
118
119
120
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
208
209
210
211
212
213
214
215
216
217
218
219
220
221
232
233
237
238
239
240
241
242
249
250
251
252
253
254
255
256
257
258
259
260
261
262
266
267
268
269
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
295
296
297
298
299
300
301
302
306
307
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
425
426
427
428
429
430
431
432
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
478
479
480
481
482
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
501
502
503
504
508
/* ... */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "log.h"
#include "command.h"
#include "replacements.h"
#include "time_support.h"
#include <server/gdb_server.h>
#include <server/server.h>
#include <stdarg.h>
7 includes
#ifdef _DEBUG_FREE_SPACE_
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#else
#error "malloc.h is required to use --enable-malloc-logging"
#endif/* ... */
#endif
int debug_level = LOG_LVL_INFO;
static FILE *log_output;
static struct log_callback *log_callbacks;
static int64_t last_time;
static int64_t start;
static const char * const log_strings[6] = {
"User : ",
"Error: ",
"Warn : ",
"Info : ",
"Debug: ",
"Debug: "
...};
static int count;
static void log_forward(const char *file, unsigned line, const char *function, const char *string)
{
struct log_callback *cb, *next;
cb = log_callbacks;
while (cb) {
next = cb->next;
cb->fn(cb->priv, file, line, function, string);
cb = next;
}while (cb) { ... }
}{ ... }
/* ... */
static void log_puts(enum log_levels level,
const char *file,
int line,
const char *function,
const char *string)
{
char *f;
if (!log_output) {
fputs(string, stderr);
fflush(stderr);
return;
}if (!log_output) { ... }
if (level == LOG_LVL_OUTPUT) {
fputs(string, log_output);
fflush(log_output);
return;
}if (level == LOG_LVL_OUTPUT) { ... }
f = strrchr(file, '/');
if (f)
file = f + 1;
if (debug_level >= LOG_LVL_DEBUG) {
int64_t t = timeval_ms() - start;
#ifdef _DEBUG_FREE_SPACE_
struct mallinfo info;
info = mallinfo();/* ... */
#endif
fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()"
#ifdef _DEBUG_FREE_SPACE_
" %d"
#endif
": %s", log_strings[level + 1], count, t, file, line, function,
#ifdef _DEBUG_FREE_SPACE_
info.fordblks,
#endif
string);
}if (debug_level >= LOG_LVL_DEBUG) { ... } else {
/* ... */
fprintf(log_output, "%s%s",
(level > LOG_LVL_USER) ? log_strings[level + 1] : "", string);
}else { ... }
fflush(log_output);
if (level <= LOG_LVL_INFO)
log_forward(file, line, function, string);
}{ ... }
void log_printf(enum log_levels level,
const char *file,
unsigned line,
const char *function,
const char *format,
...)
{
char *string;
va_list ap;
count++;
if (level > debug_level)
return;
va_start(ap, format);
string = alloc_vprintf(format, ap);
if (string) {
log_puts(level, file, line, function, string);
free(string);
}if (string) { ... }
va_end(ap);
}{ ... }
void log_vprintf_lf(enum log_levels level, const char *file, unsigned line,
const char *function, const char *format, va_list args)
{
char *tmp;
count++;
if (level > debug_level)
return;
tmp = alloc_vprintf(format, args);
if (!tmp)
return;
/* ... */
strcat(tmp, "\n");
log_puts(level, file, line, function, tmp);
free(tmp);
}{ ... }
void log_printf_lf(enum log_levels level,
const char *file,
unsigned line,
const char *function,
const char *format,
...)
{
va_list ap;
va_start(ap, format);
log_vprintf_lf(level, file, line, function, format, ap);
va_end(ap);
}{ ... }
COMMAND_HANDLER(handle_debug_level_command)
{
if (CMD_ARGC == 1) {
int new_level;
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level);
if ((new_level > LOG_LVL_DEBUG_IO) || (new_level < LOG_LVL_SILENT)) {
LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO);
return ERROR_COMMAND_SYNTAX_ERROR;
}if ((new_level > LOG_LVL_DEBUG_IO) || (new_level < LOG_LVL_SILENT)) { ... }
debug_level = new_level;
}if (CMD_ARGC == 1) { ... } else if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD, "debug_level: %i", debug_level);
return ERROR_OK;
}{ ... }
COMMAND_HANDLER(handle_log_output_command)
{
if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
FILE *file;
if (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") != 0) {
file = fopen(CMD_ARGV[0], "w");
if (!file) {
command_print(CMD, "failed to open output log \"%s\"", CMD_ARGV[0]);
return ERROR_FAIL;
}if (!file) { ... }
command_print(CMD, "set log_output to \"%s\"", CMD_ARGV[0]);
}if (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") != 0) { ... } else {
file = stderr;
command_print(CMD, "set log_output to default");
}else { ... }
if (log_output != stderr && log_output) {
fclose(log_output);
}if (log_output != stderr && log_output) { ... }
log_output = file;
return ERROR_OK;
}{ ... }
static const struct command_registration log_command_handlers[] = {
{
.name = "log_output",
.handler = handle_log_output_command,
.mode = COMMAND_ANY,
.help = "redirect logging to a file (default: stderr)",
.usage = "[file_name | 'default']",
...},
{
.name = "debug_level",
.handler = handle_debug_level_command,
.mode = COMMAND_ANY,
.help = "Sets the verbosity level of debugging output. "
"0 shows errors only; 1 adds warnings; "
"2 (default) adds other info; 3 adds debugging; "
"4 adds extra verbose debugging.",
.usage = "number",
...},
COMMAND_REGISTRATION_DONE
...};
int log_register_commands(struct command_context *cmd_ctx)
{
return register_commands(cmd_ctx, NULL, log_command_handlers);
}{ ... }
void log_init(void)
{
/* ... */
char *debug_env = getenv("OPENOCD_DEBUG_LEVEL");
if (debug_env) {
int value;
int retval = parse_int(debug_env, &value);
if (retval == ERROR_OK &&
debug_level >= LOG_LVL_SILENT &&
debug_level <= LOG_LVL_DEBUG_IO)
debug_level = value;
}if (debug_env) { ... }
if (!log_output)
log_output = stderr;
start = last_time = timeval_ms();
}{ ... }
void log_exit(void)
{
if (log_output && log_output != stderr) {
fclose(log_output);
}if (log_output && log_output != stderr) { ... }
log_output = NULL;
}{ ... }
int log_add_callback(log_callback_fn fn, void *priv)
{
struct log_callback *cb;
for (cb = log_callbacks; cb; cb = cb->next) {
if (cb->fn == fn && cb->priv == priv)
return ERROR_COMMAND_SYNTAX_ERROR;
}for (cb = log_callbacks; cb; cb = cb->next) { ... }
/* ... */
cb = malloc(sizeof(struct log_callback));
if (!cb)
return ERROR_BUF_TOO_SMALL;
cb->fn = fn;
cb->priv = priv;
cb->next = log_callbacks;
log_callbacks = cb;
return ERROR_OK;
}{ ... }
int log_remove_callback(log_callback_fn fn, void *priv)
{
struct log_callback *cb, **p;
for (p = &log_callbacks; (cb = *p); p = &(*p)->next) {
if (cb->fn == fn && cb->priv == priv) {
*p = cb->next;
free(cb);
return ERROR_OK;
}if (cb->fn == fn && cb->priv == priv) { ... }
}for (p = &log_callbacks; (cb = *p); p = &(*p)->next) { ... }
return ERROR_COMMAND_SYNTAX_ERROR;
}{ ... }
char *alloc_vprintf(const char *fmt, va_list ap)
{
va_list ap_copy;
int len;
char *string;
va_copy(ap_copy, ap);
len = vsnprintf(NULL, 0, fmt, ap_copy);
va_end(ap_copy);
/* ... */
string = malloc(len + 2);
if (!string)
return NULL;
vsnprintf(string, len + 1, fmt, ap);
return string;
}{ ... }
char *alloc_printf(const char *format, ...)
{
char *string;
va_list ap;
va_start(ap, format);
string = alloc_vprintf(format, ap);
va_end(ap);
return string;
}{ ... }
/* ... */
#define KEEP_ALIVE_KICK_TIME_MS 500
#define KEEP_ALIVE_TIMEOUT_MS 1000
static void gdb_timeout_warning(int64_t delta_time)
{
if (gdb_get_actual_connections())
LOG_WARNING("keep_alive() was not invoked in the "
"%d ms timelimit. GDB alive packet not "
"sent! (%" PRId64 " ms). Workaround: increase "
"\"set remotetimeout\" in GDB",
KEEP_ALIVE_TIMEOUT_MS,
delta_time);
else
LOG_DEBUG("keep_alive() was not invoked in the "
"%d ms timelimit (%" PRId64 " ms). This may cause "
"trouble with GDB connections.",
KEEP_ALIVE_TIMEOUT_MS,
delta_time);
}{ ... }
void keep_alive(void)
{
int64_t current_time = timeval_ms();
int64_t delta_time = current_time - last_time;
if (delta_time > KEEP_ALIVE_TIMEOUT_MS) {
last_time = current_time;
gdb_timeout_warning(delta_time);
}if (delta_time > KEEP_ALIVE_TIMEOUT_MS) { ... }
if (delta_time > KEEP_ALIVE_KICK_TIME_MS) {
last_time = current_time;
server_keep_clients_alive();
/* ... */
}if (delta_time > KEEP_ALIVE_KICK_TIME_MS) { ... }
}{ ... }
void kept_alive(void)
{
int64_t current_time = timeval_ms();
int64_t delta_time = current_time - last_time;
last_time = current_time;
if (delta_time > KEEP_ALIVE_TIMEOUT_MS)
gdb_timeout_warning(delta_time);
}{ ... }
void alive_sleep(uint64_t ms)
{
uint64_t nap_time = 10;
for (uint64_t i = 0; i < ms; i += nap_time) {
uint64_t sleep_a_bit = ms - i;
if (sleep_a_bit > nap_time)
sleep_a_bit = nap_time;
usleep(sleep_a_bit * 1000);
keep_alive();
}for (uint64_t i = 0; i < ms; i += nap_time) { ... }
}{ ... }
void busy_sleep(uint64_t ms)
{
uint64_t then = timeval_ms();
while (timeval_ms() - then < ms) {
/* ... */
}while (timeval_ms() - then < ms) { ... }
}{ ... }
#define MAX_SOCKET_ERR_MSG_LENGTH 256
/* ... */
void log_socket_error(const char *socket_desc)
{
int error_code;
#ifdef _WIN32
error_code = WSAGetLastError();
char error_message[MAX_SOCKET_ERR_MSG_LENGTH];
error_message[0] = '\0';
DWORD retval = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, 0,
error_message, MAX_SOCKET_ERR_MSG_LENGTH, NULL);
error_message[MAX_SOCKET_ERR_MSG_LENGTH - 1] = '\0';
const bool have_message = (retval != 0) && (error_message[0] != '\0');
LOG_ERROR("Error on socket '%s': WSAGetLastError==%d%s%s.", socket_desc, error_code,
(have_message ? ", message: " : ""),
(have_message ? error_message : ""));/* ... */
#else
error_code = errno;
LOG_ERROR("Error on socket '%s': errno==%d, message: %s.", socket_desc, error_code, strerror(error_code));/* ... */
#endif
}{ ... }
/* ... */
char *find_nonprint_char(char *buf, unsigned buf_len)
{
for (unsigned int i = 0; i < buf_len; i++) {
if (!isprint(buf[i]))
return buf + i;
}for (unsigned int i = 0; i < buf_len; i++) { ... }
return NULL;
}{ ... }