kNCurses/Debug.hpp

139 lines
5.5 KiB
C++

/**
* @brief Writes messages to `debug.log` if `NDEBUG` is not defined.
* @author Christian Burger (christian@krikkel.de)
* @todo refactor macros
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifndef NDEBUG
#include <fstream>
#include <string>
#include <ctime>
#include <locale>
namespace krikkel
{
class Debug
{
private:
std::fstream logFile;
static const int MAX_NUMBER_OF_SYSCALLS = 1024;
static const char * syscalls[MAX_NUMBER_OF_SYSCALLS];
Debug();
std::string getTimestamp();
std::string getUname();
std::string peekData(pid_t shellPid, void *data, size_t length);
std::string formatToAddress(unsigned long long address);
public:
void log(std::string message, std::string fileName, int lineNo
, std::string functionName);
void logPtraceSysCall(pid_t shellPid, uint16_t sysCallId, bool returnedFromSysCall, unsigned long long result, unsigned long long firstArgument, unsigned long long secondArgument, unsigned long long thirdArgument, unsigned long long fourthArgument, std::string fileName, int lineNo, std::string functionName);
static Debug *getInstance();
};
}
#define __debug_log(message) \
krikkel::Debug::getInstance()->log(message, __FILE__, __LINE__, __func__)
#define __debug_log_ptrace_syscall(shellPid, sysCallId, returnedFromSysCall, result, firstArgument, secondArgument, thirdArgument, fourthArgument) \
krikkel::Debug::getInstance()->logPtraceSysCall(shellPid, sysCallId, returnedFromSysCall, result, firstArgument, secondArgument, thirdArgument, fourthArgument, __FILE__, __LINE__, __func__);
/// @todo need an explanation on why and how to use this
/// this is the complete opposite of self-explanatory
#define __debug_stringify_switch_begin(closureName, __prop, __value) \
auto __debug_stringify__##closureName = [__prop, __value]() -> std::string \
{ \
std::string propertyName, valueString; \
switch(__prop) \
{
#define __debug_stringify_switch_case(caseTestValue) \
case caseTestValue: \
propertyName = (propertyName.empty() ? #caseTestValue : propertyName); \
[[fallthrough]]
#define __debug_stringify_switch_last_case_bool(caseTestValue, value) \
case caseTestValue: \
propertyName = (propertyName.empty() ? #caseTestValue : propertyName); \
valueString = (value ? "true" : "false"); \
break
#define __debug_stringify_switch_last_case_string(caseTestValue, value) \
case caseTestValue: \
propertyName = (propertyName.empty() ? #caseTestValue : propertyName); \
valueString = "\"" + std::string(value) + "\""; \
break
#define __debug_stringify_switch_last_case_number(caseTestValue, value) \
case caseTestValue: \
propertyName = (propertyName.empty() ? #caseTestValue : propertyName); \
valueString = std::to_string(value); \
break;
#define __debug_stringify_switch_end(__prop) \
default: \
propertyName = "default case triggerd for " + std::to_string(__prop); \
break; \
} \
return propertyName + " = " + valueString; \
}
#define __debug_stringify_get_string(closureName) __debug_stringify__##closureName()
#define __debug_make_bytes_printable_table(__bytes) ([](std::string bytes) -> std::string \
{ \
std::locale loc; \
std::string result = "\n"; \
int index; \
for(index = 0; index < bytes.length(); ++index) \
{ \
static const uint8_t TRANSLATION_BUFFER_SIZE = 4; \
char translationBuffer[TRANSLATION_BUFFER_SIZE]; \
if(std::isprint(bytes[index], loc)) \
{ \
translationBuffer[0] = translationBuffer[1] = ' '; \
translationBuffer[2] = bytes[index]; \
translationBuffer[3] = '\0'; \
} \
else \
std::snprintf(translationBuffer, TRANSLATION_BUFFER_SIZE, " %02x", bytes[index]); \
result += (index % 16 == 0 ? " | " : " "); \
result += translationBuffer; \
if(index % 16 == 15) \
result += '\n'; \
} \
if(index % 16) \
result += '\n'; \
return result; \
} \
)(__bytes)
#define __debug_make_bytes_printable(__bytes) ([](std::string bytes) -> std::string \
{ \
std::locale loc; \
std::string result; \
for(char character : bytes) \
{ \
if(std::isprint(character, loc) && character != '<') \
result += character; \
else \
result += '<' + std::to_string((unsigned char) character) + '>'; \
} \
return result; \
})(__bytes)
#else
/// @todo check what's the business with this "((void)0)" instead of empty macro
#define __debug_log(message)
#define __debug_stringify_switch_begin(closureName, __prop, __value)
#define __debug_stringify_switch_case(caseTestValue)
#define __debug_stringify_switch_last_case_bool(caseTestValue, value)
#define __debug_stringify_switch_last_case_string(caseTestValue, value)
#define __debug_stringify_switch_last_case_number(caseTestValue, value)
#define __debug_stringify_switch_end(__prop)
#define __debug_make_bytes_printable_table(__bytes)
#define __debug_make_bytes_printable(__bytes)
#endif /* NDEBUG */
#endif // __DEBUG_H__