~ubuntu-branches/ubuntu/vivid/fceux/vivid

« back to all changes in this revision

Viewing changes to src/utils/backward.hpp

  • Committer: Package Import Robot
  • Author(s): Joe Nahmias
  • Date: 2014-03-02 19:22:04 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20140302192204-9f0aehi5stfnhn7d
Tags: 2.2.2+dfsg0-1
* Imported Upstream version 2.2.2
  + remove patches merged upstream; refresh remaining
  + remove windows compiled help files and non-free Visual C files
* Use C++11 standard static assertion functionality
* fix upstream installation of support files
* New patch 0004-ignore-missing-windows-help-CHM-file.patch
* update d/copyright for new, renamed, deleted files
* d/control: bump std-ver to 3.9.5, no changes needed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * backward.hpp
 
3
 * Copyright 2013 Google Inc. All Rights Reserved.
 
4
 *
 
5
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 
6
 * of this software and associated documentation files (the "Software"), to deal
 
7
 * in the Software without restriction, including without limitation the rights
 
8
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
9
 * copies of the Software, and to permit persons to whom the Software is
 
10
 * furnished to do so, subject to the following conditions:
 
11
 *
 
12
 * The above copyright notice and this permission notice shall be included in
 
13
 * all copies or substantial portions of the Software.
 
14
 *
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
18
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
20
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
21
 * SOFTWARE.
 
22
 */
 
23
 
 
24
#ifndef H_6B9572DA_A64B_49E6_B234_051480991C89
 
25
#define H_6B9572DA_A64B_49E6_B234_051480991C89
 
26
 
 
27
#ifndef __cplusplus
 
28
#       error "It's not going to compile without a C++ compiler..."
 
29
#endif
 
30
 
 
31
#if       defined(BACKWARD_CXX11)
 
32
#elif defined(BACKWARD_CXX98)
 
33
#else
 
34
#       if __cplusplus >= 201103L
 
35
#               define BACKWARD_CXX11
 
36
#       else
 
37
#               define BACKWARD_CXX98
 
38
#       endif
 
39
#endif
 
40
 
 
41
// You can define one of the following (or leave it to the auto-detection):
 
42
//
 
43
// #define BACKWARD_SYSTEM_LINUX
 
44
//      - specialization for linux
 
45
//
 
46
// #define BACKWARD_SYSTEM_UNKNOWN
 
47
//      - placebo implementation, does nothing.
 
48
//
 
49
#if   defined(BACKWARD_SYSTEM_LINUX)
 
50
#elif defined(BACKWARD_SYSTEM_UNKNOWN)
 
51
#else
 
52
#       if defined(__linux)
 
53
#               define BACKWARD_SYSTEM_LINUX
 
54
#       else
 
55
#               define BACKWARD_SYSTEM_UNKNOWN
 
56
#       endif
 
57
#endif
 
58
 
 
59
#include <fstream>
 
60
#include <iostream>
 
61
#include <algorithm>
 
62
#include <cstdlib>
 
63
#include <cstdio>
 
64
#include <cstring>
 
65
#include <new>
 
66
#include <iomanip>
 
67
#include <vector>
 
68
 
 
69
#if defined(BACKWARD_SYSTEM_LINUX)
 
70
 
 
71
// On linux, backtrace can back-trace or "walk" the stack using the following
 
72
// library:
 
73
//
 
74
// #define BACKWARD_HAS_UNWIND 1
 
75
//  - unwind comes from libgcc, but I saw an equivalent inside clang itself.
 
76
//  - with unwind, the stacktrace is as accurate as it can possibly be, since
 
77
//  this is used by the C++ runtine in gcc/clang for stack unwinding on
 
78
//  exception.
 
79
//  - normally libgcc is already linked to your program by default.
 
80
//
 
81
// #define BACKWARD_HAS_BACKTRACE == 1
 
82
//  - backtrace seems to be a little bit more portable than libunwind, but on
 
83
//  linux, it uses unwind anyway, but abstract away a tiny information that is
 
84
//  sadly really important in order to get perfectly accurate stack traces.
 
85
//  - backtrace is part of the (e)glib library.
 
86
//
 
87
// The default is:
 
88
// #define BACKWARD_HAS_UNWIND == 1
 
89
//
 
90
#       if   BACKWARD_HAS_UNWIND == 1
 
91
#       elif BACKWARD_HAS_BACKTRACE == 1
 
92
#       else
 
93
#               undef  BACKWARD_HAS_UNWIND
 
94
#               define BACKWARD_HAS_UNWIND 1
 
95
#               undef  BACKWARD_HAS_BACKTRACE
 
96
#               define BACKWARD_HAS_BACKTRACE 0
 
97
#       endif
 
98
 
 
99
// On linux, backward can extract detailed information about a stack trace
 
100
// using one of the following library:
 
101
//
 
102
// #define BACKWARD_HAS_DW 1
 
103
//  - libdw gives you the most juicy details out of your stack traces:
 
104
//    - object filename
 
105
//    - function name
 
106
//    - source filename
 
107
//        - line and column numbers
 
108
//        - source code snippet (assuming the file is accessible)
 
109
//        - variables name and values (if not optimized out)
 
110
//  - You need to link with the lib "dw":
 
111
//    - apt-get install libdw-dev
 
112
//    - g++/clang++ -ldw ...
 
113
//
 
114
// #define BACKWARD_HAS_BFD 1
 
115
//  - With libbfd, you get a fair about of details:
 
116
//    - object filename
 
117
//    - function name
 
118
//    - source filename
 
119
//        - line numbers
 
120
//        - source code snippet (assuming the file is accessible)
 
121
//  - You need to link with the lib "bfd":
 
122
//    - apt-get install binutils-dev
 
123
//    - g++/clang++ -lbfd ...
 
124
//
 
125
// #define BACKWARD_HAS_BACKTRACE_SYMBOL 1
 
126
//  - backtrace provides minimal details for a stack trace:
 
127
//    - object filename
 
128
//    - function name
 
129
//  - backtrace is part of the (e)glib library.
 
130
//
 
131
// The default is:
 
132
// #define BACKWARD_HAS_BACKTRACE_SYMBOL == 1
 
133
//
 
134
#       if   BACKWARD_HAS_DW == 1
 
135
#       elif BACKWARD_HAS_BFD == 1
 
136
#       elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
 
137
#       else
 
138
#               undef  BACKWARD_HAS_DW
 
139
#               define BACKWARD_HAS_DW 0
 
140
#               undef  BACKWARD_HAS_BFD
 
141
#               define BACKWARD_HAS_BFD 0
 
142
#               undef  BACKWARD_HAS_BACKTRACE_SYMBOL
 
143
#               define BACKWARD_HAS_BACKTRACE_SYMBOL 1
 
144
#       endif
 
145
 
 
146
 
 
147
#       if BACKWARD_HAS_UNWIND == 1
 
148
 
 
149
#               include <unwind.h>
 
150
// while gcc's unwind.h defines something like that:
 
151
//  extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
 
152
//  extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
 
153
//
 
154
// clang's unwind.h defines something like this:
 
155
//  uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
 
156
//
 
157
// Even if the _Unwind_GetIPInfo can be linked to, it is not declared, worse we
 
158
// cannot just redeclare it because clang's unwind.h doesn't define _Unwind_Ptr
 
159
// anyway.
 
160
//
 
161
// Luckily we can play on the fact that the guard macros have a different name:
 
162
#ifdef __CLANG_UNWIND_H
 
163
// In fact, this function still comes from libgcc (on my different linux boxes,
 
164
// clang links against libgcc).
 
165
#               include <inttypes.h>
 
166
extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*);
 
167
#endif
 
168
 
 
169
#       endif
 
170
 
 
171
#       include <cxxabi.h>
 
172
#       include <fcntl.h>
 
173
#       include <link.h>
 
174
#       include <sys/stat.h>
 
175
#       include <syscall.h>
 
176
#       include <unistd.h>
 
177
#       include <signal.h>
 
178
 
 
179
#       if BACKWARD_HAS_BFD == 1
 
180
#               include <bfd.h>
 
181
#               ifndef _GNU_SOURCE
 
182
#                       define _GNU_SOURCE
 
183
#                       include <dlfcn.h>
 
184
#                       undef _GNU_SOURCE
 
185
#               else
 
186
#                       include <dlfcn.h>
 
187
#               endif
 
188
#       endif
 
189
 
 
190
#       if BACKWARD_HAS_DW == 1
 
191
#               include <elfutils/libdw.h>
 
192
#               include <elfutils/libdwfl.h>
 
193
#               include <dwarf.h>
 
194
#       endif
 
195
 
 
196
#       if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1)
 
197
                // then we shall rely on backtrace
 
198
#               include <execinfo.h>
 
199
#       endif
 
200
 
 
201
#endif // defined(BACKWARD_SYSTEM_LINUX)
 
202
 
 
203
#if   defined(BACKWARD_CXX11)
 
204
#       include <unordered_map>
 
205
#       include <utility> // for std::swap
 
206
        namespace backward {
 
207
        namespace details {
 
208
                template <typename K, typename V>
 
209
                struct hashtable {
 
210
                        typedef std::unordered_map<K, V> type;
 
211
                };
 
212
                using std::move;
 
213
        } // namespace details
 
214
        } // namespace backward
 
215
#elif defined(BACKWARD_CXX98)
 
216
#       include <map>
 
217
        namespace backward {
 
218
        namespace details {
 
219
                template <typename K, typename V>
 
220
                struct hashtable {
 
221
                        typedef std::map<K, V> type;
 
222
                };
 
223
                template <typename T>
 
224
                        const T& move(const T& v) { return v; }
 
225
                template <typename T>
 
226
                        T& move(T& v) { return v; }
 
227
        } // namespace details
 
228
        } // namespace backward
 
229
#else
 
230
#       error "Mmm if its not C++11 nor C++98... go play in the toaster."
 
231
#endif
 
