-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathexception_hook.cc
120 lines (91 loc) · 3.51 KB
/
exception_hook.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* exception_hook.cc
Jeremy Barnes, 7 February 2005
Copyright (c) 2005 Jeremy Barnes. All rights reserved.
This file is part of "Jeremy's Machine Learning Library", copyright (c)
1999-2005 Jeremy Barnes.
This program is available under the GNU General Public License, the terms
of which are given by the file "license.txt" in the top level directory of
the source code distribution. If this file is missing, you have no right
to use the program; please contact the author.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
---
Object file to install the exception tracer.
*/
#include "exception_hook.h"
#include <iostream>
#include <dlfcn.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include <stdlib.h>
using namespace std;
namespace ML {
/** Hook for the function to call when we throw an exception. The first
argument is a pointer to the object thrown; the second is the type
info block for the thrown object.
Starts off at null which means that no hook is installed.
*/
void (*exception_tracer) (void *, const std::type_info *) = 0;
namespace {
/** The signature of __cxa_throw. */
typedef void (*cxa_throw_type) (void *, std::type_info *, void (*) (void *));
void * handle = 0;
cxa_throw_type old_handler = 0;
bool done_init = false;
struct Init {
Init()
{
if (done_init) return;
/* Find the __cxa_throw function from libstdc++.so. This is the
original function that would have been used if we hadn't overridden
it here.
*/
/** Fist, we dynamically load the C++ standard library */
handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
cerr << "in __cxa_throw override:" << endl;
cerr << "error loading libstdc++.so.6: " << dlerror() << endl;
abort();
}
/** Secondly, we lookup the symbol __cxa_throw */
old_handler = (cxa_throw_type) dlvsym(handle, "__cxa_throw", "CXXABI_1.3");
if (!old_handler) {
cerr << "in __cxa_throw override:" << endl;
cerr << "error finding __cxa_throw: " << dlerror() << endl;
abort();
}
/** Close the dynamic library. */
dlclose(handle);
done_init = true;
}
} init;
} // file scope
} // namespace ML
/** Our overridden version of __cxa_throw. The first argument is the
object that was thrown. The second is the type info block for the
object. The third is the destructor for the object that should be
called with thrown_object as an argument when we are finished with
the exception object.
*/
extern "C"
void
__cxa_throw (void *thrown_object, std::type_info *tinfo,
void (*destructor) (void *) )
{
using namespace ML;
/** If we have installed an exception tracing hook, we follow it here. */
if (exception_tracer) exception_tracer(thrown_object, tinfo);
if (!done_init) {
Init();
}
/** Now we finish by calling the old handler which will propegate the
exception as usual. */
old_handler(thrown_object, tinfo, destructor);
/** This should never happen, as __cxa_throw is a noreturn() function.
If for some reason it returns, we abort out. */
cerr << "got back from __cxa_throw; error" << endl;
abort();
}