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:
parent
c53f760dfe
commit
39782e55fa
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 *);
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user