Files
SingularityViewer/indra/cwdebug/debug.h
2012-02-16 02:30:14 +01:00

259 lines
9.8 KiB
C++

// slviewer -- Second Life Viewer Source Code
//
//! @file debug.h
//! @brief This file contains the declaration of debug related macros, objects and functions.
//
// Copyright (C) 2008, by
//
// Carlo Wood, Run on IRC <carlo@alinoe.com>
// RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
//
// 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, see <http://www.gnu.org/licenses/>.
#ifndef DEBUG_H
#define DEBUG_H
#ifndef CWDEBUG
#ifndef DOXYGEN // No need to document this. See http://libcwd.sourceforge.net/ for more info.
#include <iostream>
#include <cstdlib> // std::exit, EXIT_FAILURE
#define AllocTag1(p)
#define AllocTag2(p, desc)
#define AllocTag_dynamic_description(p, x)
#define AllocTag(p, x)
#define Debug(x)
#define Dout(a, b)
#define DoutEntering(a, b)
#define DoutFatal(a, b) LibcwDoutFatal(::std, , a, b)
#define ForAllDebugChannels(STATEMENT)
#define ForAllDebugObjects(STATEMENT)
#define LibcwDebug(dc_namespace, x)
#define LibcwDout(a, b, c, d)
#define LibcwDoutFatal(a, b, c, d) do { ::std::cerr << d << ::std::endl; ::std::exit(EXIT_FAILURE); } while (1)
#define NEW(x) new x
#define CWDEBUG_ALLOC 0
#define CWDEBUG_MAGIC 0
#define CWDEBUG_LOCATION 0
#define CWDEBUG_LIBBFD 0
#define CWDEBUG_DEBUG 0
#define CWDEBUG_DEBUGOUTPUT 0
#define CWDEBUG_DEBUGM 0
#define CWDEBUG_DEBUGT 0
#define CWDEBUG_MARKER 0
#define BACKTRACE do { } while(0)
#endif // !DOXYGEN
#include <cassert>
#ifdef DEBUG
#define ASSERT(x) assert(x)
#else
#define ASSERT(x)
#endif
#else // CWDEBUG
//! Assert \a x, if debugging is turned on.
#define ASSERT(x) LIBCWD_ASSERT(x)
#define builtin_return_address(addr) ((char*)__builtin_return_address(addr) + libcwd::builtin_return_address_offset)
#ifndef DEBUGCHANNELS
//! @brief The namespace in which the \c dc namespace is declared.
//
// <A HREF="http://libcwd.sourceforge.net/">Libcwd</A> demands that this macro is defined
// before <libcwd/debug.h> is included and must be the name of the namespace containing
// the \c dc (Debug Channels) namespace.
//
// @sa debug::channels::dc
#define DEBUGCHANNELS ::debug::channels
#endif
#include <libcwd/debug.h>
#include <boost/shared_array.hpp>
#if CWDEBUG_LOCATION
#include <execinfo.h> // Needed for 'backtrace'.
#endif
#define CWD_API __attribute__ ((visibility("default")))
//! Debug specific code.
namespace debug {
void CWD_API init(void); // Initialize debugging code, called once from main.
void CWD_API init_thread(void); // Initialize debugging code, called once for each thread.
//! @brief Debug Channels (dc) namespace.
//
// @sa debug::channels::dc
namespace channels { // namespace DEBUGCHANNELS
//! The namespace containing the actual debug channels.
namespace dc {
using namespace libcwd::channels::dc;
using libcwd::channel_ct;
#ifndef DOXYGEN // Doxygen bug causes a warning here.
// Add the declaration of new debug channels here
// and add their definition in a custom debug.cc file.
extern CWD_API channel_ct viewer; // The normal logging output of the viewer (normally to stderr).
extern CWD_API channel_ct primbackup;
extern CWD_API channel_ct gtk;
extern CWD_API channel_ct sdl;
extern CWD_API channel_ct backtrace;
extern CWD_API channel_ct statemachine;
extern CWD_API channel_ct caps;
#endif
} // namespace dc
} // namespace DEBUGCHANNELS
#if CWDEBUG_LOCATION
std::string call_location(void const* return_addr);
#endif
//! @brief Interface for marking scopes of invisible memory allocations.
//
// Creation of the object does nothing, you have to explicitly call
// InvisibleAllocations::on. Destruction of the object automatically
// cancels any call to \c on of this object. This makes it exception-
// (stack unwinding) and recursive-safe.
struct InvisibleAllocations {
int M_on; //!< The number of times that InvisibleAllocations::on() was called.
//! Constructor.
InvisibleAllocations() : M_on(0) { }
//! Destructor.
~InvisibleAllocations() { while (M_on > 0) off(); }
//! Set invisible allocations on. Can be called recursively.
void on(void) { libcwd::set_invisible_on(); ++M_on; }
//! Cancel one call to on().
void off(void) { assert(M_on > 0); --M_on; libcwd::set_invisible_off(); }
};
//! @brief Interface for marking scopes with indented debug output.
//
// Creation of the object increments the debug indentation. Destruction
// of the object automatically decrements the indentation again.
struct Indent {
int M_indent; //!< The extra number of spaces that were added to the indentation.
//! Construct an Indent object.
Indent(int indent) : M_indent(indent) { if (M_indent > 0) libcwd::libcw_do.inc_indent(M_indent); }
//! Destructor.
~Indent() { if (M_indent > 0) libcwd::libcw_do.dec_indent(M_indent); }
};
// A class streambuf that splits what is written to two streambufs.
class TeeBuf : public std::streambuf {
private:
std::streambuf* M_sb1;
std::streambuf* M_sb2;
public:
TeeBuf(std::streambuf* sb1, std::streambuf* sb2) : M_sb1(sb1), M_sb2(sb2) { }
protected:
virtual int sync(void) { M_sb2->pubsync(); return M_sb1->pubsync(); }
virtual std::streamsize xsputn(char_type const* p, std::streamsize n) { M_sb2->sputn(p, n); return M_sb1->sputn(p, n); }
virtual int_type overflow(int_type c = traits_type::eof()) { M_sb2->sputc(c); return M_sb1->sputc(c); }
};
// An ostream that passes what is written to it on to two other ostreams.
class TeeStream : public std::ostream {
private:
TeeBuf M_teebuf;
public:
TeeStream(std::ostream& os1, std::ostream& os2) : std::ostream(&M_teebuf), M_teebuf(os1.rdbuf(), os2.rdbuf()) { }
};
#if CWDEBUG_LOCATION
class BackTrace {
private:
boost::shared_array<void*> M_buffer;
int M_frames;
public:
BackTrace(void** buffer, int frames) : M_buffer(new void* [frames]), M_frames(frames) { std::memcpy(M_buffer.get(), buffer, sizeof(void*) * frames); }
friend bool operator<(BackTrace const& bt1, BackTrace const& bt2)
{
if (bt1.M_frames != bt2.M_frames)
return bt1.M_frames < bt2.M_frames;
for (int frame = 0; frame < bt1.M_frames; ++frame)
if (bt1.M_buffer[frame] < bt2.M_buffer[frame])
return true;
else if (bt1.M_buffer[frame] > bt2.M_buffer[frame])
return true;
return false;
}
void dump_backtrace(void) const;
int frames(void) const { return M_frames; }
boost::shared_array<void*> const& buffer(void) const { return M_buffer; }
};
extern std::vector<BackTrace> backtraces;
extern pthread_mutex_t backtrace_mutex;
#define BACKTRACE do { \
using namespace debug; \
void* buffer[32]; \
int frames = backtrace(buffer, 32); \
size_t size; \
{ \
pthread_mutex_lock(&backtrace_mutex); \
backtraces.push_back(BackTrace(buffer, frames)); \
size = backtraces.size(); \
pthread_mutex_unlock(&backtrace_mutex); \
} \
Dout(dc::backtrace, "Stored backtrace #" << size); \
} while(0)
#else
#define BACKTRACE do { } while(0)
#endif // CWDEBUG_LOCATION
} // namespace debug
//! Debugging macro.
//
// Print "Entering " << \a data to channel \a cntrl and increment
// debugging output indentation until the end of the current scope.
#define DoutEntering(cntrl, data) \
int __slviewer_debug_indentation = 2; \
{ \
LIBCWD_TSD_DECLARATION; \
if (LIBCWD_DO_TSD_MEMBER_OFF(::libcwd::libcw_do) < 0) \
{ \
::libcwd::channel_set_bootstrap_st __libcwd_channel_set(LIBCWD_DO_TSD(::libcwd::libcw_do) LIBCWD_COMMA_TSD); \
bool on; \
{ \
using namespace LIBCWD_DEBUGCHANNELS; \
on = (__libcwd_channel_set|cntrl).on; \
} \
if (on) \
Dout(cntrl, "Entering " << data); \
else \
__slviewer_debug_indentation = 0; \
} \
} \
debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation);
#endif // CWDEBUG
#include "debug_ostream_operators.h"
#endif // DEBUG_H