Handout
This commit is contained in:
11
kernel/debug/assert.cc
Normal file
11
kernel/debug/assert.cc
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "assert.h"
|
||||
|
||||
#include "../arch/core.h"
|
||||
#include "output.h"
|
||||
|
||||
[[noreturn]] void assertion_failed(const char* exp, const char* func,
|
||||
const char* file, int line) {
|
||||
DBG << "Assertion '" << exp << "' failed (" << func << " @ " << file << ":"
|
||||
<< dec << line << ") - CPU stopped." << endl;
|
||||
Core::die();
|
||||
}
|
||||
74
kernel/debug/assert.h
Normal file
74
kernel/debug/assert.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
||||
/*! \file
|
||||
* \brief Contains several macros usable for making assertions
|
||||
*
|
||||
* Depending on the type of assertion (either static or at runtime), a failing
|
||||
* assertion will trigger an error. For static assertion, this error will be
|
||||
* shown at compile time and abort compilation. Runtime assertions will trigger
|
||||
* a message containing details about the error occurred and will make the CPU
|
||||
* die.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \defgroup debug Debugging functions
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
#ifndef STRINGIFY
|
||||
/*! \def STRINGIFY(S)
|
||||
* \brief Converts a macro parameter into a string
|
||||
* \ingroup debug
|
||||
* \param S Expression to be converted
|
||||
* \return stringified version of S
|
||||
*/
|
||||
#define STRINGIFY(S) #S
|
||||
#endif
|
||||
|
||||
/*! \def assert_size(TYPE, SIZE)
|
||||
* \brief Statically ensure (at compile time) that a data type (or variable)
|
||||
* has the expected size.
|
||||
*
|
||||
* \ingroup debug
|
||||
* \param TYPE The type to be checked
|
||||
* \param SIZE Expected size in bytes
|
||||
*/
|
||||
#define assert_size(TYPE, SIZE) \
|
||||
static_assert(sizeof(TYPE) == (SIZE), "Wrong size for " STRINGIFY(TYPE))
|
||||
|
||||
/*! \def assert(EXP)
|
||||
* \brief Ensure (at execution time) an expression evaluates to `true`, print
|
||||
* an error message and stop the CPU otherwise.
|
||||
*
|
||||
* \ingroup debug
|
||||
* \param EXP The expression to be checked
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#define assert(EXP) ((void)0)
|
||||
#else
|
||||
#define assert(EXP) \
|
||||
do { \
|
||||
if (__builtin_expect(!(EXP), 0)) { \
|
||||
assertion_failed(STRINGIFY(EXP), __func__, __FILE__, __LINE__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
/*! \brief Handles a failed assertion
|
||||
*
|
||||
* This function will print a message containing further information about the
|
||||
* failed assertion and stops the current CPU permanently.
|
||||
*
|
||||
* \note This function should never be called directly, but only via the macro
|
||||
* `assert`.
|
||||
*
|
||||
*
|
||||
* \param exp Expression that did not hold
|
||||
* \param func Name of the function in which the assertion failed
|
||||
* \param file Name of the file in which the assertion failed
|
||||
* \param line Line in which the assertion failed
|
||||
*/
|
||||
[[noreturn]] void assertion_failed(const char* exp, const char* func,
|
||||
const char* file, int line);
|
||||
#endif
|
||||
44
kernel/debug/copystream.h
Normal file
44
kernel/debug/copystream.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*! \file
|
||||
* \brief \ref CopyStream duplicates \ref OutputStream "output streams"
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../object/outputstream.h"
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief Duplicate all data passed by the stream operator to two \ref
|
||||
* OutputStream "output streams"
|
||||
* \ingroup io
|
||||
*
|
||||
* Can be used as replacement for any \ref OutputStream -- for example,
|
||||
* forwarding the \ref DBG output simultaneously to screen (\ref TextStream) and
|
||||
* serial console (\ref SerialStream).
|
||||
*
|
||||
*/
|
||||
class CopyStream : public OutputStream {
|
||||
/*! \brief First recipient
|
||||
*/
|
||||
OutputStream* first;
|
||||
|
||||
/*! \brief Second recipient
|
||||
*/
|
||||
OutputStream* second;
|
||||
|
||||
public:
|
||||
/*! \brief Constructor
|
||||
*
|
||||
* \param first First recipient for output passed to this object
|
||||
* \param second Second recipient for output passed to this object
|
||||
*/
|
||||
CopyStream(OutputStream* first, OutputStream* second)
|
||||
: first(first), second(second) {}
|
||||
|
||||
/*! \brief Redirect the buffer to both streams and flush them, too.
|
||||
*/
|
||||
void flush() override {
|
||||
buffer[pos] = '\0'; // make sure buffer will only be printed until pos.
|
||||
*first << buffer << ::flush;
|
||||
*second << buffer << ::flush;
|
||||
pos = 0;
|
||||
}
|
||||
};
|
||||
27
kernel/debug/kernelpanic.h
Normal file
27
kernel/debug/kernelpanic.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
||||
/*! \file
|
||||
* \brief Macro to print an error message and stop the current core.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
/*! \def kernelpanic
|
||||
* \brief Print an error message in the debug window and \ref Core::die "stop
|
||||
* the current core"
|
||||
*
|
||||
* \param MSG error message
|
||||
* \ingroup debug
|
||||
*/
|
||||
#define kernelpanic(MSG) \
|
||||
do { \
|
||||
DBG << "PANIC: '" << (MSG) << "' in " << __func__ << " @ " << __FILE__ \
|
||||
<< ":" << __LINE__ << ") - CPU stopped." << endl; \
|
||||
Core::die(); \
|
||||
} while (0)
|
||||
|
||||
// The includes are intentionally placed at the end, so the macro can be used
|
||||
// inside those included files as well.
|
||||
#include "../arch/core.h"
|
||||
#include "./output.h"
|
||||
4
kernel/debug/nullstream.cc
Normal file
4
kernel/debug/nullstream.cc
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "nullstream.h"
|
||||
|
||||
// Instance
|
||||
NullStream nullstream;
|
||||
45
kernel/debug/nullstream.h
Normal file
45
kernel/debug/nullstream.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*! \file
|
||||
* \brief \ref NullStream is a stream discarding everything
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../object/outputstream.h"
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief Ignore all data passed by the stream operator
|
||||
* \ingroup io
|
||||
*
|
||||
* Can be used instead of the \ref OutputStream if (for debugging reasons) all
|
||||
* output should be ignored, e.g. for \ref DBG_VERBOSE
|
||||
*
|
||||
* By using template programming, a single generic methods is sufficient
|
||||
* (which simply discard everything).
|
||||
*/
|
||||
class NullStream {
|
||||
/*! \brief Check if type is supported by output stream
|
||||
*/
|
||||
template <typename T>
|
||||
auto check(T v, OutputStream* p = nullptr) -> decltype(*p << v, void()) {}
|
||||
|
||||
public:
|
||||
/*! \brief Empty default constructor
|
||||
*/
|
||||
NullStream() {}
|
||||
|
||||
/*! \brief Generic stream operator for any data type
|
||||
*
|
||||
* Uses template meta programming for a generic & short solution
|
||||
*
|
||||
* \tparam T Type of data to ignore
|
||||
* \param value data to be ignore
|
||||
* \return Reference to the \ref NullStream object allowing concatenation of
|
||||
* operators
|
||||
*/
|
||||
template <typename T>
|
||||
NullStream& operator<<(T value) {
|
||||
check(value);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
extern NullStream nullstream;
|
||||
69
kernel/debug/output.h
Normal file
69
kernel/debug/output.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
||||
/*! \file
|
||||
* \brief Debug macros enabling debug output on a separate window for each
|
||||
* core.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../object/outputstream.h"
|
||||
#include "../types.h"
|
||||
#include "nullstream.h"
|
||||
|
||||
/*! \def DBG_VERBOSE
|
||||
* \brief An output stream, which is only displayed in the debug window in
|
||||
* verbose mode
|
||||
*
|
||||
* \note If a serial console has been implemented, the output can be redirected
|
||||
* to the serial stream instead (by changing the macro) -- this makes the
|
||||
* (usually) very large output more readable (since it allows scrolling
|
||||
* back)
|
||||
*/
|
||||
#ifdef VERBOSE
|
||||
// If VERBOSE is defined, forward everything to \ref DBG
|
||||
#define DBG_VERBOSE (DBG << __FILE__ << ":" << __LINE__ << " ")
|
||||
#else
|
||||
// Otherwise sent everything to the NullStream (which will simply discard
|
||||
// everything)
|
||||
#define DBG_VERBOSE nullstream
|
||||
#endif
|
||||
|
||||
/*! \def DBG
|
||||
* \brief An output stream, which is displayed in the debug window
|
||||
*
|
||||
* This is also used by the \ref assert macro and its underlying \ref
|
||||
* assertion_failed method.
|
||||
*
|
||||
* In single core (\OOStuBS) this is just an alias to the debug window object
|
||||
* `dout`.
|
||||
*/
|
||||
#define DBG *copyout
|
||||
|
||||
#include "../device/textstream.h"
|
||||
|
||||
/*! \brief Debug window
|
||||
*
|
||||
* Debug output using \ref DBG like
|
||||
* `DBG << "var = " << var << endl`
|
||||
* should be displayed in separate window.
|
||||
*
|
||||
* Ideally, this window should be placed below the normal output window
|
||||
* without any overlap and be able to display 4 lines.
|
||||
*
|
||||
*/
|
||||
extern TextStream dout;
|
||||
|
||||
/*! \brief Debug window with copy function to serial
|
||||
*
|
||||
* Provide an additional layer to also ouput debug prints to serial.
|
||||
* While this is a simple CopyStream pointer in the single core case, it is
|
||||
* an array in the multi core case, which consists of three TextStreams and
|
||||
* one CopyStream.
|
||||
* For that, construction is done like:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* OutputStream* copyout[Core::MAX]{&dout[0], &dout[1], ...}
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
extern OutputStream* copyout;
|
||||
Reference in New Issue
Block a user