232
 
 
233
namespace backward {
 
234
 
 
235
namespace system_tag {
 
236
        struct linux_tag; // seems that I cannot call that "linux" because the name
 
237
        // is already defined... so I am adding _tag everywhere.
 
238
        struct unknown_tag;
 
239
 
 
240
#if   defined(BACKWARD_SYSTEM_LINUX)
 
241
        typedef linux_tag current_tag;
 
242
#elif defined(BACKWARD_SYSTEM_UNKNOWN)
 
243
        typedef unknown_tag current_tag;
 
244
#else
 
245
#       error "May I please get my system defines?"
 
246
#endif
 
247
} // namespace system_tag
 
248
 
 
249
 
 
250
namespace stacktrace_tag {
 
251
#ifdef BACKWARD_SYSTEM_LINUX
 
252
        struct unwind;
 
253
        struct backtrace;
 
254
 
 
255
#       if   BACKWARD_HAS_UNWIND == 1
 
256
        typedef unwind currnet;
 
257
#       elif BACKWARD_HAS_BACKTRACE == 1
 
258
        typedef backtrace current;
 
259
#       else
 
260
#               error "I know it's difficult but you need to make a choice!"
 
261
#       endif
 
262
#endif // BACKWARD_SYSTEM_LINUX
 
263
} // namespace stacktrace_tag
 
264
 
 
265
 
 
266
namespace trace_resolver_tag {
 
267
#ifdef BACKWARD_SYSTEM_LINUX
 
268
        struct libdw;
 
269
        struct libbfd;
 
270
        struct backtrace_symbol;
 
271
 
 
272
#       if   BACKWARD_HAS_DW == 1
 
273
        typedef libdw current;
 
274
#       elif BACKWARD_HAS_BFD == 1
 
275
        typedef libbfd current;
 
276
#       elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
 
277
        typedef backtrace_symbol current;
 
278
#       else
 
279
#               error "You shall not pass, until you know what you want."
 
280
#       endif
 
281
#endif // BACKWARD_SYSTEM_LINUX
 
282
} // namespace trace_resolver_tag
 
283
 
 
284
namespace details {
 
285
 
 
286
template <typename T>
 
287
        struct rm_ptr { typedef T type; };
 
288
 
 
289
template <typename T>
 
290
        struct rm_ptr<T*> { typedef T type; };
 
291
 
 
292
template <typename T>
 
293
        struct rm_ptr<const T*> { typedef const T type; };
 
294
 
 
295
template <typename R, typename T, R (*F)(T)>
 
296
struct deleter {
 
297
        template <typename U>
 
298
                void operator()(U& ptr) const {
 
299
                        (*F)(ptr);
 
300
                }
 
301
};
 
302
 
 
303
template <typename T>
 
304
struct default_delete {
 
305
        void operator()(T& ptr) const {
 
306
                delete ptr;
 
307
        }
 
308
};
 
309
 
 
310
template <typename T, typename Deleter = deleter<void, void*, &::free> >
 
311
class handle {
 
312
        struct dummy;
 
313
        T    _val;
 
314
        bool _empty;
 
315
 
 
316
#if defined(BACKWARD_CXX11)
 
317
        handle(const handle&) = delete;
 
318
        handle& operator=(const handle&) = delete;
 
319
#endif
 
320
 
 
321
public:
 
322
        ~handle() {
 
323
                if (not _empty) {
 
324
                        Deleter()(_val);
 
325
                }
 
326
        }
 
327
 
 
328
        explicit handle(): _val(), _empty(true) {}
 
329
        explicit handle(T val): _val(val), _empty(false) {}
 
330
 
 
331
#if defined(BACKWARD_CXX11)
 
332
        handle(handle&& from): _empty(true) {
 
333
                swap(from);
 
334
        }
 
335
        handle& operator=(handle&& from) {
 
336
                swap(from); return *this;
 
337
        }
 
338
#else
 
339
        explicit handle(const handle& from): _empty(true) {
 
340
                // some sort of poor man's move semantic.
 
341
                swap(const_cast<handle&>(from));
 
342
        }
 
343
        handle& operator=(const handle& from) {
 
344
                // some sort of poor man's move semantic.
 
345
                swap(const_cast<handle&>(from)); return *this;
 
346
        }
 
347
#endif
 
348
 
 
349
        void reset(T new_val) {
 
350
                handle tmp(new_val);
 
351
                swap(tmp);
 
352
        }
 
353
        operator const dummy*() const {
 
354
                if (_empty) {
 
355
                        return 0;
 
356
                }
 
357
                return reinterpret_cast<const dummy*>(_val);
 
358
        }
 
359
        T get() {
 
360
                return _val;
 
361
        }
 
362
        T release() {
 
363
                _empty = true;
 
364
                return _val;
 
365
        }
 
366
        void swap(handle& b) {
 
367
                using std::swap;
 
368
                swap(b._val, _val); // can throw, we are safe here.
 
369
                swap(b._empty, _empty); // should not throw: if you cannot swap two
 
370
                // bools without throwing... It's a lost cause anyway!
 
371
        }
 
372
 
 
373
        T operator->() { return _val; }
 
374
        const T operator->() const { return _val; }
 
375
 
 
376
        typedef typename rm_ptr<T>::type& ref_t;
 
377
        ref_t operator*() { return *_val; }
 
378
        const ref_t operator*() const { return *_val; }
 
379
        ref_t operator[](size_t idx) { return _val[idx]; }
 
380
 
 
381
        // Watch out, we've got a badass over here
 
382
        T* operator&() {
 
383
                _empty = false;
 
384
                return &_val;
 
385
        }
 
386
};
 
387
 
 
388
} // namespace details
 
389
 
 
390
/*************** A TRACE ***************/
 
391
 
 
392
struct Trace {
 
393
        void*    addr;
 
394
        unsigned idx;
 
395
 
 
396
        Trace():
 
397
                addr(0), idx(0) {}
 
398
 
 
399
        explicit Trace(void* addr, size_t idx):
 
400
                addr(addr), idx(idx) {}
 
401
};
 
402
 
 
403
// Really simple, generic, and dumb representation of a variable.
 
404
// A variable has a name and can represent either:
 
405
//  - a value (as a string)
 
406
//  - a list of values (a list of strings)
 
407
//  - a map of values (a list of variable)
 
408
class Variable {
 
409
public:
 
410
        enum Kind { VALUE, LIST, MAP };
 
411
 
 
412
        typedef std::vector<std::string> list_t;
 
413
        typedef std::vector<Variable>    map_t;
 
414
 
 
415
        std::string name;
 
416
        Kind kind;
 
417
 
 
418
        Variable(Kind k): kind(k) {
 
419
                switch (k) {
 
420
                        case VALUE:
 
421
                                new (&storage) std::string();
 
422
                                break;
 
423
 
 
424
                        case LIST:
 
425
                                new (&storage) list_t();
 
426
                                break;
 
427
 
 
428
                        case MAP:
 
429
                                new (&storage) map_t();
 
430
                                break;
 
431
                }
 
432
        }
 
433
 
 
434
        std::string& value() {
 
435
                return reinterpret_cast<std::string&>(storage);
 
436
        }
 
437
        list_t& list() {
 
438
                return reinterpret_cast<list_t&>(storage);
 
439
        }
 
440
        map_t& map() {
 
441
                return reinterpret_cast<map_t&>(storage);
 
442
        }
 
443
 
 
444
 
 
445
        const std::string& value() const {
 
446
                return reinterpret_cast<const std::string&>(storage);
 
447
        }
 
448
        const list_t& list() const {
 
449
                return reinterpret_cast<const list_t&>(storage);
 
450
        }
 
451
        const map_t& map() const {
 
452
                return reinterpret_cast<const map_t&>(storage);
 
453
        }
 
454
 
 
455
private:
 
456
        // the C++98 style union for non-trivial objects, yes yes I know, its not
 
457
        // aligned as good as it can be, blabla... Screw this.
 
458
        union {
 
459
                char s1[sizeof (std::string)];
 
460
                char s2[sizeof (list_t)];
 
461
                char s3[sizeof (map_t)];
 
462
        } storage;
 
463
};
 
464
 
 
465
struct TraceWithLocals: public Trace {
 
466
        // Locals variable and values.
 
467
        std::vector<Variable> locals;
 
468
 
 
469
        TraceWithLocals(): Trace() {}
 
470
        TraceWithLocals(const Trace& mini_trace):
 
471
                Trace(mini_trace) {}
 
472
};
 
473
 
 
474
struct ResolvedTrace: public TraceWithLocals {
 
475
 
 
476
        struct SourceLoc {
 
477
                std::string function;
 
478
                std::string filename;
 
479
                unsigned    line;
 
480
                unsigned    col;
 
481
 
 
482
                SourceLoc(): line(0), col(0) {}
 
483
 
 
484
                bool operator==(const SourceLoc& b) const {
 
485
                        return function == b.function
 
486
                                and filename == b.filename
 
487
                                and line == b.line
 
488
                                and col == b.col;
 
489
                }
 
490
 
 
491
                bool operator!=(const SourceLoc& b) const {
 
492
                        return not (*this == b);
 
493
                }
 
494
        };
 
495
 
 
496
        // In which binary object this trace is located.
 
497
        std::string                    object_filename;
 
498
 
 
499
        // The function in the object that contain the trace. This is not the same
 
500
        // as source.function which can be an function inlined in object_function.
 
501
        std::string                    object_function;
 
502
 
 
503
        // The source location of this trace. It is possible for filename to be
 
504
        // empty and for line/col to be invalid (value 0) if this information
 
505
        // couldn't be deduced, for example if there is no debug information in the
 
506
        // binary object.
 
507
        SourceLoc                      source;
 
508
 
 
509
        // An optionals list of "inliners". All the successive sources location
 
510
        // from where the source location of the trace (the attribute right above)
 
511
        // is inlined. It is especially useful when you compiled with optimization.
 
512
        typedef std::vector<SourceLoc> source_locs_t;
 
513
        source_locs_t                  inliners;
 
514
 
 
515
        ResolvedTrace(const Trace& mini_trace):
 
516
                TraceWithLocals(mini_trace) {}
 
517
        ResolvedTrace(const TraceWithLocals& mini_trace_with_locals):
 
518
                TraceWithLocals(mini_trace_with_locals) {}
 
519
};
 
520
 
 
521
/*************** STACK TRACE ***************/
 
522
 
 
523
// default implemention.
 
524
template <typename TAG>
 
525
class StackTraceImpl {
 
526
public:
 
527
        size_t size() const { return 0; }
 
528
        Trace operator[](size_t) { return Trace(); }
 
529
        size_t load_here(size_t=0) { return 0; }
 
530
        size_t load_from(void*, size_t=0) { return 0; }
 
531
        unsigned thread_id() const { return 0; }
 
532
};
 
533
 
 
534
#ifdef BACKWARD_SYSTEM_LINUX
 
535
 
 
536
class StackTraceLinuxImplBase {
 
537
public:
 
538
        StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
 
539
 
 
540
        unsigned thread_id() const {
 
541
                return _thread_id;
 
542
        }
 
543
 
 
544
protected:
 
545
        void load_thread_info() {
 
546
                _thread_id = syscall(SYS_gettid);
 
547
                if (_thread_id == (size_t) getpid()) {
 
548
                        // If the thread is the main one, let's hide that.
 
549
                        // I like to keep little secret sometimes.
 
550
                        _thread_id = 0;
 
551
                }
 
552
        }
 
553
 
 
554
        void skip_n_firsts(size_t n) { _skip = n; }
 
555
        size_t skip_n_firsts() const { return _skip; }
 
556
 
 
557
private:
 
558
        size_t _thread_id;
 
559
        size_t _skip;
 
560
};
 
561
 
 
562
class StackTraceLinuxImplHolder: public StackTraceLinuxImplBase {
 
563
public:
 
564
        size_t size() const {
 
565
                return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
 
566
        }
 
567
        Trace operator[](size_t idx) {
 
568
                if (idx >= size()) {
 
569
                        return Trace();
 
570
                }
 
571
                return Trace(_stacktrace[idx + skip_n_firsts()], idx);
 
572
        }
 
573
        void** begin() {
 
574
                if (size()) {
 
575
                        return &_stacktrace[skip_n_firsts()];
 
576
                }
 
577
                return 0;
 
578
        }
 
579
 
 
580
protected:
 
581
        std::vector<void*> _stacktrace;
 
582
};
 
583
 
 
584
 
 
585
#if BACKWARD_HAS_UNWIND == 1
 
586
 
 
587
namespace details {
 
588
 
 
589
template <typename F>
 
590
class Unwinder {
 
591
public:
 
592
        size_t operator()(F& f, size_t depth) {
 
593
                _f = &f;
 
594
                _index = -1;
 
595
                _depth = depth;
 
596
                _Unwind_Backtrace(&this->backtrace_trampoline, this);
 
597
                return _index;
 
598
        }
 
599
 
 
600
private:
 
601
        F*      _f;
 
602
        ssize_t _index;
 
603
        size_t  _depth;
 
604
 
 
605
        static _Unwind_Reason_Code backtrace_trampoline(
 
606
                        _Unwind_Context* ctx, void *self) {
 
607
                return ((Unwinder*)self)->backtrace(ctx);
 
608
        }
 
609
 
 
610
        _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) {
 
611
                if (_index >= 0 and static_cast<size_t>(_index) >= _depth)
 
612
                        return _URC_END_OF_STACK;
 
613
 
 
614
                int ip_before_instruction = 0;
 
615
                uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction);
 
616
 
 
617
                if (not ip_before_instruction) {
 
618
                        ip -= 1;
 
619
                }
 
620
 
 
621
                if (_index >= 0) { // ignore first frame.
 
622
                        (*_f)(_index, (void*)ip);
 
623
                }
 
624
                _index += 1;
 
625
                return _URC_NO_REASON;
 
626
        }
 
627
};
 
