RtsMessages.c 7.45 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team, 1998-2004
 *
 * General utility functions used in the RTS.
 *
 * ---------------------------------------------------------------------------*/

#include "PosixSource.h"
#include "Rts.h"

12
13
#include "eventlog/EventLog.h"

14
15
16
17
#if USE_LIBDW
#include <Libdw.h>
#endif

18
#include <stdio.h>
Simon Marlow's avatar
Simon Marlow committed
19
20
#include <string.h>
#include <errno.h>
21

Ben Gamari's avatar
Ben Gamari committed
22
#if defined(HAVE_WINDOWS_H)
23
#include <windows.h>
24
#include <fcntl.h>
25
26
#endif

27
28
29
30
31
32
33
34
35
36
/* -----------------------------------------------------------------------------
   General message generation functions

   All messages should go through here.  We can't guarantee that
   stdout/stderr will be available - e.g. in a Windows program there
   is no console for generating messages, so they have to either go to
   to the debug console, or pop up message boxes.
   -------------------------------------------------------------------------- */

// Default to the stdio implementation of these hooks.
37
38
39
RtsMsgFunction *fatalInternalErrorFn = rtsFatalInternalErrorFn;
RtsMsgFunction *debugMsgFn           = rtsDebugMsgFn;
RtsMsgFunction *errorMsgFn           = rtsErrorMsgFn;
40
RtsMsgFunction *sysErrorMsgFn        = rtsSysErrorMsgFn;
41
42

void
43
barf(const char*s, ...)
44
45
46
47
48
49
50
51
52
{
  va_list ap;
  va_start(ap,s);
  (*fatalInternalErrorFn)(s,ap);
  stg_exit(EXIT_INTERNAL_ERROR); // just in case fatalInternalErrorFn() returns
  va_end(ap);
}

void
53
vbarf(const char*s, va_list ap)
54
55
56
57
58
{
  (*fatalInternalErrorFn)(s,ap);
  stg_exit(EXIT_INTERNAL_ERROR); // just in case fatalInternalErrorFn() returns
}

59
void
60
_assertFail(const char*filename, unsigned int linenum)
61
{
62
    barf("ASSERTION FAILED: file %s, line %u\n", filename, linenum);
63
64
}

65
void
66
errorBelch(const char*s, ...)
67
68
69
70
71
72
73
74
{
  va_list ap;
  va_start(ap,s);
  (*errorMsgFn)(s,ap);
  va_end(ap);
}

void
75
verrorBelch(const char*s, va_list ap)
76
77
78
79
{
  (*errorMsgFn)(s,ap);
}

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
void
sysErrorBelch(const char*s, ...)
{
  va_list ap;
  va_start(ap,s);
  (*sysErrorMsgFn)(s,ap);
  va_end(ap);
}

void
vsysErrorBelch(const char*s, va_list ap)
{
  (*sysErrorMsgFn)(s,ap);
}

95
void
96
debugBelch(const char*s, ...)
97
98
99
100
101
102
103
104
{
  va_list ap;
  va_start(ap,s);
  (*debugMsgFn)(s,ap);
  va_end(ap);
}

void
105
vdebugBelch(const char*s, va_list ap)
106
107
108
109
110
111
112
113
{
  (*debugMsgFn)(s,ap);
}

/* -----------------------------------------------------------------------------
   stdio versions of the message functions
   -------------------------------------------------------------------------- */

114
115
#define BUFSIZE 512

116
#if defined (mingw32_HOST_OS)
117
static int
118
isGUIApp(void)
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
{
  PIMAGE_DOS_HEADER pDOSHeader;
  PIMAGE_NT_HEADERS pPEHeader;

  pDOSHeader = (PIMAGE_DOS_HEADER) GetModuleHandleA(NULL);
  if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
    return 0;

  pPEHeader = (PIMAGE_NT_HEADERS) ((char *)pDOSHeader + pDOSHeader->e_lfanew);
  if (pPEHeader->Signature != IMAGE_NT_SIGNATURE)
    return 0;

  return (pPEHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI);
}
#endif

135
136
137
#define xstr(s) str(s)
#define str(s) #s

