From c012e7e9305fa8acbf3ead9f8b1ca19b7c677b06 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 11 Apr 2015 23:21:50 +0200 Subject: [PATCH] libroot: Add private __arch_get_stack_trace(). It can be used to get a stack trace of the current thread. Note that this works by walking frame pointers and will not produce anything useful if an application is compiled with the frame pointers omitted. The stack base and end addresses have to be provided as arguments and are used to check that the frame pointers fall within that range. These values are thread specific and can be retrieved with get_thread_info(). No other sanity checks (like checking for loops in the linked list) are done. This is a simplified rewrite of the stack trace code from the kernel debugger. As this code is common to x86 and x86_64 but is not generic across architectures I introduced x86_common as a directory to put such sources. --- headers/private/libroot/libroot_private.h | 2 + src/system/libroot/os/arch/x86/Jamfile | 5 ++ src/system/libroot/os/arch/x86_64/Jamfile | 9 +++- .../os/arch/x86_common/stack_trace.cpp | 47 +++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/system/libroot/os/arch/x86_common/stack_trace.cpp diff --git a/headers/private/libroot/libroot_private.h b/headers/private/libroot/libroot_private.h index 85036df0bf..1d5fad3045 100644 --- a/headers/private/libroot/libroot_private.h +++ b/headers/private/libroot/libroot_private.h @@ -44,6 +44,8 @@ bigtime_t __get_system_time_offset(); void __init_pwd_backend(void); void __reinit_pwd_backend_after_fork(void); void* __arch_get_caller(void); +int32 __arch_get_stack_trace(addr_t* returnAddresses, int32 maxCount, + int32 skipFrames, addr_t stackBase, addr_t stackEnd); void __set_stack_protection(void); diff --git a/src/system/libroot/os/arch/x86/Jamfile b/src/system/libroot/os/arch/x86/Jamfile index e04e18a5d6..98821562b8 100644 --- a/src/system/libroot/os/arch/x86/Jamfile +++ b/src/system/libroot/os/arch/x86/Jamfile @@ -17,6 +17,8 @@ for architectureObject in [ MultiArchSubDirSetup x86 x86_gcc2 ] { ; } + SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) x86_common ] ; + MergeObject <$(architecture)>os_arch_$(TARGET_ARCH).o : atomic.S byteorder.S @@ -28,6 +30,9 @@ for architectureObject in [ MultiArchSubDirSetup x86 x86_gcc2 ] { tls.c $(compatibilitySources) + + # sources from x86_common + stack_trace.cpp ; } } diff --git a/src/system/libroot/os/arch/x86_64/Jamfile b/src/system/libroot/os/arch/x86_64/Jamfile index fcf8b591bd..61d76d6335 100644 --- a/src/system/libroot/os/arch/x86_64/Jamfile +++ b/src/system/libroot/os/arch/x86_64/Jamfile @@ -12,7 +12,10 @@ for architectureObject in [ MultiArchSubDirSetup x86_64 ] { # TODO in time.c! UsePrivateSystemHeaders ; - SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ; + SEARCH_SOURCE += + [ FDirName $(SUBDIR) $(DOTDOT) generic ] + [ FDirName $(SUBDIR) $(DOTDOT) x86_common ] + ; MergeObject <$(architecture)>os_arch_$(TARGET_ARCH).o : byteorder.S @@ -23,6 +26,10 @@ for architectureObject in [ MultiArchSubDirSetup x86_64 ] { time.cpp tls.cpp + # sources from x86_common + stack_trace.cpp + + # sources from generic generic_atomic.cpp ; } diff --git a/src/system/libroot/os/arch/x86_common/stack_trace.cpp b/src/system/libroot/os/arch/x86_common/stack_trace.cpp new file mode 100644 index 0000000000..48b82ae0df --- /dev/null +++ b/src/system/libroot/os/arch/x86_common/stack_trace.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2015 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ + +#include + + +/*! Captures a stack trace (the return addresses) of the current thread. + \param returnAddresses The array the return address shall be written to. + \param maxCount The maximum number of return addresses to be captured. + \param skipFrames The number of stack frames that shall be skipped. + \param stackBase The base address of the thread stack. + \param stackEnd The first address past the thread stack. + \return The number of return addresses written to the given array. +*/ +int32 +__arch_get_stack_trace(addr_t* returnAddresses, int32 maxCount, + int32 skipFrames, addr_t stackBase, addr_t stackEnd) +{ + int32 count = 0; + addr_t basePointer = (addr_t)get_stack_frame(); + + while (basePointer != 0 && count < maxCount) { + if (basePointer < stackBase || basePointer >= stackEnd) + break; + + struct stack_frame { + addr_t previous; + addr_t return_address; + }; + + stack_frame* frame = (stack_frame*)basePointer; + + if (skipFrames <= 0) + returnAddresses[count++] = frame->return_address; + else + skipFrames--; + + basePointer = frame->previous; + } + + return count; +}