Initial import.

This commit is contained in:
François-Xavier Bourlet 2013-03-14 23:10:06 -07:00
commit 1ae978ab77
20 changed files with 3321 additions and 0 deletions

87
CMakeLists.txt Normal file
View File

@ -0,0 +1,87 @@
#
# CMakeLists.txt
# Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 2.8)
project(backward CXX)
###############################################################################
# COMPILER FLAGS
###############################################################################
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
endif()
include_directories(${CMAKE_SOURCE_DIR}/include)
enable_testing()
###############################################################################
# TESTS
###############################################################################
include_directories(${CMAKE_SOURCE_DIR})
add_library(test_main SHARED test/_test_main.cpp)
macro(backward_add_test src src_dep definition)
get_filename_component(name ${src} NAME_WE)
set(test_name "test_${name}")
add_executable(${test_name} ${src} ${src_dep})
set(_definition ${definition})
if(_definition)
set_target_properties(${test_name}
PROPERTIES COMPILE_DEFINITIONS ${definition})
endif()
target_link_libraries(${test_name} dw bfd dl test_main)
add_test(${test_name} ${test_name})
endmacro()
set(TESTS
compile
minitrace
smalltrace
simplerecursive
fib
segfault
invalidread
suicide
divbyzero
)
foreach(test ${TESTS})
backward_add_test(test/${test}.cpp "" "")
endforeach()
set(TESTS
invalidread2
)
set(some_definition "BACKWARD_HAS_BFD=1")
#set(some_definition "BACKWARD_NOTHING")
foreach(test ${TESTS})
backward_add_test(test/${test}.cpp backward.cpp ${some_definition})
endforeach()

20
LICENSE.txt Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT) Copyright (c) 2013 François-Xavier Bourlet
<bombela@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

331
README.md Normal file
View File

