CppCMS
booster/backtrace.h
00001 //
00002 //  Copyright (C) 2009-2012 Artyom Beilis (Tonkikh)
00003 //
00004 //  Distributed under the Boost Software License, Version 1.0. (See
00005 //  accompanying file LICENSE_1_0.txt or copy at
00006 //  http://www.boost.org/LICENSE_1_0.txt)
00007 //
00008 #ifndef BOOSTER_BACKTRACE_H
00009 #define BOOSTER_BACKTRACE_H
00010 
00011 #include <booster/config.h>
00012 #include <stdexcept>
00013 #include <typeinfo>
00014 #include <string>
00015 #include <vector>
00016 #include <iosfwd>
00017 
00018 namespace booster {
00019 
00024     namespace stack_trace {
00033         BOOSTER_API int trace(void **addresses,int size);
00039         BOOSTER_API void write_symbols(void *const *addresses,int size,std::ostream &);
00043         BOOSTER_API std::string get_symbol(void *address);
00047         BOOSTER_API std::string get_symbols(void * const *address,int size);
00048     } // stack_trace
00049 
00055 
00056     class backtrace {
00057     public:
00058        
00062         static size_t const default_stack_size = 32;
00063 
00067         backtrace(size_t frames_no = default_stack_size) 
00068         {
00069             if(frames_no == 0)
00070                 return;
00071             frames_.resize(frames_no,0);
00072             int size = stack_trace::trace(&frames_.front(),frames_no);
00073             frames_.resize(size);
00074         }
00075 
00076         virtual ~backtrace() throw()
00077         {
00078         }
00079 
00083         size_t stack_size() const
00084         {
00085             return frames_.size();
00086         }
00087 
00091         void *return_address(unsigned frame_no) const
00092         {
00093             if(frame_no < stack_size())
00094                 return frames_[frame_no];
00095             return 0;
00096         }
00097 
00101         void trace_line(unsigned frame_no,std::ostream &out) const
00102         {
00103             if(frame_no < frames_.size())
00104                 stack_trace::write_symbols(&frames_[frame_no],1,out);
00105         }
00106 
00110         std::string trace_line(unsigned frame_no) const
00111         {
00112             if(frame_no < frames_.size())
00113                 return stack_trace::get_symbol(frames_[frame_no]);
00114             return std::string();
00115         }
00116 
00120         std::string trace() const
00121         {
00122             if(frames_.empty())
00123                 return std::string();
00124             return stack_trace::get_symbols(&frames_.front(),frames_.size());
00125         }
00126 
00130         void trace(std::ostream &out) const
00131         {
00132             if(frames_.empty())
00133                 return;
00134             stack_trace::write_symbols(&frames_.front(),frames_.size(),out);
00135         }
00136     
00137     private:
00138         std::vector<void *> frames_;
00139     };
00140 
00144     class exception : public std::exception, public backtrace {
00145     public:
00146     };
00147     
00151     class bad_cast : public std::bad_cast, public backtrace {
00152     public:
00153     };
00154 
00158     class runtime_error: public std::runtime_error, public backtrace {
00159     public:
00160         explicit runtime_error(std::string const &s) : std::runtime_error(s) 
00161         {
00162         }
00163     };
00164 
00168     class range_error: public std::range_error, public backtrace {
00169     public:
00170         explicit range_error(std::string const &s) : std::range_error(s) 
00171         {
00172         }
00173     };
00174 
00178     class overflow_error: public std::overflow_error, public backtrace {
00179     public:
00180         explicit overflow_error(std::string const &s) : std::overflow_error(s) 
00181         {
00182         }
00183     };
00184 
00188     class underflow_error: public std::underflow_error, public backtrace {
00189     public:
00190         explicit underflow_error(std::string const &s) : std::underflow_error(s) 
00191         {
00192         }
00193     };
00194 
00198     class logic_error: public std::logic_error, public backtrace {
00199     public:
00200         explicit logic_error(std::string const &s) : std::logic_error(s) 
00201         {
00202         }
00203     };
00204 
00208     class domain_error: public std::domain_error, public backtrace {
00209     public:
00210         explicit domain_error(std::string const &s) : std::domain_error(s) 
00211         {
00212         }
00213     };
00214 
00218     class length_error: public std::length_error, public backtrace {
00219     public:
00220         explicit length_error(std::string const &s) : std::length_error(s) 
00221         {
00222         }
00223     };
00224 
00228     class invalid_argument : public std::invalid_argument, public backtrace {
00229     public:
00230         explicit invalid_argument(std::string const &s) : std::invalid_argument(s)
00231         {
00232         }
00233     };
00234     
00238     class out_of_range : public std::out_of_range, public backtrace {
00239     public:
00240         explicit out_of_range(std::string const &s) : std::out_of_range(s)
00241         {
00242         }
00243     };
00244 
00246     namespace details {
00247         class trace_manip {
00248         public:
00249             trace_manip(backtrace const *tr) :
00250                 tr_(tr)
00251             {
00252             }
00253             std::ostream &write(std::ostream &out) const
00254             {
00255                 if(tr_)
00256                     tr_->trace(out);
00257                 return out;
00258             }
00259         private:
00260             backtrace const *tr_;
00261         };
00262 
00263         inline std::ostream &operator<<(std::ostream &out,details::trace_manip const &t)
00264         {
00265             return t.write(out);
00266         }
00267     }
00269 
00284     template<typename E>
00285     details::trace_manip trace(E const &e)
00286     {
00287         backtrace const *tr = dynamic_cast<backtrace const *>(&e);
00288         return details::trace_manip(tr);
00289     }
00290 
00291 
00292 } // booster
00293 
00294 #endif
00295 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
00296