628
 
 
629
template <typename F>
 
630
size_t unwind(F f, size_t depth) {
 
631
        Unwinder<F> unwinder;
 
632
        return unwinder(f, depth);
 
633
}
 
634
 
 
635
} // namespace details
 
636
 
 
637
 
 
638
template <>
 
639
class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
 
640
public:
 
641
        __attribute__ ((noinline)) // TODO use some macro
 
642
        size_t load_here(size_t depth=32) {
 
643
                load_thread_info();
 
644
                if (depth == 0) {
 
645
                        return 0;
 
646
                }
 
647
                _stacktrace.resize(depth);
 
648
                size_t trace_cnt = details::unwind(callback(*this), depth);
 
649
                _stacktrace.resize(trace_cnt);
 
650
                skip_n_firsts(0);
 
651
                return size();
 
652
        }
 
653
        size_t load_from(void* addr, size_t depth=32) {
 
654
                load_here(depth + 8);
 
655
 
 
656
                for (size_t i = 0; i < _stacktrace.size(); ++i) {
 
657
                        if (_stacktrace[i] == addr) {
 
658
                                skip_n_firsts(i);
 
659
                                break;
 
660
                        }
 
661
                }
 
662
 
 
663
                _stacktrace.resize(std::min(_stacktrace.size(),
 
664
                                        skip_n_firsts() + depth));
 
665
                return size();
 
666
        }
 
667
 
 
668
private:
 
669
        struct callback {
 
670
                StackTraceImpl& self;
 
671
                callback(StackTraceImpl& self): self(self) {}
 
672
 
 
673
                void operator()(size_t idx, void* addr) {
 
674
                        self._stacktrace[idx] = addr;
 
675
                }
 
676
        };
 
677
};
 
678
 
 
679
 
 
680
#else // BACKWARD_HAS_UNWIND == 0
 
681
 
 
682
template <>
 
683
class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
 
684
public:
 
685
        __attribute__ ((noinline)) // TODO use some macro
 
686
        size_t load_here(size_t depth=32) {
 
687
                load_thread_info();
 
688
                if (depth == 0) {
 
689
                        return 0;
 
690
                }
 
691
                _stacktrace.resize(depth + 1);
 
692
                size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
 
693
                _stacktrace.resize(trace_cnt);
 
694
                skip_n_firsts(1);
 
695
                return size();
 
696
        }
 
697
 
 
698
        size_t load_from(void* addr, size_t depth=32) {
 
699
                load_here(depth + 8);
 
700
 
 
701
                for (size_t i = 0; i < _stacktrace.size(); ++i) {
 
702
                        if (_stacktrace[i] == addr) {
 
703
                                skip_n_firsts(i);
 
704
                                _stacktrace[i] = (void*)( (uintptr_t)_stacktrace[i] + 1);
 
705
                                break;
 
706
                        }
 
707
                }
 
708
 
 
709
                _stacktrace.resize(std::min(_stacktrace.size(),
 
710
                                        skip_n_firsts() + depth));
 
711
                return size();
 
712
        }
 
713
};
 
714
 
 
715
#endif // BACKWARD_HAS_UNWIND
 
716
#endif // BACKWARD_SYSTEM_LINUX
 
717
 
 
718
class StackTrace:
 
719
        public StackTraceImpl<system_tag::current_tag> {};
 
720
 
 
721
/*********** STACKTRACE WITH LOCALS ***********/
 
722
 
 
723
// default implemention.
 
724
template <typename TAG>
 
725
class StackTraceWithLocalsImpl:
 
726
        public StackTrace {};
 
727
 
 
728
#ifdef BACKWARD_SYSTEM_LINUX
 
729
#if BACKWARD_HAS_UNWIND
 
730
#if BACKWARD_HAS_DW
 
731
 
 
732
template <>
 
733
class StackTraceWithLocalsImpl<system_tag::linux_tag>:
 
734
        public StackTraceLinuxImplBase {
 
735
public:
 
736
        __attribute__ ((noinline)) // TODO use some macro
 
737
        size_t load_here(size_t depth=32) {
 
738
                load_thread_info();
 
739
                if (depth == 0) {
 
740
                        return 0;
 
741
                }
 
742
                _stacktrace.resize(depth);
 
743
                size_t trace_cnt = details::unwind(callback(*this), depth);
 
744
                _stacktrace.resize(trace_cnt);
 
745
                skip_n_firsts(0);
 
746
                return size();
 
747
        }
 
748
        size_t load_from(void* addr, size_t depth=32) {
 
749
                load_here(depth + 8);
 
750
 
 
751
                for (size_t i = 0; i < _stacktrace.size(); ++i) {
 
752
                        if (_stacktrace[i].addr == addr) {
 
753
                                skip_n_firsts(i);
 
754
                                break;
 
755
                        }
 
756
                }
 
757
                _stacktrace.resize(std::min(_stacktrace.size(),
 
758
                                        skip_n_firsts() + depth));
 
759
                return size();
 
760
        }
 
761
        size_t size() const {
 
762
                return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
 
763
        }
 
764
        const TraceWithLocals& operator[](size_t idx) {
 
765
                if (idx >= size()) {
 
766
                        return _nil_trace;
 
767
                }
 
768
                return _stacktrace[idx + skip_n_firsts()];
 
769
        }
 
770
 
 
771
private:
 
772
        std::vector<TraceWithLocals> _stacktrace;
 
773
        TraceWithLocals              _nil_trace;
 
774
 
 
775
        void resolve_trace(TraceWithLocals& trace) {
 
776
                Variable v(Variable::VALUE);
 
777
                v.name = "var";
 
778
                v.value() = "42";
 
779
                trace.locals.push_back(v);
 
780
        }
 
781
 
 
782
        struct callback {
 
783
                StackTraceWithLocalsImpl& self;
 
784
                callback(StackTraceWithLocalsImpl& self): self(self) {}
 
785
 
 
786
                void operator()(size_t idx, void* addr) {
 
787
                        self._stacktrace[idx].addr = addr;
 
788
                        self.resolve_trace(self._stacktrace[idx]);
 
789
                }
 
790
        };
 
791
};
 
792
 
 
793
#endif // BACKWARD_HAS_DW
 
794
#endif // BACKWARD_HAS_UNWIND
 
795
#endif // BACKWARD_SYSTEM_LINUX
 
796
 
 
797
class StackTraceWithLocals:
 
798
        public StackTraceWithLocalsImpl<system_tag::current_tag> {};
 
799
 
 
800
/*************** TRACE RESOLVER ***************/
 
801
 
 
802
template <typename TAG>
 
803
class TraceResolverImpl;
 
804
 
 
805
#ifdef BACKWARD_SYSTEM_UNKNOWN
 
806
 
 
807
template <>
 
808
class TraceResolverImpl<system_tag::unknown_tag> {
 
809
public:
 
810
        template <class ST>
 
811
                void load_stacktrace(ST&) {}
 
812
        ResolvedTrace resolve(ResolvedTrace t) {
 
813
                return t;
 
814
        }
 
815
};
 
816
 
 
817
#endif
 
818
 
 
819
#ifdef BACKWARD_SYSTEM_LINUX
 
820
 
 
821
class TraceResolverLinuxImplBase {
 
822
protected:
 
823
        std::string demangle(const char* funcname) {
 
824
                using namespace details;
 
825
                _demangle_buffer.reset(
 
826
                                abi::__cxa_demangle(funcname, _demangle_buffer.release(),
 
827
                                        &_demangle_buffer_length, 0)
 
828
                                );
 
829
                if (_demangle_buffer) {
 
830
                        return _demangle_buffer.get();
 
831
                }
 
832
                return funcname;
 
833
        }
 
834
 
 
835
private:
 
836
        details::handle<char*> _demangle_buffer;
 
837
        size_t                 _demangle_buffer_length;
 
838
};
 
839
 
 
840
template <typename STACKTRACE_TAG>
 
841
class TraceResolverLinuxImpl;
 
842
 
 
843
#if BACKWARD_HAS_BACKTRACE_SYMBOL == 1
 
844
 
 
845
template <>
 
846
class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
 
847
        public TraceResolverLinuxImplBase {
 
848
public:
 
849
        template <class ST>
 
850
                void load_stacktrace(ST& st) {
 
851
                        using namespace details;
 
852
                        if (st.size() == 0) {
 
853
                                return;
 
854
                        }
 
855
                        _symbols.reset(
 
856
                                        backtrace_symbols(st.begin(), st.size())
 
857
                                        );
 
858
                }
 
859
 
 
860
        ResolvedTrace resolve(ResolvedTrace trace) {
 
861
                char* filename = _symbols[trace.idx];
 
862
                char* funcname = filename;
 
863
                while (*funcname && *funcname != '(') {
 
864
                        funcname += 1;
 
865
                }
 
866
                trace.object_filename.assign(filename, funcname++);
 
867
                char* funcname_end = funcname;
 
868
                while (*funcname_end && *funcname_end != ')' && *funcname_end != '+') {
 
869
                        funcname_end += 1;
 
870
                }
 
871
                *funcname_end = '\0';
 
872
                trace.object_function = this->demangle(funcname);
 
873
                trace.source.function = trace.object_function; // we cannot do better.
 
874
                return trace;
 
875
        }
 
876
 
 
877
private:
 
878
        details::handle<char**> _symbols;
 
879
};
 
880
 
 
881
#endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1
 
882
 
 
883
#if BACKWARD_HAS_BFD == 1
 
884
 
 
885
template <>
 
886
class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
 
