* Copyright 2023, Trung Nguyen, trungnt282910@gmail.com.
* Distributed under the terms of the MIT License.
*/
#include <stdio.h>
#include <string>
#include "signals.h"
#include "strace.h"
#include "Context.h"
#include "MemoryReader.h"
#include "Syscall.h"
#include "TypeHandler.h"
struct enum_info {
int index;
const char *name;
};
#define ENUM_INFO_ENTRY(name) \
{ name, #name }
static const enum_info kSignals[] = {
{ 0, "SIG0"},
ENUM_INFO_ENTRY(SIGHUP),
ENUM_INFO_ENTRY(SIGINT),
ENUM_INFO_ENTRY(SIGQUIT),
ENUM_INFO_ENTRY(SIGILL),
ENUM_INFO_ENTRY(SIGCHLD),
ENUM_INFO_ENTRY(SIGABRT),
ENUM_INFO_ENTRY(SIGPIPE),
ENUM_INFO_ENTRY(SIGFPE),
ENUM_INFO_ENTRY(SIGKILL),
ENUM_INFO_ENTRY(SIGSTOP),
ENUM_INFO_ENTRY(SIGSEGV),
ENUM_INFO_ENTRY(SIGCONT),
ENUM_INFO_ENTRY(SIGTSTP),
ENUM_INFO_ENTRY(SIGALRM),
ENUM_INFO_ENTRY(SIGTERM),
ENUM_INFO_ENTRY(SIGTTIN),
ENUM_INFO_ENTRY(SIGTTOU),
ENUM_INFO_ENTRY(SIGUSR1),
ENUM_INFO_ENTRY(SIGUSR2),
ENUM_INFO_ENTRY(SIGWINCH),
ENUM_INFO_ENTRY(SIGKILLTHR),
ENUM_INFO_ENTRY(SIGTRAP),
ENUM_INFO_ENTRY(SIGPOLL),
ENUM_INFO_ENTRY(SIGPROF),
ENUM_INFO_ENTRY(SIGSYS),
ENUM_INFO_ENTRY(SIGURG),
ENUM_INFO_ENTRY(SIGVTALRM),
ENUM_INFO_ENTRY(SIGXCPU),
ENUM_INFO_ENTRY(SIGXFSZ),
ENUM_INFO_ENTRY(SIGBUS),
ENUM_INFO_ENTRY(SIGRESERVED1),
ENUM_INFO_ENTRY(SIGRESERVED2),
{ 0, NULL }
};
static EnumTypeHandler::EnumMap kSignalsMap;
static const enum_info kSigmaskHow[] = {
ENUM_INFO_ENTRY(SIG_BLOCK),
ENUM_INFO_ENTRY(SIG_UNBLOCK),
ENUM_INFO_ENTRY(SIG_SETMASK),
{ 0, NULL }
};
#define sigmask(sig) (1 << ((sig) - 1))
#define FLAG_INFO_ENTRY(name) \
{ sigmask( SIG##name ), #name }
static const FlagsTypeHandler::FlagInfo kSigmaskFlagsInfo[] = {
FLAG_INFO_ENTRY(HUP),
FLAG_INFO_ENTRY(INT),
FLAG_INFO_ENTRY(QUIT),
FLAG_INFO_ENTRY(ILL),
FLAG_INFO_ENTRY(CHLD),
FLAG_INFO_ENTRY(ABRT),
FLAG_INFO_ENTRY(PIPE),
FLAG_INFO_ENTRY(FPE),
FLAG_INFO_ENTRY(KILL),
FLAG_INFO_ENTRY(STOP),
FLAG_INFO_ENTRY(SEGV),
FLAG_INFO_ENTRY(CONT),
FLAG_INFO_ENTRY(TSTP),
FLAG_INFO_ENTRY(ALRM),
FLAG_INFO_ENTRY(TERM),
FLAG_INFO_ENTRY(TTIN),
FLAG_INFO_ENTRY(TTOU),
FLAG_INFO_ENTRY(USR1),
FLAG_INFO_ENTRY(USR2),
FLAG_INFO_ENTRY(WINCH),
FLAG_INFO_ENTRY(KILLTHR),
FLAG_INFO_ENTRY(TRAP),
FLAG_INFO_ENTRY(POLL),
FLAG_INFO_ENTRY(PROF),
FLAG_INFO_ENTRY(SYS),
FLAG_INFO_ENTRY(URG),
FLAG_INFO_ENTRY(VTALRM),
FLAG_INFO_ENTRY(XCPU),
FLAG_INFO_ENTRY(XFSZ),
FLAG_INFO_ENTRY(BUS),
{ 0, NULL }
};
static FlagsTypeHandler::FlagsList kSigmaskFlags;
static EnumTypeHandler::EnumMap kSigmaskHowMap;
std::string
signal_name(int signal)
{
EnumTypeHandler::EnumMap::const_iterator i = kSignalsMap.find(signal);
if (i != kSignalsMap.end() && i->second != NULL)
return i->second;
static char buffer[32];
sprintf(buffer, "%d", signal);
return buffer;
}
static const char *
signal_code(int signal, int code)
{
#define CASE(X) case X: return #X;
switch (code) {
CASE(SI_USER)
CASE(SI_QUEUE)
CASE(SI_TIMER)
CASE(SI_ASYNCIO)
CASE(SI_MESGQ)
}
switch (signal) {
case SIGILL:
switch (code) {
CASE(ILL_ILLOPC)
CASE(ILL_ILLOPN)
CASE(ILL_ILLADR)
CASE(ILL_ILLTRP)
CASE(ILL_PRVOPC)
CASE(ILL_PRVREG)
CASE(ILL_COPROC)
CASE(ILL_BADSTK)
}
break;
case SIGFPE:
switch (code) {
CASE(FPE_INTDIV)
CASE(FPE_INTOVF)
CASE(FPE_FLTDIV)
CASE(FPE_FLTOVF)
CASE(FPE_FLTUND)
CASE(FPE_FLTRES)
CASE(FPE_FLTINV)
CASE(FPE_FLTSUB)
}
break;
case SIGSEGV:
switch (code) {
CASE(SEGV_MAPERR)
CASE(SEGV_ACCERR)
}
break;
case SIGBUS:
switch (code) {
CASE(BUS_ADRALN)
CASE(BUS_ADRERR)
CASE(BUS_OBJERR)
}
break;
case SIGTRAP:
switch (code) {
CASE(TRAP_BRKPT)
CASE(TRAP_TRACE)
}
break;
case SIGCHLD:
switch (code) {
CASE(CLD_EXITED)
CASE(CLD_KILLED)
CASE(CLD_DUMPED)
CASE(CLD_TRAPPED)
CASE(CLD_STOPPED)
CASE(CLD_CONTINUED)
}
break;
case SIGPOLL:
switch (code) {
CASE(POLL_IN)
CASE(POLL_OUT)
CASE(POLL_MSG)
CASE(POLL_ERR)
CASE(POLL_PRI)
CASE(POLL_HUP)
}
break;
}
#undef CASE
static char buffer[32];
sprintf(buffer, "%d", code);
return buffer;
}
std::string
signal_info(siginfo_t& info)
{
static char buffer[32];
std::string string;
string.reserve(256);
string += "{";
string += "si_signo=";
string += signal_name(info.si_signo);
string += ", si_code=";
string += signal_code(info.si_signo, info.si_code);
if (info.si_errno != 0) {
string += ", si_errno=0x";
sprintf(buffer, "%x", info.si_errno);
string += buffer;
}
string += ", si_pid=";
sprintf(buffer, "%d", (int)info.si_pid);
string += buffer;
string += ", si_uid=";
sprintf(buffer, "%d", (int)info.si_uid);
string += buffer;
if (info.si_signo == SIGILL || info.si_signo == SIGFPE || info.si_signo == SIGSEGV
|| info.si_signo == SIGBUS || info.si_signo == SIGTRAP) {
string += ", si_addr=";
sprintf(buffer, "%p", info.si_addr);
string += buffer;
}
if (info.si_signo == SIGCHLD) {
string += ", si_status=";
sprintf(buffer, "%d", info.si_status);
string += buffer;
}
if (info.si_signo == SIGPOLL) {
string += ", si_band=";
sprintf(buffer, "%ld", info.si_band);
string += buffer;
}
string += ", si_value=";
sprintf(buffer, "%p", info.si_value.sival_ptr);
string += buffer;
string += "}";
return string;
}
class SigsetTypeHandler : public FlagsTypeHandler {
public:
SigsetTypeHandler()
:
FlagsTypeHandler(kSigmaskFlags)
{
}
string GetParameterValue(Context &context, Parameter *param,
const void *address)
{
void *data = *(void **)address;
if (context.GetContents(Context::POINTER_VALUES)) {
int32 bytesRead;
sigset_t value;
status_t err = context.Reader().Read(data, &value, sizeof(value), bytesRead);
if (err != B_OK)
return context.FormatPointer(data);
uint32 count = 0;
#if __GNUC__ > 2
count += __builtin_popcount(value);
#else
{
sigset_t mask = value;
while (mask > 0) {
if ((mask & 1) == 1)
count++;
mask >>= 1;
}
}
#endif
string r;
if (count > SIGRESERVED2 * 2 / 3) {
value = ~value;
r += "~";
}
value &= (((sigset_t)1 << SIGRESERVED2) - 1);
r += "[";
r += RenderValue(context, value);
r += "]";
return r;
}
return context.FormatPointer(data);
}
string GetReturnValue(Context &context, uint64 value)
{
return context.FormatPointer((void *)value);
}
};
void
patch_signal()
{
for (int i = 0; kSigmaskFlagsInfo[i].name != NULL; i++)
kSigmaskFlags.push_back(kSigmaskFlagsInfo[i]);
for (int i = 0; kSigmaskHow[i].name != NULL; i++)
kSigmaskHowMap[kSigmaskHow[i].index] = kSigmaskHow[i].name;
for (int i = 0; kSignals[i].name != NULL; i++)
kSignalsMap[kSignals[i].index] = kSignals[i].name;
Syscall *setSignalMask = get_syscall("_kern_set_signal_mask");
setSignalMask->GetParameter("how")->SetHandler(new EnumTypeHandler(kSigmaskHowMap));
setSignalMask->GetParameter("set")->SetHandler(new SigsetTypeHandler());
setSignalMask->GetParameter("oldSet")->SetHandler(new SigsetTypeHandler());
setSignalMask->GetParameter("oldSet")->SetOut(true);
Syscall *sigwait = get_syscall("_kern_sigwait");
sigwait->GetParameter("set")->SetHandler(new SigsetTypeHandler());
sigwait->GetParameter("info")->SetOut(true);
Syscall *sigsuspend = get_syscall("_kern_sigsuspend");
sigsuspend->GetParameter("mask")->SetHandler(new SigsetTypeHandler());
Syscall *sigpending = get_syscall("_kern_sigpending");
sigpending->GetParameter("set")->SetHandler(new SigsetTypeHandler());
sigpending->GetParameter("set")->SetOut(true);
Syscall *sendSignal = get_syscall("_kern_send_signal");
sendSignal->GetParameter("signal")->SetHandler(new EnumTypeHandler(kSignalsMap));
Syscall *sigaction = get_syscall("_kern_sigaction");
sigaction->GetParameter("sig")->SetHandler(new EnumTypeHandler(kSignalsMap));
}