| /* | |
| * debug.c | |
| * | |
| * Copyright (C) 2004 - 2018 Vladislav Bolkhovitin <vst@vlnb.net> | |
| * Copyright (C) 2004 - 2005 Leonid Stoljar | |
| * Copyright (C) 2007 - 2018 Western Digital Corporation | |
| * | |
| * Contains helper functions for execution tracing and error reporting. | |
| * Intended to be included in main .c file. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License | |
| * as published by the Free Software Foundation, version 2 | |
| * of the License. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| */ | |
| #include <stdio.h> | |
| #include <time.h> | |
| #include <pthread.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <sys/syscall.h> | |
| #include "debug.h" | |
| pid_t gettid(void) | |
| { | |
| return syscall(__NR_gettid); | |
| } | |
| #if defined(DEBUG) || defined(TRACING) | |
| #define TRACE_BUF_SIZE 512 | |
| static char trace_buf[TRACE_BUF_SIZE]; | |
| static pthread_spinlock_t trace_buf_lock; | |
| int debug_print_prefix(unsigned long trace_flag, const char *prefix, | |
| const char *func, int line) | |
| { | |
| int i = 0; | |
| pthread_spin_lock(&trace_buf_lock); | |
| if (trace_flag & TRACE_TIME) { | |
| struct tm t; | |
| time_t tt; | |
| time(&tt); | |
| localtime_r(&tt, &t); | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%d:%d:%d ", | |
| t.tm_hour, t.tm_min, t.tm_sec); | |
| } | |
| if (trace_flag & TRACE_PID) | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "[%d]: ", | |
| gettid()); | |
| if (prefix != NULL) | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", prefix); | |
| if (trace_flag & TRACE_FUNCTION) | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", func); | |
| if (trace_flag & TRACE_LINE) | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%i:", line); | |
| if (i > 0) | |
| PRINTN(LOG_INFO, "%s", trace_buf); | |
| pthread_spin_unlock(&trace_buf_lock); | |
| return i; | |
| } | |
| void debug_print_buffer(const void *data, int len) | |
| { | |
| int z, z1, i; | |
| const unsigned char *buf = (const unsigned char *) data; | |
| int f = 0; | |
| if (buf == NULL) | |
| return; | |
| pthread_spin_lock(&trace_buf_lock); | |
| PRINT(LOG_INFO, " (h)___0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F"); | |
| for (z = 0, z1 = 0, i = 0; z < len; z++) { | |
| if (z % 16 == 0) { | |
| if (z != 0) { | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, | |
| " "); | |
| for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1); | |
| z1++) { | |
| if ((buf[z1] >= 0x20) && | |
| (buf[z1] < 0x80)) | |
| trace_buf[i++] = buf[z1]; | |
| else | |
| trace_buf[i++] = '.'; | |
| } | |
| trace_buf[i] = '\0'; | |
| PRINT(LOG_INFO, "%s", trace_buf); | |
| i = 0; | |
| f = 1; | |
| } | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, | |
| "%4x: ", z); | |
| } | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%02x ", | |
| buf[z]); | |
| } | |
| i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, " "); | |
| for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1); z1++) { | |
| if ((buf[z1] > 0x20) && (buf[z1] < 0x80)) | |
| trace_buf[i++] = buf[z1]; | |
| else | |
| trace_buf[i++] = '.'; | |
| } | |
| trace_buf[i] = '\0'; | |
| if (f) | |
| PRINT(LOG_INFO, "%s", trace_buf); | |
| else | |
| PRINT(LOG_INFO, "%s", trace_buf); | |
| pthread_spin_unlock(&trace_buf_lock); | |
| } | |
| int debug_init(void) | |
| { | |
| int res; | |
| res = pthread_spin_init(&trace_buf_lock, PTHREAD_PROCESS_PRIVATE); | |
| if (res != 0) { | |
| res = errno; | |
| PRINT_ERROR("pthread_spin_init() failed: %s", strerror(res)); | |
| } | |
| return res; | |
| } | |
| void debug_done(void) | |
| { | |
| pthread_spin_destroy(&trace_buf_lock); | |
| } | |
| #endif /* DEBUG || TRACING */ |