887
        public TraceResolverLinuxImplBase {
 
888
public:
 
889
        TraceResolverLinuxImpl(): _bfd_loaded(false) {}
 
890
 
 
891
        template <class ST>
 
892
                void load_stacktrace(ST&) {}
 
893
 
 
894
        ResolvedTrace resolve(ResolvedTrace trace) {
 
895
                Dl_info symbol_info;
 
896
 
 
897
                // trace.addr is a virtual address in memory pointing to some code.
 
898
                // Let's try to find from which loaded object it comes from.
 
899
                // The loaded object can be yourself btw.
 
900
                if (not dladdr(trace.addr, &symbol_info)) {
 
901
                        return trace; // dat broken trace...
 
902
                }
 
903
 
 
904
                // Now we get in symbol_info:
 
905
                // .dli_fname:
 
906
                //              pathname of the shared object that contains the address.
 
907
                // .dli_fbase:
 
908
                //              where the object is loaded in memory.
 
909
                // .dli_sname:
 
910
                //              the name of the nearest symbol to trace.addr, we expect a
 
911
                //              function name.
 
912
                // .dli_saddr:
 
913
                //              the exact address corresponding to .dli_sname.
 
914
 
 
915
                if (symbol_info.dli_sname) {
 
916
                        trace.object_function = demangle(symbol_info.dli_sname);
 
917
                }
 
918
 
 
919
                if (not symbol_info.dli_fname) {
 
920
                        return trace;
 
921
                }
 
922
 
 
923
                trace.object_filename = symbol_info.dli_fname;
 
924
                bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
 
925
                if (not fobj.handle) {
 
926
                        return trace; // sad, we couldn't load the object :(
 
927
                }
 
928
 
 
929
 
 
930
                find_sym_result* details_selected; // to be filled.
 
931
 
 
932
                // trace.addr is the next instruction to be executed after returning
 
933
                // from the nested stack frame. In C++ this usually relate to the next
 
934
                // statement right after the function call that leaded to a new stack
 
935
                // frame. This is not usually what you want to see when printing out a
 
936
                // stacktrace...
 
937
                find_sym_result details_call_site = find_symbol_details(fobj,
 
938
                                trace.addr, symbol_info.dli_fbase);
 
939
                details_selected = &details_call_site;
 
940
 
 
941
#if BACKWARD_HAS_UNWIND == 0
 
942
                // ...this is why we also try to resolve the symbol that is right
 
943
                // before the return address. If we are lucky enough, we will get the
 
944
                // line of the function that was called. But if the code is optimized,
 
945
                // we might get something absolutely not related since the compiler
 
946
                // can reschedule the return address with inline functions and
 
947
                // tail-call optimisation (among other things that I don't even know
 
948
                // or cannot even dream about with my tiny limited brain).
 
949
                find_sym_result details_adjusted_call_site = find_symbol_details(fobj,
 
950
                                (void*) (uintptr_t(trace.addr) - 1),
 
951
                                symbol_info.dli_fbase);
 
952
 
 
953
                // In debug mode, we should always get the right thing(TM).
 
954
                if (details_call_site.found and details_adjusted_call_site.found) {
 
955
                        // Ok, we assume that details_adjusted_call_site is a better estimation.
 
956
                        details_selected = &details_adjusted_call_site;
 
957
                        trace.addr = (void*) (uintptr_t(trace.addr) - 1);
 
958
                }
 
959
 
 
960
                if (details_selected == &details_call_site and details_call_site.found) {
 
961
                        // we have to re-resolve the symbol in order to reset some
 
962
                        // internal state in BFD... so we can call backtrace_inliners
 
963
                        // thereafter...
 
964
                        details_call_site = find_symbol_details(fobj, trace.addr,
 
965
                                        symbol_info.dli_fbase);
 
966
                }
 
967
#endif // BACKWARD_HAS_UNWIND
 
968
 
 
969
                if (details_selected->found) {
 
970
                        if (details_selected->filename) {
 
971
                                trace.source.filename = details_selected->filename;
 
972
                        }
 
973
                        trace.source.line = details_selected->line;
 
974
 
 
975
                        if (details_selected->funcname) {
 
976
                                // this time we get the name of the function where the code is
 
977
                                // located, instead of the function were the address is
 
978
                                // located. In short, if the code was inlined, we get the
 
979
                                // function correspoding to the code. Else we already got in
 
980
                                // trace.function.
 
981
                                trace.source.function = demangle(details_selected->funcname);
 
982
 
 
983
                                if (not symbol_info.dli_sname) {
 
984
                                        // for the case dladdr failed to find the symbol name of
 
985
                                        // the function, we might as well try to put something
 
986
                                        // here.
 
987
                                        trace.object_function = trace.source.function;
 
988
                                }
 
989
                        }
 
990
 
 
991
                        // Maybe the source of the trace got inlined inside the function
 
992
                        // (trace.source.function). Let's see if we can get all the inlined
 
993
                        // calls along the way up to the initial call site.
 
994
                        trace.inliners = backtrace_inliners(fobj, *details_selected);
 
995
 
 
996
#if 0
 
997
                        if (trace.inliners.size() == 0) {
 
998
                                // Maybe the trace was not inlined... or maybe it was and we
 
999
                                // are lacking the debug information. Let's try to make the
 
1000
                                // world better and see if we can get the line number of the
 
1001
                                // function (trace.source.function) now.
 
1002
                                //
 
1003
                                // We will get the location of where the function start (to be
 
1004
                                // exact: the first instruction that really start the
 
1005
                                // function), not where the name of the function is defined.
 
1006
                                // This can be quite far away from the name of the function
 
1007
                                // btw.
 
1008
                                //
 
1009
                                // If the source of the function is the same as the source of
 
1010
                                // the trace, we cannot say if the trace was really inlined or
 
1011
                                // not.  However, if the filename of the source is different
 
1012
                                // between the function and the trace... we can declare it as
 
1013
                                // an inliner.  This is not 100% accurate, but better than
 
1014
                                // nothing.
 
1015
 
 
1016
                                if (symbol_info.dli_saddr) {
 
1017
                                        find_sym_result details = find_symbol_details(fobj,
 
1018
                                                        symbol_info.dli_saddr,
 
1019
                                                        symbol_info.dli_fbase);
 
1020
 
 
1021
                                        if (details.found) {
 
1022
                                                ResolvedTrace::SourceLoc diy_inliner;
 
1023
                                                diy_inliner.line = details.line;
 
1024
                                                if (details.filename) {
 
1025
                                                        diy_inliner.filename = details.filename;
 
1026
                                                }
 
1027
                                                if (details.funcname) {
 
1028
                                                        diy_inliner.function = demangle(details.funcname);
 
1029
                                                } else {
 
1030
                                                        diy_inliner.function = trace.source.function;
 
1031
                                                }
 
1032
                                                if (diy_inliner != trace.source) {
 
1033
                                                        trace.inliners.push_back(diy_inliner);
 
1034
                                                }
 
1035
                                        }
 
1036
                                }
 
1037
                        }
 
1038
#endif
 
1039
                }
 
1040
 
 
1041
                return trace;
 
1042
        }
 
1043
 
 
1044
private:
 
1045
        bool                _bfd_loaded;
 
1046
 
 
1047
        typedef details::handle<bfd*,
 
1048
                        details::deleter<bfd_boolean, bfd*, &bfd_close>
 
1049
                                > bfd_handle_t;
 
1050
 
 
1051
        typedef details::handle<asymbol**> bfd_symtab_t;
 
1052
 
 
1053
 
 
1054
        struct bfd_fileobject {
 
1055
                bfd_handle_t handle;
 
1056
                bfd_vma      base_addr;
 
1057
                bfd_symtab_t symtab;
 
1058
                bfd_symtab_t dynamic_symtab;
 
1059
        };
 
1060
 
 
1061
        typedef details::hashtable<std::string, bfd_fileobject>::type
 
1062
                fobj_bfd_map_t;
 
1063
        fobj_bfd_map_t      _fobj_bfd_map;
 
1064
 
 
1065
        bfd_fileobject& load_object_with_bfd(const std::string& filename_object) {
 
1066
                using namespace details;
 
1067
 
 
1068
                if (not _bfd_loaded) {
 
1069
                        using namespace details;
 
1070
                        bfd_init();
 
1071
                        _bfd_loaded = true;
 
1072
                }
 
1073
 
 
1074
                fobj_bfd_map_t::iterator it =
 
1075
                        _fobj_bfd_map.find(filename_object);
 
1076
                if (it != _fobj_bfd_map.end()) {
 
1077
                        return it->second;
 
1078
                }
 
1079
 
 
1080
                // this new object is empty for now.
 
1081
                bfd_fileobject& r = _fobj_bfd_map[filename_object];
 
1082
 
 
1083
                // we do the work temporary in this one;
 
1084
                bfd_handle_t bfd_handle;
 
1085
 
 
1086
                int fd = open(filename_object.c_str(), O_RDONLY);
 
1087
                bfd_handle.reset(
 
1088
                                bfd_fdopenr(filename_object.c_str(), "default", fd)
 
1089
                                );
 
1090
                if (not bfd_handle) {
 
1091
                        close(fd);
 
1092
                        return r;
 
1093
                }
 
1094
 
 
1095
                if (not bfd_check_format(bfd_handle.get(), bfd_object)) {
 
1096
                        return r; // not an object? You lose.
 
1097
                }
 
1098
 
 
1099
                if ((bfd_get_file_flags(bfd_handle.get()) & HAS_SYMS) == 0) {
 
1100
                        return r; // that's what happen when you forget to compile in debug.
 
1101
                }
 
1102
 
 
1103
                ssize_t symtab_storage_size =
 
1104
                        bfd_get_symtab_upper_bound(bfd_handle.get());
 
1105
 
 
1106
                ssize_t dyn_symtab_storage_size =
 
1107
                        bfd_get_dynamic_symtab_upper_bound(bfd_handle.get());
 
1108
 
 
1109
                if (symtab_storage_size <= 0 and dyn_symtab_storage_size <= 0) {
 
1110
                        return r; // weird, is the file is corrupted?
 
1111
                }
 
1112
 
 
1113
                bfd_symtab_t symtab, dynamic_symtab;
 
1114
                ssize_t symcount = 0, dyn_symcount = 0;
 
1115
 
 
1116
                if (symtab_storage_size > 0) {
 
1117
                        symtab.reset(
 
1118
                                        (bfd_symbol**) malloc(symtab_storage_size)
 
1119
                                        );
 
1120
                        symcount = bfd_canonicalize_symtab(
 
1121
                                        bfd_handle.get(), symtab.get()
 
1122
                                        );
 
1123
                }
 
1124
 
 
1125
                if (dyn_symtab_storage_size > 0) {
 
1126
                        dynamic_symtab.reset(
 
1127
                                        (bfd_symbol**) malloc(dyn_symtab_storage_size)
 
1128
                                        );
 
1129
                        dyn_symcount = bfd_canonicalize_dynamic_symtab(
 
1130
                                        bfd_handle.get(), dynamic_symtab.get()
 
1131
                                        );
 
1132
                }
 
1133
 
 
1134
 
 
1135
                if (symcount <= 0 and dyn_symcount <= 0) {
 
1136
                        return r; // damned, that's a stripped file that you got there!
 
1137
                }
 
1138
 
 
1139
                r.handle = move(bfd_handle);
 
1140
                r.symtab = move(symtab);
 
1141
                r.dynamic_symtab = move(dynamic_symtab);
 
1142
                return r;
 
1143
        }
 
1144
 
 
1145
        struct find_sym_result {
 
1146
                bool found;
 
1147
                const char* filename;
 
1148
                const char* funcname;
 
1149
                unsigned int line;
 
1150
        };
 
1151
 
 
1152
        struct find_sym_context {
 
1153
                TraceResolverLinuxImpl* self;
 
1154
                bfd_fileobject* fobj;
 
1155
                void* addr;
 
1156
                void* base_addr;
 
1157
                find_sym_result result;
 
1158
        };
 
1159
 
 
1160
        find_sym_result find_symbol_details(bfd_fileobject& fobj, void* addr,
 
1161
                        void* base_addr) {
 
1162
                find_sym_context context;
 
1163
                context.self = this;
 
1164
                context.fobj = &fobj;
 
1165
                context.addr = addr;
 
1166
                context.base_addr = base_addr;
 
1167
                context.result.found = false;
 
1168
                bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline,
 
1169
                                (void*)&context);
 
1170
                return context.result;
 
1171
        }
 
