From 39c9d198ea892211dae72aafce42ddcca6e681d0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 11 Feb 2005 05:09:36 +0000 Subject: [PATCH] * Moved strace source into separate subdirectory. * Now syscall names and parameters are printed. const char* parameters and return values are retrieved from the client and printed as string. * Missing are still color output (does consoled support that?) and searching for given commands in the PATH. Nothing besides the standard mode has been tested yet, so it's probably not working. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11345 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/bin/strace/Jamfile | 33 ++ src/apps/bin/strace/MemoryReader.cpp | 105 ++++++ src/apps/bin/strace/MemoryReader.h | 25 ++ src/apps/bin/strace/Syscall.h | 104 +++++ src/apps/bin/strace/TypeHandler.cpp | 251 +++++++++++++ src/apps/bin/strace/TypeHandler.h | 124 ++++++ src/apps/bin/strace/strace.cpp | 480 ++++++++++++++++++++++++ src/apps/bin/strace/strace_syscalls.cpp | 13 + 8 files changed, 1135 insertions(+) create mode 100644 src/apps/bin/strace/Jamfile create mode 100644 src/apps/bin/strace/MemoryReader.cpp create mode 100644 src/apps/bin/strace/MemoryReader.h create mode 100644 src/apps/bin/strace/Syscall.h create mode 100644 src/apps/bin/strace/TypeHandler.cpp create mode 100644 src/apps/bin/strace/TypeHandler.h create mode 100644 src/apps/bin/strace/strace.cpp create mode 100644 src/apps/bin/strace/strace_syscalls.cpp diff --git a/src/apps/bin/strace/Jamfile b/src/apps/bin/strace/Jamfile new file mode 100644 index 0000000000..42aa9abb07 --- /dev/null +++ b/src/apps/bin/strace/Jamfile @@ -0,0 +1,33 @@ +SubDir OBOS_TOP src apps bin strace ; + +# We need our objects dir in the include paths. +SetupObjectsDir ; + +UseArchHeaders $(OBOS_ARCH) ; +UsePrivateHeaders kernel ; +UsePrivateHeaders shared ; + +local straceSources = strace.cpp MemoryReader.cpp TypeHandler.cpp ; + +local straceSyscallsIndices + = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; + +local straceSyscallsSource = [ FGristFiles strace_syscalls.cpp ] ; +local straceSyscallsObjects ; + +local i ; +for i in $(straceSyscallsIndices) { + local object = [ FGristFiles strace_syscalls$(i).o ] ; + straceSyscallsObjects += $(object) ; + + Object $(object) : $(straceSyscallsSource) ; + + ObjectDefines $(object) + : GET_SYSCALLS=get_syscalls$(i) SYSCALLS_CHUNK_$(i) ; +} + +BinCommand strace : $(straceSources) + : $(straceSyscallsObjects) libroot.so libstdc++.r4.so ; + +# We need to specify the dependency on the generated syscalls file explicitly. +Includes $(straceSyscallsSource) : strace_syscalls.h ; diff --git a/src/apps/bin/strace/MemoryReader.cpp b/src/apps/bin/strace/MemoryReader.cpp new file mode 100644 index 0000000000..f0f7893655 --- /dev/null +++ b/src/apps/bin/strace/MemoryReader.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ + +#include +#include + +#include + +#include "MemoryReader.h" + +// constructor +MemoryReader::MemoryReader(port_id nubPort) + : fNubPort(nubPort), + fReplyPort(-1) +{ + fReplyPort = create_port(1, "memory reader reply"); + if (fReplyPort < 0) { + fprintf(stderr, "Failed to create memory reader reply port: %s\n", + strerror(fReplyPort)); + exit(1); + } +} + +// constructor +MemoryReader::~MemoryReader() +{ + if (fReplyPort >= 0) + delete_port(fReplyPort); +} + +// Read +status_t +MemoryReader::Read(void *_address, void *_buffer, int32 size, int32 &bytesRead) +{ + char *address = (char*)_address; + char *buffer = (char*)_buffer; + bytesRead = 0; + + // If the region to be read crosses page boundaries, we split it up into + // smaller chunks. + while (size > 0) { + int32 toRead = size; + if (toRead > B_MAX_READ_WRITE_MEMORY_SIZE) + toRead = B_MAX_READ_WRITE_MEMORY_SIZE; + if ((uint32)address % B_PAGE_SIZE + toRead > B_PAGE_SIZE) + toRead = B_PAGE_SIZE - (uint32)address % B_PAGE_SIZE; + + status_t error = _Read(address, buffer, toRead); + + // If reading fails, we only fail, if we haven't read something yet. + if (error != B_OK) { + if (bytesRead > 0) + return B_OK; + return error; + } + + bytesRead += toRead; + address += toRead; + buffer += toRead; + size -= toRead; + } + + return B_OK; +} + +// _Read +status_t +MemoryReader::_Read(void *address, void *buffer, int32 size) +{ + // prepare message + debug_nub_read_memory message; + message.reply_port = fReplyPort; + message.address = address; + message.size = size; + + // send message + while (true) { + status_t error = write_port(fNubPort, B_DEBUG_MESSAGE_READ_MEMORY, + &message, sizeof(message)); + if (error == B_OK) + break; + if (error != B_INTERRUPTED) + return error; + } + + // get reply + int32 code; + debug_nub_read_memory_reply reply; + while (true) { + ssize_t bytesRead = read_port(fReplyPort, &code, &reply, sizeof(reply)); + if (bytesRead > 0) + break; + if (bytesRead != B_INTERRUPTED) + return bytesRead; + } + + if (reply.error != B_OK) + return reply.error; + + memcpy(buffer, reply.data, size); + + return B_OK; +} diff --git a/src/apps/bin/strace/MemoryReader.h b/src/apps/bin/strace/MemoryReader.h new file mode 100644 index 0000000000..0033746e46 --- /dev/null +++ b/src/apps/bin/strace/MemoryReader.h @@ -0,0 +1,25 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ +#ifndef STRACE_MEMORY_READER_H +#define STRACE_MEMORY_READER_H + +#include + +class MemoryReader { +public: + MemoryReader(port_id nubPort); + ~MemoryReader(); + + status_t Read(void *address, void *buffer, int32 size, int32 &bytesRead); + +private: + status_t _Read(void *address, void *buffer, int32 size); + + port_id fNubPort; + port_id fReplyPort; +}; + + +#endif // STRACE_MEMORY_READER_H diff --git a/src/apps/bin/strace/Syscall.h b/src/apps/bin/strace/Syscall.h new file mode 100644 index 0000000000..b080e6126d --- /dev/null +++ b/src/apps/bin/strace/Syscall.h @@ -0,0 +1,104 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ +#ifndef STRACE_SYSCALL_H +#define STRACE_SYSCALL_H + +#include +#include + +#include + +#include "TypeHandler.h" + +// Type +class Type { +public: + Type(TypeHandler *handler) : fHandler(handler) {} + + void SetHandler(TypeHandler *handler) + { + delete fHandler; + fHandler = handler; + } + + TypeHandler *Handler() const { return fHandler; } + +private: + TypeHandler *fHandler; +}; + +// Parameter +class Parameter : public Type { +public: + Parameter(string name, int32 offset, TypeHandler *handler) + : Type(handler), + fName(name), + fOffset(offset) + { + } + + const string &Name() const { return fName; } + int32 Offset() const { return fOffset; } + +private: + string fName; + int32 fOffset; +}; + +// Syscall +class Syscall { +public: + Syscall(string name, TypeHandler *returnTypeHandler) + : fName(name), fReturnType(new Type(returnTypeHandler)) {} + + const string &Name() const + { + return fName; + } + + Type *ReturnType() const + { + return fReturnType; + } + + void AddParameter(Parameter *parameter) + { + fParameters.push_back(parameter); + } + + void AddParameter(string name, int32 offset, TypeHandler *handler) + { + AddParameter(new Parameter(name, offset, handler)); + } + + int32 CountParameters() const + { + return fParameters.size(); + } + + Parameter *ParameterAt(int32 index) const + { + return fParameters[index]; + } + + Parameter *GetParameter(string name) const + { + int32 count = CountParameters(); + for (int32 i = 0; i < count; i++) { + Parameter *parameter = ParameterAt(i); + if (parameter->Name() == name) + return parameter; + } + + return NULL; + } + +private: + string fName; + Type *fReturnType; + vector fParameters; +}; + +#endif // STRACE_SYSCALL_H diff --git a/src/apps/bin/strace/TypeHandler.cpp b/src/apps/bin/strace/TypeHandler.cpp new file mode 100644 index 0000000000..396f1e7221 --- /dev/null +++ b/src/apps/bin/strace/TypeHandler.cpp @@ -0,0 +1,251 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ + +#include "MemoryReader.h" +#include "TypeHandler.h" + +// complete specializations + +// void +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) +{ + return "void"; +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return ""; +} + +// bool +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) +{ + return (*(align_t*)address ? "true" : "false"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return (value ? "true" : "false"); +} + +// char +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) +{ + return get_number_value(address, "0x%x"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%x"); +} + +// short +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) +{ + return get_number_value(address, "0x%x"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%x"); +} + +// unsigned short +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, + bool getContents, MemoryReader &reader) +{ + return get_number_value(address, "0x%x"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%x"); +} + +// int +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) +{ + return get_number_value(address, "0x%x"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%x"); +} + +// unsigned int +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, + bool getContents, MemoryReader &reader) +{ + return get_number_value(address, "0x%x"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%x"); +} + +// long +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) +{ + return get_number_value(address, "0x%lx"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%lx"); +} + +// unsigned long +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, + bool getContents, MemoryReader &reader) +{ + return get_number_value(address, "0x%lx"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%lx"); +} + +// long long +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, + bool getContents, MemoryReader &reader) +{ + return get_number_value(address, "0x%llx"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_number_value(value, "0x%llx"); +} + +// unsigned long +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, + bool getContents, MemoryReader &reader) +{ + return get_number_value(address, "0x%llx"); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, + bool getContents, MemoryReader &reader) +{ + return get_number_value(value, "0x%llx"); +} + +// read_string +static +string +read_string(MemoryReader &reader, void *data) +{ + char buffer[256]; + int32 bytesRead; + status_t error = reader.Read(data, buffer, sizeof(buffer), bytesRead); + if (error == B_OK) { +// return string("\"") + string(buffer, bytesRead) + "\""; +//string result("\""); +//result += string(buffer, bytesRead); +//result += "\""; +//return result; + +// TODO: Unless I'm missing something obvious, our STL string class is broken. +// The appended "\"" doesn't appear in either of the above cases. + + int32 len = strnlen(buffer, sizeof(buffer)); + char largeBuffer[259]; + largeBuffer[0] = '"'; + memcpy(largeBuffer + 1, buffer, len); + largeBuffer[len + 1] = '"'; + largeBuffer[len + 2] = '\0'; + return largeBuffer; + } + return get_pointer_value(&data) + " (" + strerror(error) + ")"; +} + + +// const char* +template<> +string +TypeHandlerImpl::GetParameterValue(const void *address, + bool getContents, MemoryReader &reader) +{ + void *data = *(void**)address; + if (getContents && data) + return read_string(reader, data); + + return get_pointer_value(&data); +} + +template<> +string +TypeHandlerImpl::GetReturnValue(uint64 value, + bool getContents, MemoryReader &reader) +{ + void *data = (void*)value; + if (getContents && data) + return read_string(reader, data); + + return get_pointer_value(&data); +} diff --git a/src/apps/bin/strace/TypeHandler.h b/src/apps/bin/strace/TypeHandler.h new file mode 100644 index 0000000000..5d98fefecc --- /dev/null +++ b/src/apps/bin/strace/TypeHandler.h @@ -0,0 +1,124 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ +#ifndef STRACE_TYPE_HANDLER_H +#define STRACE_TYPE_HANDLER_H + +#include + +#include +#include + +class MemoryReader; + +typedef FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE align_t; + +// TypeHandler +class TypeHandler { +public: + TypeHandler() {} + virtual ~TypeHandler() {} + + virtual string GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) = 0; + + virtual string GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) = 0; +}; + +// TypeHandlerImpl +template +class TypeHandlerImpl : public TypeHandler { +public: + virtual string GetParameterValue(const void *address, bool getContents, + MemoryReader &reader); + + virtual string GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader); +}; + + +// TypeHandlerImpl +template +class TypeHandlerImpl : public TypeHandler { +public: + virtual string GetParameterValue(const void *address, bool getContents, + MemoryReader &reader); + + virtual string GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader); +}; + +//// TypeHandlerImpl +//template<> +//class TypeHandlerImpl : public TypeHandler { +//public: +// virtual string GetParameterValue(const void *address, bool getContents, +// MemoryReader &reader); +// +// virtual string GetReturnValue(uint64 value, bool getContents, +// MemoryReader &reader); +//}; + +// get_number_value +template +static inline +string +get_number_value(const void *address, const char *format) +{ + if (sizeof(align_t) > sizeof(value_t)) + return get_number_value(value_t(*(align_t*)address), format); + else + return get_number_value(*(value_t*)address, format); +} + +// get_number_value +template +static inline +string +get_number_value(value_t value, const char *format) +{ + char buffer[32]; + sprintf(buffer, format, value); + return buffer; +} + +// get_pointer_value +static inline +string +get_pointer_value(const void *address) +{ + char buffer[32]; + sprintf(buffer, "%p", *(void **)address); + return buffer; +} + +// get_pointer_value +static inline +string +get_pointer_value(uint64 value) +{ + char buffer[32]; + sprintf(buffer, "%p", (void*)value); + return buffer; +} + +// generic pointer +template +string +TypeHandlerImpl::GetParameterValue(const void *address, bool getContents, + MemoryReader &reader) +{ + return get_pointer_value(address); +} + +template +string +TypeHandlerImpl::GetReturnValue(uint64 value, bool getContents, + MemoryReader &reader) +{ + return get_pointer_value(value); +} + +#endif // STRACE_TYPE_HANDLER_H diff --git a/src/apps/bin/strace/strace.cpp b/src/apps/bin/strace/strace.cpp new file mode 100644 index 0000000000..1098e8b0eb --- /dev/null +++ b/src/apps/bin/strace/strace.cpp @@ -0,0 +1,480 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "MemoryReader.h" +#include "Syscall.h" +#include "TypeHandler.h" + +extern void get_syscalls0(vector &syscalls); +extern void get_syscalls1(vector &syscalls); +extern void get_syscalls2(vector &syscalls); +extern void get_syscalls3(vector &syscalls); +extern void get_syscalls4(vector &syscalls); +extern void get_syscalls5(vector &syscalls); +extern void get_syscalls6(vector &syscalls); +extern void get_syscalls7(vector &syscalls); +extern void get_syscalls8(vector &syscalls); +extern void get_syscalls9(vector &syscalls); +extern void get_syscalls10(vector &syscalls); +extern void get_syscalls11(vector &syscalls); +extern void get_syscalls12(vector &syscalls); +extern void get_syscalls13(vector &syscalls); +extern void get_syscalls14(vector &syscalls); +extern void get_syscalls15(vector &syscalls); +extern void get_syscalls16(vector &syscalls); +extern void get_syscalls17(vector &syscalls); +extern void get_syscalls18(vector &syscalls); +extern void get_syscalls19(vector &syscalls); + +static const char *kDefaultCommandName = "strace"; + +// usage +static const char *kUsage = +"Usage: %s [ ] [ | ]\n" +"\n" +"Traces the the syscalls of a thread or a team. If an executable with\n" +"arguments is supplied, it is loaded and it's main thread traced.\n" +"\n" +"Options:\n" +" -a - Don't print syscall arguments.\n" +" -c - Don't colorize output.\n" +" -f - Fast mode. Syscall arguments contents aren't retrieved.\n" +" -h, --help - Print this text.\n" +" -r - Don't print syscall return values.\n" +" -s - Also trace all threads spawned by the supplied thread,\n" +" respectively the loaded executable's main thread.\n" +" -T - Trace all threads of the supplied or loaded executable's\n" +" team. If an ID is supplied, it is interpreted as a team\n" +" ID." +; + +// command line args +static int sArgc; +static const char *const *sArgv; + +// syscalls +static vector sSyscallVector; +static map sSyscallMap; + + +// print_usage +void +print_usage(bool error) +{ + // get nice program name + const char *programName = (sArgc > 0 ? sArgv[0] : kDefaultCommandName); + if (const char *lastSlash = strrchr(programName, '/')) + programName = lastSlash + 1; + + // print usage + fprintf((error ? stderr : stdout), kUsage, programName); +} + +// print_usage_and_exit +static +void +print_usage_and_exit(bool error) +{ + print_usage(error); + exit(error ? 1 : 0); +} + +// get_id +static +bool +get_id(const char *str, int32 &id) +{ + int32 len = strlen(str); + for (int32 i = 0; i < len; i++) { + if (!isdigit(str[i])) + return false; + } + + id = atol(str); + return true; +} + +// load_program +thread_id +load_program(const char *const *args, int32 argCount) +{ +// TODO: We need to find the program in the PATH, if no absolute or relative +// path has been given (i.e. only a name). + return load_image(argCount, (const char**)args, (const char**)environ); +} + + +// set_team_debugging_flags +static +void +set_team_debugging_flags(port_id nubPort, int32 flags) +{ + debug_nub_set_team_flags message; + message.flags = flags; + + while (true) { + status_t error = write_port(nubPort, B_DEBUG_MESSAGE_SET_TEAM_FLAGS, + &message, sizeof(message)); + if (error == B_OK) + return; + + if (error != B_INTERRUPTED) { + fprintf(stderr, "Failed to set team debug flags: %s\n", + strerror(error)); + exit(1); + } + } +} + +// set_thread_debugging_flags +static +void +set_thread_debugging_flags(port_id nubPort, thread_id thread, int32 flags) +{ + debug_nub_set_thread_flags message; + message.thread = thread; + message.flags = flags; + + while (true) { + status_t error = write_port(nubPort, B_DEBUG_MESSAGE_SET_THREAD_FLAGS, + &message, sizeof(message)); + if (error == B_OK) + return; + + if (error != B_INTERRUPTED) { + fprintf(stderr, "Failed to set thread debug flags: %s\n", + strerror(error)); + exit(1); + } + } +} + +// run_thread +static +void +run_thread(port_id nubPort, thread_id thread) +{ + debug_nub_run_thread message; + message.thread = thread; + + while (true) { + status_t error = write_port(nubPort, B_DEBUG_MESSAGE_RUN_THREAD, + &message, sizeof(message)); + if (error == B_OK) + return; + + if (error != B_INTERRUPTED) { + fprintf(stderr, "Failed to run thread %ld: %s\n", + thread, strerror(error)); + exit(1); + } + } +} + +// init_syscalls +static +void +init_syscalls() +{ + // init the syscall vector + get_syscalls0(sSyscallVector); + get_syscalls1(sSyscallVector); + get_syscalls2(sSyscallVector); + get_syscalls3(sSyscallVector); + get_syscalls4(sSyscallVector); + get_syscalls5(sSyscallVector); + get_syscalls6(sSyscallVector); + get_syscalls7(sSyscallVector); + get_syscalls8(sSyscallVector); + get_syscalls9(sSyscallVector); + get_syscalls10(sSyscallVector); + get_syscalls11(sSyscallVector); + get_syscalls12(sSyscallVector); + get_syscalls13(sSyscallVector); + get_syscalls14(sSyscallVector); + get_syscalls15(sSyscallVector); + get_syscalls16(sSyscallVector); + get_syscalls17(sSyscallVector); + get_syscalls18(sSyscallVector); + get_syscalls19(sSyscallVector); + + // init the syscall map + int32 count = sSyscallVector.size(); + for (int32 i = 0; i < count; i++) { + Syscall *syscall = sSyscallVector[i]; + sSyscallMap[syscall->Name()] = syscall; + } +} + +// print_syscall +static +void +print_syscall(debug_pre_syscall &message, MemoryReader &memoryReader, + bool printArguments, bool getContents, bool printReturnValue, + bool colorize) +{ + int32 syscallNumber = message.syscall; + Syscall *syscall = sSyscallVector[syscallNumber]; + + // print syscall name + printf("[%6ld] %s(", message.thread, syscall->Name().c_str()); + + // 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( + (char*)message.args + parameter->Offset(), getContents, + memoryReader); + + printf((i > 0 ? ", %s" : "%s"), value.c_str()); + } + } + + printf(") pre\n"); +} + +// print_syscall +static +void +print_syscall(debug_post_syscall &message, MemoryReader &memoryReader, + bool printArguments, bool getContents, bool printReturnValue, + bool colorize) +{ +// TODO: colorize support + int32 syscallNumber = message.syscall; + Syscall *syscall = sSyscallVector[syscallNumber]; + + // print syscall name + printf("[%6ld] %s(", message.thread, syscall->Name().c_str()); + + // 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( + (char*)message.args + parameter->Offset(), getContents, + memoryReader); + + printf((i > 0 ? ", %s" : "%s"), value.c_str()); + } + } + + printf(")"); + + // print return value + if (printReturnValue) { + TypeHandler *handler = syscall->ReturnType()->Handler(); + string value = handler->GetReturnValue(message.return_value, + getContents, memoryReader); + if (value.length() > 0) + printf(" = %s", value.c_str()); +// TODO: If the return value is a status_t, print the error code. + } + + printf(" (%lld us)\n", message.end_time - message.start_time); + +//for (int32 i = 0; i < 16; i++) { +// if (i % 4 == 0) { +// if (i > 0) +// printf("\n"); +// printf(" "); +// } else +// printf(" "); +// printf("%08lx", message.args[i]); +//} +//printf("\n"); + +} + + +// main +int +main(int argc, const char *const *argv) +{ + sArgc = argc; + sArgv = argv; + + // parameters + const char *const *programArgs = NULL; + int32 programArgCount = 0; + bool printArguments = true; + bool colorize = true; + bool fastMode = false; + bool printReturnValues = true; + bool traceChildThreads = false; + bool traceTeam = false; + + // parse arguments + for (int argi = 1; argi < argc; argi++) { + const char *arg = argv[argi]; + if (arg[0] == '-') { + if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { + print_usage_and_exit(false); + } else if (strcmp(arg, "-a") == 0) { + printArguments = false; + } else if (strcmp(arg, "-c") == 0) { + colorize = false; + } else if (strcmp(arg, "-f") == 0) { + fastMode = true; + } else if (strcmp(arg, "-r") == 0) { + printReturnValues = false; + } else if (strcmp(arg, "-s") == 0) { + traceChildThreads = true; + } else if (strcmp(arg, "-T") == 0) { + traceTeam = true; + } else { + print_usage_and_exit(true); + } + } else { + programArgs = argv + argi; + programArgCount = argc - argi; + break; + } + } + + // check parameters + if (!programArgs) + print_usage_and_exit(true); + + // initialize our syscalls vector and map + init_syscalls(); + + // get thread/team to be debugged + thread_id thread = -1; + team_id team = -1; + if (programArgCount > 1 + || !get_id(*programArgs, (traceTeam ? team : thread))) { + // we've been given an executable and need to load it + thread = load_program(programArgs, programArgCount); + } + + // get the team ID, if we have none yet + if (team < 0) { + thread_info threadInfo; + status_t error = get_thread_info(thread, &threadInfo); + if (error != B_OK) { + fprintf(stderr, "Failed to get info for thread %ld: %s\n", thread, + strerror(error)); + exit(1); + } + team = threadInfo.team; + } + + // create a debugger port + port_id debuggerPort = create_port(10, "debugger port"); + if (debuggerPort < 0) { + fprintf(stderr, "Failed to create debugger port: %s\n", + strerror(debuggerPort)); + exit(1); + } + + // install ourselves as the team debugger + port_id nubPort = install_team_debugger(team, debuggerPort); + if (nubPort < 0) { + fprintf(stderr, "Failed to install team debugger: %s\n", + strerror(nubPort)); + exit(1); + } + + // set team debugging flags + int32 teamDebugFlags + = (printArguments ? 0 : B_TEAM_DEBUG_SYSCALL_FAST_TRACE) + | (traceTeam ? B_TEAM_DEBUG_POST_SYSCALL : 0); + set_team_debugging_flags(nubPort, teamDebugFlags); + + // set thread debugging flags + if (thread >= 0) { + int32 threadDebugFlags = 0; + if (!traceTeam) { + threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL + | (traceChildThreads + ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0); + } + set_thread_debugging_flags(nubPort, thread, threadDebugFlags); + + // resume the target thread to be sure, it's running + resume_thread(thread); + } + + MemoryReader memoryReader(nubPort); + + // debug loop + while (true) { + int32 code; + debug_debugger_message_data message; + ssize_t messageSize = read_port(debuggerPort, &code, &message, + sizeof(message)); + + if (messageSize < 0) { + if (messageSize == B_INTERRUPTED) + continue; + + fprintf(stderr, "Reading from debugger port failed: %s\n", + strerror(messageSize)); + exit(1); + } + + thread_id concernedThread = -1; + switch (code) { + case B_DEBUGGER_MESSAGE_THREAD_STOPPED: + concernedThread = message.thread_stopped.thread; +printf("B_DEBUGGER_MESSAGE_THREAD_STOPPED: thread: %ld\n", concernedThread); + break; + case B_DEBUGGER_MESSAGE_PRE_SYSCALL: + { + concernedThread = message.pre_syscall.thread; +//printf("B_DEBUGGER_MESSAGE_PRE_SYSCALL: thread: %ld\n", concernedThread); +print_syscall(message.pre_syscall, memoryReader, + printArguments, !fastMode, printReturnValues, colorize); + + break; + } + case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: + concernedThread = message.signal_received.thread; +printf("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %ld\n", concernedThread); + break; + case B_DEBUGGER_MESSAGE_POST_SYSCALL: + { + concernedThread = message.post_syscall.thread; + print_syscall(message.post_syscall, memoryReader, + printArguments, !fastMode, printReturnValues, colorize); + + break; + } + case B_DEBUGGER_MESSAGE_TEAM_DELETED: + { + printf("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %ld\n", + message.team_deleted.team); + exit(0); + } + } + + // tell the thread to continue + if (concernedThread >= 0) { + run_thread(nubPort, concernedThread); + } + } + + return 0; +} diff --git a/src/apps/bin/strace/strace_syscalls.cpp b/src/apps/bin/strace/strace_syscalls.cpp new file mode 100644 index 0000000000..a4ef90dc28 --- /dev/null +++ b/src/apps/bin/strace/strace_syscalls.cpp @@ -0,0 +1,13 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ + +#include + +#include "Syscall.h" +#include "TypeHandler.h" + +#include "strace_syscalls.h" + // generated by gensyscalls +