@ -0,0 +1,331 @@
Backward-cpp
============
Backward is a beautiful stack trace pretty printer for C++.
If you are bored to see this:
![default trace](doc/rude.png)
Backward will spice it up for you:
![pretty stackstrace](doc/pretty.png)
There is not much to say. Of course it will be able to display the code
snippets only if the source files are accessible (else see trace #4 in the
example).
All "Source" line and code snippet prefixed by a pipe "|" are source code that
inlines the trace.
You can see that for the trace #1 in the example, the function
`you_shall_not_pass()` was inlined in the function `...read2::do_test()` by the
compiler.
##Installation
#### Install backward.*hpp*
Backward is a header only library. So installing Backward is easy, simply drop
a copy of `backward.hpp` along with your other source file in your C++ project.
You can also use a git submodule or really any other way that fit bests your
environment, as long as you can import `backward.hpp`.
#### Install backward.*cpp*
If you want Backward to automatically print a stack trace on most common fatal
errors (segfault, abort, un-handled exception...), simply add a copy of
`backward.cpp` to your project, and don't forget to tell your build system.
The code in `backward.cpp` is trivial anyway, you can simply copy what's its
doing at your convenience.
##Configuration & Dependencies
### Compile with debug info
You need to compile your project with the generation of the debug symbols
enabled, usually `-g` with clang++ and g++.
Note that you can use `-g` with any level of optimization, with modern debug
information encoding like DWARF, it only takes space in the binary (its not
loaded in memory until your debugger or Backward makes use of it, don't worry),
and it doesn't impact the code generation (at least on GNU/Linux x86\_64 for
what I know).
If you are missing debug information, the stack trace will lack details about
your sources.
### Libraries to read the debug info
Backward support pretty printed stack trace on GNU/Linux only, it will compile
fine under other platforms but will not do anything. **Pull requests are
welcome :)**
Also, by default you will get a really basic stack trace, based on the
`backtrace_symbols` API:
![default trace](doc/nice.png)
You will need to install some dependencies to get the ultimate stack trace. Two
libraries are currently supported, the only difference is which one is easier
for you to install, so pick your poison:
#### libbfd from the [GNU/binutils](http://www.gnu.org/software/binutils/)
apt-get install binutils-dev (or equivalent)
And do not forget to link with the lib: `g++/clang++ -lbfd ...`
Then define the following before every inclusion of `backward.hpp` (don't
forget to update `backward.cpp` as well):
#define BACKWARD_HAS_BFD 1
#### libdw from the [elfutils](https://fedorahosted.org/elfutils/)
apt-get install libdw-dev (or equivalent)
And do not forget to link with the lib and inform Backward to use it:
#define BACKWARD_HAS_DW 1
Of course you can simply add the define (`-DBACKWARD_HAS_...=1`) and the
linkage details in your build system and even auto-detect which library is
installed, it's up to you.
Thats it, you are all set, you should be getting nice stack trace like the one
at the beginning of this document.
## API
If you don't want to limit yourself to the default offered by `backward.cpp`,
that you want take random stack trace for whatever reason and pretty print them
the way you prefer or send to your buddies over the internet, you will
appreciate the simplicity of Backward's API.
### Stacktrace
The Stacktrace object let you take a "snapshot" of the current stack.
You can use it like this:
```c++
using namespace backward;
Stacktrace st; st.load_here(32);
Printer p; p.print(st);
```
All the public methods are:
```c++
class StackTrace { public:
// Take a snapshot of the current stack, with at most "trace_cnt_max"
// traces in it. The first trace is the most recent (ie the current
// frame). You can also provide a trace address to load_from() assuming
// the address is a valid stack frame (useful for signal handling traces).
// Both function return size().
size_t load_here(size_t trace_cnt_max)
size_t load_from(void* address, size_t trace_cnt_max)
// The number of traces loaded. This can be less than "trace_cnt_max".
size_t size() const
// A unique id for the thread in which the trace was taken. The value
// 0 means the stack trace comes from the main thread.
size_t thread_id() const
// Retrieve a trace by index. Index is the most recent trace, size()-1
// is the older one.
Trace operator[](size_t trace_idx)
};
```
### TraceResolver
The `TraceResolver` does the heavy lifting, and intent to transform a simple
`Trace` from it's address onto a fully detailed `ResolvedTrace` with the
filename of the source, line numbers, inliners functions and so on.
You can use it like this:
```c++
using namespace backward;
Stacktrace st; st.load_here(32);
TraceResolver tr; tr.load_stacktrace(st);
for (size_t i = 0; i < st.size(); ++i) {
ResolvedTrace trace = tr.resolve(st[i]);
std::cout << "#" << i
<< " " << trace.object_filename
<< " " << trace.object_function
<< " [" << trace.addr << "]"
<< std::endl;
}
```
All the public methods are:
```c++
class TraceResolver { public:
// Pre-load whatever is necessary from the stacktrace.
template <class ST>
void load_stacktrace(ST&)
// Resolve a trace. It takes a ResolvedTrace, because a `Trace` or a
// `TraceWithLocals` are implicitly convertible to a ResolvedTrace.
ResolvedTrace resolve(ResolvedTrace t)
};
```
### SnippetFactory
The SnippetFactory is a simple helper class to automatically load and cache
source files in order to extract code snippets.
```c++
class SnippetFactory { public:
// A snippet is a list of line number and content of the line.
typedef std::vector<std::pair<size_t, std::string> > lines_t;
// Return a snippet starting at line_start with as much as context_size
// lines.
lines_t get_snippet(const std::string& filename,
size_t line_start, size_t context_size)
// Return a combined snippet from two different location and combine them
// together. context_size / 2 lines will be extracted from each location.
lines_t get_combined_snippet(
const std::string& filename_a, size_t line_a,
const std::string& filename_b, size_t line_b,
size_t context_size)
// Tries to return an unified snippet if the two location from the same
// file are close enough to fit inside one context_size, else returns
// the equivalent of get_combined_snippet().
lines_t get_coalesced_snippet(const std::string& filename,
size_t line_a, size_t line_b, size_t context_size)
```
### Printer
A simpler way to pretty print a stack trace to the terminal. It will
automatically resolve the traces for you:
```c++
using namespace backward;
Stacktrace st; st.load_here(32);
Printer p;
p.object = true;
p.color = false;
p.address = true;
p.print(st, stderr);
```
You can select few options:
```c++
class Printer { public:
// Print a little snippet of code if possible.
bool snippet = true;
// Colorize the trace (only set a color when printing on a terminal)
bool color = true;
// Add the address on the trace to every source location.
bool address = false;
// Even if there is a source location, prints the object the trace comes
// from as well.
bool object = false;
// Resolve and print a stacktrace. It takes a C FILE* object, for the only
// reason that it is possible to access the underalying OS-level file
// descriptor, which is then used to determine if the output is a terminal
// to print in color.
template <typename StackTrace>
FILE* print(StackTrace& st, FILE* os = stderr)
```
### SignalHandling
A simple helper class that registers for you the most common signals and other
callbacks to segfault, hardware exception, un-handled exception etc.
`backward.cpp` uses it simply like that:
```c++
backward::SignalHandling sh;
```
Creating the object registers all the different signals and hooks. Destroying
this object doesn't do anything. It exposes only one method:
```c++
bool loaded() const // true if loaded with success
```
### Trace object
To keep the memory footprint of a loaded `StackTrace` on the low-side, there a
hierarchy of trace object, from a minimal `Trace `to a `ResolvedTrace`.
#### Simple trace
```c++
struct Trace {
void* addr; // address of the trace
size_t idx; // its index (0 == most recent)
};
```
#### Trace with local variables
This is not used for now, but it might be used to carry Traces with snapshotted
variables in the future.
```c++
struct TraceWithLocals: public Trace {
std::vector<Variable> locals; // Locals variable and values.
};
```
#### Resolved trace
A `ResolvedTrace` should contains a maximum of details about the location of
the trace in the source code. Note that not all fields might be set.
```c++
struct ResolvedTrace: public TraceWithLocals {
struct SourceLoc {
std::string function;
std::string filename;
size_t line;
size_t col;
};
// In which binary object this trace is located.
std::string object_filename;
// The function in the object that contain the trace. This is not the same
// as source.function which can be an function inlined in object_function.
std::string object_function;
// The source location of this trace. It is possible for filename to be
// empty and for line/col to be invalid (value 0) if this information
// couldn't be deduced, for example if there is no debug information in the
// binary object.
SourceLoc source;
// An optionals list of "inliners". All the successive sources location
// from where the source location of the trace (the attribute right above)
// is inlined. It is especially useful when you compile with optimization.
typedef std::vector<SourceLoc> source_locs_t;
source_locs_t inliners;
};
```
## Contact and copyright
François-Xavier Bourlet <bombela@gmail.com>.
MIT License.