1172
 
 
1173
        static void find_in_section_trampoline(bfd*, asection* section,
 
1174
                        void* data) {
 
1175
                find_sym_context* context = static_cast<find_sym_context*>(data);
 
1176
                context->self->find_in_section(
 
1177
                                reinterpret_cast<bfd_vma>(context->addr),
 
1178
                                reinterpret_cast<bfd_vma>(context->base_addr),
 
1179
                                *context->fobj,
 
1180
                                section, context->result
 
1181
                                );
 
1182
        }
 
1183
 
 
1184
        void find_in_section(bfd_vma addr, bfd_vma base_addr,
 
1185
                        bfd_fileobject& fobj, asection* section, find_sym_result& result)
 
1186
        {
 
1187
                if (result.found) return;
 
1188
 
 
1189
                if ((bfd_get_section_flags(fobj.handle.get(), section)
 
1190
                                        & SEC_ALLOC) == 0)
 
1191
                        return; // a debug section is never loaded automatically.
 
1192
 
 
1193
                bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section);
 
1194
                bfd_size_type size = bfd_get_section_size(section);
 
1195
 
 
1196
                // are we in the boundaries of the section?
 
1197
                if (addr < sec_addr or addr >= sec_addr + size) {
 
1198
                        addr -= base_addr; // oups, a relocated object, lets try again...
 
1199
                        if (addr < sec_addr or addr >= sec_addr + size) {
 
1200
                                return;
 
1201
                        }
 
1202
                }
 
1203
 
 
1204
                if (not result.found and fobj.symtab) {
 
1205
                        result.found = bfd_find_nearest_line(fobj.handle.get(), section,
 
1206
                                        fobj.symtab.get(), addr - sec_addr, &result.filename,
 
1207
                                        &result.funcname, &result.line);
 
1208
                }
 
1209
 
 
1210
                if (not result.found and fobj.dynamic_symtab) {
 
1211
                        result.found = bfd_find_nearest_line(fobj.handle.get(), section,
 
1212
                                        fobj.dynamic_symtab.get(), addr - sec_addr,
 
1213
                                        &result.filename, &result.funcname, &result.line);
 
1214
                }
 
1215
 
 
1216
        }
 
1217
 
 
1218
        ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj,
 
1219
                        find_sym_result previous_result) {
 
1220
                // This function can be called ONLY after a SUCCESSFUL call to
 
1221
                // find_symbol_details. The state is global to the bfd_handle.
 
1222
                ResolvedTrace::source_locs_t results;
 
1223
                while (previous_result.found) {
 
1224
                        find_sym_result result;
 
1225
                        result.found = bfd_find_inliner_info(fobj.handle.get(),
 
1226
                                        &result.filename, &result.funcname, &result.line);
 
1227
 
 
1228
                        if (result.found) /* and not (
 
1229
                                                cstrings_eq(previous_result.filename, result.filename)
 
1230
                                                and cstrings_eq(previous_result.funcname, result.funcname)
 
1231
                                                and result.line == previous_result.line
 
1232
                                                )) */ {
 
1233
                                ResolvedTrace::SourceLoc src_loc;
 
1234
                                src_loc.line = result.line;
 
1235
                                if (result.filename) {
 
1236
                                        src_loc.filename = result.filename;
 
1237
                                }
 
1238
                                if (result.funcname) {
 
1239
                                        src_loc.function = demangle(result.funcname);
 
1240
                                }
 
1241
                                results.push_back(src_loc);
 
1242
                        }
 
1243
                        previous_result = result;
 
1244
                }
 
1245
                return results;
 
1246
        }
 
1247
 
 
1248
        bool cstrings_eq(const char* a, const char* b) {
 
1249
                if (not a or not b) {
 
1250
                        return false;
 
1251
                }
 
1252
                return strcmp(a, b) == 0;
 
1253
        }
 
1254
 
 
1255
};
 
1256
#endif // BACKWARD_HAS_BFD == 1
 
1257
 
 
1258
#if BACKWARD_HAS_DW == 1
 
1259
 
 
1260
template <>
 
1261
class TraceResolverLinuxImpl<trace_resolver_tag::libdw>:
 
1262
        public TraceResolverLinuxImplBase {
 
1263
public:
 
1264
        TraceResolverLinuxImpl(): _dwfl_handle_initialized(false) {}
 
1265
 
 
1266
        template <class ST>
 
1267
                void load_stacktrace(ST&) {}
 
1268
 
 
1269
        ResolvedTrace resolve(ResolvedTrace trace) {
 
1270
                using namespace details;
 
1271
 
 
1272
                Dwarf_Addr trace_addr = (Dwarf_Addr) trace.addr;
 
1273
 
 
1274
                if (not _dwfl_handle_initialized) {
 
1275
                        // initialize dwfl...
 
1276
                        _dwfl_cb.reset(new Dwfl_Callbacks);
 
1277
                        _dwfl_cb->find_elf = &dwfl_linux_proc_find_elf;
 
1278
                        _dwfl_cb->find_debuginfo = &dwfl_standard_find_debuginfo;
 
1279
                        _dwfl_cb->debuginfo_path = 0;
 
1280
 
 
1281
                        _dwfl_handle.reset(dwfl_begin(_dwfl_cb.get()));
 
1282
                        _dwfl_handle_initialized = true;
 
1283
 
 
1284
                        if (not _dwfl_handle) {
 
1285
                                return trace;
 
1286
                        }
 
1287
 
 
1288
                        // ...from the current process.
 
1289
                        dwfl_report_begin(_dwfl_handle.get());
 
1290
                        int r = dwfl_linux_proc_report (_dwfl_handle.get(), getpid());
 
1291
                        dwfl_report_end(_dwfl_handle.get(), NULL, NULL);
 
1292
                        if (r < 0) {
 
1293
                                return trace;
 
1294
                        }
 
1295
                }
 
1296
 
 
1297
                if (not _dwfl_handle) {
 
1298
                        return trace;
 
1299
                }
 
1300
 
 
1301
                // find the module (binary object) that contains the trace's address.
 
1302
                // This is not using any debug information, but the addresses ranges of
 
1303
                // all the currently loaded binary object.
 
1304
                Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr);
 
1305
                if (mod) {
 
1306
                        // now that we found it, lets get the name of it, this will be the
 
1307
                        // full path to the running binary or one of the loaded library.
 
1308
                        const char* module_name = dwfl_module_info (mod,
 
1309
                                        0, 0, 0, 0, 0, 0, 0);
 
1310
                        if (module_name) {
 
1311
                                trace.object_filename = module_name;
 
1312
                        }
 
1313
                        // We also look after the name of the symbol, equal or before this
 
1314
                        // address. This is found by walking the symtab. We should get the
 
1315
                        // symbol corresponding to the function (mangled) containing the
 
1316
                        // address. If the code corresponding to the address was inlined,
 
1317
                        // this is the name of the out-most inliner function.
 
1318
                        const char* sym_name = dwfl_module_addrname(mod, trace_addr);
 
1319
                        if (sym_name) {
 
1320
                                trace.object_function = demangle(sym_name);
 
1321
                        }
 
1322
                }
 
1323
 
 
1324
                // now let's get serious, and find out the source location (file and
 
1325
                // line number) of the address.
 
1326
 
 
1327
                // This function will look in .debug_aranges for the address and map it
 
1328
                // to the location of the compilation unit DIE in .debug_info and
 
1329
                // return it.
 
1330
                Dwarf_Addr mod_bias = 0;
 
1331
                Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias);
 
1332
 
 
1333
#if 1
 
1334
                if (not cudie) {
 
1335
                        // Sadly clang does not generate the section .debug_aranges, thus
 
1336
                        // dwfl_module_addrdie will fail early. Clang doesn't either set
 
1337
                        // the lowpc/highpc/range info for every compilation unit.
 
1338
                        //
 
1339
                        // So in order to save the world:
 
1340
                        // for every compilation unit, we will iterate over every single
 
1341
                        // DIEs. Normally functions should have a lowpc/highpc/range, which
 
1342
                        // we will use to infer the compilation unit.
 
1343
 
 
1344
                        // note that this is probably badly inefficient.
 
1345
                        while ((cudie = dwfl_module_nextcu(mod, cudie, &mod_bias))) {
 
1346
                                Dwarf_Die die_mem;
 
1347
                                Dwarf_Die* fundie = find_fundie_by_pc(cudie,
 
1348
                                                trace_addr - mod_bias, &die_mem);
 
1349
                                if (fundie) {
 
1350
                                        break;
 
1351
                                }
 
1352
                        }
 
1353
                }
 
1354
#endif
 
1355
 
 
1356
//#define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
 
1357
#ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
 
1358
                if (not cudie) {
 
1359
                        // If it's still not enough, lets dive deeper in the shit, and try
 
1360
                        // to save the world again: for every compilation unit, we will
 
1361
                        // load the corresponding .debug_line section, and see if we can
 
1362
                        // find our address in it.
 
1363
 
 
1364
                        Dwarf_Addr cfi_bias;
 
1365
                        Dwarf_CFI* cfi_cache = dwfl_module_eh_cfi(mod, &cfi_bias);
 
1366
 
 
1367
                        Dwarf_Addr bias;
 
1368
                        while ((cudie = dwfl_module_nextcu(mod, cudie, &bias))) {
 
1369
                                if (dwarf_getsrc_die(cudie, trace_addr - bias)) {
 
1370
 
 
1371
                                        // ...but if we get a match, it might be a false positive
 
1372
                                        // because our (address - bias) might as well be valid in a
 
1373
                                        // different compilation unit. So we throw our last card on
 
1374
                                        // the table and lookup for the address into the .eh_frame
 
1375
                                        // section.
 
1376
 
 
1377
                                        handle<Dwarf_Frame*> frame;
 
1378
                                        dwarf_cfi_addrframe(cfi_cache, trace_addr - cfi_bias, &frame);
 
1379
                                        if (frame) {
 
1380
                                                break;
 
1381
                                        }
 
1382
                                }
 
1383
                        }
 
1384
                }
 
