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 <no-reply+buildbot@haiku-os.org>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Jérôme Duval 2021-12-04 19:22:05 +01:00 committed by waddlesplash
parent c53f760dfe
commit 39782e55fa
5 changed files with 267 additions and 8 deletions

View File

@ -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

View File

@ -8,6 +8,7 @@
*/
#include <arpa/inet.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -110,6 +111,138 @@ TypeHandlerImpl<fd_set *>::GetReturnValue(Context &context, uint64 value)
}
template<typename value_t>
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<nfds_t>(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<pollfd *>::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<pollfd *>::GetReturnValue(Context &context, uint64 value)
{
return context.FormatPointer((void *)value);
}
template<typename Type>
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);

View File

@ -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<Parameter*> fParameters;
bool fPreSyscall;
};
#endif // STRACE_SYSCALL_H

View File

@ -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 *);

View File

@ -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: