Statistics
| Branch: | Revision:

root / src / sim / cexception.cc @ e1750c09

History | View | Annotate | Download (9.19 KB)

1 01873262 Georg Kunz
//=========================================================================
2
//  CEXCEPTION.CC - part of
3
//
4
//                  OMNeT++/OMNEST
5
//           Discrete System Simulation in C++
6
//
7
//   Exception classes
8
//
9
//  Author: Andras Varga
10
//=========================================================================
11
12
/*--------------------------------------------------------------*
13
  Copyright (C) 1992-2008 Andras Varga
14
  Copyright (C) 2006-2008 OpenSim Ltd.
15

16
  This file is distributed WITHOUT ANY WARRANTY. See the file
17
  `license' for details on this and other legal matters.
18
*--------------------------------------------------------------*/
19
20
#include <stdio.h>
21
#include <string.h>
22
#include <stdlib.h>  // for exit()
23
#include <stdarg.h>  // for va_list
24
#include <signal.h>  // raise()
25
#include "cexception.h"
26
#include "csimulation.h"
27
#include "ccomponent.h"
28
#include "cmodule.h"
29
#include "cenvir.h"
30
#include "cconfiguration.h"
31
#include "stringutil.h"
32
#include "commonutil.h"
33
34
USING_NAMESPACE
35
36
#if defined _MSC_VER
37
#define DEBUG_TRAP  __asm int 3  // Visual C++: debug interrupt
38
#elif defined _WIN32 and defined __GNUC__
39
#define DEBUG_TRAP  asm("int $3\n")  // MinGW or Cygwin: debug interrupt with gnu syntax
40
#else
41
#define DEBUG_TRAP  raise(6)  // SIGABRT
42
#endif
43
44
45
#define BUFLEN 1024
46
static char buffer[BUFLEN];
47
static char buffer2[BUFLEN];
48
49
#define LL  INT64_PRINTF_FORMAT
50
51
cException::cException() : std::exception()
52
{
53
    errorcode = eCUSTOM;
54
    storeCtx();
55
    msg = "n/a";
56
}
57
58
cException::cException(OppErrorCode errorcode...) : std::exception()
59
{
60
    va_list va;
61
    va_start(va, errorcode);
62
    init(NULL, errorcode, cErrorMessages::get(errorcode), va);
63
    va_end(va);
64
}
65
66
cException::cException(const char *msgformat...) : std::exception()
67
{
68
    va_list va;
69
    va_start(va, msgformat);
70
    init(NULL, eCUSTOM, msgformat, va);
71
    va_end(va);
72
}
73
74
cException::cException(const cObject *where, OppErrorCode errorcode...) : std::exception()
75
{
76
    va_list va;
77
    va_start(va, errorcode);
78
    init(where, errorcode, cErrorMessages::get(errorcode), va);
79
    va_end(va);
80
}
81
82
cException::cException(const cObject *where, const char *msgformat...) : std::exception()
83
{
84
    va_list va;
85
    va_start(va, msgformat);
86
    init(where, eCUSTOM, msgformat, va);
87
    va_end(va);
88
}
89
90
cException::cException(const cException& e)
91
{
92
    errorcode = e.errorcode;
93
    msg = e.msg;
94
95
    simulationstage = e.simulationstage;
96
    eventnumber = e.eventnumber;
97
    simtime = e.simtime;
98
99
    hascontext = e.hascontext;
100
    contextclassname = e.contextclassname;
101
    contextfullpath = e.contextfullpath;
102
    moduleid = e.moduleid;
103
}
104
105
void cException::storeCtx()
106
{
107
    cSimulation *sim = cSimulation::getActiveSimulation();
108
109
    if (!sim)
110
    {
111
        simulationstage = CTX_NONE;
112
        eventnumber = 0;
113
        simtime = SIMTIME_ZERO;
114
    }
115
    else
116
    {
117
        simulationstage = sim->getSimulationStage();
118
        eventnumber = sim->getEventNumber();
119
        simtime = sim->getSimTime();
120
    }
121
122
    if (!sim || !sim->getContext())
123
    {
124
        hascontext = false;
125
        moduleid = -1;
126
    }
127
    else
128
    {
129
        hascontext = true;
130
        contextclassname = sim->getContext()->getClassName();
131
        contextfullpath = sim->getContext()->getFullPath().c_str();
132
        moduleid = sim->getContextModule() ? sim->getContextModule()->getId() : -1;
133
    }
134
}
135
136
void cException::exitIfStartupError()
137
{
138
    if (!cStaticFlag::isSet())
139
    {
140
        // note: ev may not be available at this time
141
        fprintf(stderr, "<!> Error during startup/shutdown: %s. Aborting.", what());
142
        abort();
143
    }
144
}
145
146
void cException::init(const cObject *where, OppErrorCode errorcode, const char *fmt, va_list va)
147
{
148
    // store error code
149
    errorcode = errorcode;
150
151
    // prefix message with "where" object conditionally, as "(%s)%s:"
152
    //  - if object is the module itself: skip
153
    //  - if object is local in module: use getFullName()
154
    //  - if object is somewhere else: use getFullPath()
155
    buffer[0] = '\0';
156
    cSimulation *sim = cSimulation::getActiveSimulation();
157
    cComponent *context = sim ? sim->getContext() : NULL;
158
    if (where && where!=context)
159
    {
160
        // try: if context's fullpath is same as module fullpath + object fullname, no need to print path
161
        sprintf(buffer2, "%s.%s", (context ? context->getFullPath().c_str() : ""), where->getFullName());
162
        bool needpath = strcmp(buffer2,where->getFullPath().c_str())!=0;
163
        sprintf(buffer, "(%s)%s: ", where->getClassName(), needpath ? where->getFullPath().c_str() : where->getFullName());
164
    }
165
166
    vsnprintf(buffer+strlen(buffer), BUFLEN-strlen(buffer), fmt, va);
167
    buffer[BUFLEN] = '\0';
168
    msg = buffer;
169
170
    // store context
171
    storeCtx();
172
173
    // if a global object's ctor/dtor throws an exception, there won't be
174
    // anyone around to catch it, so print it and abort here.
175
    exitIfStartupError();
176
}
177
178
std::string cException::getFormattedMessage() const
179
{
180
    std::string when;
181
    switch (getSimulationStage())
182
    {
183
        case CTX_NONE: when = ""; break;
184
        case CTX_BUILD: when = " during network setup"; break; // note leading spaces
185
        case CTX_INITIALIZE: when = " during network initialization"; break;
186
        case CTX_EVENT: when = opp_stringf(" at event #%"LL"d, t=%s",getEventNumber(), SIMTIME_STR(getSimtime())); break; // note we say "at" and not "in", because error may have occurred outside handleMessage()
187
        case CTX_FINISH: when = " during finalization"; break;
188
        case CTX_CLEANUP: when = " during network cleanup"; break;
189
    }
190
191
    std::string result;
192
    if (isError())
193
    {
194
        if (!hasContext())
195
            result = opp_stringf("Error%s: %s.", when.c_str(), what());
196
        else if (getModuleID()==-1)
197
            result = opp_stringf("Error in component (%s) %s%s: %s.", getContextClassName(), getContextFullPath(), when.c_str(), what());
198
        else
199
            result = opp_stringf("Error in module (%s) %s (id=%d)%s: %s.", getContextClassName(), getContextFullPath(), getModuleID(), when.c_str(), what());
200
    }
201
    else
202
    {
203
        if (!hasContext())
204
            result = opp_stringf("%s%s.", what(), when.c_str());
205
        else if (getModuleID()==-1)
206
            result = opp_stringf("Component (%s) %s%s: %s.", getContextClassName(), getContextFullPath(), when.c_str(), what());
207
        else
208
            result = opp_stringf("Module (%s) %s (id=%d)%s: %s.", getContextClassName(), getContextFullPath(), getModuleID(), when.c_str(), what());
209
    }
210
211
    return result;
212
}
213
214
//---
215
216
cTerminationException::cTerminationException(OppErrorCode errorcode...)
217
{
218
    va_list va;
219
    va_start(va, errorcode);
220
    init(NULL, errorcode, cErrorMessages::get(errorcode), va);
221
    va_end(va);
222
}
223
224
cTerminationException::cTerminationException(const char *msgformat...)
225
{
226
    va_list va;
227
    va_start(va, msgformat);
228
    init(NULL, eCUSTOM, msgformat, va);
229
    va_end(va);
230
}
231
232
//---
233
234
cRuntimeError::cRuntimeError(OppErrorCode errorcode...)
235
{
236
    va_list va;
237
    va_start(va, errorcode);
238
    init(NULL, errorcode, cErrorMessages::get(errorcode), va);
239
    va_end(va);
240
    breakIntoDebuggerIfRequested();
241
}
242
243
cRuntimeError::cRuntimeError(const char *msgformat...)
244
{
245
    va_list va;
246
    va_start(va, msgformat);
247
    init(NULL, eCUSTOM, msgformat, va);
248
    va_end(va);
249
    breakIntoDebuggerIfRequested();
250
}
251
252
cRuntimeError::cRuntimeError(const cObject *where, OppErrorCode errorcode...)
253
{
254
    va_list va;
255
    va_start(va, errorcode);
256
    init(where, errorcode, cErrorMessages::get(errorcode), va);
257
    va_end(va);
258
    breakIntoDebuggerIfRequested();
259
}
260
261
cRuntimeError::cRuntimeError(const cObject *where, const char *msgformat...)
262
{
263
    va_list va;
264
    va_start(va, msgformat);
265
    init(where, eCUSTOM, msgformat, va);
266
    va_end(va);
267
    breakIntoDebuggerIfRequested();
268
}
269
270
void cRuntimeError::breakIntoDebuggerIfRequested()
271
{
272
    if (ev.debug_on_errors)
273
    {
274
        printf("\n"
275
               "RUNTIME ERROR. A cRuntimeError exception is about to be thrown, and you\n"
276
               "requested (by setting debug-on-errors=true in the ini file) that errors\n"
277
               "abort execution and break into the debugger.\n\n"
278
#ifdef _MSC_VER
279
               "If you see a [Debug] button on the Windows crash dialog and you have\n"
280
               "just-in-time debugging enabled, select it to get into the Visual Studio\n"
281
               "debugger. Otherwise, you should already have attached to this process from\n"
282
               "Visual Studio. Once in the debugger, see you can browse to the context of\n"
283
               "the error in the \"Call stack\" debug view.\n\n"
284
#else
285
               "You should now probably be running the simulation under gdb or another\n"
286
               "debugger. The simulation kernel will now raise a SIGABRT signal which will\n"
287
               "get you into the debugger. If you are not running under a debugger, you can\n"
288
               "still use the core dump for post-mortem debugging. Once in the debugger,\n"
289
               "view the call stack (in gdb: \"bt\" command) to see the context of the\n"
290
               "runtime error.\n\n"
291
#endif
292
               );
293
294
        printf("<!> %s\n", getFormattedMessage().c_str());
295
        printf("\nTRAPPING on the exception above, due to a debug-on-errors=true configuration option. Is your debugger ready?\n");
296
        fflush(stdout);
297
298
        // cause debugger interrupt or signal
299
        DEBUG_TRAP;
300
    }
301
}
302