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:
Trung Nguyen
2023-05-31 16:34:12 +00:00
committed by waddlesplash
parent 0992009d13
commit bfd3d33765
8 changed files with 245 additions and 59 deletions
+1
View File
@@ -533,6 +533,7 @@ typedef struct {
debug_origin origin; debug_origin origin;
int signal; // the signal int signal; // the signal
struct sigaction handler; // the signal handler struct sigaction handler; // the signal handler
siginfo_t info; // the signal info
bool deadly; // true, if handling the signal will kill bool deadly; // true, if handling the signal will kill
// the team // the team
} debug_signal_received; } debug_signal_received;
+1 -1
View File
@@ -255,7 +255,7 @@ void user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
bigtime_t startTime); bigtime_t startTime);
bool user_debug_exception_occurred(debug_exception_type exception, int signal); bool user_debug_exception_occurred(debug_exception_type exception, int signal);
bool user_debug_handle_signal(int signal, struct sigaction *handler, 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_stop_thread();
void user_debug_team_created(team_id teamID); void user_debug_team_created(team_id teamID);
void user_debug_team_deleted(team_id teamID, port_id debuggerPort); void user_debug_team_deleted(team_id teamID, port_id debuggerPort);
+1
View File
@@ -24,6 +24,7 @@ local straceSources =
fcntl.cpp fcntl.cpp
ioctl.cpp ioctl.cpp
network.cpp network.cpp
signals.cpp
; ;
# Our compiler badly chokes when compiling the generated file. So will # Our compiler badly chokes when compiling the generated file. So will
+201
View File
@@ -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;
}
+18
View File
@@ -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
+8 -56
View File
@@ -25,6 +25,7 @@
#include "debug_utils.h" #include "debug_utils.h"
#include "signals.h"
#include "Context.h" #include "Context.h"
#include "MemoryReader.h" #include "MemoryReader.h"
#include "Syscall.h" #include "Syscall.h"
@@ -115,44 +116,6 @@ static const char *kTerminalTextMagenta = "\33[35m";
static const char *kTerminalTextBlue = "\33[34m"; 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 // command line args
static int sArgc; static int sArgc;
static const char *const *sArgv; 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 static void
print_signal(FILE *outputFile, debug_signal_received &message, print_signal(FILE *outputFile, debug_signal_received &message,
bool colorize) bool colorize)
@@ -529,13 +480,14 @@ print_signal(FILE *outputFile, debug_signal_received &message,
// print signal name // print signal name
if (colorize) { if (colorize) {
print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s%s (%s) %s---\n", print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s%s (%s)%s %s ---\n",
message.origin.thread, kTerminalTextRed, signal_name(signalNumber), message.origin.thread, kTerminalTextRed,
strsignal(signalNumber), kTerminalTextNormal); signal_name(signalNumber).c_str(), strsignal(signalNumber),
kTerminalTextNormal, signal_info(message.info).c_str());
} else { } else {
print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s (%s) ---\n", print_to_string(&string, &length, "[%6" B_PRId32 "] --- %s (%s) %s ---\n",
message.origin.thread, signal_name(signalNumber), message.origin.thread, signal_name(signalNumber).c_str(),
strsignal(signalNumber)); strsignal(signalNumber), signal_info(message.info).c_str());
} }
print_buffer(outputFile, buffer, sizeof(buffer) - length); print_buffer(outputFile, buffer, sizeof(buffer) - length);
+3 -1
View File
@@ -928,7 +928,8 @@ user_debug_exception_occurred(debug_exception_type exception, int signal)
bool 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 // check, if a debugger is installed and is interested in signals
Thread *thread = thread_get_current_thread(); 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; debug_signal_received message;
message.signal = signal; message.signal = signal;
message.handler = *handler; message.handler = *handler;
message.info = *info;
message.deadly = deadly; message.deadly = deadly;
status_t result = thread_hit_debug_event(B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED, status_t result = thread_hit_debug_event(B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED,
+12 -1
View File
@@ -821,8 +821,19 @@ notify_debugger(Thread* thread, Signal* signal, struct sigaction& handler,
threadDebugInfoLocker.Unlock(); 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 // deliver the event
return user_debug_handle_signal(signal->Number(), &handler, deadly); return user_debug_handle_signal(signal->Number(), &handler, &info, deadly);
} }