1385
#endif
 
1386
 
 
1387
                if (not cudie) {
 
1388
                        return trace; // this time we lost the game :/
 
1389
                }
 
1390
 
 
1391
                // Now that we have a compilation unit DIE, this function will be able
 
1392
                // to load the corresponding section in .debug_line (if not already
 
1393
                // loaded) and hopefully find the source location mapped to our
 
1394
                // address.
 
1395
                Dwarf_Line* srcloc = dwarf_getsrc_die(cudie, trace_addr - mod_bias);
 
1396
 
 
1397
                if (srcloc) {
 
1398
                        const char* srcfile = dwarf_linesrc(srcloc, 0, 0);
 
1399
                        if (srcfile) {
 
1400
                                trace.source.filename = srcfile;
 
1401
                        }
 
1402
                        int line = 0, col = 0;
 
1403
                        dwarf_lineno(srcloc, &line);
 
1404
                        dwarf_linecol(srcloc, &col);
 
1405
                        trace.source.line = line;
 
1406
                        trace.source.col = col;
 
1407
                }
 
1408
 
 
1409
                deep_first_search_by_pc(cudie, trace_addr - mod_bias,
 
1410
                                inliners_search_cb(trace));
 
1411
                if (trace.source.function.size() == 0) {
 
1412
                        // fallback.
 
1413
                        trace.source.function = trace.object_function;
 
1414
                }
 
1415
 
 
1416
                return trace;
 
1417
        }
 
1418
 
 
1419
private:
 
1420
        typedef details::handle<Dwfl*, details::deleter<void, Dwfl*, &dwfl_end> >
 
1421
                dwfl_handle_t;
 
1422
        details::handle<Dwfl_Callbacks*, details::default_delete<Dwfl_Callbacks*> >
 
1423
                           _dwfl_cb;
 
1424
        dwfl_handle_t  _dwfl_handle;
 
1425
        bool           _dwfl_handle_initialized;
 
1426
 
 
1427
        // defined here because in C++98, template function cannot take locally
 
1428
        // defined types... grrr.
 
1429
        struct inliners_search_cb {
 
1430
                void operator()(Dwarf_Die* die) {
 
1431
                        switch (dwarf_tag(die)) {
 
1432
                                const char* name;
 
1433
                                case DW_TAG_subprogram:
 
1434
                                        if ((name = dwarf_diename(die))) {
 
1435
                                                trace.source.function = name;
 
1436
                                        }
 
1437
                                        break;
 
1438
 
 
1439
                                case DW_TAG_inlined_subroutine:
 
1440
                                        ResolvedTrace::SourceLoc sloc;
 
1441
                                        Dwarf_Attribute attr_mem;
 
1442
 
 
1443
                                        if ((name = dwarf_diename(die))) {
 
1444
                                                trace.source.function = name;
 
1445
                                        }
 
1446
                                        if ((name = die_call_file(die))) {
 
1447
                                                sloc.filename = name;
 
1448
                                        }
 
1449
 
 
1450
                                        Dwarf_Word line = 0, col = 0;
 
1451
                                        dwarf_formudata(dwarf_attr(die, DW_AT_call_line,
 
1452
                                                                &attr_mem), &line);
 
1453
                                        dwarf_formudata(dwarf_attr(die, DW_AT_call_column,
 
1454
                                                                &attr_mem), &col);
 
1455
                                        sloc.line = line;
 
1456
                                        sloc.col = col;
 
1457
 
 
1458
                                        trace.inliners.push_back(sloc);
 
1459
                                        break;
 
1460
                        };
 
1461
                }
 
1462
                ResolvedTrace& trace;
 
1463
                inliners_search_cb(ResolvedTrace& t): trace(t) {}
 
1464
        };
 
1465
 
 
1466
 
 
1467
        static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
 
1468
                Dwarf_Addr low, high;
 
1469
 
 
1470
                // continuous range
 
1471
                if (dwarf_hasattr(die, DW_AT_low_pc) and
 
1472
                                                        dwarf_hasattr(die, DW_AT_high_pc)) {
 
1473
                        if (dwarf_lowpc(die, &low) != 0) {
 
1474
                                return false;
 
1475
                        }
 
1476
                        if (dwarf_highpc(die, &high) != 0) {
 
1477
                                Dwarf_Attribute attr_mem;
 
1478
                                Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem);
 
1479
                                Dwarf_Word value;
 
1480
                                if (dwarf_formudata(attr, &value) != 0) {
 
1481
                                        return false;
 
1482
                                }
 
1483
                                high = low + value;
 
1484
                        }
 
1485
                        return pc >= low and pc < high;
 
1486
                }
 
1487
 
 
1488
                // non-continuous range.
 
1489
                Dwarf_Addr base;
 
1490
                ptrdiff_t offset = 0;
 
1491
                while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
 
1492
                        if (pc >= low and pc < high) {
 
1493
                                return true;
 
1494
                        }
 
1495
                }
 
1496
                return false;
 
1497
        }
 
1498
 
 
1499
        static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc,
 
1500
                        Dwarf_Die* result) {
 
1501
                if (dwarf_child(parent_die, result) != 0) {
 
1502
                        return 0;
 
1503
                }
 
1504
 
 
1505
                Dwarf_Die* die = result;
 
1506
                do {
 
1507
                        switch (dwarf_tag(die)) {
 
1508
                                case DW_TAG_subprogram:
 
1509
                                case DW_TAG_inlined_subroutine:
 
1510
                                        if (die_has_pc(die, pc)) {
 
1511
                                                return result;
 
1512
                                        }
 
1513
                                default:
 
1514
                                        bool declaration = false;
 
1515
                                        Dwarf_Attribute attr_mem;
 
1516
                                        dwarf_formflag(dwarf_attr(die, DW_AT_declaration,
 
1517
                                                                &attr_mem), &declaration);
 
1518
                                        if (not declaration) {
 
1519
                                                // let's be curious and look deeper in the tree,
 
1520
                                                // function are not necessarily at the first level, but
 
1521
                                                // might be nested inside a namespace, structure etc.
 
1522
                                                Dwarf_Die die_mem;
 
1523
                                                Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem);
 
1524
                                                if (indie) {
 
1525
                                                        *result = die_mem;
 
1526
                                                        return result;
 
1527
                                                }
 
1528
                                        }
 
1529
                        };
 
1530
                } while (dwarf_siblingof(die, result) == 0);
 
1531
                return 0;
 
1532
        }
 
1533
 
 
1534
        template <typename CB>
 
1535
                static bool deep_first_search_by_pc(Dwarf_Die* parent_die,
 
1536
                                Dwarf_Addr pc, CB cb) {
 
1537
                Dwarf_Die die_mem;
 
1538
                if (dwarf_child(parent_die, &die_mem) != 0) {
 
1539
                        return false;
 
1540
                }
 
1541
 
 
1542
                bool branch_has_pc = false;
 
1543
                Dwarf_Die* die = &die_mem;
 
1544
                do {
 
1545
                        bool declaration = false;
 
1546
                        Dwarf_Attribute attr_mem;
 
1547
                        dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration);
 
1548
                        if (not declaration) {
 
1549
                                // let's be curious and look deeper in the tree, function are
 
1550
                                // not necessarily at the first level, but might be nested
 
1551
                                // inside a namespace, structure, a function, an inlined
 
1552
                                // function etc.
 
1553
                                branch_has_pc = deep_first_search_by_pc(die, pc, cb);
 
1554
                        }
 
1555
                        if (not branch_has_pc) {
 
1556
                                branch_has_pc = die_has_pc(die, pc);
 
1557
                        }
 
1558
                        if (branch_has_pc) {
 
1559
                                cb(die);
 
1560
                        }
 
1561
                } while (dwarf_siblingof(die, &die_mem) == 0);
 
1562
                return branch_has_pc;
 
1563
        }
 
1564
 
 
1565
        static const char* die_call_file(Dwarf_Die *die) {
 
1566
                Dwarf_Attribute attr_mem;
 
1567
                Dwarf_Sword file_idx = 0;
 
1568
 
 
1569
                dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem),
 
1570
                                &file_idx);
 
1571
 
 
1572
                if (file_idx == 0) {
 
1573
                        return 0;
 
1574
                }
 
1575
 
 
1576
                Dwarf_Die die_mem;
 
1577
                Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0);
 
1578
                if (not cudie) {
 
1579
                        return 0;
 
1580
                }
 
1581
 
 
1582
                Dwarf_Files* files = 0;
 
1583
                size_t nfiles;
 
1584
                dwarf_getsrcfiles(cudie, &files, &nfiles);
 
1585
                if (not files) {
 
1586
                        return 0;
 
1587
                }
 
1588
 
 
1589
                return dwarf_filesrc(files, file_idx, 0, 0);
 
1590
        }
 
1591
 
 
1592
};
 
1593
#endif // BACKWARD_HAS_DW == 1
 
1594
 
 
1595
template<>
 
1596
class TraceResolverImpl<system_tag::linux_tag>:
 
1597
        public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
 
1598
 
 
1599
#endif // BACKWARD_SYSTEM_LINUX
 
1600
 
 
1601
class TraceResolver:
 
1602
        public TraceResolverImpl<system_tag::current_tag> {};
 
1603
 
 
1604
/*************** CODE SNIPPET ***************/
 