Simon Marlow's avatar
Simon Marlow committed
138
void GNU_ATTRIBUTE(__noreturn__)
139
rtsFatalInternalErrorFn(const char *s, va_list ap)
140
{
141
142
143
#if defined(mingw32_HOST_OS)
  /* Ensure we're in text mode so newlines get encoded properly.  */
  int mode = _setmode (_fileno(stderr), _O_TEXT);
144
145
146
147
  if (isGUIApp())
  {
     char title[BUFSIZE], message[BUFSIZE];

148
149
     snprintf(title,   BUFSIZE, "%s: internal error", prog_name);
     vsnprintf(message, BUFSIZE, s, ap);
150

151
     MessageBox(NULL /* hWnd */,
152
153
154
155
                message,
                title,
                MB_OK | MB_ICONERROR | MB_TASKMODAL
               );
156
157
158
159
160
161
162
163
164
165
166
  }
  else
#endif
  {
     /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
     if (prog_argv != NULL && prog_name != NULL) {
       fprintf(stderr, "%s: internal error: ", prog_name);
     } else {
       fprintf(stderr, "internal error: ");
     }
     vfprintf(stderr, s, ap);
167
168
#if USE_LIBDW
     fprintf(stderr, "\n");
169
     fprintf(stderr, "Stack trace:\n");
170
171
172
173
174
     LibdwSession *session = libdwInit();
     Backtrace *bt = libdwGetBacktrace(session);
     libdwPrintBacktrace(session, stderr, bt);
     libdwFree(session);
#endif
175
     fprintf(stderr, "\n");
176
177
     fprintf(stderr, "    (GHC version %s for %s)\n", ProjectVersion, xstr(HostPlatform_TYPE));
     fprintf(stderr, "    Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug\n");
178
     fflush(stderr);
179
  }
180
181
182
#if defined(mingw32_HOST_OS)
  _setmode (_fileno(stderr), mode);
#endif
183

Ben Gamari's avatar
Ben Gamari committed
184
#if defined(TRACING)
185
186
187
  if (RtsFlags.TraceFlags.tracing == TRACE_EVENTLOG) endEventLogging();
#endif

188
189
  abort();
  // stg_exit(EXIT_INTERNAL_ERROR);
190
191
192
}

void
193
rtsErrorMsgFn(const char *s, va_list ap)
194
{
195
196
197
#if defined(mingw32_HOST_OS)
  /* Ensure we're in text mode so newlines get encoded properly.  */
  int mode = _setmode (_fileno(stderr), _O_TEXT);
198
199
200
201
202
  if (isGUIApp())
  {
     char buf[BUFSIZE];
     int r;

203
204
205
         r = vsnprintf(buf, BUFSIZE, s, ap);
         if (r > 0 && r < BUFSIZE) {
                MessageBox(NULL /* hWnd */,
206
207
208
209
210
211
212
213
214
215
              buf,
              prog_name,
              MB_OK | MB_ICONERROR | MB_TASKMODAL
              );
     }
  }
  else
#endif
  {
     /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
216
     if (prog_name != NULL) {
217
218
219
220
221
       fprintf(stderr, "%s: ", prog_name);
     }
     vfprintf(stderr, s, ap);
     fprintf(stderr, "\n");
  }
222
223
224
#if defined(mingw32_HOST_OS)
  _setmode (_fileno(stderr), mode);
#endif
225
226
}

227
228
229
230
231
void
rtsSysErrorMsgFn(const char *s, va_list ap)
{
    char *syserr;

232
233
234
#if defined(mingw32_HOST_OS)
    /* Ensure we're in text mode so newlines get encoded properly.  */
    int mode = _setmode (_fileno(stderr), _O_TEXT);
235
236
237
238
239
240
241
242
243
244
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        GetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR) &syserr,
        0,
        NULL );
245
246
247

    if (isGUIApp())
    {
248
249
250
251
252
253
254
255
256
257
258
259
        char buf[BUFSIZE];
        int r;

        r = vsnprintf(buf, BUFSIZE, s, ap);
        if (r > 0 && r < BUFSIZE) {
            r = vsnprintf(buf+r, BUFSIZE-r, ": %s", syserr);
            MessageBox(NULL /* hWnd */,
                       buf,
                       prog_name,
                       MB_OK | MB_ICONERROR | MB_TASKMODAL
                );
        }
260
261
262
263
264
265
266
    }
    else
#else
    syserr = strerror(errno);
    // ToDo: use strerror_r() if available
#endif
    {
267
268
269
270
271
272
        /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
        if (prog_argv != NULL && prog_name != NULL) {
            fprintf(stderr, "%s: ", prog_name);
        }
        vfprintf(stderr, s, ap);
        if (syserr) {
273
#if defined(mingw32_HOST_OS)
274
            // Win32 error messages have a terminating \n
275
            fprintf(stderr, ": %s", syserr);
276
#else
277
            fprintf(stderr, ": %s\n", syserr);
278
#endif
279
280
281
        } else {
            fprintf(stderr, "\n");
        }
282
283
    }

284
#if defined(mingw32_HOST_OS)
285
    if (syserr) LocalFree(syserr);
286
    _setmode (_fileno(stderr), mode);
287
288
289
#endif
}

290
void
291
rtsDebugMsgFn(const char *s, va_list ap)
292
{
293
294
295
#if defined(mingw32_HOST_OS)
  /* Ensure we're in text mode so newlines get encoded properly.  */
  int mode = _setmode (_fileno(stderr), _O_TEXT);
296
297
298
  if (isGUIApp())
  {
     char buf[BUFSIZE];
299
         int r;
300

301
302
         r = vsnprintf(buf, BUFSIZE, s, ap);
         if (r > 0 && r < BUFSIZE) {
303
304
305
306
307
308
309
310
311
312
       OutputDebugString(buf);
     }
  }
  else
#endif
  {
     /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
     vfprintf(stderr, s, ap);
     fflush(stderr);
  }
313
314
315
#if defined(mingw32_HOST_OS)
  _setmode (_fileno(stderr), mode);
#endif
316
}