Giter Club home page Giter Club logo

callstacklibrary's Introduction

Welcome to the CallstackLibrary!

The CallstackLibrary is a library designed to create human-readable callstacks for natively compiled applications.

It can be used with pure C, although some features using C++ optionally can be enabled.

Its API is available for both C and C++.

Quickstart

Use the CallstackLibrary for creating human-readable callstacks and for creating C++ exceptions that can print their stacktrace.

  1. Clone the repository: git clone --recursive https://github.com/mhahnFr/CallstackLibrary.git
  2. Build it: cd CallstackLibrary && make
  3. Link your code with -L<path/to/library> -lcallstack

Now, you can use the headers callstack.h and callstack_exception.hpp, respectively.

More explanation can be found in the wiki; the detailed explanation follows below.

Usage

Installation

Get started by either downloading a prebuilt version of this library here. Alternatively you can also build it from source:

  1. Clone the repository: git clone --recursive https://github.com/mhahnFr/CallstackLibrary.git
  2. go into the cloned repository: cd CallstackLibrary
  3. and build the library: make

Or in one step:

git clone --recursive https://github.com/mhahnFr/CallstackLibrary.git && cd CallstackLibrary && make

To enable the optional C++ exclusive functions add CXX_FUNCTIONS=true as argument to make.

Tip

Example:

make CXX_FUNCTIONS=true

Note

When statically linking against the CallstackLibrary with C++ exclusive functions enabled make sure to also link against the C++ standard library of your compiler (this is usually already the case when linking C++ code).

More information about the C++ exclusive functions here.

Once you have a copy of the CallstackLibrary you can install it using the following command:

make INSTALL_PATH=/usr/local install

Adapt the value of the INSTALL_PATH argument to your needs.

If you downloaded a release you can simply move the headers and the library anywhere you like.

Uninstallation

Uninstall the library by simply removing it and its header files from the installation directory.
This can be done using the following command:

make INSTALL_PATH=/usr/local uninstall

Adapt the value of the INSTALL_PATH argument to your needs.

How to use

In order to use this library, simply include the header callstack.h and callstack_exception.hpp.

Linking

Note

Add -L<path/to/library> if the CallstackLibrary has not been installed in one of the default directories.

Link with -lcallstack

Tip

Example: -L<path/to/library> -lcallstack

Callstacks

// main.c

#include <stdio.h> // For printf(...)

#include <callstack.h>

void printCallstack(void) {
    struct callstack* callstack = callstack_new();
    struct callstack_frame* frames = callstack_toArray(callstack);

    printf("The current callstack:\n");
    for (size_t i = 0; i < callstack_getFrameCount(callstack); ++i) {
        printf("In: (%s) %s (%s:%ld)\n", callstack_frame_getShortestName(&frames[i]), 
                                         (frames[i].function == NULL ? "???" : frames[i].function),
                                         callstack_frame_getShortestSourceFileOr(&frames[i], "???"),
                                         frames[i].sourceLine);
    }
    callstack_delete(callstack);
}

void bar(void) { printCallstack(); }

void foo(void)  { bar();  }
void bar2(void) { foo();  }
void foo2(void) { bar2(); }

int main(void) {
    foo2();
}

Compiled and linked on macOS with cc -g main.c -I<path/to/library>/include -L<path/to/library> -lcallstack the example creates the following output:

The current callstack:
In: (a.out) printCallstack (main.c:8)
In: (a.out) bar (main.c:21)
In: (a.out) foo (main.c:23)
In: (a.out) bar2 (main.c:24)
In: (a.out) foo2 (main.c:25)
In: (a.out) main (main.c:28)
In: (/usr/lib/dyld) start + 1942 (???:0)

C++

The example above can be written in C++ using the C++ wrapper class as follows:

// main.cpp

#include <iostream>

#include <callstack.h>

void printCallstack() {
    lcs::callstack callstack;
    callstack_frame* frames = callstack_toArray(callstack);
    
    std::cout << "The current callstack:" << std::endl;
    for (size_t i = 0; i < callstack_getFrameCount(callstack); ++i) {
        std::cout << "In: (" << callstack_frame_getShortestName(&frames[i])
                  << ") "    << (frames[i].function == NULL ? "???" : frames[i].function)
                  << " ("    << callstack_frame_getShortestSourceFileOr(&frames[i], "???")
                  << ":"     << frames[i].sourceLine
                  << ")"     << std::endl;
    }   
}

void bar() { printCallstack(); }

void foo()  { bar();  }
void bar2() { foo();  }
void foo2() { bar2(); }

int main() {
    foo2();
}

