Skip to content

MaulingMonkey/libMmkDebugStack

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 

libMmkDebugStack

A cross-platform library for simple callstack tracing with C89 and C++03 public APIs.

Requires a C++11 compiler to build.

License: Apache 2.0

Possible Use Cases

  • Fancy assertion or logging macros
  • Automatic tracing for bug database submission (JIRA, Sentry.IO, etc.)
  • Stack traces for leaked allocations or refcounting

Compatability

Tested OS Compiler SDK Unwind Impl Symbols Impl
Windows 7 VS2015 u1 DbgHelp DbgHelp
Android 5.0 GCC 4.9 nVidia Codeworks 1R4 libunwind Custom elf/dwarf parser
Android 5.0 Clang 3.6 Microsoft's Android SDK __builtin_return_address Custom elf/dwarf parser
Ubuntu 16.10 Clang 3.8.1 None (noop/fallback) None
Ubuntu 16.10 GCC 6.2.0 None (noop/fallback) None

Other C++11 capable platforms/compilers should at least be able to use the Fallback implementation, feel free to file an issue if they don't!

Example

#include <mmk/debug/stack.h> // mmkDebugStackCurrentThread etc.
#include <stdio.h>           // printf
#include <string.h>

#define NO_INLINE   ZMMK_DEBUG_STACK_NO_INLINE // Note: ZMMK_* isn't part of the public API

const char* nameOnly(const char* filename) {
	if (const char* bs = strrchr(filename, '\\')) return bs+1;
	if (const char* fs = strrchr(filename, '/'))  return fs+1;
	return filename;
}

#define TRACE() (void)(printf("Trace:\n"),   mmk::debug::stackCurrentThread(mmkDebugStackResolveAll, 0, 25, \
    [](const mmk::debug::stackFunction& f) {                                                                \
        printf("    %s(%d): %s @ %p\n", nameOnly(f.file), f.line, f.name, f.address);                       \
        return true; /* continue trace */                                                                   \
    }, MMK_DEBUG_STACK_HINT()),   printf("\n\n\n"),   0)

NO_INLINE void test_trace() { TRACE(); }
template < size_t N > struct recursive { NO_INLINE static void test_trace() { recursive<N-1>::test_trace(); } };
template <>        struct recursive<0> { NO_INLINE static void test_trace() { ::test_trace(); } };

int main()
{
	recursive<10>::test_trace();
}

Resulting Debug|x86 Console:

Trace:
    main.cpp(19): test_trace @ 013B2C76
    main.cpp(21): recursive<0>::test_trace @ 013B2C03
    main.cpp(20): recursive<1>::test_trace @ 013B28E3
    main.cpp(20): recursive<2>::test_trace @ 013B2933
    main.cpp(20): recursive<3>::test_trace @ 013B2983
    main.cpp(20): recursive<4>::test_trace @ 013B29D3
    main.cpp(20): recursive<5>::test_trace @ 013B2A23
    main.cpp(20): recursive<6>::test_trace @ 013B2A73
    main.cpp(20): recursive<7>::test_trace @ 013B2AC3
    main.cpp(20): recursive<8>::test_trace @ 013B2B13
    main.cpp(20): recursive<9>::test_trace @ 013B2B63
    main.cpp(20): recursive<10>::test_trace @ 013B2BB3
    main.cpp(26): main @ 013B2DB3
    exe_common.inl(74): invoke_main @ 013B6B4E
    exe_common.inl(264): __scrt_common_main_seh @ 013B699A
    exe_common.inl(309): __scrt_common_main @ 013B682D
    exe_main.cpp(17): mainCRTStartup @ 013B6B68
    <unknown>(0): BaseThreadInitThunk @ 76F3336A
    <unknown>(0): RtlInitializeExceptionChain @ 77C39902
    <unknown>(0): RtlInitializeExceptionChain @ 77C398D5

More examples:

  • mmkDebugStackTest (c++)
  • mmkNvidiaCodeworksTest (java, c++)
  • mmkAndroidTest (java, c++)

Installation

NuGet

Add libMmkDebugStack to your project via nuget. Done!

From Source (on Windows development machine)

  • Clone the repository
  • Use libMmkDebugStack.sln to build libMmkDebugStack.lib in the configurations/platforms of your choice.
  • Add HAS_MMK_DEBUG_STACK to your preprocessor definitions.
  • Add libMmkDebugStack\include\ to your #include paths.
  • Targeting Windows:
    • Add build\native\lib\$(PlatformTarget)\$(PlatformToolset)\$(Configuration)\ to your library paths
    • Add libMmkDebugStack.lib and DbgHelp.lib to your additional dependencies list.
  • Targeting Android via the nVidia Codeworks for Android 1R4 SDK:
    • Add build\native\lib\$(ArchAbi)\$(ToolchainIdentifier)\$(Configuration)\ to your library paths
    • Add MmkDebugStack to your additional dependencies list.
  • Targeting Android via the Microsoft Android SDK:
    • Add build\native\lib\$(Platform)\$(PlatformToolset)\$(Configuration)\ to your library paths
    • Add -lMmkDebugStack to your additional dependencies list.

From Source (on Linux development machine)

  • Clone the repository
  • Run make
  • Add -DHAS_MMK_DEBUG_STACK to your CCFLAGS
  • Add -Lbin/$(compiler)-$(arch)-$(build)-$(language)/ to your LDFLAGS
  • Add -lMmkDebugStack to your LDFLAGS
  • Add bin/$(compiler)-$(arch)-$(build)-$(language)/ to your LD_LIBRARY_PATH

TODO

  • Add option to use separate debugger process for stability / collecting stacks of foreign threads
  • Backport to C++03 for wider compatability
  • Properly port to Linux, OS X, iOS
  • Port to Consoles, Handhelds, etc. (Blocker: Devkit access)
  • Add Windows CDB backend for possible stability improvements, multi-thread stacks, crash dump analysis, etc.