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 +