* 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
This commit is contained in:
Ingo Weinhold 2008-01-18 02:13:27 +00:00
parent 21c92a08d4
commit 548dcc600e
3 changed files with 175 additions and 7 deletions

View File

@ -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

View File

@ -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) \

View File

@ -9,8 +9,9 @@
#include <ksyscalls.h>
#include <syscalls.h>
#include <generic_syscall.h>
#include <int.h>
#include <debug.h>
#include <int.h>
#include <elf.h>
#include <vfs.h>
#include <vm.h>
#include <thread.h>
@ -25,9 +26,10 @@
#include <kimage.h>
#include <ksignal.h>
#include <real_time_clock.h>
#include <system_info.h>
#include <user_atomic.h>
#include <safemode.h>
#include <system_info.h>
#include <tracing.h>
#include <user_atomic.h>
#include <arch/system_info.h>
#include <messaging.h>
#include <frame_buffer_console.h>
@ -37,6 +39,9 @@
#include <string.h>
//#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 "<invalid syscall number>";
if (elf_debug_lookup_symbol_address(
(addr_t)kSyscallInfos[syscall].function,
&baseAddress, &symbolName, &imageName,
&exactMatch) != B_OK) {
return "<lookup failed>";
}
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
*/