1605
 
 
1606
class SourceFile {
 
1607
public:
 
1608
        typedef std::vector<std::pair<size_t, std::string> > lines_t;
 
1609
 
 
1610
        SourceFile() {}
 
1611
        SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {}
 
1612
        bool is_open() const { return _file->is_open(); }
 
1613
 
 
1614
        lines_t& get_lines(size_t line_start, size_t line_count, lines_t& lines) {
 
1615
                using namespace std;
 
1616
                // This function make uses of the dumbest algo ever:
 
1617
                //      1) seek(0)
 
1618
                //      2) read lines one by one and discard until line_start
 
1619
                //      3) read line one by one until line_start + line_count
 
1620
                //
 
1621
                // If you are getting snippets many time from the same file, it is
 
1622
                // somewhat a waste of CPU, feel free to benchmark and propose a
 
1623
                // better solution ;)
 
1624
 
 
1625
                _file->clear();
 
1626
                _file->seekg(0);
 
1627
                string line;
 
1628
                size_t line_idx;
 
1629
 
 
1630
                for (line_idx = 1; line_idx < line_start; ++line_idx) {
 
1631
                        getline(*_file, line);
 
1632
                        if (not *_file) {
 
1633
                                return lines;
 
1634
                        }
 
1635
                }
 
1636
 
 
1637
                // think of it like a lambda in C++98 ;)
 
1638
                // but look, I will reuse it two times!
 
1639
                // What a good boy am I.
 
1640
                struct isspace {
 
1641
                        bool operator()(char c) {
 
1642
                                return std::isspace(c);
 
1643
                        }
 
1644
                };
 
1645
 
 
1646
                bool started = false;
 
1647
                for (; line_idx < line_start + line_count; ++line_idx) {
 
1648
                        getline(*_file, line);
 
1649
                        if (not *_file) {
 
1650
                                return lines;
 
1651
                        }
 
1652
                        if (not started) {
 
1653
                                if (std::find_if(line.begin(), line.end(),
 
1654
                                                        not_isspace()) == line.end())
 
1655
                                        continue;
 
1656
                                started = true;
 
1657
                        }
 
1658
                        lines.push_back(make_pair(line_idx, line));
 
1659
                }
 
1660
 
 
1661
                lines.erase(
 
1662
                                std::find_if(lines.rbegin(), lines.rend(),
 
1663
                                        not_isempty()).base(), lines.end()
 
1664
                                );
 
1665
                return lines;
 
1666
        }
 
1667
 
 
1668
        lines_t get_lines(size_t line_start, size_t line_count) {
 
1669
                lines_t lines;
 
1670
                return get_lines(line_start, line_count, lines);
 
1671
        }
 
1672
 
 
1673
        // there is no find_if_not in C++98, lets do something crappy to
 
1674
        // workaround.
 
1675
        struct not_isspace {
 
1676
                bool operator()(char c) {
 
1677
                        return not std::isspace(c);
 
1678
                }
 
1679
        };
 
1680
        // and define this one here because C++98 is not happy with local defined
 
1681
        // struct passed to template functions, fuuuu.
 
1682
        struct not_isempty {
 
1683
                bool operator()(const lines_t::value_type& p) {
 
1684
                        return not (std::find_if(p.second.begin(), p.second.end(),
 
1685
                                                not_isspace()) == p.second.end());
 
1686
                }
 
1687
        };
 
1688
 
 
1689
        void swap(SourceFile& b) {
 
1690
                _file.swap(b._file);
 
1691
        }
 
1692
 
 
1693
#if defined(BACKWARD_CXX11)
 
1694
        SourceFile(SourceFile&& from): _file(0) {
 
1695
                swap(from);
 
1696
        }
 
1697
        SourceFile& operator=(SourceFile&& from) {
 
1698
                swap(from); return *this;
 
1699
        }
 
1700
#else
 
1701
        explicit SourceFile(const SourceFile& from) {
 
1702
                // some sort of poor man's move semantic.
 
1703
                swap(const_cast<SourceFile&>(from));
 
1704
        }
 
1705
        SourceFile& operator=(const SourceFile& from) {
 
1706
                // some sort of poor man's move semantic.
 
1707
                swap(const_cast<SourceFile&>(from)); return *this;
 
1708
        }
 
1709
#endif
 
1710
 
 
1711
private:
 
1712
        details::handle<std::ifstream*,
 
1713
                details::default_delete<std::ifstream*>
 
1714
                        > _file;
 
1715
 
 
1716
#if defined(BACKWARD_CXX11)
 
1717
        SourceFile(const SourceFile&) = delete;
 
1718
        SourceFile& operator=(const SourceFile&) = delete;
 
1719
#endif
 
1720
};
 
1721
 
 
1722
class SnippetFactory {
 
1723
public:
 
1724
        typedef SourceFile::lines_t lines_t;
 
1725
 
 
1726
        lines_t get_snippet(const std::string& filename,
 
1727
                        size_t line_start, size_t context_size) {
 
1728
 
 
1729
                SourceFile& src_file = get_src_file(filename);
 
1730
                size_t start = line_start - context_size / 2;
 
1731
                return src_file.get_lines(start, context_size);
 
1732
        }
 
1733
 
 
1734
        lines_t get_combined_snippet(
 
1735
                        const std::string& filename_a, size_t line_a,
 
1736
                        const std::string& filename_b, size_t line_b,
 
1737
                        size_t context_size) {
 
1738
                SourceFile& src_file_a = get_src_file(filename_a);
 
1739
                SourceFile& src_file_b = get_src_file(filename_b);
 
1740
 
 
1741
                lines_t lines = src_file_a.get_lines(line_a - context_size / 4,
 
1742
                                context_size / 2);
 
1743
                src_file_b.get_lines(line_b - context_size / 4, context_size / 2,
 
1744
                                lines);
 
1745
                return lines;
 
1746
        }
 
1747
 
 
1748
        lines_t get_coalesced_snippet(const std::string& filename,
 
1749
                        size_t line_a, size_t line_b, size_t context_size) {
 
1750
                SourceFile& src_file = get_src_file(filename);
 
1751
 
 
1752
                using std::min; using std::max;
 
1753
                size_t a = min(line_a, line_b);
 
1754
                size_t b = max(line_a, line_b);
 
1755
 
 
1756
                if ((b - a) < (context_size / 3)) {
 
1757
                        return src_file.get_lines((a + b - context_size + 1) / 2,
 
1758
                                        context_size);
 
1759
                }
 
1760
 
 
1761
                lines_t lines = src_file.get_lines(a - context_size / 4,
 
1762
                                context_size / 2);
 
1763
                src_file.get_lines(b - context_size / 4, context_size / 2, lines);
 
1764
                return lines;
 
1765
        }
 
1766
 
 
1767
 
 
1768
private:
 
1769
        typedef details::hashtable<std::string, SourceFile>::type src_files_t;
 
1770
        src_files_t _src_files;
 
1771
 
 
1772
        SourceFile& get_src_file(const std::string& filename) {
 
1773
                src_files_t::iterator it = _src_files.find(filename);
 
1774
                if (it != _src_files.end()) {
 
1775
                        return it->second;
 
1776
                }
 
1777
                SourceFile& new_src_file = _src_files[filename];
 
1778
                new_src_file = SourceFile(filename);
 
1779
                return new_src_file;
 
1780
        }
 
1781
};
 
1782
 
 
1783
/*************** PRINTER ***************/
 
1784
 
 
1785
#ifdef BACKWARD_SYSTEM_LINUX
 
1786
 
 
1787
namespace Color {
 
1788
        enum type {
 
1789
                yellow = 33,
 
1790
                purple = 35,
 
1791
                reset  = 39
 
1792
        };
 
1793
} // namespace Color
 
1794
 
 
1795
class Colorize {
 
1796
public:
 
1797
        Colorize(std::FILE* os):
 
1798
                _os(os), _reset(false), _istty(false) {}
 
1799
 
 
1800
        void init() {
 
1801
                _istty = isatty(fileno(_os));
 
1802
        }
 
1803
 
 
1804
        void set_color(Color::type ccode) {
 
1805
                if (not _istty) return;
 
1806
 
 
1807
                // I assume that the terminal can handle basic colors. Seriously I
 
1808
                // don't want to deal with all the termcap shit.
 
1809
                fprintf(_os, "\033[%im", static_cast<int>(ccode));
 
1810
                _reset = (ccode != Color::reset);
 
1811
        }
 
1812
 
 
1813
        ~Colorize() {
 
1814
                if (_reset) {
 
1815
                        set_color(Color::reset);
 
1816
                }
 
1817
        }
 
1818
 
 
1819
private:
 
1820
        std::FILE* _os;
 
1821
        bool       _reset;
 
1822
        bool       _istty;
 
1823
};
 
1824
 
 
1825
#else // ndef BACKWARD_SYSTEM_LINUX
 
1826
 
 
1827
 
 
1828
namespace Color {
 
1829
        enum type {
 
1830
                yellow = 0,
 
1831
                purple = 0,
 
1832
                reset  = 0
 
1833
        };
 
1834
} // namespace Color
 
1835
 
 
1836
class Colorize {
 
1837
public:
 
1838
        Colorize(std::FILE*) {}
 
1839
        void init();
 
1840
        void set_color(Color::type) {}
 
1841
};
 
1842
 
 
1843
#endif // BACKWARD_SYSTEM_LINUX
 
