The report.c bit committed today reminded me that I had an old stashed change for that file. There should be no change in behavior.
664 lines
19 KiB
C
664 lines
19 KiB
C
/* NetHack 3.7 report.c $NHDT-Date: 1741406837 2025/03/07 20:07:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ */
|
|
/* Copyright (c) Kenneth Lorber, Kensington, Maryland, 2024 */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
/* NB: CRASHREPORT implies PANICTRACE */
|
|
|
|
# ifndef NO_SIGNAL
|
|
#include <signal.h>
|
|
# endif
|
|
# ifndef LONG_MAX
|
|
#include <limits.h>
|
|
# endif
|
|
#include "dlb.h"
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
# ifdef PANICTRACE_LIBC
|
|
#include <execinfo.h>
|
|
# endif
|
|
|
|
#ifdef CRASHREPORT
|
|
# ifdef WIN32
|
|
# define HASH_PRAGMA_START
|
|
# define HASH_PRAGMA_END
|
|
# else
|
|
# define HASH_PRAGMA_START \
|
|
_Pragma("GCC diagnostic push"); \
|
|
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
|
# define HASH_PRAGMA_END _Pragma("GCC diagnostic pop");
|
|
# endif
|
|
# ifdef MACOS
|
|
#include <CommonCrypto/CommonDigest.h>
|
|
# define HASH_CONTEXTPTR(CTXP) \
|
|
unsigned char tmp[CC_MD4_DIGEST_LENGTH]; \
|
|
CC_MD4_CTX CTXP ## _; \
|
|
CC_MD4_CTX *CTXP = &CTXP ## _
|
|
# define HASH_INIT(ctxp) !CC_MD4_Init(ctxp)
|
|
# define HASH_UPDATE(ctx, ptr, len) !CC_MD4_Update(ctx, ptr, len)
|
|
# define HASH_FINISH(ctxp) !CC_MD4_Final(tmp, ctxp)
|
|
# define HASH_RESULT_SIZE(ctxp) CC_MD4_DIGEST_LENGTH
|
|
# define HASH_RESULT(ctx, inp) *inp = (unsigned char *) ctx
|
|
# define HASH_CLEANUP(ctxp)
|
|
# define HASH_OFLAGS O_RDONLY
|
|
# define HASH_BINFILE_DECL char *binfile = argv[0];
|
|
# if (NH_DEVEL_STATUS == NH_STATUS_BETA)
|
|
# define HASH_BINFILE() \
|
|
if (!binfile || !*binfile) { \
|
|
/* If this triggers, investigate CFBundleGetMainBundle */ \
|
|
/* or CFBundleCopyExecutableURL. */ \
|
|
raw_print( \
|
|
"BETA warning: crashreport_init called without useful info"); \
|
|
goto skip; \
|
|
}
|
|
# else /* BETA */
|
|
# define HASH_BINFILE() \
|
|
if (!binfile || !*binfile) { \
|
|
goto skip; \
|
|
}
|
|
# endif /* BETA */
|
|
# endif /* MACOS */
|
|
|
|
# ifdef __linux__
|
|
#include "nhmd4.h"
|
|
/* v0 is just to suppress compiler warnings about unreachable code */
|
|
# define HASH_CONTEXTPTR(CTXP) \
|
|
volatile int v0 = 0; \
|
|
unsigned char tmp[NHMD4_DIGEST_LENGTH]; \
|
|
NHMD4_CTX CTXP ## _; \
|
|
NHMD4_CTX *CTXP = &CTXP ## _
|
|
# define HASH_INIT(ctxp) (nhmd4_init(ctxp), v0)
|
|
# define HASH_UPDATE(ctx, ptr, len) (nhmd4_update(ctx, ptr, len), v0)
|
|
# define HASH_FINISH(ctxp) (nhmd4_final(ctxp, tmp), v0)
|
|
# define HASH_RESULT_SIZE(ctxp) NHMD4_RESULTLEN
|
|
# define HASH_RESULT(ctx, inp) *inp = tmp
|
|
# define HASH_CLEANUP(ctxp)
|
|
# define HASH_OFLAGS O_RDONLY
|
|
# define HASH_BINFILE_DECL char binfile[PATH_MAX+1];
|
|
# define HASH_BINFILE() \
|
|
int len = readlink("/proc/self/exe", binfile, sizeof binfile - 1); \
|
|
if (len > 0) { \
|
|
binfile[len] = '\0'; \
|
|
} else { \
|
|
goto skip; \
|
|
}
|
|
# endif // __linux__
|
|
|
|
# ifdef WIN32
|
|
/* WIN32 takes too much code and is dependent on OS includes we can't
|
|
* pull in here, so we call out to code in sys/windows/windsys.c */
|
|
# define HASH_CONTEXTPTR(CTXP)
|
|
# define HASH_INIT(ctxp) win32_cr_helper('i', ctxp, NULL, 0)
|
|
# define HASH_UPDATE(ctxp, ptr, len) win32_cr_helper('u', ctxp, ptr, len)
|
|
# define HASH_FINISH(ctxp) win32_cr_helper('f', ctxp, NULL, 0)
|
|
# define HASH_CLEANUP(ctxp) win32_cr_helper('c', ctxp, NULL, 0)
|
|
# define HASH_RESULT_SIZE(ctxp) win32_cr_helper('s', ctxp, NULL, 0)
|
|
# define HASH_RESULT(ctxp, inp) win32_cr_helper('r', ctxp, inp, 0)
|
|
# define HASH_OFLAGS _O_RDONLY | _O_BINARY
|
|
# define HASH_BINFILE_DECL char *binfile;
|
|
# define HASH_BINFILE() \
|
|
if (win32_cr_helper('b', NULL, &binfile, 0)) { \
|
|
goto skip; \
|
|
}
|
|
# endif // WIN32
|
|
|
|
/* Binary ID - Use only as a hint to contact.html for recognizing our own
|
|
binaries. This is easily spoofed! */
|
|
static char bid[40];
|
|
|
|
/* ARGSUSED */
|
|
void
|
|
crashreport_init(int argc UNUSED, char *argv[] UNUSED)
|
|
{
|
|
static int once = 0;
|
|
if (once++) /* NetHackW.exe calls us twice */
|
|
return;
|
|
HASH_BINFILE_DECL;
|
|
HASH_PRAGMA_START
|
|
HASH_CONTEXTPTR(ctxp);
|
|
if (HASH_INIT(ctxp))
|
|
goto skip;
|
|
HASH_BINFILE(); /* Does "goto skip" on error. */
|
|
|
|
int fd = open(binfile, HASH_OFLAGS, 0);
|
|
if (fd == -1) {
|
|
# ifdef BETA
|
|
raw_printf("open e=%s", strerror(errno));
|
|
# endif
|
|
goto skip;
|
|
}
|
|
|
|
int segsize;
|
|
unsigned char segment[4096];
|
|
|
|
while (0 < (segsize = read(fd, segment, sizeof segment))) {
|
|
if (HASH_UPDATE(ctxp, segment, segsize))
|
|
goto skip;
|
|
}
|
|
if (segsize < 0) {
|
|
close(fd);
|
|
goto skip;
|
|
}
|
|
if (HASH_FINISH(ctxp))
|
|
goto skip;
|
|
close(fd);
|
|
|
|
static const char hexdigits[] = "0123456789abcdef";
|
|
char *p = bid;
|
|
unsigned char *in;
|
|
HASH_RESULT(ctxp, &in);
|
|
uint8 cnt = (uint8) HASH_RESULT_SIZE(ctxp);
|
|
/* Just in case, make sure not to overflow the bid buffer.
|
|
Divide size by 2 because each octet in the hash uses two slots
|
|
in bid[] when formatted as a pair of hexadecimal digits. */
|
|
if (cnt >= (uint8) sizeof bid / 2)
|
|
cnt = (uint8) sizeof bid / 2 - 1;
|
|
while (cnt) {
|
|
/* sprintf(p, "%02x", *in++), p += 2; */
|
|
*p++ = hexdigits[(*in >> 4) & 0x0f];
|
|
*p++ = hexdigits[*in++ & 0x0f];
|
|
--cnt;
|
|
}
|
|
*p = '\0';
|
|
HASH_CLEANUP(ctxp);
|
|
return;
|
|
|
|
skip:
|
|
Strcpy(bid, "unknown");
|
|
HASH_CLEANUP(ctxp);
|
|
HASH_PRAGMA_END
|
|
}
|
|
|
|
#undef HASH_CONTEXTPTR
|
|
#undef HASH_INIT
|
|
#undef HASH_UPDATE
|
|
#undef HASH_FINISH
|
|
#undef HASH_CLEANUP
|
|
#undef HASH_RESULT
|
|
#undef HASH_RESULT_SIZE
|
|
#undef HASH_PRAGMA_START
|
|
#undef HASH_PRAGMA_END
|
|
#undef HASH_BINFILE_DECL
|
|
#undef HASH_BINFILE
|
|
|
|
void
|
|
crashreport_bidshow(void)
|
|
{
|
|
# if defined(WIN32) && !defined(WIN32CON)
|
|
if (0 == win32_cr_helper('D', ctxp, bid, 0))
|
|
# endif
|
|
{
|
|
raw_print(bid);
|
|
# ifdef WIN32notyet
|
|
wait_synch();
|
|
# endif
|
|
}
|
|
}
|
|
|
|
/* Build a URL with a query string and try to launch a new browser window
|
|
* to report from panic() or impossible(). Requires libc support for
|
|
* the stacktrace. Uses memory on the stack to avoid memory allocation
|
|
* (on most platforms) (but libc can still do anything it wants). */
|
|
|
|
// No theoretial limit for URL length but reality is messy.
|
|
// This should work on all modern platforms.
|
|
# ifndef MAX_URL
|
|
# define MAX_URL 8192
|
|
# endif
|
|
# ifndef SWR_FRAMES
|
|
# define SWR_FRAMES 20
|
|
# endif
|
|
|
|
// mark holds the initial eos; if we can't get the value in
|
|
// then we can remove the whole item if desired. For other
|
|
// semantics, caller can handle mark.
|
|
#define SWR_ADD(str) \
|
|
utmp = strlen(str); \
|
|
mark = uend; \
|
|
if (utmp >= urem) \
|
|
goto full; \
|
|
memcpy(uend, str, utmp); \
|
|
uend += utmp; urem -= utmp; \
|
|
*uend = '\0';
|
|
|
|
// NB: on overflow this rolls us back to mark, so if we don't
|
|
// want to roll back to the last SWR_ADD, update mark before
|
|
// calling this macro.
|
|
#define SWR_ADD_URIcoded(str) \
|
|
if (swr_add_uricoded(str, &uend, &urem, mark)) \
|
|
goto full;
|
|
|
|
/* On overflow, truncate to markp (but only if markp != NULL). */
|
|
boolean
|
|
swr_add_uricoded(
|
|
const char *in,
|
|
char **out,
|
|
int *remaining,
|
|
char *markp)
|
|
{
|
|
while (*in) {
|
|
if (isalnum(*in) || strchr("_-.~", *in)) {
|
|
**out = *in;
|
|
(*out)++;
|
|
(*remaining)--;
|
|
} else if (*in == ' ') {
|
|
**out = '+';
|
|
(*out)++;
|
|
(*remaining)--;
|
|
} else {
|
|
if (*remaining <= 3) {
|
|
if (markp)
|
|
*out = markp, *remaining = 0;
|
|
**out = '\0';
|
|
return TRUE;
|
|
} else {
|
|
char chr[40]; /* [4] should suffice */
|
|
int x;
|
|
|
|
Sprintf(chr, "%%%02X", *in);
|
|
x = (int) strlen(chr);
|
|
if (x <= *remaining) {
|
|
Strcpy(*out, chr);
|
|
*out += x;
|
|
*remaining -= x;
|
|
}
|
|
}
|
|
}
|
|
in++;
|
|
if (!*remaining) {
|
|
if (markp)
|
|
*out = markp, *remaining = 0;
|
|
**out = '\0';
|
|
return TRUE;
|
|
}
|
|
**out = '\0';
|
|
}
|
|
return FALSE; /* normal return */
|
|
}
|
|
|
|
static char url[MAX_URL]; // XXX too bad this isn't allocated as needed
|
|
static int urem = MAX_URL; // adjusted for gc.crash_urlmax below
|
|
static char *uend = url;
|
|
static int utmp; // used inside macros
|
|
static char *mark; // holds previous terminator (generally)
|
|
|
|
boolean
|
|
submit_web_report(int cos, const char *msg, const char *why)
|
|
{
|
|
urem = (gc.crash_urlmax < 0 || gc.crash_urlmax > MAX_URL)
|
|
? MAX_URL : min(MAX_URL,gc.crash_urlmax);
|
|
char temp[200];
|
|
char temp2[200];
|
|
int countpp = 0; /* pre and post traceback lines */
|
|
// URL loaded for creating reports to the NetHack DevTeam
|
|
// CRASHREPORTURL=https://nethack.org/links/cr-37BETA.html
|
|
if (!sysopt.crashreporturl)
|
|
return FALSE;
|
|
SWR_ADD(sysopt.crashreporturl);
|
|
/*
|
|
* Note: all snprintf() calls here changed to sprintf() to avoid
|
|
* complaints from static analyzer. All but one were unnecessary
|
|
* since they were formatting int or unsigned into a large buffer.
|
|
*/
|
|
/* cos - operation, v - version */
|
|
Sprintf(temp, "?cos=%d&v=1", cos);
|
|
SWR_ADD(temp);
|
|
|
|
/* msg==NULL for #bugreport */
|
|
if (msg) {
|
|
SWR_ADD("&subject=");
|
|
Sprintf(temp, "%.40s report for NetHack %.40s",
|
|
msg, version_string(temp2, sizeof temp2 ));
|
|
SWR_ADD_URIcoded(temp);
|
|
}
|
|
|
|
SWR_ADD("&gitver=");
|
|
SWR_ADD_URIcoded(getversionstring(temp2, sizeof temp2));
|
|
|
|
if (gc.crash_name) {
|
|
SWR_ADD("&name=");
|
|
SWR_ADD_URIcoded(gc.crash_name);
|
|
}
|
|
|
|
if(gc.crash_email) {
|
|
SWR_ADD("&email=");
|
|
SWR_ADD_URIcoded(gc.crash_email);
|
|
}
|
|
// hardware: leave for user
|
|
// software: leave for user
|
|
// comments: leave for user
|
|
|
|
SWR_ADD("&details=");
|
|
if (why) {
|
|
SWR_ADD_URIcoded(why);
|
|
SWR_ADD_URIcoded("\n");
|
|
mark = uend;
|
|
countpp++;
|
|
}
|
|
|
|
SWR_ADD_URIcoded("bid: ");
|
|
SWR_ADD_URIcoded(bid);
|
|
SWR_ADD_URIcoded("\n");
|
|
mark = uend;
|
|
countpp++;
|
|
|
|
int count = 0;
|
|
if (cos == 1) {
|
|
# ifdef WIN32
|
|
count = win32_cr_gettrace(SWR_FRAMES, uend, MAX_URL - (uend - url));
|
|
uend = eos(url);
|
|
# else
|
|
void *bt[SWR_FRAMES];
|
|
int x;
|
|
char **info;
|
|
|
|
count = backtrace(bt, SIZE(bt));
|
|
info = backtrace_symbols(bt, count);
|
|
for (x = 0; x < count; x++) {
|
|
copynchars(temp, info[x], (int) sizeof temp - 1 - 1); /* \n\0 */
|
|
/* try to remove up to 16 blank spaces by removing 8 twice */
|
|
(void) strsubst(temp, " ", "");
|
|
(void) strsubst(temp, " ", "");
|
|
(void) strncat(temp, "\n", sizeof temp - 1);
|
|
# if 0 // __linux__
|
|
// not needed for MacOS
|
|
// XXX is it actually needed for linux? TBD
|
|
Sprintf(temp2, "[%02lu]\n", (unsigned long) x);
|
|
uend--; // remove the \n we added above
|
|
SWR_ADD_URIcoded(temp2);
|
|
# endif // linux
|
|
SWR_ADD_URIcoded(temp);
|
|
mark = uend;
|
|
}
|
|
# endif // !WIN32
|
|
}
|
|
|
|
# ifdef DUMPLOG_CORE
|
|
// config.h turns this on, but make it easy to turn off if needed
|
|
if (cos == 1) {
|
|
int k;
|
|
SWR_ADD_URIcoded("Latest messages:\n");
|
|
mark=uend;
|
|
countpp++;
|
|
for (k = 0; k < 5; k++) {
|
|
const char *line = get_saved_pline(k);
|
|
if (!line)
|
|
break;
|
|
SWR_ADD_URIcoded(line);
|
|
SWR_ADD_URIcoded("\n");
|
|
countpp++;
|
|
mark = uend;
|
|
}
|
|
}
|
|
# endif /* DUMPLOG_CORE */
|
|
|
|
// detailrows: Guess since we can't know the
|
|
// width of the window.
|
|
SWR_ADD("&detailrows=");
|
|
Sprintf(temp, "%d", min(count + countpp, 30));
|
|
SWR_ADD_URIcoded(temp);
|
|
|
|
full:
|
|
;
|
|
//printf("URL=%ld '%s'\n",strlen(url),url);
|
|
# ifdef WIN32
|
|
int *rv = win32_cr_shellexecute(url);
|
|
// XXX TESTING
|
|
printf("ShellExecute returned: %p\n",rv); // >32 is ok
|
|
# else /* !WIN32 */
|
|
const char *xargv[] = {
|
|
CRASHREPORT,
|
|
url,
|
|
NULL
|
|
};
|
|
int pid = fork();
|
|
extern char **environ;
|
|
if (pid == 0) {
|
|
char err[400];
|
|
# ifdef CRASHREPORT_EXEC_NOSTDERR
|
|
int devnull;
|
|
/* Keep the output clean - firefox spews useless errors on
|
|
* my system. */
|
|
(void) close(2);
|
|
devnull = open("/dev/null", O_WRONLY);
|
|
# endif
|
|
|
|
(void) execve(CRASHREPORT, (char * const *) xargv, environ);
|
|
Sprintf(err, "Can't start " CRASHREPORT ": %.*s",
|
|
(int) (sizeof err
|
|
- sizeof "Can't start " CRASHREPORT ": "),
|
|
strerror(errno));
|
|
raw_print(err);
|
|
# ifdef CRASHREPORT_EXEC_NOSTDERR
|
|
(void) close(devnull);
|
|
# endif
|
|
exit(1);
|
|
} else {
|
|
int status;
|
|
errno = 0;
|
|
(void) waitpid(pid, &status, 0);
|
|
if (status) { /* XXX check could be more precise */
|
|
# ifdef BETA
|
|
/* Not useful at the moment. XXX */
|
|
char err[100];
|
|
|
|
Sprintf(err, "pid=%d e=%d status=%0x", wpid, errno, status);
|
|
raw_print(err);
|
|
# endif
|
|
return FALSE;
|
|
}
|
|
}
|
|
/* free(info); -- Don't risk it. */
|
|
# endif /* !WIN32 */
|
|
return TRUE;
|
|
}
|
|
|
|
int
|
|
dobugreport(void)
|
|
{
|
|
if (!submit_web_report(2, NULL, "#bugreport command")) {
|
|
pline("Unable to send bug report. Please visit %s instead.",
|
|
(sysopt.crashreporturl && *sysopt.crashreporturl)
|
|
? sysopt.crashreporturl
|
|
: DEVTEAM_URL
|
|
);
|
|
}
|
|
return ECMD_OK;
|
|
}
|
|
|
|
#undef SWR_ADD
|
|
#undef SWR_ADD_URIcoded
|
|
#undef SWR_FRAMES
|
|
#undef SWR_HDR
|
|
#undef SWR_LINES
|
|
|
|
#endif /* CRASHREPORT */
|
|
|
|
#ifdef PANICTRACE
|
|
|
|
/*ARGSUSED*/
|
|
boolean
|
|
NH_panictrace_libc(void)
|
|
{
|
|
# if 0 /* XXX how did this get left here? */
|
|
if (submit_web_report("Panic", why))
|
|
return TRUE;
|
|
# endif
|
|
|
|
# ifdef PANICTRACE_LIBC
|
|
void *bt[20];
|
|
int count, x;
|
|
char **info, buf[BUFSZ];
|
|
|
|
raw_print(" Generating more information you may report:\n");
|
|
count = backtrace(bt, SIZE(bt));
|
|
info = backtrace_symbols(bt, count);
|
|
for (x = 0; x < count; x++) {
|
|
copynchars(buf, info[x], (int) sizeof buf - 1);
|
|
/* try to remove up to 16 blank spaces by removing 8 twice */
|
|
(void) strsubst(buf, " ", "");
|
|
(void) strsubst(buf, " ", "");
|
|
raw_printf("[%02lu] %s", (unsigned long) x, buf);
|
|
}
|
|
/* free(info); -- Don't risk it. */
|
|
return TRUE;
|
|
# else
|
|
return FALSE;
|
|
# endif /* !PANICTRACE_LIBC */
|
|
}
|
|
|
|
/*
|
|
* fooPATH file system path for foo
|
|
* fooVAR (possibly const) variable containing fooPATH
|
|
*/
|
|
# ifdef PANICTRACE_GDB
|
|
# ifdef SYSCF
|
|
# define GDBVAR sysopt.gdbpath
|
|
# define GREPVAR sysopt.greppath
|
|
# else /* SYSCF */
|
|
# define GDBVAR GDBPATH
|
|
# define GREPVAR GREPPATH
|
|
# endif /* SYSCF */
|
|
# endif /* PANICTRACE_GDB */
|
|
|
|
boolean
|
|
NH_panictrace_gdb(void)
|
|
{
|
|
# ifdef PANICTRACE_GDB
|
|
/* A (more) generic method to get a stack trace - invoke
|
|
* gdb on ourself. */
|
|
const char *gdbpath = GDBVAR;
|
|
const char *greppath = GREPVAR;
|
|
char buf[BUFSZ];
|
|
FILE *gdb;
|
|
|
|
if (gdbpath == NULL || gdbpath[0] == 0)
|
|
return FALSE;
|
|
if (greppath == NULL || greppath[0] == 0)
|
|
return FALSE;
|
|
|
|
Snprintf(buf, sizeof buf, "%s -n -q %s %d 2>&1 | %s '^#'",
|
|
gdbpath, ARGV0, getpid(), greppath);
|
|
gdb = popen(buf, "w");
|
|
if (gdb) {
|
|
raw_print(" Generating more information you may report:\n");
|
|
(void) fprintf(gdb, "bt\nquit\ny");
|
|
(void) fflush(gdb);
|
|
sleep(4); /* ugly */
|
|
(void) pclose(gdb);
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
# else
|
|
return FALSE;
|
|
# endif /* !PANICTRACE_GDB */
|
|
}
|
|
|
|
#ifdef DUMPLOG_CORE
|
|
#define USED_if_dumplog
|
|
#else
|
|
#define USED_if_dumplog UNUSED
|
|
#endif
|
|
|
|
/* lineno==0 gives the most recent message (e.g.
|
|
"Do you want to call panic..." if called from #panic) */
|
|
const char *
|
|
get_saved_pline(int lineno USED_if_dumplog)
|
|
{
|
|
#ifdef DUMPLOG_CORE
|
|
int p;
|
|
int limit = DUMPLOG_MSG_COUNT;
|
|
|
|
if (lineno >= DUMPLOG_MSG_COUNT)
|
|
return NULL;
|
|
p = (gs.saved_pline_index - 1) % DUMPLOG_MSG_COUNT;
|
|
|
|
while (limit--) {
|
|
if (gs.saved_plines[p]) { /* valid line */
|
|
if (lineno--) {
|
|
p = (p - 1 + DUMPLOG_MSG_COUNT) % DUMPLOG_MSG_COUNT;
|
|
} else {
|
|
return gs.saved_plines[p];
|
|
}
|
|
}
|
|
}
|
|
#endif /* DUMPLOG_CORE */
|
|
return NULL;
|
|
}
|
|
|
|
#undef USED_if_dumplog
|
|
|
|
# ifndef NO_SIGNAL
|
|
/* called as signal() handler, so sent at least one arg */
|
|
/*ARGUSED*/
|
|
void
|
|
panictrace_handler(int sig_unused UNUSED)
|
|
{
|
|
#define SIG_MSG "\nSignal received.\n"
|
|
int f2;
|
|
|
|
# ifdef CURSES_GRAPHICS
|
|
if (iflags.window_inited && WINDOWPORT(curses)) {
|
|
extern void curses_uncurse_terminal(void); /* wincurs.h */
|
|
|
|
/* it is risky calling this during a program-terminating signal,
|
|
but without it the subsequent backtrace is useless because
|
|
that ends up being scrawled all over the screen; call is
|
|
here rather than in NH_abort() because panic() calls both
|
|
exit_nhwindows(), which makes this same call under curses,
|
|
then NH_abort() and we don't want to call this twice */
|
|
curses_uncurse_terminal();
|
|
}
|
|
# endif
|
|
|
|
f2 = (int) write(2, SIG_MSG, sizeof SIG_MSG - 1);
|
|
nhUse(f2); /* what could we do if write to fd#2 (stderr) fails */
|
|
NH_abort(NULL); /* ... and we're already in the process of quitting? */
|
|
}
|
|
|
|
void
|
|
panictrace_setsignals(boolean set)
|
|
{
|
|
#define SETSIGNAL(sig) \
|
|
(void) signal(sig, set ? (SIG_RET_TYPE) panictrace_handler : SIG_DFL);
|
|
# ifdef SIGILL
|
|
SETSIGNAL(SIGILL);
|
|
# endif
|
|
# ifdef SIGTRAP
|
|
SETSIGNAL(SIGTRAP);
|
|
# endif
|
|
# ifdef SIGIOT
|
|
SETSIGNAL(SIGIOT);
|
|
# endif
|
|
# ifdef SIGBUS
|
|
SETSIGNAL(SIGBUS);
|
|
# endif
|
|
# ifdef SIGFPE
|
|
SETSIGNAL(SIGFPE);
|
|
# endif
|
|
# ifdef SIGSEGV
|
|
SETSIGNAL(SIGSEGV);
|
|
# endif
|
|
# ifdef SIGSTKFLT
|
|
SETSIGNAL(SIGSTKFLT);
|
|
# endif
|
|
# ifdef SIGSYS
|
|
SETSIGNAL(SIGSYS);
|
|
# endif
|
|
# ifdef SIGEMT
|
|
SETSIGNAL(SIGEMT);
|
|
# endif
|
|
#undef SETSIGNAL
|
|
}
|
|
# endif /* NO_SIGNAL */
|
|
#endif /* PANICTRACE */
|
|
|
|
/*
|
|
* FIXME: this should have a lot of '#undef's for onefile support.
|
|
*/
|
|
|
|
/*report.c*/
|