18ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
28ba0b6e1STyler Dauwalder//  This software is part of the OpenBeOS distribution and is covered
3b6f76ebeSAugustin Cavalier//  by the MIT License.
48ba0b6e1STyler Dauwalder//
58ba0b6e1STyler Dauwalder//  This version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
68ba0b6e1STyler Dauwalder//  Initial version copyright (c) 2002 Axel D��rfler, axeld@pinc-software.de
78ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
88ba0b6e1STyler Dauwalder
98ba0b6e1STyler Dauwalder/*! \file Debug.cpp
108ba0b6e1STyler Dauwalder
118ba0b6e1STyler Dauwalder	Support code for handy debugging macros.
128ba0b6e1STyler Dauwalder*/
138ba0b6e1STyler Dauwalder
148ba0b6e1STyler Dauwalder#include "Debug.h"
158ba0b6e1STyler Dauwalder
168ba0b6e1STyler Dauwalder#include <KernelExport.h>
178ba0b6e1STyler Dauwalder#include <TLS.h>
188ba0b6e1STyler Dauwalder
191c4552a2SAxel Dörfler#include <string.h>
201c4552a2SAxel Dörfler
218ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
228ba0b6e1STyler Dauwalder// Long-winded overview of the debug output macros:
238ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
248ba0b6e1STyler Dauwalder/*! \def DEBUG_INIT()
258ba0b6e1STyler Dauwalder	\brief Increases the indentation level, prints out the enclosing function's
268ba0b6e1STyler Dauwalder	name, and creates a \c DebugHelper object on the stack to automatically
278ba0b6e1STyler Dauwalder	decrease the indentation level upon function exit.
288ba0b6e1STyler Dauwalder
298ba0b6e1STyler Dauwalder	This macro should be called at the very beginning of any function in
308ba0b6e1STyler Dauwalder	which you wish to use any of the other debugging macros.
318ba0b6e1STyler Dauwalder
328ba0b6e1STyler Dauwalder	If DEBUG is undefined, does nothing.
338ba0b6e1STyler Dauwalder*/
348ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
358ba0b6e1STyler Dauwalder/*! \def PRINT(x)
368ba0b6e1STyler Dauwalder	\brief Prints out the enclosing function's name followed by the contents
378ba0b6e1STyler Dauwalder	of \a x at the current indentation level.
388ba0b6e1STyler Dauwalder
398ba0b6e1STyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
408ba0b6e1STyler Dauwalder	         e.g. PRINT(("%d\n", 0));
418ba0b6e1STyler Dauwalder
428ba0b6e1STyler Dauwalder	If DEBUG is undefined, does nothing.
438ba0b6e1STyler Dauwalder*/
448ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
458ba0b6e1STyler Dauwalder/*! \def LPRINT(x)
468ba0b6e1STyler Dauwalder	\brief Identical to \c PRINT(x), except that the line number in the source
478ba0b6e1STyler Dauwalder	file at which the macro is invoked is also printed.
488ba0b6e1STyler Dauwalder
498ba0b6e1STyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
508ba0b6e1STyler Dauwalder	         e.g. PRINT(("%d\n", 0));
518ba0b6e1STyler Dauwalder
528ba0b6e1STyler Dauwalder	If DEBUG is undefined, does nothing.
538ba0b6e1STyler Dauwalder*/
548ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
558ba0b6e1STyler Dauwalder/*! \def SIMPLE_PRINT(x)
568ba0b6e1STyler Dauwalder	\brief Directly prints the contents of \a x with no extra formatting or
578ba0b6e1STyler Dauwalder	information included (just like a straight \c printf() call).
588ba0b6e1STyler Dauwalder
598ba0b6e1STyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
608ba0b6e1STyler Dauwalder	         e.g. PRINT(("%d\n", 0));
618ba0b6e1STyler Dauwalder
628ba0b6e1STyler Dauwalder	If DEBUG is undefined, does nothing.
638ba0b6e1STyler Dauwalder*/
648ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
658ba0b6e1STyler Dauwalder/*! \def PRINT_INDENT()
668ba0b6e1STyler Dauwalder	\brief Prints out enough indentation characters to indent the current line
678ba0b6e1STyler Dauwalder	to the current indentation level (assuming the cursor was flush left to
688ba0b6e1STyler Dauwalder	begin with...).
698ba0b6e1STyler Dauwalder
708ba0b6e1STyler Dauwalder	This function is called by the other \c *PRINT* macros, and isn't really
718ba0b6e1STyler Dauwalder	intended for general consumption, but you might find it useful.
728ba0b6e1STyler Dauwalder
738ba0b6e1STyler Dauwalder	If DEBUG is undefined, does nothing.
748ba0b6e1STyler Dauwalder*/
758ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
768ba0b6e1STyler Dauwalder/*! \def REPORT_ERROR(error)
778ba0b6e1STyler Dauwalder	\brief Calls \c LPRINT(x) with a format string listing the error
788ba0b6e1STyler Dauwalder	code in \c error (assumed to be a \c status_t value) and the
798ba0b6e1STyler Dauwalder	corresponding text error code returned by a call to \c strerror().
808ba0b6e1STyler Dauwalder
818ba0b6e1STyler Dauwalder	This function is called by the \c RETURN* macros, and isn't really
828ba0b6e1STyler Dauwalder	intended for general consumption, but you might find it useful.
838ba0b6e1STyler Dauwalder
848ba0b6e1STyler Dauwalder	\param error A \c status_t error code to report.
858ba0b6e1STyler Dauwalder
868ba0b6e1STyler Dauwalder	If DEBUG is undefined, does nothing.
878ba0b6e1STyler Dauwalder*/
888ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
898ba0b6e1STyler Dauwalder/*! \def RETURN_ERROR(error)
908ba0b6e1STyler Dauwalder	\brief Calls \c REPORT_ERROR(error) if error is a an error code (i.e.
918ba0b6e1STyler Dauwalder	negative), otherwise remains silent. In either case, the enclosing
928ba0b6e1STyler Dauwalder	function is then exited with a call to \c "return error;".
938ba0b6e1STyler Dauwalder
948ba0b6e1STyler Dauwalder	\param error A \c status_t error code to report (if negative) and return.
958ba0b6e1STyler Dauwalder
968ba0b6e1STyler Dauwalder	If DEBUG is undefined, silently returns the value in \c error.
978ba0b6e1STyler Dauwalder*/
988ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
998ba0b6e1STyler Dauwalder/*! \def RETURN(error)
1008ba0b6e1STyler Dauwalder	\brief Prints out a description of the error code being returned
1018ba0b6e1STyler Dauwalder	(which, in this case, may be either "erroneous" or "successful")
1028ba0b6e1STyler Dauwalder	and then exits the enclosing function with a call to \c "return error;".
1038ba0b6e1STyler Dauwalder
1048ba0b6e1STyler Dauwalder	\param error A \c status_t error code to report and return.
1058ba0b6e1STyler Dauwalder
1068ba0b6e1STyler Dauwalder	If DEBUG is undefined, silently returns the value in \c error.
1078ba0b6e1STyler Dauwalder*/
1088ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1098ba0b6e1STyler Dauwalder/*! \def FATAL(x)
1108ba0b6e1STyler Dauwalder	\brief Prints out a fatal error message.
1118ba0b6e1STyler Dauwalder
1128ba0b6e1STyler Dauwalder	This one's still a work in progress...
1138ba0b6e1STyler Dauwalder
1148ba0b6e1STyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
1158ba0b6e1STyler Dauwalder	         e.g. PRINT(("%d\n", 0));
1168ba0b6e1STyler Dauwalder
1178ba0b6e1STyler Dauwalder	If DEBUG is undefined, does nothing.
1188ba0b6e1STyler Dauwalder*/
1198ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1208ba0b6e1STyler Dauwalder/*! \def INFORM(x)
1218ba0b6e1STyler Dauwalder	\brief Directly prints the contents of \a x with no extra formatting or
1228ba0b6e1STyler Dauwalder	information included (just like a straight \c printf() call). Does so
1238ba0b6e1STyler Dauwalder	whether \c DEBUG is defined or not.
1248ba0b6e1STyler Dauwalder
1258ba0b6e1STyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
1268ba0b6e1STyler Dauwalder	         e.g. PRINT(("%d\n", 0));
1278ba0b6e1STyler Dauwalder
1288ba0b6e1STyler Dauwalder	I'll say it again: Prints its output regardless to DEBUG being defined or
1298ba0b6e1STyler Dauwalder	undefined.
1308ba0b6e1STyler Dauwalder*/
1318ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1328ba0b6e1STyler Dauwalder/*! \def DBG(x)
1338ba0b6e1STyler Dauwalder	\brief If debug is defined, \a x is passed along to the code and
1348ba0b6e1STyler Dauwalder	executed unmodified. If \c DEBUG is undefined, the contents of
1358ba0b6e1STyler Dauwalder	\a x disappear into the ether.
1368ba0b6e1STyler Dauwalder
1378ba0b6e1STyler Dauwalder	\param x Damn near anything resembling valid C\C++.
1388ba0b6e1STyler Dauwalder*/
1398ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1408ba0b6e1STyler Dauwalder/*! \def DIE(x)
1418ba0b6e1STyler Dauwalder	\brief Drops the user into the appropriate debugger (user or kernel)
1428ba0b6e1STyler Dauwalder	after printing out the handy message bundled in the parenthesee
1438ba0b6e1STyler Dauwalder	enclosed printf-style format string found in \a x.
1448ba0b6e1STyler Dauwalder
1458ba0b6e1STyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
1468ba0b6e1STyler Dauwalder	         e.g. PRINT(("%d\n", 0));
1478ba0b6e1STyler Dauwalder*/
1488ba0b6e1STyler Dauwalder
1498ba0b6e1STyler Dauwalder
1508ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1518ba0b6e1STyler Dauwalder// declarations
1528ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1538ba0b6e1STyler Dauwalder
1548ba0b6e1STyler Dauwalderstatic void indent(uint8 tabCount);
1558ba0b6e1STyler Dauwalderstatic void unindent(uint8 tabCount);
1568ba0b6e1STyler Dauwalder#ifdef USER
1578ba0b6e1STyler Dauwalder	static int32 get_tls_handle();
1588ba0b6e1STyler Dauwalder#endif
1598ba0b6e1STyler Dauwalder
1608ba0b6e1STyler Dauwalder//! Used to keep the tls handle from being allocated more than once.
1618ba0b6e1STyler Dauwaldervint32 tls_spinlock = 0;
1628ba0b6e1STyler Dauwalder
1638ba0b6e1STyler Dauwalder/*! \brief Used to flag whether the tls handle has been allocated yet.
1648ba0b6e1STyler Dauwalder
1658ba0b6e1STyler Dauwalder	Not sure if this really needs to be \c volatile or not...
1668ba0b6e1STyler Dauwalder*/
1678ba0b6e1STyler Dauwaldervolatile bool tls_handle_initialized = false;
1688ba0b6e1STyler Dauwalder
1698ba0b6e1STyler Dauwalder//! The tls handle of the tls var used to store indentation info.
1708ba0b6e1STyler Dauwalderint32 tls_handle = 0;
1718ba0b6e1STyler Dauwalder
1728ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1738ba0b6e1STyler Dauwalder// public functions
1748ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1758ba0b6e1STyler Dauwalder
1768ba0b6e1STyler Dauwalder/*! \brief Returns the current debug indentation level for the
1778ba0b6e1STyler Dauwalder	current thread.
1788ba0b6e1STyler Dauwalder
1798ba0b6e1STyler Dauwalder	NOTE: indentation is currently unsupported for R5::kernelland due
1808ba0b6e1STyler Dauwalder	to lack of thread local storage support.
1818ba0b6e1STyler Dauwalder*/
1828ba0b6e1STyler Dauwalderint32
1838ba0b6e1STyler Dauwalder_get_debug_indent_level()
1848ba0b6e1STyler Dauwalder{
1858ba0b6e1STyler Dauwalder#ifdef USER
1868ba0b6e1STyler Dauwalder	return (int32)tls_get(get_tls_handle());
1878ba0b6e1STyler Dauwalder#else
1888ba0b6e1STyler Dauwalder	return 1;
1898ba0b6e1STyler Dauwalder#endif
1908ba0b6e1STyler Dauwalder}
1918ba0b6e1STyler Dauwalder
1928ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1938ba0b6e1STyler Dauwalder// static functions
1948ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
1958ba0b6e1STyler Dauwalder
1968ba0b6e1STyler Dauwalder/*! \brief Increases the current debug indentation level for
1978ba0b6e1STyler Dauwalder	the current thread by 1.
1988ba0b6e1STyler Dauwalder*/
1998ba0b6e1STyler Dauwaldervoid
2008ba0b6e1STyler Dauwalderindent(uint8 tabCount)
2018ba0b6e1STyler Dauwalder{
2028ba0b6e1STyler Dauwalder#ifdef USER
2038ba0b6e1STyler Dauwalder	tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()+tabCount));
2048ba0b6e1STyler Dauwalder#endif
2058ba0b6e1STyler Dauwalder}
2068ba0b6e1STyler Dauwalder
2078ba0b6e1STyler Dauwalder/*! \brief Decreases the current debug indentation level for
2088ba0b6e1STyler Dauwalder	the current thread by 1.
2098ba0b6e1STyler Dauwalder*/
2108ba0b6e1STyler Dauwaldervoid
2118ba0b6e1STyler Dauwalderunindent(uint8 tabCount)
2128ba0b6e1STyler Dauwalder{
2138ba0b6e1STyler Dauwalder#ifdef USER
2148ba0b6e1STyler Dauwalder	tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()-tabCount));
2158ba0b6e1STyler Dauwalder#endif
2168ba0b6e1STyler Dauwalder}
2178ba0b6e1STyler Dauwalder
2188ba0b6e1STyler Dauwalder#ifdef USER
2198ba0b6e1STyler Dauwalder/*! \brief Returns the thread local storage handle used to store
2208ba0b6e1STyler Dauwalder	indentation information, allocating the handle first if
2218ba0b6e1STyler Dauwalder	necessary.
2228ba0b6e1STyler Dauwalder*/
2238ba0b6e1STyler Dauwalderint32
2248ba0b6e1STyler Dauwalderget_tls_handle()
2258ba0b6e1STyler Dauwalder{
2268ba0b6e1STyler Dauwalder	// Init the tls handle if this is the first call.
2278ba0b6e1STyler Dauwalder	if (!tls_handle_initialized) {
2288ba0b6e1STyler Dauwalder		if (atomic_or(&tls_spinlock, 1) == 0) {
2298ba0b6e1STyler Dauwalder			// First one in gets to init
2308ba0b6e1STyler Dauwalder			tls_handle = tls_allocate();
2318ba0b6e1STyler Dauwalder			tls_handle_initialized = true;
2328ba0b6e1STyler Dauwalder			atomic_and(&tls_spinlock, 0);
2338ba0b6e1STyler Dauwalder		} else {
2348ba0b6e1STyler Dauwalder			// All others must wait patiently
2358ba0b6e1STyler Dauwalder			while (!tls_handle_initialized) {
2368ba0b6e1STyler Dauwalder				snooze(1);
2378ba0b6e1STyler Dauwalder			}
2388ba0b6e1STyler Dauwalder		}
2398ba0b6e1STyler Dauwalder	}
2408ba0b6e1STyler Dauwalder	return tls_handle;
2418ba0b6e1STyler Dauwalder}
2428ba0b6e1STyler Dauwalder#endif
2438ba0b6e1STyler Dauwalder
2448ba0b6e1STyler Dauwalder/*! \brief Helper class for initializing the debugging output
2458ba0b6e1STyler Dauwalder	file.
2468ba0b6e1STyler Dauwalder
2478ba0b6e1STyler Dauwalder	Note that this hummer isn't threadsafe, but it doesn't really
2488ba0b6e1STyler Dauwalder	matter for our concerns, since the worst it'll result in is
2498ba0b6e1STyler Dauwalder	a dangling file descriptor, and that would be in the case of
2508ba0b6e1STyler Dauwalder	two or more volumes being mounted almost simultaneously...
2518ba0b6e1STyler Dauwalder	not too big of a worry.
2528ba0b6e1STyler Dauwalder*/
2538ba0b6e1STyler Dauwalderclass DebugOutputFile {
2548ba0b6e1STyler Dauwalderpublic:
2558ba0b6e1STyler Dauwalder	DebugOutputFile(const char *filename = NULL)
2568ba0b6e1STyler Dauwalder		: fFile(-1)
2578ba0b6e1STyler Dauwalder	{
2588ba0b6e1STyler Dauwalder		Init(filename);
2598ba0b6e1STyler Dauwalder	}
2608ba0b6e1STyler Dauwalder
2618ba0b6e1STyler Dauwalder	~DebugOutputFile() {
2628ba0b6e1STyler Dauwalder		if (fFile >= 0)
2638ba0b6e1STyler Dauwalder			close(fFile);
2648ba0b6e1STyler Dauwalder	}
2658ba0b6e1STyler Dauwalder
2668ba0b6e1STyler Dauwalder	void Init(const char *filename) {
2678ba0b6e1STyler Dauwalder		if (fFile < 0 && filename)
2688ba0b6e1STyler Dauwalder			fFile = open(filename, O_RDWR | O_CREAT | O_TRUNC);
2698ba0b6e1STyler Dauwalder	}
2708ba0b6e1STyler Dauwalder
2718ba0b6e1STyler Dauwalder	int File() const { return fFile; }
2728ba0b6e1STyler Dauwalderprivate:
2738ba0b6e1STyler Dauwalder	int fFile;
2748ba0b6e1STyler Dauwalder};
2758ba0b6e1STyler Dauwalder
2768ba0b6e1STyler DauwalderDebugOutputFile *out = NULL;
2778ba0b6e1STyler Dauwalder
2788ba0b6e1STyler Dauwalder/*!	\brief It doesn't appear that the constructor for the global
2798ba0b6e1STyler Dauwalder	\c out variable is called when built as an R5 filesystem add-on,
2808ba0b6e1STyler Dauwalder	so this function needs to be called in udf_mount to let the
2818ba0b6e1STyler Dauwalder	magic happen.
2828ba0b6e1STyler Dauwalder*/
2838ba0b6e1STyler Dauwaldervoid initialize_debugger(const char *filename)
2848ba0b6e1STyler Dauwalder{
2858ba0b6e1STyler Dauwalder#if DEBUG_TO_FILE
2868ba0b6e1STyler Dauwalder	if (!out) {
2878ba0b6e1STyler Dauwalder		out = new DebugOutputFile(filename);
2888ba0b6e1STyler Dauwalder		dbg_printf("out was NULL!\n");
2898ba0b6e1STyler Dauwalder	} else {
2908ba0b6e1STyler Dauwalder		DebugOutputFile *temp = out;
2918ba0b6e1STyler Dauwalder		out = new DebugOutputFile(filename);
2928ba0b6e1STyler Dauwalder		dbg_printf("out was %p!\n", temp);
2938ba0b6e1STyler Dauwalder	}
2948ba0b6e1STyler Dauwalder#endif
2958ba0b6e1STyler Dauwalder}
2968ba0b6e1STyler Dauwalder
2978ba0b6e1STyler Dauwalder// dbg_printf, stolen from Ingo's ReiserFS::Debug.cpp.
2988ba0b6e1STyler Dauwaldervoid
2998ba0b6e1STyler Dauwalderdbg_printf(const char *format,...)
3008ba0b6e1STyler Dauwalder{
3018ba0b6e1STyler Dauwalder#if DEBUG_TO_FILE
3028ba0b6e1STyler Dauwalder	if (!out)
3038ba0b6e1STyler Dauwalder		return;
3048ba0b6e1STyler Dauwalder
3058ba0b6e1STyler Dauwalder	char buffer[1024];
3068ba0b6e1STyler Dauwalder	va_list args;
3078ba0b6e1STyler Dauwalder	va_start(args, format);
3088ba0b6e1STyler Dauwalder	// no vsnprintf() on PPC and in kernel
3095ffbe7d7SAugustin Cavalier	#if defined(__i386__) && USER
3108ba0b6e1STyler Dauwalder		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
3118ba0b6e1STyler Dauwalder	#else
3128ba0b6e1STyler Dauwalder		vsprintf(buffer, format, args);
3138ba0b6e1STyler Dauwalder	#endif
3148ba0b6e1STyler Dauwalder	va_end(args);
3158ba0b6e1STyler Dauwalder	buffer[sizeof(buffer) - 1] = '\0';
3168ba0b6e1STyler Dauwalder	write(out->File(), buffer, strlen(buffer));
3178ba0b6e1STyler Dauwalder#endif
3188ba0b6e1STyler Dauwalder}
3198ba0b6e1STyler Dauwalder
3208ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
3218ba0b6e1STyler Dauwalder// DebugHelper
3228ba0b6e1STyler Dauwalder//----------------------------------------------------------------------
3238ba0b6e1STyler Dauwalder
3248ba0b6e1STyler Dauwalder/*! \brief Increases the current indentation level.
3258ba0b6e1STyler Dauwalder*/
3268ba0b6e1STyler DauwalderDebugHelper::DebugHelper(const char *className, uint8 tabCount)
3278ba0b6e1STyler Dauwalder	: fTabCount(tabCount)
3288ba0b6e1STyler Dauwalder	, fClassName(NULL)
3298ba0b6e1STyler Dauwalder{
3308ba0b6e1STyler Dauwalder	indent(fTabCount);
3318ba0b6e1STyler Dauwalder	if (className) {
3328ba0b6e1STyler Dauwalder		fClassName = (char*)malloc(strlen(className)+1);
3338ba0b6e1STyler Dauwalder		if (fClassName)
3348ba0b6e1STyler Dauwalder			strcpy(fClassName, className);
3358ba0b6e1STyler Dauwalder	}
3368ba0b6e1STyler Dauwalder}
3378ba0b6e1STyler Dauwalder
3388ba0b6e1STyler Dauwalder/*! \brief Decreases the current indentation level.
3398ba0b6e1STyler Dauwalder*/
3408ba0b6e1STyler DauwalderDebugHelper::~DebugHelper()
3418ba0b6e1STyler Dauwalder{
3428ba0b6e1STyler Dauwalder	unindent(fTabCount);
3438ba0b6e1STyler Dauwalder	free(fClassName);
3448ba0b6e1STyler Dauwalder}
3458ba0b6e1STyler Dauwalder