From 39782e55fab9b19be3141d7158f0d0c45c27339e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 4 Dec 2021 19:22:05 +0100 Subject: [PATCH] strace: support trace for poll() and select() in the case of poll(), the events should be printed before the actual syscall, and the revents after, while taking in account the return value. thus B_DEBUGGER_MESSAGE_PRE_SYSCALL needs to be enabled and handled. the attribute "preSyscall" is added to identify such syscalls, and the parameters are identified with the attribute "inOut". Change-Id: I390643ea176c720738c5ec4fc75a3a4c7125a3cd Reviewed-on: https://review.haiku-os.org/c/haiku/+/4763 Tested-by: Commit checker robot Reviewed-by: waddlesplash --- src/bin/debug/strace/Context.h | 13 ++- src/bin/debug/strace/NetworkTypes.cpp | 134 ++++++++++++++++++++++++++ src/bin/debug/strace/Syscall.h | 14 +++ src/bin/debug/strace/TypeHandler.h | 2 + src/bin/debug/strace/strace.cpp | 112 ++++++++++++++++++++- 5 files changed, 267 insertions(+), 8 deletions(-) diff --git a/src/bin/debug/strace/Context.h b/src/bin/debug/strace/Context.h index f8ba3bfbeb..377b2bd6de 100644 --- a/src/bin/debug/strace/Context.h +++ b/src/bin/debug/strace/Context.h @@ -19,13 +19,15 @@ public: SIMPLE_STRUCTS = 1 << 2, COMPLEX_STRUCTS = 1 << 3, POINTER_VALUES = 1 << 4, - ALL = 0xffffffff + INPUT_VALUES = 1 << 5, + OUTPUT_VALUES = 1 << 6, + ALL = 0xffffff9f }; Context(Syscall *sc, char *data, MemoryReader &reader, - uint32 flags, bool decimal) + uint32 flags, bool decimal, uint64 returnValue = 0) : fSyscall(sc), fData(data), fReader(reader), - fFlags(flags), fDecimal(decimal) {} + fFlags(flags), fDecimal(decimal), fReturnValue(returnValue) {} Parameter *GetSibling(int32 index) const { return fSyscall->ParameterAt(index); @@ -35,6 +37,10 @@ public: return fData + param->Offset(); } + uint64 GetReturnValue() const { + return fReturnValue; + } + MemoryReader &Reader() { return fReader; } bool GetContents(uint32 what) const { return fFlags & what; } @@ -50,6 +56,7 @@ private: MemoryReader &fReader; uint32 fFlags; bool fDecimal; + uint64 fReturnValue; }; #endif // STRACE_CONTEXT_H diff --git a/src/bin/debug/strace/NetworkTypes.cpp b/src/bin/debug/strace/NetworkTypes.cpp index 9d5d2c4e72..a5411e7748 100644 --- a/src/bin/debug/strace/NetworkTypes.cpp +++ b/src/bin/debug/strace/NetworkTypes.cpp @@ -8,6 +8,7 @@ */ #include +#include #include #include @@ -110,6 +111,138 @@ TypeHandlerImpl::GetReturnValue(Context &context, uint64 value) } +template +static inline value_t +get_value(const void *address) +{ + if (sizeof(align_t) > sizeof(value_t)) + return value_t(*(align_t*)address); + else + return *(value_t*)address; +} + + +static string +format_signed_number(int32 value) +{ + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%d", (signed int)value); + return tmp; +} + + +static string +read_pollfd(Context &context, void *data) +{ + nfds_t numfds = 0; + if (context.GetContents(Context::INPUT_VALUES)) + numfds = get_value(context.GetValue(context.GetSibling(1))); + else if (context.GetContents(Context::OUTPUT_VALUES)) + numfds = context.GetReturnValue(); + if ((int64)numfds <= 0) + return string(); + + pollfd tmp[numfds]; + int32 bytesRead; + + status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead); + if (err != B_OK) + return context.FormatPointer(data); + + int added = 0; + + string r; + r.reserve(16); + + r = "["; + + for (nfds_t i = 0; i < numfds && added < 8; i++) { + if (added > 0) + r += ", "; + r += "{fd=" + format_signed_number(tmp[i].fd); + if (tmp[i].fd != -1 && context.GetContents(Context::INPUT_VALUES)) { + r += ", events="; + int flags = 0; + if ((tmp[i].events & POLLIN) != 0) { + if (flags > 0) + r += "|"; + r += "POLLIN"; + flags++; + } + if ((tmp[i].events & POLLOUT) != 0) { + if (flags > 0) + r += "|"; + r += "POLLOUT"; + flags++; + } + } + if (tmp[i].fd != -1 && context.GetContents(Context::OUTPUT_VALUES)) { + r += ", revents="; + int flags = 0; + if ((tmp[i].revents & POLLIN) != 0) { + if (flags > 0) + r += "|"; + r += "POLLIN"; + flags++; + } + if ((tmp[i].revents & POLLOUT) != 0) { + if (flags > 0) + r += "|"; + r += "POLLOUT"; + flags++; + } + if ((tmp[i].revents & POLLERR) != 0) { + if (flags > 0) + r += "|"; + r += "POLLERR"; + flags++; + } + if ((tmp[i].revents & POLLHUP) != 0) { + if (flags > 0) + r += "|"; + r += "POLLHUP"; + flags++; + } + if ((tmp[i].revents & POLLNVAL) != 0) { + if (flags > 0) + r += "|"; + r += "POLLNVAL"; + flags++; + } + } + added++; + r += "}"; + } + + if (added >= 8) + r += " ..."; + + r += "]"; + + return r; +} + + +template<> +string +TypeHandlerImpl::GetParameterValue(Context &context, Parameter *, + const void *address) +{ + void *data = *(void **)address; + if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS)) + return read_pollfd(context, data); + return context.FormatPointer(data); +} + + +template<> +string +TypeHandlerImpl::GetReturnValue(Context &context, uint64 value) +{ + return context.FormatPointer((void *)value); +} + + template static string format_pointer_value(Context &context, void *address) @@ -502,6 +635,7 @@ class SpecializedPointerTypeHandler : public TypeHandler { DEFINE_TYPE(fdset_ptr, fd_set *); POINTER_TYPE(ifconf_ptr, ifconf); POINTER_TYPE(ifreq_ptr, ifreq); +DEFINE_TYPE(pollfd_ptr, pollfd *); #if 0 POINTER_TYPE(message_args_ptr, message_args); POINTER_TYPE(msghdr_ptr, msghdr); diff --git a/src/bin/debug/strace/Syscall.h b/src/bin/debug/strace/Syscall.h index a59904ea76..29971c2c0e 100644 --- a/src/bin/debug/strace/Syscall.h +++ b/src/bin/debug/strace/Syscall.h @@ -48,10 +48,13 @@ public: const string &Name() const { return fName; } int32 Offset() const { return fOffset; } + bool InOut() const { return fInOut; } + void SetInOut(bool inout) { fInOut = inout; } private: string fName; int32 fOffset; + bool fInOut; }; // Syscall @@ -106,10 +109,21 @@ public: return NULL; } + bool IsPreSyscall() const + { + return fPreSyscall; + } + + void SetPreSyscall(bool preSyscall) + { + fPreSyscall = preSyscall; + } + private: string fName; Type *fReturnType; vector fParameters; + bool fPreSyscall; }; #endif // STRACE_SYSCALL_H diff --git a/src/bin/debug/strace/TypeHandler.h b/src/bin/debug/strace/TypeHandler.h index 86e80e5948..ce7367303d 100644 --- a/src/bin/debug/strace/TypeHandler.h +++ b/src/bin/debug/strace/TypeHandler.h @@ -101,6 +101,7 @@ struct fd_set; struct ifconf; struct ifreq; struct message_args; +struct pollfd; struct sockaddr_args; struct socket_args; struct sockopt_args; @@ -109,6 +110,7 @@ DEFINE_FACTORY(fdset_ptr, fd_set *); DEFINE_FACTORY(ifconf_ptr, ifconf *); DEFINE_FACTORY(ifreq_ptr, ifreq *); DEFINE_FACTORY(message_args_ptr, message_args *); +DEFINE_FACTORY(pollfd_ptr, pollfd *); DEFINE_FACTORY(sockaddr_args_ptr, sockaddr_args *); DEFINE_FACTORY(socket_args_ptr, socket_args *); DEFINE_FACTORY(sockopt_args_ptr, sockopt_args *); diff --git a/src/bin/debug/strace/strace.cpp b/src/bin/debug/strace/strace.cpp index 7d17b704e8..9a0e7ce599 100644 --- a/src/bin/debug/strace/strace.cpp +++ b/src/bin/debug/strace/strace.cpp @@ -262,6 +262,16 @@ patch_syscalls() extern void patch_ioctl(); patch_ioctl(); + + Syscall *poll = get_syscall("_kern_poll"); + poll->SetPreSyscall(true); + poll->ParameterAt(0)->SetInOut(true); + + Syscall *select = get_syscall("_kern_select"); + select->SetPreSyscall(true); + select->ParameterAt(1)->SetInOut(true); + select->ParameterAt(2)->SetInOut(true); + select->ParameterAt(3)->SetInOut(true); } @@ -338,15 +348,15 @@ print_to_string(char **_buffer, int32 *_length, const char *format, ...) static void -print_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message, +print_syscall(FILE *outputFile, Syscall* syscall, debug_pre_syscall &message, MemoryReader &memoryReader, bool printArguments, uint32 contentsFlags, - bool printReturnValue, bool colorize, bool decimal) + bool colorize, bool decimal) { char buffer[4096], *string = buffer; int32 length = (int32)sizeof(buffer); Context ctx(syscall, (char *)message.args, memoryReader, - contentsFlags, decimal); + contentsFlags | Context::INPUT_VALUES, decimal); // print syscall name, without the "_kern_" if (colorize) { @@ -376,6 +386,50 @@ print_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message, print_to_string(&string, &length, ")"); + print_buffer(outputFile, buffer, sizeof(buffer) - length); +} + + +static void +print_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message, + MemoryReader &memoryReader, bool printArguments, uint32 contentsFlags, + bool printReturnValue, bool colorize, bool decimal) +{ + char buffer[4096], *string = buffer; + int32 length = (int32)sizeof(buffer); + + Context ctx(syscall, (char *)message.args, memoryReader, + contentsFlags | Context::OUTPUT_VALUES, decimal, message.return_value); + + if (!syscall->IsPreSyscall()) { + // print syscall name, without the "_kern_" + if (colorize) { + print_to_string(&string, &length, "[%6" B_PRId32 "] %s%s%s(", + message.origin.thread, kTerminalTextBlue, + syscall->Name().c_str() + 6, kTerminalTextNormal); + } else { + print_to_string(&string, &length, "[%6" B_PRId32 "] %s(", + message.origin.thread, syscall->Name().c_str() + 6); + } + + // print arguments + if (printArguments) { + int32 count = syscall->CountParameters(); + for (int32 i = 0; i < count; i++) { + // get the value + Parameter *parameter = syscall->ParameterAt(i); + TypeHandler *handler = parameter->Handler(); + ::string value = + handler->GetParameterValue(ctx, parameter, + ctx.GetValue(parameter)); + + print_to_string(&string, &length, (i > 0 ? ", %s" : "%s"), + value.c_str()); + } + } + + print_to_string(&string, &length, ")"); + } // print return value if (printReturnValue) { Type *returnType = syscall->ReturnType(); @@ -395,6 +449,30 @@ print_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message, } } + if (syscall->IsPreSyscall()) { + // print arguments + if (printArguments) { + int32 count = syscall->CountParameters(); + int added = 0; + print_to_string(&string, &length, " ("); + for (int32 i = 0; i < count; i++) { + // get the value + Parameter *parameter = syscall->ParameterAt(i); + if (!parameter->InOut()) + continue; + TypeHandler *handler = parameter->Handler(); + ::string value = + handler->GetParameterValue(ctx, parameter, + ctx.GetValue(parameter)); + + print_to_string(&string, &length, (added > 0 ? ", %s" : "%s"), + value.c_str()); + added++; + } + print_to_string(&string, &length, ")"); + } + } + if (colorize) { print_to_string(&string, &length, " %s(%lld us)%s\n", kTerminalTextMagenta, message.end_time - message.start_time, kTerminalTextNormal); @@ -684,7 +762,7 @@ main(int argc, const char *const *argv) if (threadID >= 0) { int32 threadDebugFlags = 0; if (!traceTeam) { - threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL + threadDebugFlags = B_THREAD_DEBUG_PRE_SYSCALL | B_THREAD_DEBUG_POST_SYSCALL | (traceChildThreads ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0); } @@ -715,6 +793,31 @@ main(int argc, const char *const *argv) } switch (code) { + case B_DEBUGGER_MESSAGE_PRE_SYSCALL: + { + TeamMap::iterator it = debuggedTeams.find(message.origin.team); + if (it == debuggedTeams.end()) + break; + + Team* team = it->second; + MemoryReader& memoryReader = team->GetMemoryReader(); + + uint32 syscallNumber = message.pre_syscall.syscall; + if (syscallNumber >= sSyscallVector.size()) { + fprintf(stderr, "%s: invalid syscall %" B_PRIu32 " attempted\n", + kCommandName, syscallNumber); + break; + } + Syscall* syscall = sSyscallVector[syscallNumber]; + + if (syscall->IsPreSyscall() && trace) { + print_syscall(outputFile, syscall, message.pre_syscall, + memoryReader, printArguments, contentsFlags, + colorize, decimalFormat); + } + break; + } + case B_DEBUGGER_MESSAGE_POST_SYSCALL: { TeamMap::iterator it = debuggedTeams.find(message.origin.team); @@ -755,7 +858,6 @@ main(int argc, const char *const *argv) case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: case B_DEBUGGER_MESSAGE_SINGLE_STEP: - case B_DEBUGGER_MESSAGE_PRE_SYSCALL: case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: case B_DEBUGGER_MESSAGE_THREAD_CREATED: case B_DEBUGGER_MESSAGE_THREAD_DELETED: