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

#include "PosixSource.h"
#include "Rts.h"
11
#include "RtsUtils.h"
12

13 14
#include "eventlog/EventLog.h"

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

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

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

28 29 30 31 32 33 34 35 36 37
/* -----------------------------------------------------------------------------
   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.
38 39 40
RtsMsgFunction *fatalInternalErrorFn = rtsFatalInternalErrorFn;
RtsMsgFunction *debugMsgFn           = rtsDebugMsgFn;
RtsMsgFunction *errorMsgFn           = rtsErrorMsgFn;
41
RtsMsgFunction *sysErrorMsgFn        = rtsSysErrorMsgFn;
42 43

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

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

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

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

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

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
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);
}

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

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

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

115 116
#define BUFSIZE 512

117
#if defined (mingw32_HOST_OS)
118
static int
119
isGUIApp(void)
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
{
  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

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

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

149
     MessageBox(NULL /* hWnd */,
150 151 152 153
                message,
                title,
                MB_OK | MB_ICONERROR | MB_TASKMODAL
               );
154 155 156 157 158 159 160 161 162 163 164
  }
  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);
165 166
#if USE_LIBDW
     fprintf(stderr, "\n");
167
     fprintf(stderr, "Stack trace:\n");
168 169 170 171 172
     LibdwSession *session = libdwInit();
     Backtrace *bt = libdwGetBacktrace(session);
     libdwPrintBacktrace(session, stderr, bt);
     libdwFree(session);
#endif
173
     fprintf(stderr, "\n");
174 175
     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");
176
     fflush(stderr);
177
  }
178 179 180
#if defined(mingw32_HOST_OS)
  _setmode (_fileno(stderr), mode);
#endif
181

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

186 187
  abort();
  // stg_exit(EXIT_INTERNAL_ERROR);
188 189 190
}

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

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

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

230 231 232
#if defined(mingw32_HOST_OS)
    /* Ensure we're in text mode so newlines get encoded properly.  */
    int mode = _setmode (_fileno(stderr), _O_TEXT);
233 234 235 236 237 238 239 240 241 242
    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 );
243 244 245

    if (isGUIApp())
    {
246 247 248 249 250 251 252 253 254 255 256 257
        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
                );
        }
258 259 260 261 262 263 264
    }
    else
#else
    syserr = strerror(errno);
    // ToDo: use strerror_r() if available
#endif
    {
265 266 267 268 269 270
        /* 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) {
271
#if defined(mingw32_HOST_OS)
272
            // Win32 error messages have a terminating \n
273
            fprintf(stderr, ": %s", syserr);
274
#else
275
            fprintf(stderr, ": %s\n", syserr);
276
#endif
277 278 279
        } else {
            fprintf(stderr, "\n");
        }
280 281
    }

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

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

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


// Used in stg_badAlignment_entry defined in StgStartup.cmm.
void rtsBadAlignmentBarf(void) GNUC3_ATTRIBUTE(__noreturn__);

void
rtsBadAlignmentBarf()
{
    barf("Encountered incorrectly aligned pointer. This can't be good.");
}