Compiled and linked on Debian with g++ -g main.cpp -I<path/to/library>/include -L<path/to/library> -lcallstack and after enabling C++ functions of the library the following output is produced:

The current callstack:
In: (a.out) lcs::callstack::callstack(bool) (include/callstack.hpp:81)
In: (a.out) printCallstack() (main.cpp:8)
In: (a.out) bar() (main.cpp:21)
In: (a.out) foo() (main.cpp:23)
In: (a.out) bar2() (main.cpp:24)
In: (a.out) foo2() (main.cpp:25)
In: (a.out) main (main.cpp:28)
In: (/usr/lib/x86_64-linux-gnu/libc.so.6) ??? (???:0)
In: (/usr/lib/x86_64-linux-gnu/libc.so.6) __libc_start_main + 133 (???:0)
In: (a.out) _start + 33 (???:0)

Tip

The C++ functions can be enabled as described here.

Callstack exceptions

With the callstack exception an exception capable of printing its construction stacktrace is available.

It can be thrown directly:

// main.cpp

#include <iostream>

#include <callstack_exception.hpp>

void printCallstack() {
    throw lcs::exception("Callstack exception with a message");
}

void bar2() { printCallstack(); }
void foo2() { bar2();           }

void bar() { foo2(); }
void foo() { bar();  }

int main() {
    try {
        foo();
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}

Compiled and linked on macOS using c++ -g main.cpp -I<path/to/library>/include -L<path/to/library> -lcallstack and after enabling C++ functions of the library the following output is produced:

lcs::exception: "Callstack exception with a message", stacktrace:
At: (a.out) lcs::callstack::callstack(bool) (include/callstack.hpp:81)
in: (a.out) lcs::callstack::callstack(bool) (include/callstack.hpp:79)
in: (a.out) lcs::exception::exception(char const*, bool) (include/callstack_exception.hpp:126)
in: (a.out) lcs::exception::exception(char const*, bool) (include/callstack_exception.hpp:127)
in: (a.out) printCallstack() (main.cpp:8)
in: (a.out) bar2() (main.cpp:11)
in: (a.out) foo2() (main.cpp:12)
in: (a.out) bar() (main.cpp:14)
in: (a.out) foo() (main.cpp:15)
in: (a.out) main (main.cpp:19)
in: (/usr/lib/dyld) start + 1942

Extending the callstack exception

The callstack exception can easily serve as base class for other exceptions:

// main.cpp

#include <iostream>

#include <callstack_exception.hpp>

class CustomStacktraceException: public lcs::exception {};

void printCallstack() {
    throw CustomStacktraceException();
}

void bar2() { printCallstack(); }
void foo2() { bar2();           }

void bar() { foo2(); }
void foo() { bar();  }

int main() {
    try {
        foo();
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}

Compiled and linked on Debian using g++ -g main.cpp -I<path/to/library>/include -L<path/to/library> -lcallstack and after enabling C++ functions of the library the example creates the following output:

CustomStacktraceException, stacktrace:
At: (a.out) lcs::callstack::callstack(bool) (include/callstack.hpp:81)
in: (a.out) lcs::exception::exception(bool) (include/callstack_exception.hpp:116)
in: (a.out) CustomStacktraceException::CustomStacktraceException() (main.cpp:7)
in: (a.out) printCallstack() (main.cpp:10)
in: (a.out) bar2() (main.cpp:13)
in: (a.out) foo2() (main.cpp:14)
in: (a.out) bar() (main.cpp:16)
in: (a.out) foo() (main.cpp:17)
in: (a.out) main (main.cpp:21)
in: (/usr/lib/x86_64-linux-gnu/libc.so.6) << Unknown >>
in: (/usr/lib/x86_64-linux-gnu/libc.so.6) __libc_start_main + 133
in: (a.out) _start + 33

Symbolization

The callstacks are generated using the function backtrace of the libexecinfo, which is commonly preinstalled.

Note

If this is not the case, you probably need to add -lexecinfo to the linking flags of the library.

The generated callstacks are symbolized using an ELF file parser on Linux and a Mach-O file parser on macOS.
They are enriched using the appropriate DWARF debugging information that is available.

The DWARF parser supports DWARF in version 2, 3, 4 and 5.

Tip

Usually the appropriate compilation flag for debug symbols is -g.

macOS

On macOS the debug information available in the Mach-O binaries is used. The following kinds of debug symbols are supported:

  • .dSYM bundles
  • Mach-O debug symbol maps (DWARF inside the object files)

Linux

On Linux the debug information available in the ELF binaries is used.

Final notes

This library is licensed under the terms of the GNU GPL in version 3 or later.

© Copyright 2022 - 2024 mhahnFr

callstacklibrary's People

Contributors

mhahnfr avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.