diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index 36797a187c..0a9ebdaf58 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -37,7 +37,7 @@ KernelMergeObject kernel_core.o : signal.cpp system_info.c smp.c - syscalls.c + syscalls.cpp team.cpp thread.cpp timer.c diff --git a/src/system/kernel/arch/x86/arch_interrupts.S b/src/system/kernel/arch/x86/arch_interrupts.S index 7ff9d82a00..344ac03e9f 100644 --- a/src/system/kernel/arch/x86/arch_interrupts.S +++ b/src/system/kernel/arch/x86/arch_interrupts.S @@ -18,6 +18,9 @@ #include "syscall_table.h" +//#define SYSCALL_TRACING + // also define this macro in syscalls.cpp + #define FUNCTION(x) .global x; .type x,@function; x #define UPDATE_THREAD_USER_TIME_COMMON() \ @@ -131,6 +134,31 @@ movl %dr3, %edi; /* thread pointer */ \ movl $0, THREAD_fault_handler(%edi) +#ifdef SYSCALL_TRACING +# define TRACE_PRE_SYSCALL() \ + movl %esp, %eax; /* syscall parameters */ \ + push %eax; \ + movl IFRAME_orig_eax(%ebp), %eax; /* syscall number */ \ + push %eax; \ + call trace_pre_syscall; \ + addl $8, %esp; + +# define TRACE_POST_SYSCALL() \ + testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi); \ + jnz 1f; \ + xor %edx, %edx; \ +1: \ + push %edx; /* syscall return value */ \ + push %eax; \ + movl IFRAME_orig_eax(%ebp), %eax; /* syscall number */ \ + push %eax; \ + call trace_post_syscall; \ + addl $12, %esp +#else +# define TRACE_PRE_SYSCALL() +# define TRACE_POST_SYSCALL() +#endif + .text @@ -308,6 +336,7 @@ trap99: COPY_SYSCALL_PARAMETERS() // pre syscall debugging + TRACE_PRE_SYSCALL() testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) jnz do_pre_syscall_debug pre_syscall_debug_done: @@ -320,6 +349,8 @@ trap99: movl %edx, IFRAME_edx(%ebp) movl %eax, IFRAME_eax(%ebp) + TRACE_POST_SYSCALL() + testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \ , THREAD_flags(%edi) @@ -365,7 +396,7 @@ trap99: movl IFRAME_orig_eax(%ebp), %eax // syscall number push %eax call user_debug_post_syscall - addl $8, %esp + addl $24, %esp 1: bad_syscall_number: @@ -454,6 +485,7 @@ FUNCTION(x86_sysenter): COPY_SYSCALL_PARAMETERS() // pre syscall debugging + TRACE_PRE_SYSCALL() testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) jnz do_pre_syscall_debug // if debugging is enabled, we take the slow syscall exit @@ -466,6 +498,8 @@ FUNCTION(x86_sysenter): movl %edx, IFRAME_edx(%ebp) movl %eax, IFRAME_eax(%ebp) + TRACE_POST_SYSCALL() + testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ | THREAD_FLAGS_64_BIT_SYSCALL_RETURN) \ diff --git a/src/system/kernel/syscalls.c b/src/system/kernel/syscalls.cpp similarity index 69% rename from src/system/kernel/syscalls.c rename to src/system/kernel/syscalls.cpp index a0c21112cf..523a7cf164 100644 --- a/src/system/kernel/syscalls.c +++ b/src/system/kernel/syscalls.cpp @@ -9,8 +9,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -25,9 +26,10 @@ #include #include #include -#include -#include #include +#include +#include +#include #include #include #include @@ -37,6 +39,9 @@ #include +//#define SYSCALL_TRACING + + typedef struct generic_syscall generic_syscall; struct generic_syscall { @@ -59,7 +64,8 @@ find_generic_syscall(const char *subsystem) ASSERT_LOCKED_MUTEX(&sGenericSyscallLock); - while ((syscall = list_get_next_item(&sGenericSyscalls, syscall)) != NULL) { + while ((syscall = (generic_syscall*)list_get_next_item(&sGenericSyscalls, + syscall)) != NULL) { if (!strcmp(syscall->subsystem, subsystem)) return syscall; } @@ -193,7 +199,7 @@ syscall_dispatcher(uint32 call_num, void *args, uint64 *call_ret) #include "syscall_dispatcher.h" default: - *call_ret = -1; + *call_ret = (uint64)B_BAD_VALUE; } user_debug_post_syscall(call_num, args, *call_ret, startTime); @@ -290,6 +296,134 @@ unregister_generic_syscall(const char *subsystem, uint32 version) return status; } + +// #pragma mark - syscall tracing + + +#ifdef SYSCALL_TRACING + +namespace SyscallTracing { + + +static const char* +get_syscall_name(uint32 syscall) +{ + addr_t baseAddress; + const char* symbolName; + const char* imageName; + bool exactMatch; + + if (syscall >= (uint32)kSyscallCount) + return ""; + + if (elf_debug_lookup_symbol_address( + (addr_t)kSyscallInfos[syscall].function, + &baseAddress, &symbolName, &imageName, + &exactMatch) != B_OK) { + return ""; + } + + return symbolName; +} + + +class PreSyscall : public AbstractTraceEntry { + public: + PreSyscall(uint32 syscall, const void* parameters) + : + fSyscall(syscall), + fParameters(NULL) + { + if (syscall < (uint32)kSyscallCount) { + fParameters = alloc_tracing_buffer_memcpy(parameters, + kSyscallInfos[syscall].parameter_size, false); + } + + Initialized(); + } + + virtual void AddDump(char *buffer, size_t size) + { + snprintf(buffer, size, "syscall pre: %s(", + get_syscall_name(fSyscall)); + + size_t bytesPrinted = strlen(buffer); + buffer += bytesPrinted; + size -= bytesPrinted; + + if (fParameters != NULL) { + uint32* params = (uint32*)fParameters; + int32 paramSize = kSyscallInfos[fSyscall].parameter_size; + bool first = true; + while (paramSize >= 4 && size > 0) { + if (first) { + snprintf(buffer, size, "0x%lx", *params); + first = false; + } else + snprintf(buffer, size, ", 0x%lx", *params); + + bytesPrinted = strlen(buffer); + buffer += bytesPrinted; + size -= bytesPrinted; + params++; + paramSize -= 4; + } + } + + strlcat(buffer, ")", size); + } + + private: + uint32 fSyscall; + void* fParameters; +}; + + +class PostSyscall : public AbstractTraceEntry { + public: + PostSyscall(uint32 syscall, uint64 returnValue) + : + fSyscall(syscall), + fReturnValue(returnValue) + { + Initialized(); + } + + virtual void AddDump(char *buffer, size_t size) + { + snprintf(buffer, size, "syscall post: %s() -> 0x%llx", + get_syscall_name(fSyscall), fReturnValue); + } + + private: + uint32 fSyscall; + uint64 fReturnValue; +}; + +} // namespace TeamTracing + + +extern "C" void trace_pre_syscall(uint32 syscallNumber, const void* parameters); + +void +trace_pre_syscall(uint32 syscallNumber, const void* parameters) +{ + new(std::nothrow) SyscallTracing::PreSyscall(syscallNumber, parameters); +} + + +extern "C" void trace_post_syscall(int syscallNumber, uint64 returnValue); + +void +trace_post_syscall(int syscallNumber, uint64 returnValue) +{ + new(std::nothrow) SyscallTracing::PostSyscall(syscallNumber, returnValue); +} + + +#endif // SYSCALL_TRACING + + /* * kSyscallCount and kSyscallInfos here */