Files
SingularityViewer/indra/cwdebug/debug.h
Aleric Inglewood caef97ad36 Print all libcurl calls if -DDEBUG_CURLIO. Don't create static lib for cwdebug.
Basically, cmake doesn't support linking static libs into a shared lib.
The correct way is to just specify source files in subdirectories
directly as source files of the shared library. This patch changes that.

Also, after this commit, when DEBUG_CURLIO is defined, every call to
libcurl is printed to llinfos (or to dc::curl when using libcwd).
2012-08-05 18:51:21 +02:00

365 lines
13 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
#ifdef DEBUG_CURLIO
#if LL_WINDOWS
#define CWD_DLLEXPORT __declspec(dllexport)
#define CWD_DLLIMPORT __declspec(dllimport)
#elif LL_LINUX
#define CWD_DLLEXPORT __attribute__ ((visibility("default")))
#define CWD_DLLIMPORT
#else
#define CWD_DLLEXPORT
#define CWD_DLLIMPORT
#endif // LL_WINDOWS
#if LL_COMMON_LINK_SHARED
#if defined(llcommon_EXPORTS)
#define CWD_API CWD_DLLEXPORT
#else // cwdebug_EXPORTS
#define CWD_API CWD_DLLIMPORT
#endif // cwdebug_EXPORTS
#else // LL_COMMON_LINK_SHARED
#error LL_COMMON_LINK_SHARED not defined
#endif // LL_COMMON_LINK_SHARED
// If CWDEBUG is not defined, but DEBUG_CURLIO is, then replace
// some of the cwd macro's with something that generates viewer
// specific debug output. Note that this generates a LOT of
// output and should not normally be defined.
#include <string>
#if LL_WINDOWS
#define CWD_API_TLS __declspec(thread)
#define CWD_TLS __declspec(thread)
#else
#define CWD_API_TLS CWD_API __thread
#define CWD_TLS __thread
#endif
namespace debug {
namespace libcwd {
struct buf2str {
buf2str(char const* buf, int size) : mBuf(buf), mSize(size) { }
char const* mBuf;
int mSize;
};
} // namespace libcwd
inline void init() { }
struct libcwd_do_type {
void on() const { }
};
extern CWD_API libcwd_do_type const libcw_do;
struct Indent {
int M_indent;
static CWD_API_TLS int S_indentation;
enum CWD_API print_nt { print };
CWD_API Indent(int indent) : M_indent(indent) { S_indentation += M_indent; }
CWD_API ~Indent() { S_indentation -= M_indent; }
};
extern CWD_API std::ostream& operator<<(std::ostream& os, libcwd::buf2str const& b2s);
extern CWD_API std::ostream& operator<<(std::ostream& os, Indent::print_nt);
namespace dc {
struct fake_channel {
int mOn;
char const* mLabel;
fake_channel(int on, char const* label) : mOn(on), mLabel(label) { }
fake_channel(void) : mOn(0) { }
bool is_on() const { return !!mOn; }
bool is_off() const { return !mOn; }
void on() const { }
void off() const { }
};
extern CWD_API fake_channel const warning;
extern CWD_API fake_channel const curl;
extern CWD_API fake_channel const curlio;
extern CWD_API fake_channel const statemachine;
extern CWD_API fake_channel const notice;
} // namespace dc
} // namespace debug
#define Debug(x) do { using namespace debug; x; } while(0)
#define Dout(a, b) do { using namespace debug; if ((a).mOn) { llinfos_nf << (a).mLabel << ": " << Indent::print << b << llendl; } } while(0)
#define DoutEntering(a, b) \
int __slviewer_debug_indentation = 2; \
{ \
using namespace debug; \
if ((a).mOn) \
llinfos_nf << (a).mLabel << ": " << Indent::print << "Entering " << b << llendl; \
else \
__slviewer_debug_indentation = 0; \
} \
debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation);
#else // !DEBUG_CURLIO
#define Debug(x)
#define Dout(a, b)
#define DoutEntering(a, b)
#endif // !DEBUG_CURLIO
#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 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;
extern CWD_API channel_ct curl;
extern CWD_API channel_ct curlio;
#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