mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	Import 'debug' support from OpenBSC into libosmocore
This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
				
			|||||||
osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h \
 | 
					osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h \
 | 
				
			||||||
		   tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \
 | 
							   tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \
 | 
				
			||||||
		   gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h mncc.h \
 | 
							   gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h mncc.h \
 | 
				
			||||||
		   gsm48_ie.h
 | 
							   gsm48_ie.h debug.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ENABLE_TALLOC
 | 
					if ENABLE_TALLOC
 | 
				
			||||||
osmocore_HEADERS += talloc.h
 | 
					osmocore_HEADERS += talloc.h
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										131
									
								
								include/osmocore/debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								include/osmocore/debug.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					#ifndef _OSMOCORE_DEBUG_H
 | 
				
			||||||
 | 
					#define _OSMOCORE_DEBUG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <osmocore/linuxlist.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUG_MAX_CATEGORY	32
 | 
				
			||||||
 | 
					#define DEBUG_MAX_CTX		8
 | 
				
			||||||
 | 
					#define DEBUG_MAX_FILTERS	8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG
 | 
				
			||||||
 | 
					#define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args)
 | 
				
			||||||
 | 
					#define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define DEBUGP(xss, fmt, args...)
 | 
				
			||||||
 | 
					#define DEBUGPC(ss, fmt, args...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *hexdump(const unsigned char *buf, int len);
 | 
				
			||||||
 | 
					void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* new logging interface */
 | 
				
			||||||
 | 
					#define LOGP(ss, level, fmt, args...) \
 | 
				
			||||||
 | 
						debugp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
 | 
				
			||||||
 | 
					#define LOGPC(ss, level, fmt, args...) \
 | 
				
			||||||
 | 
						debugp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* different levels */
 | 
				
			||||||
 | 
					#define LOGL_DEBUG	1	/* debugging information */
 | 
				
			||||||
 | 
					#define LOGL_INFO	3
 | 
				
			||||||
 | 
					#define LOGL_NOTICE	5	/* abnormal/unexpected condition */
 | 
				
			||||||
 | 
					#define LOGL_ERROR	7	/* error condition, requires user action */
 | 
				
			||||||
 | 
					#define LOGL_FATAL	8	/* fatal, program aborted */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUG_FILTER_ALL	0x0001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct debug_category {
 | 
				
			||||||
 | 
						uint8_t loglevel;
 | 
				
			||||||
 | 
						uint8_t enabled;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct debug_info_cat {
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
						const char *color;
 | 
				
			||||||
 | 
						const char *description;
 | 
				
			||||||
 | 
						int number;
 | 
				
			||||||
 | 
						uint8_t loglevel;
 | 
				
			||||||
 | 
						uint8_t enabled;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* debug context information, passed to filter */
 | 
				
			||||||
 | 
					struct debug_context {
 | 
				
			||||||
 | 
						void *ctx[DEBUG_MAX_CTX+1];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct debug_target;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef int debug_filter(const struct debug_context *ctx,
 | 
				
			||||||
 | 
								 struct debug_target *target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct debug_info {
 | 
				
			||||||
 | 
						/* filter callback function */
 | 
				
			||||||
 | 
						debug_filter *filter_fn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* per-category information */
 | 
				
			||||||
 | 
						const struct debug_info_cat *cat;
 | 
				
			||||||
 | 
						unsigned int num_cat;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct debug_target {
 | 
				
			||||||
 | 
					        struct llist_head entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int filter_map;
 | 
				
			||||||
 | 
						void *filter_data[DEBUG_MAX_FILTERS+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct debug_category categories[DEBUG_MAX_CATEGORY+1];
 | 
				
			||||||
 | 
						uint8_t loglevel;
 | 
				
			||||||
 | 
						int use_color:1;
 | 
				
			||||||
 | 
						int print_timestamp:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								FILE *out;
 | 
				
			||||||
 | 
							} tgt_stdout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								int priority;
 | 
				
			||||||
 | 
							} tgt_syslog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								void *vty;
 | 
				
			||||||
 | 
							} tgt_vty;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void (*output) (struct debug_target *target, const char *string);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* use the above macros */
 | 
				
			||||||
 | 
					void debugp2(unsigned int subsys, unsigned int level, char *file,
 | 
				
			||||||
 | 
						     int line, int cont, const char *format, ...)
 | 
				
			||||||
 | 
									__attribute__ ((format (printf, 6, 7)));
 | 
				
			||||||
 | 
					void debug_init(const struct debug_info *cat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* context management */
 | 
				
			||||||
 | 
					void debug_reset_context(void);
 | 
				
			||||||
 | 
					int debug_set_context(uint8_t ctx, void *value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* filter on the targets */
 | 
				
			||||||
 | 
					void debug_set_all_filter(struct debug_target *target, int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_set_use_color(struct debug_target *target, int);
 | 
				
			||||||
 | 
					void debug_set_print_timestamp(struct debug_target *target, int);
 | 
				
			||||||
 | 
					void debug_set_log_level(struct debug_target *target, int log_level);
 | 
				
			||||||
 | 
					void debug_parse_category_mask(struct debug_target *target, const char* mask);
 | 
				
			||||||
 | 
					int debug_parse_level(const char *lvl);
 | 
				
			||||||
 | 
					int debug_parse_category(const char *category);
 | 
				
			||||||
 | 
					void debug_set_category_filter(struct debug_target *target, int category,
 | 
				
			||||||
 | 
								       int enable, int level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* management of the targets */
 | 
				
			||||||
 | 
					struct debug_target *debug_target_create(void);
 | 
				
			||||||
 | 
					struct debug_target *debug_target_create_stderr(void);
 | 
				
			||||||
 | 
					void debug_add_target(struct debug_target *target);
 | 
				
			||||||
 | 
					void debug_del_target(struct debug_target *target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _OSMOCORE_DEBUG_H */
 | 
				
			||||||
@@ -9,7 +9,8 @@ lib_LTLIBRARIES = libosmocore.la
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \
 | 
					libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \
 | 
				
			||||||
			 tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \
 | 
								 tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \
 | 
				
			||||||
			 write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c
 | 
								 write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c \
 | 
				
			||||||
 | 
								 debug.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ENABLE_TALLOC
 | 
					if ENABLE_TALLOC
 | 
				
			||||||
libosmocore_la_SOURCES += talloc.c
 | 
					libosmocore_la_SOURCES += talloc.c
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										347
									
								
								src/debug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										347
									
								
								src/debug.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,347 @@
 | 
				
			|||||||
 | 
					/* Debugging/Logging support code */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License along
 | 
				
			||||||
 | 
					 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
				
			||||||
 | 
					 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocore/talloc.h>
 | 
				
			||||||
 | 
					#include <osmocore/utils.h>
 | 
				
			||||||
 | 
					#include <osmocore/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct debug_info *debug_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct debug_context debug_context;
 | 
				
			||||||
 | 
					static void *tall_dbg_ctx = NULL;
 | 
				
			||||||
 | 
					static LLIST_HEAD(target_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct value_string loglevel_strs[] = {
 | 
				
			||||||
 | 
						{ 0,		"EVERYTHING" },
 | 
				
			||||||
 | 
						{ LOGL_DEBUG,	"DEBUG" },
 | 
				
			||||||
 | 
						{ LOGL_INFO,	"INFO" },
 | 
				
			||||||
 | 
						{ LOGL_NOTICE,	"NOTICE" },
 | 
				
			||||||
 | 
						{ LOGL_ERROR,	"ERROR" },
 | 
				
			||||||
 | 
						{ LOGL_FATAL,	"FATAL" },
 | 
				
			||||||
 | 
						{ 0, NULL },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int debug_parse_level(const char *lvl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return get_string_value(loglevel_strs, lvl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int debug_parse_category(const char *category)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < debug_info->num_cat; ++i) {
 | 
				
			||||||
 | 
							if (!strcasecmp(debug_info->cat[i].name+1, category))
 | 
				
			||||||
 | 
								return debug_info->cat[i].number;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Parse the category mask.
 | 
				
			||||||
 | 
					 * The format can be this: category1:category2:category3
 | 
				
			||||||
 | 
					 * or category1,2:category2,3:...
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void debug_parse_category_mask(struct debug_target* target, const char *_mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						char *mask = strdup(_mask);
 | 
				
			||||||
 | 
						char *category_token = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable everything to enable it afterwards */
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
 | 
				
			||||||
 | 
							target->categories[i].enabled = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						category_token = strtok(mask, ":");
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							for (i = 0; i < debug_info->num_cat; ++i) {
 | 
				
			||||||
 | 
								char* colon = strstr(category_token, ",");
 | 
				
			||||||
 | 
								int length = strlen(category_token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (colon)
 | 
				
			||||||
 | 
								    length = colon - category_token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (strncasecmp(debug_info->cat[i].name, category_token,
 | 
				
			||||||
 | 
										length) == 0) {
 | 
				
			||||||
 | 
									int number = debug_info->cat[i].number;
 | 
				
			||||||
 | 
									int level = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (colon)
 | 
				
			||||||
 | 
										level = atoi(colon+1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									target->categories[number].enabled = 1;
 | 
				
			||||||
 | 
									target->categories[number].loglevel = level;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} while ((category_token = strtok(NULL, ":")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(mask);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char* color(int subsys)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < debug_info->num_cat; ++i) {
 | 
				
			||||||
 | 
							if (debug_info->cat[i].number == subsys)
 | 
				
			||||||
 | 
								return debug_info->cat[i].color;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void _output(struct debug_target *target, unsigned int subsys,
 | 
				
			||||||
 | 
							    char *file, int line, int cont, const char *format,
 | 
				
			||||||
 | 
							    va_list ap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char col[30];
 | 
				
			||||||
 | 
						char sub[30];
 | 
				
			||||||
 | 
						char tim[30];
 | 
				
			||||||
 | 
						char buf[4096];
 | 
				
			||||||
 | 
						char final[4096];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* prepare the data */
 | 
				
			||||||
 | 
						col[0] = '\0';
 | 
				
			||||||
 | 
						sub[0] = '\0';
 | 
				
			||||||
 | 
						tim[0] = '\0';
 | 
				
			||||||
 | 
						buf[0] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* are we using color */
 | 
				
			||||||
 | 
						if (target->use_color) {
 | 
				
			||||||
 | 
							snprintf(col, sizeof(col), "%s", color(subsys));
 | 
				
			||||||
 | 
							col[sizeof(col)-1] = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						vsnprintf(buf, sizeof(buf), format, ap);
 | 
				
			||||||
 | 
						buf[sizeof(buf)-1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!cont) {
 | 
				
			||||||
 | 
							if (target->print_timestamp) {
 | 
				
			||||||
 | 
								char *timestr;
 | 
				
			||||||
 | 
								time_t tm;
 | 
				
			||||||
 | 
								tm = time(NULL);
 | 
				
			||||||
 | 
								timestr = ctime(&tm);
 | 
				
			||||||
 | 
								timestr[strlen(timestr)-1] = '\0';
 | 
				
			||||||
 | 
								snprintf(tim, sizeof(tim), "%s ", timestr);
 | 
				
			||||||
 | 
								tim[sizeof(tim)-1] = '\0';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line);
 | 
				
			||||||
 | 
							sub[sizeof(sub)-1] = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf);
 | 
				
			||||||
 | 
						final[sizeof(final)-1] = '\0';
 | 
				
			||||||
 | 
						target->output(target, final);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void _debugp(unsigned int subsys, int level, char *file, int line,
 | 
				
			||||||
 | 
							    int cont, const char *format, va_list ap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct debug_target *tar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(tar, &target_list, entry) {
 | 
				
			||||||
 | 
							struct debug_category *category;
 | 
				
			||||||
 | 
							int output = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							category = &tar->categories[subsys];
 | 
				
			||||||
 | 
							/* subsystem is not supposed to be debugged */
 | 
				
			||||||
 | 
							if (!category->enabled)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Check the global log level */
 | 
				
			||||||
 | 
							if (tar->loglevel != 0 && level < tar->loglevel)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Check the category log level */
 | 
				
			||||||
 | 
							if (tar->loglevel == 0 && category->loglevel != 0 &&
 | 
				
			||||||
 | 
							    level < category->loglevel)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Apply filters here... if that becomes messy we will
 | 
				
			||||||
 | 
							 * need to put filters in a list and each filter will
 | 
				
			||||||
 | 
							 * say stop, continue, output */
 | 
				
			||||||
 | 
							if ((tar->filter_map & DEBUG_FILTER_ALL) != 0)
 | 
				
			||||||
 | 
								output = 1;
 | 
				
			||||||
 | 
							else if (debug_info->filter_fn)
 | 
				
			||||||
 | 
								output = debug_info->filter_fn(&debug_context,
 | 
				
			||||||
 | 
											       tar);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (output) {
 | 
				
			||||||
 | 
								/* FIXME: copying the va_list is an ugly
 | 
				
			||||||
 | 
								 * workaround against a bug hidden somewhere in
 | 
				
			||||||
 | 
								 * _output.  If we do not copy here, the first
 | 
				
			||||||
 | 
								 * call to _output() will corrupt the va_list
 | 
				
			||||||
 | 
								 * contents, and any further _output() calls
 | 
				
			||||||
 | 
								 * with the same va_list will segfault */
 | 
				
			||||||
 | 
								va_list bp;
 | 
				
			||||||
 | 
								va_copy(bp, ap);
 | 
				
			||||||
 | 
								_output(tar, subsys, file, line, cont, format, bp);
 | 
				
			||||||
 | 
								va_end(bp);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debugp(unsigned int subsys, char *file, int line, int cont,
 | 
				
			||||||
 | 
						    const char *format, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, format);
 | 
				
			||||||
 | 
						_debugp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, format);
 | 
				
			||||||
 | 
						_debugp(subsys, level, file, line, cont, format, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char hexd_buff[4096];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *hexdump(const unsigned char *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						char *cur = hexd_buff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hexd_buff[0] = 0;
 | 
				
			||||||
 | 
						for (i = 0; i < len; i++) {
 | 
				
			||||||
 | 
							int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
 | 
				
			||||||
 | 
							int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
 | 
				
			||||||
 | 
							if (rc <= 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							cur += rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						hexd_buff[sizeof(hexd_buff)-1] = 0;
 | 
				
			||||||
 | 
						return hexd_buff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_add_target(struct debug_target *target)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_add_tail(&target->entry, &target_list);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_del_target(struct debug_target *target)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_del(&target->entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_reset_context(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						memset(&debug_context, 0, sizeof(debug_context));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int debug_set_context(uint8_t ctx_nr, void *value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (ctx_nr > DEBUG_MAX_CTX)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						debug_context.ctx[ctx_nr] = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_set_all_filter(struct debug_target *target, int all)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (all)
 | 
				
			||||||
 | 
							target->filter_map |= DEBUG_FILTER_ALL;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							target->filter_map &= ~DEBUG_FILTER_ALL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_set_use_color(struct debug_target *target, int use_color)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						target->use_color = use_color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_set_print_timestamp(struct debug_target *target, int print_timestamp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						target->print_timestamp = print_timestamp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_set_log_level(struct debug_target *target, int log_level)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						target->loglevel = log_level;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_set_category_filter(struct debug_target *target, int category,
 | 
				
			||||||
 | 
								       int enable, int level)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (category >= debug_info->num_cat)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						target->categories[category].enabled = !!enable;
 | 
				
			||||||
 | 
						target->categories[category].loglevel = level;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void _stderr_output(struct debug_target *target, const char *log)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fprintf(target->tgt_stdout.out, "%s", log);
 | 
				
			||||||
 | 
						fflush(target->tgt_stdout.out);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct debug_target *debug_target_create(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct debug_target *target;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						target = talloc_zero(tall_dbg_ctx, struct debug_target);
 | 
				
			||||||
 | 
						if (!target)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&target->entry);
 | 
				
			||||||
 | 
						memcpy(target->categories, debug_info->cat,
 | 
				
			||||||
 | 
							sizeof(struct debug_category)*debug_info->num_cat);
 | 
				
			||||||
 | 
						target->use_color = 1;
 | 
				
			||||||
 | 
						target->print_timestamp = 0;
 | 
				
			||||||
 | 
						target->loglevel = 0;
 | 
				
			||||||
 | 
						return target;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct debug_target *debug_target_create_stderr(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct debug_target *target;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						target = debug_target_create();
 | 
				
			||||||
 | 
						if (!target)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						target->tgt_stdout.out = stderr;
 | 
				
			||||||
 | 
						target->output = _stderr_output;
 | 
				
			||||||
 | 
						return target;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void debug_init(const struct debug_info *cat)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						tall_dbg_ctx = talloc_named_const(NULL, 1, "debug");
 | 
				
			||||||
 | 
						debug_info = cat;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user