strace: Print detailed signal information
- Add support for retrieving the `siginfo_t` structure of a signal event from the Debugger API. - Add code to `strace` to display this information every time a signal event occurs, similar to the Linux `strace` tool. Change-Id: If4e92bbae049ee0b52efaf9fc911d66511da62f4 Reviewed-on: https://review.haiku-os.org/c/haiku/+/6393 Tested-by: Commit checker robot <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
0992009d13
commit
bfd3d33765
@@ -533,6 +533,7 @@ typedef struct {
|
||||
debug_origin origin;
|
||||
int signal; // the signal
|
||||
struct sigaction handler; // the signal handler
|
||||
siginfo_t info; // the signal info
|
||||
bool deadly; // true, if handling the signal will kill
|
||||
// the team
|
||||
} debug_signal_received;
|
||||
|
||||
@@ -255,7 +255,7 @@ void user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
|
||||
bigtime_t startTime);
|
||||
bool user_debug_exception_occurred(debug_exception_type exception, int signal);
|
||||
bool user_debug_handle_signal(int signal, struct sigaction *handler,
|
||||
bool deadly);
|
||||
siginfo_t *info, bool deadly);
|
||||
void user_debug_stop_thread();
|
||||
void user_debug_team_created(team_id teamID);
|
||||
void user_debug_team_deleted(team_id teamID, port_id debuggerPort);
|
||||
|
||||
@@ -24,6 +24,7 @@ local straceSources =
|
||||
fcntl.cpp
|
||||
ioctl.cpp
|
||||
network.cpp
|
||||
signals.cpp
|
||||
;
|
||||
|
||||
# Our compiler badly chokes when compiling the generated file. So will
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2023, Trung Nguyen, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "signals.h"
|
||||
|
||||
|
||||
// signal names
|
||||
static const char *kSignalName[] = {
|
||||
/* 0 */ "SIG0",
|
||||
/* 1 */ "SIGHUP",
|
||||
/* 2 */ "SIGINT",
|
||||
/* 3 */ "SIGQUIT",
|
||||
/* 4 */ "SIGILL",
|
||||
/* 5 */ "SIGCHLD",
|
||||
/* 6 */ "SIGABRT",
|
||||
/* 7 */ "SIGPIPE",
|
||||
/* 8 */ "SIGFPE",
|
||||
/* 9 */ "SIGKILL",
|
||||
/* 10 */ "SIGSTOP",
|
||||
/* 11 */ "SIGSEGV",
|
||||
/* 12 */ "SIGCONT",
|
||||
/* 13 */ "SIGTSTP",
|
||||
/* 14 */ "SIGALRM",
|
||||
/* 15 */ "SIGTERM",
|
||||
/* 16 */ "SIGTTIN",
|
||||
/* 17 */ "SIGTTOU",
|
||||
/* 18 */ "SIGUSR1",
|
||||
/* 19 */ "SIGUSR2",
|
||||
/* 20 */ "SIGWINCH",
|
||||
/* 21 */ "SIGKILLTHR",
|
||||
/* 22 */ "SIGTRAP",
|
||||
/* 23 */ "SIGPOLL",
|
||||
/* 24 */ "SIGPROF",
|
||||
/* 25 */ "SIGSYS",
|
||||
/* 26 */ "SIGURG",
|
||||
/* 27 */ "SIGVTALRM",
|
||||
/* 28 */ "SIGXCPU",
|
||||
/* 29 */ "SIGXFSZ",
|
||||
/* 30 */ "SIGBUS",
|
||||
/* 31 */ "SIGRESERVED1",
|
||||
/* 32 */ "SIGRESERVED2",
|
||||
};
|
||||
|
||||
|
||||
std::string
|
||||
signal_name(int signal)
|
||||
{
|
||||
if (signal >= 0 && signal <= SIGRESERVED2)
|
||||
return kSignalName[signal];
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2023, Trung Nguyen, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef STRACE_SIGNAL_H
|
||||
#define STRACE_SIGNAL_H
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
std::string signal_name(int signal);
|
||||
std::string signal_info(siginfo_t& info);
|
||||
|
||||
|
||||
#endif // STRACE_SIGNAL_H
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "debug_utils.h"
|
||||
|
||||
#include "signals.h"
|
||||
#include "Context.h"
|
||||
#include "MemoryReader.h"
|
||||
#include "Syscall.h"
|
||||
@@ -115,44 +116,6 @@ static const char *kTerminalTextMagenta = "\33[35m";
|
||||
static const char *kTerminalTextBlue = "\33[34m";
|
||||
|
||||
|
||||
// signal names
|
||||
static const char *kSignalName[] = {
|
||||
/* 0 */ "SIG0",
|
||||
/* 1 */ "SIGHUP",
|
||||
/* 2 */ "SIGINT",
|
||||
/* 3 */ "SIGQUIT",
|
||||
/* 4 */ "SIGILL",
|
||||
/* 5 */ "SIGCHLD",
|
||||
/* 6 */ "SIGABRT",
|
||||
/* 7 */ "SIGPIPE",
|
||||
/* 8 */ "SIGFPE",
|
||||
/* 9 */ "SIGKILL",
|
||||
/* 10 */ "SIGSTOP",
|
||||
/* 11 */ "SIGSEGV",
|
||||
/* 12 */ "SIGCONT",
|
||||
/* 13 */ "SIGTSTP",
|
||||
/* 14 */ "SIGALRM",
|
||||
/* 15 */ "SIGTERM",
|
||||
/* 16 */ "SIGTTIN",
|
||||
/* 17 */ "SIGTTOU",
|
||||
/* 18 */ "SIGUSR1",
|
||||
/* 19 */ "SIGUSR2",
|
||||
/* 20 */ "SIGWINCH",
|
||||
/* 21 */ "SIGKILLTHR",
|
||||
/* 22 */ "SIGTRAP",
|
||||
/* 23 */ "SIGPOLL",
|
||||
/* 24 */ "SIGPROF",
|
||||
/* 25 */ "SIGSYS",
|
||||
/* 26 */ "SIGURG",
|
||||
/* 27 */ "SIGVTALRM",
|
||||
/* 28 */ "SIGXCPU",
|
||||
/* 29 */ "SIGXFSZ",
|
||||
/* 30 */ "SIGBUS",
|
||||
/* 31 */ "SIGRESERVED1",
|
||||
/* 32 */ "SIGRESERVED2",
|
||||
};
|
||||
|
||||
|
||||
// command line args
|
||||
static int sArgc;
|
||||
static const char *const *sArgv;
|
||||
@@ -507,18 +470,6 @@ print_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message,
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
signal_name(int signal)
|
||||
{
|
||||
if (signal >= 0 && signal <= SIGRESERVED2)
|
||||
return kSignalName[signal];
|
||||
|
||||
static char buffer[32];
|
||||
sprintf(buffer, "%d", signal);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_signal(FILE *outputFile, debug_signal_received &message,
|
||||
bool colorize)
|
||||
@@ -529,13 +480,14 @@ print_signal(FILE *outputFile, debug_signal_received &message,
|
||||
|
||||
// print signal name
|
||||
if (colorize) {
|
||||
print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s%s (%s) %s---\n",
|
||||
message.origin.thread, kTerminalTextRed, signal_name(signalNumber),
|
||||
strsignal(signalNumber), kTerminalTextNormal);
|
||||
print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s%s (%s)%s %s ---\n",
|
||||
message.origin.thread, kTerminalTextRed,
|
||||
signal_name(signalNumber).c_str(), strsignal(signalNumber),
|
||||
kTerminalTextNormal, signal_info(message.info).c_str());
|
||||
} else {
|
||||
print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s (%s) ---\n",
|
||||
message.origin.thread, signal_name(signalNumber),
|
||||
strsignal(signalNumber));
|
||||
print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s (%s) %s ---\n",
|
||||
message.origin.thread, signal_name(signalNumber).c_str(),
|
||||
strsignal(signalNumber), signal_info(message.info).c_str());
|
||||
}
|
||||
|
||||
print_buffer(outputFile, buffer, sizeof(buffer) - length);
|
||||
|
||||
@@ -928,7 +928,8 @@ user_debug_exception_occurred(debug_exception_type exception, int signal)
|
||||
|
||||
|
||||
bool
|
||||
user_debug_handle_signal(int signal, struct sigaction *handler, bool deadly)
|
||||
user_debug_handle_signal(int signal, struct sigaction *handler, siginfo_t *info,
|
||||
bool deadly)
|
||||
{
|
||||
// check, if a debugger is installed and is interested in signals
|
||||
Thread *thread = thread_get_current_thread();
|
||||
@@ -942,6 +943,7 @@ user_debug_handle_signal(int signal, struct sigaction *handler, bool deadly)
|
||||
debug_signal_received message;
|
||||
message.signal = signal;
|
||||
message.handler = *handler;
|
||||
message.info = *info;
|
||||
message.deadly = deadly;
|
||||
|
||||
status_t result = thread_hit_debug_event(B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED,
|
||||
|
||||
@@ -821,8 +821,19 @@ notify_debugger(Thread* thread, Signal* signal, struct sigaction& handler,
|
||||
|
||||
threadDebugInfoLocker.Unlock();
|
||||
|
||||
siginfo_t info;
|
||||
info.si_signo = signal->Number();
|
||||
info.si_code = signal->SignalCode();
|
||||
info.si_errno = signal->ErrorCode();
|
||||
info.si_pid = signal->SendingProcess();
|
||||
info.si_uid = signal->SendingUser();
|
||||
info.si_addr = signal->Address();
|
||||
info.si_status = signal->Status();
|
||||
info.si_band = signal->PollBand();
|
||||
info.si_value = signal->UserValue();
|
||||
|
||||
// deliver the event
|
||||
return user_debug_handle_signal(signal->Number(), &handler, deadly);
|
||||
return user_debug_handle_signal(signal->Number(), &handler, &info, deadly);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user