From 548dcc600e2c1823ae0318215197db9725c52b21 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 18 Jan 2008 02:13:27 +0000 Subject: [PATCH] * syscalls.c -> syscalls.cpp * With post syscall debugging enabled, the x86 syscall handling didn't remove all parameters from the stack after calling the respective user debugger hook. Should have been harmless though, since the following code didn't rely on the stack being in order. * Added syscall pre/post (kernel) tracing functions trace_{pre,post}_syscall(). They are generic, but need to be invoked by the architecture specific syscall code. Currently only done for x86. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23600 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/Jamfile | 2 +- src/system/kernel/arch/x86/arch_interrupts.S | 36 ++++- .../kernel/{syscalls.c => syscalls.cpp} | 144 +++++++++++++++++- 3 files changed, 175 insertions(+), 7 deletions(-) rename src/system/kernel/{syscalls.c => syscalls.cpp} (69%) 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 */