emscripten-core / emsdk

Emscripten SDK
http://emscripten.org
Other
3.07k stars 700 forks source link

How to fetch callstack from C? #599

Open crazydef opened 4 years ago

crazydef commented 4 years ago

Hi,

I'm trying to compile some code (the SDK for my memory profiler) into our application that fetches the current callstack as a list of pointers and attempts to resolve each one to a function name (caching the names as it goes, so it only ever has to resolve each one once).

But I don't seem to be getting very far. :(

The function _Unwind_Backtrace seems to exist and appears to be called, but a bit deeper into that function (in the callback function I pass as the first parameter to _Unwind_Backtrace) I'm getting a crash while calling _Unwind_GetIP. This is presumably because _Unwind_GetIP is missing (the compiler tells me as such: warning: undefined symbol: _Unwind_GetIP).

So is there a better way to fetch a raw callstack at any given time (and then resolve those addresses), or do I need to link in a specific library to get _Unwind_GetIP, or is this just completely impossible in Emscripten?

crazydef commented 4 years ago

So as far as I can tell the function _Unwind_GetIPInfo exists (at least I'm not getting any warnings at build time), but it's still crashing once it's called:

abort
__Unwind_GetIPInfo
UnwindCallback
dynCall_iii
(anonymous)
__Unwind_Backtrace
OsoMP_GetCallstack
OsoMP_Allocate
operator new(unsigned long)
...
Viatorus commented 2 years ago

Any update on this?

sbc100 commented 2 years ago

I guess it is your own code or libray code outside of emscripten that is calling __Unwind_GetIPInfo. Our current implementation of __Unwind_GetIPInfo just aborts, since I guess it isn't needed by any code that we normally build and run in emscripten.

Can you see where the call is coming from? Can you share a link to that code if you have it?

Can you try perhaps just returning zero here instead of aborting?: https://github.com/emscripten-core/emscripten/blob/2e02d0eba92c9c7489bed38eff9bd1ee61e93229/src/library.js#L3097-L3099

Viatorus commented 2 years ago

@sbc100 Thank you. Hmm, maybe it is more a compiler flag issue.

I try to build a library/application which uses pthread, SDL2 and _Unwind_GetIP with emscripten for wasm.

I can get pthread to work with: -pthread I get SDL2 to work with: -s USE_SDL=2

But I don't know how to get the libunwind to build and link. How do I link against this library? The sources seem to exist under: upstream/emscripten/system/libunwind.

crazydef commented 2 years ago

I know exactly where this call is coming from. It's my code. Specifically, this function I'm using to resolve stack addresses under clang for my memory profiler's (https://osocorporation.com/memoryprofiler/index.php) SDK:

typedef struct BacktraceState
{
    void**  mCurrent;
    void**  mEnd;
}
BacktraceState;

_Unwind_Reason_Code UnwindCallback( struct _Unwind_Context* context, void* arg )
{
    BacktraceState* state = ( BacktraceState* )arg;
    uintptr_t pc = _Unwind_GetIP( context );

    if( pc )
    {
        if( state->mCurrent == state->mEnd )
        {
            return _URC_END_OF_STACK;
        }
        else
        {
            *state->mCurrent++ = ( void* )pc;
        }
    }
    return _URC_NO_REASON;
}

uint32_t OsoMP_GetCallstack( void )
{
    void* addresses[ 200 ];
    BacktraceState  state = { addresses, addresses + 200 };
    uint16_t noofaddresses;
    uint16_t idx;
    OsoMPRecord record;

    _Unwind_Backtrace( UnwindCallback, &state );
    noofaddresses = ( uint16_t )( state.mCurrent - addresses );
    ...
sbc100 commented 2 years ago

See https://github.com/emscripten-core/emscripten/blob/2e02d0eba92c9c7489bed38eff9bd1ee61e93229/src/library.js#L3097-L3099

Basically emscripten doesn't support _Unwind_GetIP today. You should try to implement it, or you could just return zero/null, or you could ifdef out that part of your code when building for emscripten.

Algomorph commented 7 months ago

In case anyone stumbles upon this thread when trying to resolve a linking issue, e.g. _Unwind_GetIP symbol missing, try the -fwasm-exceptions flag. Worked for me w/ glog depencency.