1844
 
 
1845
class Printer {
 
1846
public:
 
1847
        bool snippet;
 
1848
        bool color;
 
1849
        bool address;
 
1850
        bool object;
 
1851
 
 
1852
        Printer():
 
1853
                snippet(true),
 
1854
                color(true),
 
1855
                address(false),
 
1856
                object(false)
 
1857
                {}
 
1858
 
 
1859
        template <typename StackTrace>
 
1860
                FILE* print(StackTrace& st, FILE* os = stderr) {
 
1861
                        using namespace std;
 
1862
 
 
1863
                        Colorize colorize(os);
 
1864
                        if (color) {
 
1865
                                colorize.init();
 
1866
                        }
 
1867
 
 
1868
                        fprintf(os, "Stack trace (most recent call last)");
 
1869
                        if (st.thread_id()) {
 
1870
                                fprintf(os, " in thread %u:\n", st.thread_id());
 
1871
                        } else {
 
1872
                                fprintf(os, ":\n");
 
1873
                        }
 
1874
 
 
1875
                        _resolver.load_stacktrace(st);
 
1876
                        for (unsigned trace_idx = st.size(); trace_idx > 0; --trace_idx) {
 
1877
                                fprintf(os, "#%-2u", trace_idx);
 
1878
                                bool already_indented = true;
 
1879
                                const ResolvedTrace trace = _resolver.resolve(st[trace_idx-1]);
 
1880
 
 
1881
                                if (not trace.source.filename.size() or object) {
 
1882
                                        fprintf(os, "   Object \"%s\", at %p, in %s\n",
 
1883
                                                        trace.object_filename.c_str(), trace.addr,
 
1884
                                                        trace.object_function.c_str());
 
1885
                                        already_indented = false;
 
1886
                                }
 
1887
 
 
1888
                                if (trace.source.filename.size()) {
 
1889
                                        for (size_t inliner_idx = trace.inliners.size();
 
1890
                                                        inliner_idx > 0; --inliner_idx) {
 
1891
                                                if (not already_indented) {
 
1892
                                                        fprintf(os, "   ");
 
1893
                                                }
 
1894
                                                const ResolvedTrace::SourceLoc& inliner_loc
 
1895
                                                        = trace.inliners[inliner_idx-1];
 
1896
                                                print_source_loc(os, " | ", inliner_loc);
 
1897
                                                if (snippet) {
 
1898
                                                        print_snippet(os, "    | ", inliner_loc,
 
1899
                                                                        colorize, Color::purple, 5);
 
1900
                                                }
 
1901
                                                already_indented = false;
 
1902
                                        }
 
1903
 
 
1904
                                        if (not already_indented) {
 
1905
                                                fprintf(os, "   ");
 
1906
                                        }
 
1907
                                        print_source_loc(os, "   ", trace.source, trace.addr);
 
1908
                                        if (snippet) {
 
1909
                                                print_snippet(os, "      ", trace.source,
 
1910
                                                                colorize, Color::yellow, 7);
 
1911
                                        }
 
1912
 
 
1913
                                        if (trace.locals.size()) {
 
1914
                                                print_locals(os, "      ", trace.locals);
 
1915
                                        }
 
1916
                                }
 
1917
                        }
 
1918
                        return os;
 
1919
                }
 
1920
private:
 
1921
        TraceResolver  _resolver;
 
1922
        SnippetFactory _snippets;
 
1923
 
 
1924
        void print_snippet(FILE* os, const char* indent,
 
1925
                        const ResolvedTrace::SourceLoc& source_loc,
 
1926
                        Colorize& colorize, Color::type color_code,
 
1927
                        int context_size)
 
1928
        {
 
1929
                using namespace std;
 
1930
                typedef SnippetFactory::lines_t lines_t;
 
1931
 
 
1932
                lines_t lines = _snippets.get_snippet(source_loc.filename,
 
1933
                                source_loc.line, context_size);
 
1934
 
 
1935
                for (lines_t::const_iterator it = lines.begin();
 
1936
                                it != lines.end(); ++it) {
 
1937
                        if (it-> first == source_loc.line) {
 
1938
                                colorize.set_color(color_code);
 
1939
                                fprintf(os, "%s>", indent);
 
1940
                        } else {
 
1941
                                fprintf(os, "%s ", indent);
 
1942
                        }
 
1943
                        fprintf(os, "%4li: %s\n", it->first, it->second.c_str());
 
1944
                        if (it-> first == source_loc.line) {
 
1945
                                colorize.set_color(Color::reset);
 
1946
                        }
 
1947
                }
 
1948
        }
 
1949
 
 
1950
        void print_source_loc(FILE* os, const char* indent,
 
1951
                        const ResolvedTrace::SourceLoc& source_loc,
 
1952
                        void* addr=0) {
 
1953
                fprintf(os, "%sSource \"%s\", line %i, in %s",
 
1954
                                indent, source_loc.filename.c_str(), (int)source_loc.line,
 
1955
                                source_loc.function.c_str());
 
1956
 
 
1957
                if (address and addr != 0) {
 
1958
                        fprintf(os, " [%p]\n", addr);
 
1959
                } else {
 
1960
                        fprintf(os, "\n");
 
1961
                }
 
1962
        }
 
1963
 
 
1964
        void print_var(FILE* os, const char* base_indent, int indent,
 
1965
                        const Variable& var) {
 
1966
                fprintf(os, "%s%s: ", base_indent, var.name.c_str());
 
1967
                switch (var.kind) {
 
1968
                        case Variable::VALUE:
 
1969
                                fprintf(os, "%s\n", var.value().c_str());
 
1970
                                break;
 
1971
                        case Variable::LIST:
 
1972
                                fprintf(os, "[");
 
1973
                                for (size_t i = 0; i < var.list().size(); ++i) {
 
1974
                                        if (i > 0) {
 
1975
                                                fprintf(os, ", %s", var.list()[i].c_str());
 
1976
                                        }
 
1977
                                        fprintf(os, "%s", var.list()[i].c_str());
 
1978
                                }
 
1979
                                fprintf(os, "]\n");
 
1980
                                break;
 
1981
                        case Variable::MAP:
 
1982
                                fprintf(os, "{\n");
 
1983
                                for (size_t i = 0; i < var.map().size(); ++i) {
 
1984
                                        if (i > 0) {
 
1985
                                                fprintf(os, ",\n%s", base_indent);
 
1986
                                        }
 
1987
                                        print_var(os, base_indent, indent + 2, var.map()[i]);
 
1988
                                }
 
1989
                                fprintf(os, "]\n");
 
1990
                                break;
 
1991
                };
 
1992
        }
 
1993
 
 
1994
        void print_locals(FILE* os, const char* indent,
 
1995
                        const std::vector<Variable>& locals) {
 
1996
                fprintf(os, "%sLocal variables:\n", indent);
 
1997
                for (size_t i = 0; i < locals.size(); ++i) {
 
1998
                        if (i > 0) {
 
1999
                                fprintf(os, ",\n%s", indent);
 
2000
                        }
 
2001
                        print_var(os, indent, 0, locals[i]);
 
2002
                }
 
2003
        }
 
2004
};
 
2005
 
 
2006
/*************** SIGNALS HANDLING ***************/
 
2007
 
 
2008
#ifdef BACKWARD_SYSTEM_LINUX
 
2009
 
 
2010
class SignalHandling {
 
2011
public:
 
2012
        SignalHandling(): _loaded(false) {
 
2013
                // TODO: add a signal dedicated stack, so we can handle stack-overflow.
 
2014
                bool success = true;
 
2015
                const int signals[] = {
 
2016
                        // default action: Core
 
2017
                        SIGILL,
 
2018
                        SIGABRT,
 
2019
                        SIGFPE,
 
2020
                        SIGSEGV,
 
2021
                        SIGBUS,
 
2022
 
 
2023
                        // I am not sure the following signals should be enabled by
 
2024
                        // default:
 
2025
 
 
2026
                        // default action: Term
 
2027
                        SIGHUP,
 
2028
                        SIGINT,
 
2029
                        SIGPIPE,
 
2030
                        SIGALRM,
 
2031
                        SIGTERM,
 
2032
                        SIGUSR1,
 
2033
                        SIGUSR2,
 
2034
                        SIGPOLL,
 
2035
                        SIGPROF,
 
2036
                        SIGVTALRM,
 
2037
                        SIGIO,
 
2038
                        SIGPWR,
 
2039
 
 
2040
                        // default action: Core
 
2041
                        SIGQUIT,
 
2042
                        SIGSYS,
 
2043
                        SIGTRAP,
 
2044
                        SIGXCPU,
 
2045
                        SIGXFSZ
 
2046
                };
 
2047
                for (const int* sig = signals;
 
2048
                                sig != signals + sizeof signals / sizeof *signals; ++sig) {
 
2049
 
 
2050
                        struct sigaction action;
 
2051
                        action.sa_flags = SA_SIGINFO;
 
2052
                        sigemptyset(&action.sa_mask);
 
2053
                        action.sa_sigaction = &sig_handler;
 
2054
 
 
2055
                        int r = sigaction(*sig, &action, 0);
 
2056
                        if (r < 0) success = false;
 
2057
                }
 
2058
                _loaded = success;
 
2059
        }
 
2060
 
 
2061
        bool loaded() const { return _loaded; }
 
2062
 
 
2063
private:
 
2064
        bool _loaded;
 
2065
 
 
2066
        static void sig_handler(int, siginfo_t* info, void* _ctx) {
 
2067
                ucontext_t *uctx = (ucontext_t*) _ctx;
 
2068
 
 
2069
                StackTrace st;
 
2070
                void* error_addr = 0;
 
2071
#ifdef REG_RIP // x86_64
 
2072
                error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_RIP]);
 
2073
#elif defined(REG_EIP) // x86_32
 
2074
                error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_EIP]);
 
2075
#else
 
2076
#       warning ":/ sorry, ain't know no nothing none not of your architecture!"
 
2077
#endif
 
2078
                if (error_addr) {
 
2079
                        st.load_from(error_addr, 32);
 
2080
                } else {
 
2081
                        st.load_here(32);
 
2082
                }
 
2083
 
 
2084
                Printer printer;
 
2085
                printer.address = true;
 
2086
                printer.print(st, stderr);
 
2087
 
 
2088
                psiginfo(info, 0);
 
2089
                exit(EXIT_FAILURE);
 
2090
        }
 
2091
};
 
2092
 
 
2093
#endif // BACKWARD_SYSTEM_LINUX
 
2094
 
 
2095
#ifdef BACKWARD_SYSTEM_UNKNOWN
 
2096
 
 
2097
class SignalHandling {
 
2098
public:
 
2099
        SignalHandling() {}
 
2100
        bool init() { return false; }
 
2101
};
 
2102
 
 
2103
#endif // BACKWARD_SYSTEM_UNKNOWN
 
2104
 
 
2105
#if 0
 
2106
void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
 
2107
{
 
2108
 void *             array[50];
 
2109
 void *             caller_address;
 
2110
 char **            messages;
 
2111
 int                size, i;
 
2112
 sig_ucontext_t *   uc;
 
2113
 
 
2114
 uc = (sig_ucontext_t *)ucontext;
 
2115
 
 
2116
 /* Get the address at the time the signal was raised from the EIP (x86) */
 
2117
 caller_address = (void *) uc->uc_mcontext.eip;   
 
2118
 
 
2119
 fprintf(stderr, "signal %d (%s), address is %p from %p\n", 
 
2120
  sig_num, strsignal(sig_num), info->si_addr, 
 
2121
  (void *)caller_address);
 
2122
 
 
2123
 size = backtrace(array, 50);
 
2124
 
 
2125
 /* overwrite sigaction with caller's address */
 
2126
 array[1] = caller_address;
 
2127
 
 
2128
 messages = backtrace_symbols(array, size);
 
2129
 
 
2130
 
 
2131
void sig_handler(int sig, siginfo_t* info, void* _ctx) {
 
2132
ucontext_t *context = (ucontext_t*) _ctx;
 
2133
 
 
2134
psiginfo(info, "Shit hit the fan");
 
2135
exit(EXIT_FAILURE);
 
2136
}
 
2137
 
 
2138
using namespace std;
 
2139
 
 
2140
void badass() {
 
2141
cout << "baddass!" << endl;
 
2142
((char*)&badass)[0] = 42;
 
2143
}
 
2144
 
 
2145
int main() {
 
2146
struct sigaction action;
 
2147
action.sa_flags = SA_SIGINFO;
 
2148
sigemptyset(&action.sa_mask);
 
2149
action.sa_sigaction = &sig_handler;
 
2150
int r = sigaction(SIGSEGV, &action, 0);
 
2151
if (r < 0) { err(errno, 0); }
 
2152
r = sigaction(SIGILL, &action, 0);
 
2153
if (r < 0) { err(errno, 0); }
 
2154
 
 
2155
badass();
 
2156
return 0;
 
2157
}
 
2158
 
 
2159
 
 
2160
#endif
 
2161
 
 
2162
// i want to get a stacktrace on:
 
2163
//  - abort
 
2164
//  - signals (segfault.. abort...)
 
2165
//  - exception
 
2166
//  - dont messup with gdb!
 
2167
//  - thread ID
 
2168
//  - helper for capturing stack trace inside exception
 
2169
// propose a little magic wrapper to throw an exception adding a stacktrace,
 
2170
// and propose a specific tool to get a stacktrace from an exception (if its
 
2171
// available).
 
2172
//  - optional override __cxa_throw, then the specific magic tool could get
 
2173
//  the stacktrace. Might be possible to use a thread-local variable to do
 
2174
//  some shit. RTLD_DEEPBIND might do the tricks to override it on the fly.
 
2175
 
 
2176
// maybe I can even get the last variables and theirs values?
 
2177
// that might be possible.
 
2178
 
 
2179
// print with code snippet
 
2180
// print traceback demangled
 
2181
// detect color stuff
 
2182
// register all signals
 
2183
//
 
2184
// Seperate stacktrace (load and co function)
 
2185
// than object extracting informations about  a stack trace.
 
2186
 
 
2187
// also public a simple function to print a stacktrace.
 
2188
 
 
2189
// backtrace::StackTrace st;
 
2190
// st.snapshot();
 
2191
// print(st);
 
2192
// cout << st;
 
2193
 
 
2194
} // namespace backward
 
2195
 
 
2196
#endif /* H_GUARD */