1// vi:set ft=cpp: -*- Mode: C++ -*-
2/**
3 * \file
4 * \brief Base exceptions
5 * \ingroup l4cxx_exceptions
6 */
7/*
8 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
9 *               Alexander Warg <warg@os.inf.tu-dresden.de>
10 *     economic rights: Technische Universität Dresden (Germany)
11 *
12 * This file is part of TUD:OS and distributed under the terms of the
13 * GNU General Public License 2.
14 * Please see the COPYING-GPL-2 file for details.
15 *
16 * As a special exception, you may use this file as part of a free software
17 * library without restriction.  Specifically, if other files instantiate
18 * templates or use macros or inline functions from this file, or you compile
19 * this file and link it with other files to produce an executable, this
20 * file does not by itself cause the resulting executable to be covered by
21 * the GNU General Public License.  This exception does not however
22 * invalidate any other reasons why the executable file might be covered by
23 * the GNU General Public License.
24 */
25#pragma once
26
27#include <l4/cxx/l4types.h>
28#include <l4/cxx/basic_ostream>
29#include <l4/sys/err.h>
30#include <l4/sys/capability>
31
32
33/**
34 * \defgroup l4cxx_exceptions C++ Exceptions
35 * \ingroup api_l4re
36 */
37/*@{*/
38
39#ifndef L4_CXX_NO_EXCEPTION_BACKTRACE
40# define L4_CXX_EXCEPTION_BACKTRACE 20  ///< Number of instruction pointers in backtrace
41#endif
42
43#if defined(L4_CXX_EXCEPTION_BACKTRACE)
44#include <l4/util/backtrace.h>
45#endif
46
47/*@}*/
48namespace L4
49{
50  /**
51   * \addtogroup l4cxx_exceptions
52   */
53  /*@{*/
54  /**
55   * \brief Back-trace support for exceptions.
56   * \headerfile l4/cxx/exceptions
57   *
58   * This class holds an array of at most #L4_CXX_EXCEPTION_BACKTRACE
59   * instruction pointers containing the call trace at the instant when an
60   * exception was thrown.
61   */
62  class Exception_tracer
63  {
64#if defined(L4_CXX_EXCEPTION_BACKTRACE)
65  private:
66    void *_pc_array[L4_CXX_EXCEPTION_BACKTRACE];
67    int   _frame_cnt;
68
69  protected:
70    /**
71     * \brief Create a back trace.
72     */
73#if defined(__PIC__)
74    Exception_tracer() throw() : _frame_cnt(0) {}
75#else
76    Exception_tracer() throw()
77    : _frame_cnt(l4util_backtrace(_pc_array, L4_CXX_EXCEPTION_BACKTRACE)) {}
78#endif
79
80  public:
81    /**
82     * \brief Get the array containing the call trace.
83     */
84    void const *const *pc_array() const throw() { return _pc_array; }
85    /**
86     * \brief Get the number of entries that are valid in the call trace.
87     */
88    int frame_count() const throw() { return _frame_cnt; }
89#else
90  protected:
91    /**
92     * \brief Create a back trace.
93     */
94    Exception_tracer() throw() {}
95
96  public:
97    /**
98     * \brief Get the array containing the call trace.
99     */
100    void const *const *pc_array() const throw() { return 0; }
101    /**
102     * \brief Get the number of entries that are valid in the call trace.
103     */
104    int frame_count() const throw() { return 0; }
105#endif
106  };
107
108  /**
109   * \brief Base class for all exceptions, thrown by the L4Re framework.
110   * \headerfile l4/cxx/exceptions
111   *
112   * This is the abstract base of all exceptions thrown within the
113   * L4Re framework. It is basically also a good idea to use it as base of
114   * all user defined exceptions.
115   */
116  class Base_exception : public Exception_tracer
117  {
118  protected:
119    /// Create a base exception.
120    Base_exception() throw() {}
121
122  public:
123    /**
124     * Return a human readable string for the exception.
125     */
126    virtual char const *str() const throw () = 0;
127
128    /// Destruction
129    virtual ~Base_exception() throw () {}
130  };
131
132  /**
133   * \brief Exception for an abstract runtime error.
134   * \headerfile l4/cxx/exceptions
135   *
136   * This is the base class for a set of exceptions that cover all errors
137   * that have a C error value (see #l4_error_code_t).
138   */
139  class Runtime_error : public Base_exception
140  {
141  private:
142    long _errno;
143    char _extra[80];
144
145  public:
146    /**
147     * Create a new Runtime_error.
148     *
149     * \param err_no  Error value for this runtime error.
150     * \param extra   Description of what was happening while the error occured.
151     */
152    explicit Runtime_error(long err_no, char const *extra = 0) throw ()
153      : _errno(err_no)
154    {
155      if (!extra)
156        _extra[0] = 0;
157      else
158        {
159          unsigned i = 0;
160          for (; i < sizeof(_extra) && extra[i]; ++i)
161            _extra[i] = extra[i];
162          _extra[i < sizeof(_extra) ? i : sizeof(_extra) - 1] = 0;
163        }
164    }
165    char const *str() const throw ()
166    { return l4sys_errtostr(_errno); }
167
168    /**
169     * Get the description text for this runtime error.
170     *
171     * \return  Pointer to the description string.
172     */
173    char const *extra_str() const { return _extra; }
174    ~Runtime_error() throw () {}
175
176    /**
177     * Get the error value for this runtime error.
178     *
179     * \return  Error value.
180     */
181    long err_no() const throw() { return _errno; }
182  };
183
184  /**
185   * \brief Exception signalling insufficient memory.
186   * \headerfile l4/cxx/exceptions
187   */
188  class Out_of_memory : public Runtime_error
189  {
190  public:
191    /// Create an out-of-memory exception.
192    explicit Out_of_memory(char const *extra = "") throw()
193    : Runtime_error(-L4_ENOMEM, extra) {}
194    /// Destruction
195    ~Out_of_memory() throw() {}
196  };
197
198
199  /**
200   * \brief Exception for duplicate element insertions.
201   * \headerfile l4/cxx/exceptions
202   */
203  class Element_already_exists : public Runtime_error
204  {
205  public:
206    explicit Element_already_exists(char const *e = "") throw()
207    : Runtime_error(-L4_EEXIST, e) {}
208    ~Element_already_exists() throw() {}
209  };
210
211  /**
212   * \brief Exception for an unknown condition.
213   * \headerfile l4/cxx/exceptions
214   *
215   * This error is usually used when a server returns an unknown return state
216   * to the client, this may indicate incompatible messages used by the client
217   * and the server.
218   */
219  class Unknown_error : public Base_exception
220  {
221  public:
222    Unknown_error() throw() {}
223    char const *str() const throw() { return "unknown error"; }
224    ~Unknown_error() throw() {}
225  };
226
227  /**
228   * \brief Exception for a failed lookup (element not found).
229   * \headerfile l4/cxx/exceptions
230   */
231  class Element_not_found : public Runtime_error
232  {
233  public:
234    explicit Element_not_found(char const *e = "") throw()
235    : Runtime_error(-L4_ENOENT, e) {}
236  };
237
238  /**
239   * \brief Indicates that an invalid object was invoked.
240   * \headerfile l4/cxx/exceptions
241   *
242   * An Object is invalid if it has L4_INVALID_ID as server L4 UID,
243   * or if the server does not know the object ID.
244   */
245  class Invalid_capability : public Base_exception
246  {
247  private:
248    Cap<void> const _o;
249
250  public:
251    /**
252     * \brief Create an Invalid_object exception for the Object o.
253     * \param o The object that caused the server side error.
254     */
255    explicit Invalid_capability(Cap<void> const &o) throw() : _o(o) {}
256    template< typename T>
257    explicit Invalid_capability(Cap<T> const &o) throw() : _o(o.cap()) {}
258    char const *str() const throw() { return "invalid object"; }
259
260    /**
261     * \brief Get the object that caused the error.
262     * \return The object that caused the error on invocation.
263     */
264    Cap<void> const &cap() const throw() { return _o; }
265    ~Invalid_capability() throw() {}
266  };
267
268  /**
269   * \brief Error conditions during IPC.
270   * \headerfile l4/cxx/exceptions
271   *
272   * This exception encapsulates all IPC error conditions of L4 IPC.
273   */
274  class Com_error : public Runtime_error
275  {
276  public:
277    /**
278     * \brief Create a Com_error for the given L4 IPC error code.
279     * \param err The L4 IPC error code (l4_ipc... return value).
280     */
281    explicit Com_error(long err) throw() : Runtime_error(err) {}
282
283    ~Com_error() throw() {}
284  };
285
286  /**
287   * \brief Access out of bounds.
288   */
289  class Bounds_error : public Runtime_error
290  {
291  public:
292    explicit Bounds_error(char const *e = "") throw()
293    : Runtime_error(-L4_ERANGE, e) {}
294    ~Bounds_error() throw() {}
295  };
296  /*@}*/
297};
298
299inline
300L4::BasicOStream &
301operator << (L4::BasicOStream &o, L4::Base_exception const &e)
302{
303  o << "Exception: " << e.str() << ", backtrace ...\n";
304  for (int i = 0; i < e.frame_count(); ++i)
305    o << L4::n_hex(l4_addr_t(e.pc_array()[i])) << '\n';
306
307  return o;
308}
309
310inline
311L4::BasicOStream &
312operator << (L4::BasicOStream &o, L4::Runtime_error const &e)
313{
314  o << "Exception: " << e.str() << ": ";
315  if (e.extra_str())
316    o << e.extra_str() << ": ";
317  o << "backtrace ...\n";
318  for (int i = 0; i < e.frame_count(); ++i)
319    o << L4::n_hex(l4_addr_t(e.pc_array()[i])) << '\n';
320
321  return o;
322}
323