void iterateOverCStackTraceLibUnwind()

in agent/native/ext/platform.cpp [364:439]


void iterateOverCStackTraceLibUnwind( size_t numberOfFramesToSkip, IterateOverCStackTraceCallback callback, IterateOverCStackTraceLogErrorCallback logErrorCallback, void* callbackCtx )
{
    char txtOutStreamBuf[ ELASTIC_APM_TEXT_OUTPUT_STREAM_ON_STACK_BUFFER_SIZE ];
    TextOutputStream txtOutStream = ELASTIC_APM_TEXT_OUTPUT_STREAM_FROM_STATIC_BUFFER( txtOutStreamBuf );

#   define ELASTIC_APM_LIBUNWIND_CALL_RETURN_ON_ERROR( expr ) \
        do { \
            int temp_libUnwindRetVal = (expr); \
            if ( temp_libUnwindRetVal < 0 ) \
            { \
                textOutputStreamRewind( &txtOutStream ); \
                logErrorCallback( streamPrintf( &txtOutStream, "%s call failed (return value: %d)", ELASTIC_APM_PP_STRINGIZE( expr ), temp_libUnwindRetVal ), callbackCtx ); \
                return; \
            } \
        } while ( 0 )

    unw_cursor_t unwindCursor;
    unw_context_t unwindContext;
    enum { funcNameBufferSize = 100 };
    char funcNameBuffer[ funcNameBufferSize ];
    unw_word_t offsetInsideFunc;
    size_t frameIndex = 0;

    ELASTIC_APM_LIBUNWIND_CALL_RETURN_ON_ERROR( unw_getcontext( &unwindContext ) );
    ELASTIC_APM_LIBUNWIND_CALL_RETURN_ON_ERROR( unw_init_local( &unwindCursor, &unwindContext ) );

    for (;; ++frameIndex)
    {
        // +1 is for this function frame
        if ( frameIndex >= numberOfFramesToSkip + 1 ) {
            textOutputStreamRewind( &txtOutStream );
            unw_proc_info_t pi;
            if (unw_get_proc_info(&unwindCursor, &pi) == 0) {
                *funcNameBuffer = 0;
                offsetInsideFunc = 0;
                int getProcNameRetVal = unw_get_proc_name( &unwindCursor, funcNameBuffer, funcNameBufferSize, &offsetInsideFunc );
                if (getProcNameRetVal != UNW_ESUCCESS && getProcNameRetVal != -UNW_ENOMEM) {
                    strcpy(funcNameBuffer, "???");
                    unw_word_t  pc;
                    unw_get_reg(&unwindCursor, UNW_REG_IP, &pc);
                    offsetInsideFunc = pc - pi.start_ip;
                }

                Dl_info dlInfo;
                if (dladdr((const void *)pi.gp, &dlInfo)) {
                    callback( streamPrintf( &txtOutStream, 
                        "%s(%s+0x%lx) ModuleBase: %p FuncStart: 0x%lx FuncEnd: 0x%lx FuncStartRelative: 0x%lx FuncOffsetRelative: 0x%lx\n\t'addr2line -afCp -e \"%s\" %lx'\n",
                        dlInfo.dli_fname ? dlInfo.dli_fname : "???",
                        dlInfo.dli_sname ? dlInfo.dli_sname : funcNameBuffer,
                        offsetInsideFunc,
                        dlInfo.dli_fbase,
                        pi.start_ip,
                        pi.end_ip,
                        pi.start_ip -  reinterpret_cast<unw_word_t>(dlInfo.dli_fbase),
                        pi.start_ip -  reinterpret_cast<unw_word_t>(dlInfo.dli_fbase) + offsetInsideFunc,
                        dlInfo.dli_fname ? dlInfo.dli_fname : "???",
                        pi.start_ip -  reinterpret_cast<unw_word_t>(dlInfo.dli_fbase) + offsetInsideFunc
                        ), callbackCtx );
                } else {
                    logErrorCallback( streamPrintf( &txtOutStream, "dladdr failed on frame %zu", frameIndex), callbackCtx );
                }
            } else {
                logErrorCallback( streamPrintf( &txtOutStream, "unw_get_proc_info failed on frame %zu", frameIndex), callbackCtx );
            }
        }
       
        int unwindStepRetVal = 0;
        ELASTIC_APM_LIBUNWIND_CALL_RETURN_ON_ERROR( unwindStepRetVal = unw_step( &unwindCursor ) );
        if ( unwindStepRetVal == 0 )
        {
            break;
        }
    }

#   undef ELASTIC_APM_LIBUNWIND_CALL_RETURN_ON_ERROR
}