Files
moslab-code/src/l4/pkg/l4re-core/cxx/lib/base/include/exceptions
2025-09-12 15:55:45 +02:00

313 lines
7.8 KiB
C++

// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief Base exceptions
* \ingroup l4cxx_exceptions
*/
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/l4types.h>
#include <l4/cxx/basic_ostream>
#include <l4/sys/err.h>
#include <l4/sys/capability>
/**
* \defgroup l4cxx_exceptions C++ Exceptions
* \ingroup api_l4re
*/
/**@{*/
#ifndef L4_CXX_NO_EXCEPTION_BACKTRACE
# define L4_CXX_EXCEPTION_BACKTRACE 20 ///< Number of instruction pointers in backtrace
#endif
#if defined(L4_CXX_EXCEPTION_BACKTRACE)
#include <l4/util/backtrace.h>
#endif
/**@}*/
namespace L4
{
/**
* \addtogroup l4cxx_exceptions
*/
/**@{*/
/**
* \brief Back-trace support for exceptions.
* \headerfile l4/cxx/exceptions
*
* This class holds an array of at most #L4_CXX_EXCEPTION_BACKTRACE
* instruction pointers containing the call trace at the instant when an
* exception was thrown.
*/
class Exception_tracer
{
#if defined(L4_CXX_EXCEPTION_BACKTRACE)
private:
void *_pc_array[L4_CXX_EXCEPTION_BACKTRACE];
int _frame_cnt;
protected:
/**
* \brief Create a back trace.
*/
#if defined(__PIC__)
Exception_tracer() noexcept : _frame_cnt(0) {}
#else
Exception_tracer() noexcept
: _frame_cnt(l4util_backtrace(_pc_array, L4_CXX_EXCEPTION_BACKTRACE)) {}
#endif
public:
/**
* \brief Get the array containing the call trace.
*/
void const *const *pc_array() const noexcept { return _pc_array; }
/**
* \brief Get the number of entries that are valid in the call trace.
*/
int frame_count() const noexcept { return _frame_cnt; }
#else
protected:
/**
* \brief Create a back trace.
*/
Exception_tracer() noexcept {}
public:
/**
* \brief Get the array containing the call trace.
*/
void const *const *pc_array() const noexcept { return 0; }
/**
* \brief Get the number of entries that are valid in the call trace.
*/
int frame_count() const noexcept { return 0; }
#endif
};
/**
* \brief Base class for all exceptions, thrown by the L4Re framework.
* \headerfile l4/cxx/exceptions
*
* This is the abstract base of all exceptions thrown within the
* L4Re framework. It is basically also a good idea to use it as base of
* all user defined exceptions.
*/
class Base_exception : public Exception_tracer
{
protected:
/// Create a base exception.
Base_exception() noexcept {}
public:
/**
* Return a human readable string for the exception.
*/
virtual char const *str() const noexcept = 0;
/// Destruction
virtual ~Base_exception() noexcept {}
};
/**
* \brief Exception for an abstract runtime error.
* \headerfile l4/cxx/exceptions
*
* This is the base class for a set of exceptions that cover all errors
* that have a C error value (see #l4_error_code_t).
*/
class Runtime_error : public Base_exception
{
private:
long _errno;
char _extra[80];
public:
/**
* Create a new Runtime_error.
*
* \param err_no Error value for this runtime error.
* \param extra Description of what happened when the error occurred.
*/
explicit Runtime_error(long err_no, char const *extra = 0) noexcept
: _errno(err_no)
{
if (!extra)
_extra[0] = 0;
else
{
unsigned i = 0;
for (; i < sizeof(_extra) && extra[i]; ++i)
_extra[i] = extra[i];
_extra[i < sizeof(_extra) ? i : sizeof(_extra) - 1] = 0;
}
}
char const *str() const noexcept override
{ return l4sys_errtostr(_errno); }
/**
* Get the description text for this runtime error.
*
* \return Pointer to the description string.
*/
char const *extra_str() const { return _extra; }
~Runtime_error() noexcept {}
/**
* Get the error value for this runtime error.
*
* \return Error value.
*/
long err_no() const noexcept { return _errno; }
};
/**
* \brief Exception signalling insufficient memory.
* \headerfile l4/cxx/exceptions
*/
class Out_of_memory : public Runtime_error
{
public:
/// Create an out-of-memory exception.
explicit Out_of_memory(char const *extra = "") noexcept
: Runtime_error(-L4_ENOMEM, extra) {}
/// Destruction
~Out_of_memory() noexcept {}
};
/**
* \brief Exception for duplicate element insertions.
* \headerfile l4/cxx/exceptions
*/
class Element_already_exists : public Runtime_error
{
public:
explicit Element_already_exists(char const *e = "") noexcept
: Runtime_error(-L4_EEXIST, e) {}
~Element_already_exists() noexcept {}
};
/**
* \brief Exception for an unknown condition.
* \headerfile l4/cxx/exceptions
*
* This error is usually used when a server returns an unknown return state
* to the client, this may indicate incompatible messages used by the client
* and the server.
*/
class Unknown_error : public Base_exception
{
public:
Unknown_error() noexcept {}
char const *str() const noexcept override { return "unknown error"; }
~Unknown_error() noexcept {}
};
/**
* \brief Exception for a failed lookup (element not found).
* \headerfile l4/cxx/exceptions
*/
class Element_not_found : public Runtime_error
{
public:
explicit Element_not_found(char const *e = "") noexcept
: Runtime_error(-L4_ENOENT, e) {}
};
/**
* \brief Indicates that an invalid object was invoked.
* \headerfile l4/cxx/exceptions
*
* An Object is invalid if it has L4_INVALID_ID as server L4 UID,
* or if the server does not know the object ID.
*/
class Invalid_capability : public Base_exception
{
private:
Cap<void> const _o;
public:
/**
* \brief Create an Invalid_object exception for the Object o.
* \param o The object that caused the server side error.
*/
explicit Invalid_capability(Cap<void> const &o) noexcept : _o(o) {}
template< typename T>
explicit Invalid_capability(Cap<T> const &o) noexcept : _o(o.cap()) {}
char const *str() const noexcept override { return "invalid object"; }
/**
* \brief Get the object that caused the error.
* \return The object that caused the error on invocation.
*/
Cap<void> const &cap() const noexcept { return _o; }
~Invalid_capability() noexcept {}
};
/**
* \brief Error conditions during IPC.
* \headerfile l4/cxx/exceptions
*
* This exception encapsulates all IPC error conditions of L4 IPC.
*/
class Com_error : public Runtime_error
{
public:
/**
* \brief Create a Com_error for the given L4 IPC error code.
* \param err The L4 IPC error code (l4_ipc... return value).
*/
explicit Com_error(long err) noexcept : Runtime_error(err) {}
~Com_error() noexcept {}
};
/**
* \brief Access out of bounds.
*/
class Bounds_error : public Runtime_error
{
public:
explicit Bounds_error(char const *e = "") noexcept
: Runtime_error(-L4_ERANGE, e) {}
~Bounds_error() noexcept {}
};
/**@}*/
};
inline
L4::BasicOStream &
operator << (L4::BasicOStream &o, L4::Base_exception const &e)
{
o << "Exception: " << e.str() << ".\n";
o << "Backtrace:\n";
for (int i = 0; i < e.frame_count(); ++i)
o << " " << L4::n_hex(l4_addr_t(e.pc_array()[i])) << '\n';
return o;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &o, L4::Runtime_error const &e)
{
o << "Exception: " << e.str();
if (e.extra_str())
o << ": " << e.extra_str();
o << "\n" << "Backtrace:\n";
for (int i = 0; i < e.frame_count(); ++i)
o << " " << L4::n_hex(l4_addr_t(e.pc_array()[i])) << '\n';
return o;
}