32
backward.cpp Normal file
View File

@ -0,0 +1,32 @@
// Pick your poison.
//
// On GNU/Linux, you have few choices to get the most out of your stack trace.
//
// By default you get:
// - object filename
// - function name
//
// In order to add:
// - source filename
// - line and column numbers
// - source code snippet (assuming the file is accessible)
// Install one of the following library then uncomment one of the macro (or
// better, add the detection of the lib and the macro definition in your build
// system)
// - apt-get install libdw-dev ...
// - g++/clang++ -ldw ...
// #define BACKWARD_HAS_DW 1
// - apt-get install binutils-dev ...
// - g++/clang++ -lbfd ...
// #define BACKWARD_HAS_BFD 1
#include "backward.hpp"
namespace backward {
backward::SignalHandling sh;
} // namespace backward

2169
backward.hpp Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/nice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
doc/pretty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
doc/rude.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

46
test/_test_main.cpp Normal file
View File

@ -0,0 +1,46 @@
/*
* _test_main.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "test.hpp"
#include <stdio.h>
test::test_registry_t test::test_registry;
using namespace test;
int main()
{
size_t failed_test_cnt = 0;
for (test_registry_t::iterator test = test_registry.begin();
test != test_registry.end(); ++test) {
printf("-- running test case: %s\n", (*test)->name);
const bool success = (*test)->run();
if (not success) {
printf("\n-- test case failed: %s\n", (*test)->name);
failed_test_cnt += 1;
} else {
printf("\n-- test case success: %s\n", (*test)->name);
}
}
//printf("-- %zi/%zi test(s) case failed\n", failed_test_cnt, test_registry.size());
return failed_test_cnt != 0;
}

30
test/compile.cpp Normal file
View File

@ -0,0 +1,30 @@
/*
* test/compile.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include "test/test.hpp"
#include "backward.hpp"
TEST(i_can_compile) {
printf("Wow, I'am compiled!\n");
}

50
test/divbyzero.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
* test/divbyzero.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEN_UNKNOWN
//#define BACKWARD_HAS_UNWIND 0
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
volatile int zero = 0;
int divide_by_zero()
{
std::cout << "And the wild black hole appears..." << std::endl;
int v = 42 / zero;
return v;
}
TEST (invalid_read)
{
SignalHandling sh;
std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl;
int v = divide_by_zero();
std::cout << "v=" << v << std::endl;
}

61
test/fib.cpp Normal file
View File

@ -0,0 +1,61 @@
/*
* test/fib.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEN_UNKNOWN
//#define BACKWARD_HAS_UNWIND 1
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
int some_counter;
void end_of_our_journey(StackTrace& st) {
if (not st.size()) {
st.load_here();
}
}
int fib(StackTrace& st, int level) {
if (level == 2) {
return 1;
}
if (level <= 1) {
end_of_our_journey(st);
return 0;
}
return fib(st, level - 1) + fib(st, level - 2);
}
TEST (fibrecursive) {
StackTrace st;
const int input = 6;
int r = fib(st, input);
std::cout << "fib(" << input << ") == " << r << std::endl;
Printer printer;
printer.print(st, stdout);
}

55
test/invalidread.cpp Normal file
View File

@ -0,0 +1,55 @@
/*
* test/invalidread.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEM_UNKNOWN
//#define BACKWARD_HAS_UNWIND 1
//#define BACKWARD_HAS_BACKTRACE 1
//#define BACKWARD_HAS_DW 1
//#define BACKWARD_HAS_BFD 1
//#define BACKWARD_HAS_BACKTRACE_SYMBOL 1
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
int you_shall_not_pass()
{
char* ptr = (char*)42;
int v = *ptr;
return v;
}
TEST (invalid_read)
{
SignalHandling sh;
std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl;
int v = you_shall_not_pass();
std::cout << "v=" << v << std::endl;
}

53
test/invalidread2.cpp Normal file
View File

@ -0,0 +1,53 @@
/*
* test/invalidread.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEM_UNKNOWN
//#define BACKWARD_HAS_UNWIND 1
//#define BACKWARD_HAS_BACKTRACE 1
//#define BACKWARD_HAS_DW 1
//#define BACKWARD_HAS_BFD 1
//#define BACKWARD_HAS_BACKTRACE_SYMBOL 1
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
int you_shall_not_pass()
{
char* ptr = (char*)42;
int v = *ptr;
return v;
}
TEST(invalid_read2)
{
int v = you_shall_not_pass();
std::cout << "v=" << v << std::endl;
}

45
test/minitrace.cpp Normal file
View File

@ -0,0 +1,45 @@
/*
* test/minitrace.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEN_UNKNOWN
//#define BACKWARD_HAS_BFD 0
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
void collect_trace(StackTrace& st) {
st.load_here();
}
TEST (minitrace) {
StackTrace st;
collect_trace(st);
Printer printer;
printer.print(st, stdout);
}

46
test/segfault.cpp Normal file
View File

@ -0,0 +1,46 @@
/*
* test/segfault.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEN_UNKNOWN
//#define BACKWARD_HAS_UNWIND 0
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
void badass_function()
{
char* ptr = (char*)42;
*ptr = 42;
}
TEST (invalid_write)
{
SignalHandling sh;
std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl;
badass_function();
}

86
test/simplerecursive.cpp Normal file
View File

@ -0,0 +1,86 @@
/*
* test/simplerecursive.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_HAS_UNWIND 1
//#define BACKWARD_SYSTEN_UNKNOWN
#define BACKWARD_HAS_DW 1
//#define BACKWARD_HAS_BFD 1
//#define BACKWARD_HAS_BACKTRACE_SYMBOL 1
//#define BACKWARD_HAS_BACKTRACE 1
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
int some_counter;
typedef StackTraceWithLocals stacktrace_t;
void end_of_our_journey(stacktrace_t& st) {
if (not st.size()) {
st.load_here();
}
}
int rec(stacktrace_t& st, int level) {
if (level <= 1) {
end_of_our_journey(st);
return 0;
}
return rec(st, level - 1);
}
namespace toto {
namespace titi {
struct foo {
union bar {
__attribute__((noinline))
static int trampoline(stacktrace_t& st, int level) {
return rec(st, level);
}
};
};
} // namespace titi
} // namespace toto
TEST (simplerecursive) {
{ // lexical scope.
stacktrace_t st;
const int input = 3;
int r = toto::titi::foo::bar::trampoline(st, input);
std::cout << "rec(" << input << ") == " << r << std::endl;
Printer printer;
// printer.address = true;
printer.object = true;
printer.print(st, stdout);
}
}

65
test/smalltrace.cpp Normal file
View File

@ -0,0 +1,65 @@
/*
* test/smalltrace.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEN_UNKNOWN
//#define BACKWARD_HAS_UNWIND 0
//#define BACKWARD_HAS_DW 1
#define BACKWARD_HAS_BFD 1
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
void d(StackTrace& st)
{
st.load_here();
}
void c(StackTrace& st)
{
return d(st);
}
void b(StackTrace& st)
{
return c(st);
}
__attribute__ ((noinline))
void a(StackTrace& st)
{
return b(st);
}
TEST (smalltrace)
{
StackTrace st;
a(st);
Printer printer;
printer.print(st, stdout);
}

46
test/suicide.cpp Normal file
View File

@ -0,0 +1,46 @@
/*
* test/suicide.cpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//#define BACKWARD_SYSTEN_UNKNOWN
//#define BACKWARD_HAS_UNWIND 0
//#define BACKWARD_CXX98
#include "backward.hpp"
#include <stdio.h>
#include "test/test.hpp"
using namespace backward;
void abort_abort_I_repeat_abort_abort()
{
std::cout << "Jumping off the boat!" << std::endl;
abort();
}
TEST (invalid_read)
{
SignalHandling sh;
std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl;
abort_abort_I_repeat_abort_abort();
}

99
test/test.hpp Normal file
View File

@ -0,0 +1,99 @@
/*
* test/test.hpp
* Copyright © 2013 François-Xavier 'Bombela' Bourlet <bombela@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#ifndef H_54E531F7_9154_454B_BEB9_257408429470
#define H_54E531F7_9154_454B_BEB9_257408429470
#include <exception>
#include <vector>
#include <cstring>
#include <cstdio>
namespace test {
struct AssertFailedError {};
void assert_fail (
const char* filename,
int line,
const char* err_msg) {
const char* basename = filename + strlen(filename);
while (basename != filename && *basename != '/') {
basename -= 1;
}
basename += 1;
printf("!! assertion failed:\n\tat: %s:%i\n\t%s\n",
basename, line, err_msg);
throw AssertFailedError();
}
struct TestBase {
const char* name;
virtual ~TestBase() {}
TestBase(const char*);
virtual void do_test() = 0;
bool run() {
try {
do_test();
return true;
} catch(const AssertFailedError&) {
} catch(const std::exception& e) {
printf("/!\\ Exception: %s\n", e.what());
} catch(...) {
printf("/!\\ Unknown exception\n");
}
return false;
}
};
typedef std::vector<TestBase*> test_registry_t;
extern test_registry_t test_registry;
TestBase::TestBase(const char* n): name(n) {
test_registry.push_back(this);
}
} // namespace test
#define ASSERT(expr) \
(expr) ? static_cast<void>(0) \
: ::test::assert_fail( \
__FILE__, __LINE__, "assertion: " #expr)
#define ASSERT_EQ(a, b) \
(a == b) ? static_cast<void>(0) \
: ::test::assert_fail( \
__FILE__, __LINE__, "err: " #a " != " #b)
#define TEST(name) \
struct TEST_##name: ::test::TestBase { \
TEST_##name(): TestBase(#name) {} \
void do_test(); \
} TEST_##name; \
void TEST_##name::do_test()
#endif /* H_GUARD */