add CRASHREPORT directly to browser

add CRASHREPORT for Windows
add ^P info to report (via DUMPLOG)

new options: crash_email, crash_name, crash_urlmax
new game command: #bugreport
new config option: CRASHREPORT_EXEC_NOSTDERR
new command line option: --bidshow

deleted helper scripts:
    NetHackCrashReport.Javascript
    nhcrashreport.lua

misc:
    update CRASHREPORTURL (will need to be updated before release)
    update bitrot in winchain
    winchain for Windows
    add missing synch_wait for NetHackW --showpaths
    add PANICTRACE (and CRASHREPORT) in mdlib.c:build_opts

missing:
    packaging (Windows needs the pdb file)
    no testing with MSVC command line build

port status:
    linux: working, but glibc's backtrace doesn't show static functions
    Windows VS: working.  pdb file is large - looking into options
    MacOS: working
    msdos: not supported
    VMS: not supported
    MSVC: planned, but not attempted
    MSYS2: working, but libbacktrace not showing symbols (yet?)
This commit is contained in:
nhkeni
2024-02-06 18:33:59 -05:00
parent cf3cbcf832
commit dbe5c98dca
37 changed files with 1001 additions and 315 deletions

View File

@@ -112,7 +112,7 @@ LUA2NHTOP = ../../..
LUABASELIB = liblua-$(LUA_VERSION).a
TOPLUALIB = lib/lua/$(LUABASELIB)
ALLDEP = $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb check-nhlua
ALLDEP = $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb
# first target is also the default target for 'make' without any arguments
all: $(ALLDEP)
@@ -148,10 +148,6 @@ luabin:
( cd $(LUATOP) \
&& make $(LUAMAKEFILES) all && cd $(LUA2NHTOP) )
check-nhlua:
( util/makedefs --grep-defined CRASHREPORT && ( \
cd $(LUATOP) && make $(LUAMAKEFLAGS) ); true )
# hints file could set LUATESTTARGET to this if GITSUBMODULES is defined
submodules/lua/lua.h:
git submodule init submodules/lua

View File

@@ -291,11 +291,7 @@ VARDIR = $(HACKDIR)
POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; \
$(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; \
$(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; \
chmod $(VARFILEPERM) $(INSTDIR)/sysconf; \
( util/makedefs --grep-defined CRASHREPORT && \
( cp win/share/nhcrashreport.lua $(INSTDIR) ; \
chmod 555 $(INSTDIR)/nhcrashreport.lua ; \
cp $(LUATOP)/lua $(INSTDIR)/nhlua); true)
chmod $(VARFILEPERM) $(INSTDIR)/sysconf;
ifneq "$(CCISCLANG)" ""
# gdb may not be installed if clang is chosen compiler so the game

View File

@@ -31,6 +31,8 @@ ifndef LIBXPM
LIBXPM= -L/opt/X11/lib -lXpm
endif
#WANT_WIN_CHAIN=1
# 4. Other
#-----------------------------------------------------------------------------
@@ -98,7 +100,7 @@ NHCFLAGS+=-DNOMAIL
#NHCFLAGS+=-DNO_CHRONICLE
#NHCFLAGS+=-DLIVELOG
# not NHCFLAGS - needed for makedefs
CFLAGS+=-DCRASHREPORT=\"NetHackCrashReport.JavaScript\"
CFLAGS+=-DCRASHREPORT=\"/usr/bin/open\"
ifdef MAKEFILE_SRC
# default
@@ -334,10 +336,7 @@ PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); \
POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \
$(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \
$(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \
chmod $(VARFILEPERM) $(HACKDIR)/sysconf; \
util/makedefs --grep-defined CRASHREPORT && \
( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \
chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript )
chmod $(VARFILEPERM) $(HACKDIR)/sysconf;
else ifdef WANT_SOURCE_INSTALL
@@ -353,10 +352,7 @@ CHGRP=/usr/bin/true
GAMEPERM = 0700
VARFILEPERM = 0600
VARDIRPERM = 0700
POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \
util/makedefs --grep-defined CRASHREPORT && \
( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \
chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript )
POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf;
# We can use "make all" to build the whole thing - but it misses some things:
MOREALL=$(MAKE) install
@@ -385,10 +381,7 @@ PREINSTALL+= (mkdir $(SHELLDIR) || true);
POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \
$(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \
$(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \
chmod $(VARFILEPERM) $(HACKDIR)/sysconf; \
util/makedefs --grep-defined CRASHREPORT && \
( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \
chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript )
chmod $(VARFILEPERM) $(HACKDIR)/sysconf;
endif # !WANT_SHARE_INSTALL
@@ -731,7 +724,6 @@ build_package_root:
install -p doc/recover.6 $(PKGROOT_UG)/man/man6
install -p doc/Guidebook $(PKGROOT_UG)/doc
install -p dat/nhdat $(PKGROOT_UGLN)
#XXX no code to package NetHackCrashReport.JavaScript
sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(PKGROOT_UGLN)/sysconf
cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN)
# XXX these files should be somewhere else for good Mac form

View File

@@ -159,6 +159,9 @@ GREPPATH=/bin/grep
PANICTRACE_GDB=1
PANICTRACE_LIBC=2
# URL loaded for creating reports to the NetHack DevTeam
#CRASHREPORTURL=https://nethack.org/links/cr-37BETA.html
# 'portable_device_paths' is only supported for Windows. Starting with
# 3.6.3, nethack on Windows treats the folder containing nethack.exe and
# nethackW.exe as read-only and puts data files which are generated or

View File

@@ -151,6 +151,7 @@ main(int argc, char *argv[])
check_linux_console();
#endif
initoptions_init();
initoptions();
#ifdef PANICTRACE
ARGV0 = gh.hname; /* save for possible stack trace */
@@ -766,6 +767,7 @@ opt_showpaths(const char *dir)
nhUse(dir);
#endif
iflags.initoptions_noterminate = TRUE;
initoptions_init();
initoptions();
iflags.initoptions_noterminate = FALSE;
reveal_paths();

View File

@@ -233,3 +233,7 @@ OPTIONS=hilite_status:gold/up/yellow/down/brown
# St, Dx, Co, In, Wi, Ch
OPTIONS=hilite_status:characteristics/up/green/down/red
# CRASHREPORTURL must be set in syscf to enable these options.
# These identify you in crash reports
#OPTIONS=crash_name:Your Name
#OPTIONS=crash_email:user@example.com

View File

@@ -52,9 +52,10 @@ SOUND_LIBRARIES = windsound
#
#---------------------------------------------------------------
# Do you want debug information in the executable?
# Required for CRASHREPORT.
#
DEBUGINFO = N
DEBUGINFO = Y
#
#---------------------------------------------------------------
@@ -243,6 +244,7 @@ NHV=$(subst ",,$(NHV1))
# TTY - window port files (tty)
# MSWIN - window port files (win32)
# WCURSES - window port files (curses)
# WCHAIN - window port files (chain)
# WSHR - Tile support files
# SNDSYS - sound suppport files for win32
# QT - QT window support files
@@ -257,6 +259,7 @@ SNDSYS =../sound/windsound
MSWSYS =../sys/windows
TTY =../win/tty
MSWIN =../win/win32
WCHAIN =../win/chain
WCURSES =../win/curses
WSHR =../win/share
QT =../win/Qt
@@ -357,7 +360,7 @@ $(OBJ):
CLEAN_DIR = $(GAMEDIR) $(OBJ)
#===============-=================================================
#=================================================================
# LUA library
# Source from http://www.lua.org/ftp/lua-5.4.6.tar.gz
#=================================================================
@@ -987,6 +990,15 @@ CFLAGSW += $(NHCURSESFLAGS)
NHWONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins guitty)
endif
# uncomment for WINCHAIN
#COREOBJS += $(addsuffix .o, wc_chainin wc_chainout wc_trace)
# XXX mess for testing libbacktrace
ifeq "$(DEBUGINFO)" "Y"
CFLAGS += -I/mingw64/include -g -static -gdwarf
LIBS += -L/mingw64/lib -lbacktrace
endif
nethackw: $(NHWTARGETS)
$(GAMEDIR)/NetHackW.exe: $(NHWOBJS) $(NHWRES) $(DATEW_O) $(LUALIB) $(PDCWLIB) | $(GAMEDIR)
@@ -1028,6 +1040,9 @@ $(ONHW)/%.o: $(MSWSYS)/%.c $(NHLUAH) | $(ONHW)
$(ONHW)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONHW)
$(cc) $(CFLAGSW) $< -o$@
$(ONHW)/%.o: $(WCHAIN)/%.c $(NHLUAH) | $(ONHW)
$(cc) $(CFLAGSW) $< -o$@
$(ONHW)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONHW)
$(cc) $(CFLAGSW) $< -o$@
@@ -1068,6 +1083,7 @@ NHCURSESFLAGS = -DCURSES_GRAPHICS -DCURSES_UNICODE $(PDCURSESFLAGS) -DPDC_NCMOUS
CFLAGSNH += $(NHCURSESFLAGS)
NHONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins)
endif
DATE_O = $(addsuffix .o, $(addprefix $(ONH)/, date))
NHOBJS = $(addprefix $(ONH)/, $(COREOBJS) $(NHONLY))
@@ -1115,6 +1131,9 @@ $(ONH)/%.o: $(MSWSYS)/%.c $(NHLUAH) | $(ONH)
$(ONH)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONH)
$(cc) $(CFLAGSNH) $< -o$@
$(ONH)/%.o: $(WCHAIN)/%.c $(NHLUAH) | $(ONH)
$(cc) $(CFLAGSNH) $< -o$@
$(ONH)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONH)
$(cc) $(CFLAGSNH) $< -o$@
@@ -1148,8 +1167,9 @@ CLEAN_FILE += $(NHTARGET) $(NHOBJS) $(NHRES)
all: install
TO_INSTALL = $(GAMEDIR)/NetHack.exe $(RTARGETS) $(GAMEDIRDLLS) \
$(addprefix $(GAMEDIR)/, $(addsuffix .template, sysconf .nethackrc) \
Guidebook.txt NetHack.txt license opthelp record symbols)
$(addprefix $(GAMEDIR)/, \
$(addsuffix .template, sysconf .nethackrc symbols) \
Guidebook.txt NetHack.txt license opthelp record)
ifeq "$(HAVE_SOUNDLIB)" "Y"
TO_INSTALL += $(addprefix $(GAMEDIR)/, $(addsuffix .wav, $(WAVLIST)))
@@ -1183,7 +1203,7 @@ $(GAMEDIR)/$(FMODLIBDLL): $(FMODLIBDIR)/$(FMODLIBDLL)
cp $< $@
endif
$(GAMEDIR)/symbols: $(DAT)/symbols
$(GAMEDIR)/symbols.template: $(DAT)/symbols
cp $< $@
$(GAMEDIR)/NetHack.txt: $(DOC)/nethack.txt

View File

@@ -121,3 +121,6 @@ HIDEUSAGE=1
#
# The location that file synchronization locks are stored (writeable)
#LOCKDIR=c:\ProgramData\NetHack\3.7
# URL loaded for creating reports to the NetHack DevTeam
#CRASHREPORTURL=https://nethack.org/links/cr-37BETA.html

View File

@@ -49,7 +49,7 @@
<PreprocessorDefinitions>WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;dbghelp.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SndWavDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -297,4 +297,4 @@
<Target Name="AfterRebuild">
<MSBuild Projects="afternethack.proj" Targets="Build" Properties="Configuration=$(Configuration)" />
</Target>
</Project>
</Project>

View File

@@ -62,7 +62,7 @@
</ResourceCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dbghelp.lib;comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Manifest>
<AdditionalManifestFiles>$(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>
@@ -351,4 +351,4 @@
<Target Name="AfterRebuild">
<MSBuild Projects="$(vsDir)NetHack\afternethack.proj" Targets="Build" Properties="Configuration=$(Configuration)" />
</Target>
</Project>
</Project>

View File

@@ -545,7 +545,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
if (getcwd(orgdir, sizeof orgdir) == (char *) 0)
error("NetHack: current directory path too long");
#endif
initoptions_init(); // This allows OPTIONS in syscf on Windows.
set_default_prefix_locations(argv[0]);
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
@@ -638,6 +638,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
if (WINDOWPORT(tty))
consoletty_open(1);
#endif
#ifdef WINCHAIN
commit_windowchain();
#endif
init_nhwindows(&argc, argv);
@@ -812,6 +815,11 @@ process_options(int argc, char * argv[])
argc--;
argv++;
}
#if defined(CRASHREPORT)
if (argcheck(argc, argv, ARG_BIDSHOW) == 2) {
nethack_exit(EXIT_SUCCESS);
}
#endif
if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
/* avoid matching "-dec" for DECgraphics; since the man page
* says -d directory, hope nobody's using -desomething_else

View File

@@ -24,7 +24,10 @@
#ifdef TTY_GRAPHICS
#include "wintty.h"
#endif
#include <inttypes.h>
#ifdef WIN32
#include <VersionHelpers.h>
/*
* The following WIN32 API routines are used in this file.
@@ -758,6 +761,281 @@ nt_assert_failed(const char *expression, const char *filepath, int line)
expression, filename, line);
}
/* Windows helpers for CRASHREPORT etc */
#ifdef CRASHREPORT
struct CRctxt {
BCRYPT_ALG_HANDLE bah;
BCRYPT_HASH_HANDLE bhh;
PBYTE pbhashobj;
DWORD cbhashobj; /* temp */
DWORD cbhash; /* hash length */
DWORD cbdata; /* temp */
PBYTE pbhash; /* binary hash */
NTSTATUS st;
} ctxp_ = { NULL, NULL, NULL, 0, 0, 0, NULL, 0 };
struct CRctxt *ctxp = &ctxp_; // XXX should this now be in gc.* ?
#define win32err(fn) errname = fn; goto error
int
win32_cr_helper(char cmd, struct CRctxt *ctxp, void *p, int d){
char *errname = "unknown";
switch (cmd) {
default:
/* Not panic - we don't want to upgrade an impossible to a
* panic due to a bug in the CRASHREPORT code. */
impossible("win_cr_helper bad cmd %d", cmd);
return 1;
case 'D': {
char *bidstr = (char *) p;
wchar_t lbidstr[40]; // sizeof(bid), but const
swprintf_s(lbidstr, 40, L"%S", bidstr);
// XXX TODO: need something that will allow copy of just the bid
return MessageBoxW(NULL, lbidstr, L"bidshow", MB_SETFOREGROUND);
}
break;
case 'i': /* HASH_INIT(ctxp) */
if (!IsWindowsVistaOrGreater())
return 1; // CNG not available.
ctxp->bah = NULL;
ctxp->bhh = NULL;
ctxp->pbhashobj = NULL;
ctxp->cbhashobj = 0;
ctxp->cbhash = 0;
ctxp->cbdata = 0;
ctxp->pbhash = NULL;
ctxp->st = 0;
// win32err("test"); // TESTING - FAKE AN ERROR
if (0 > (ctxp->st = BCryptOpenAlgorithmProvider(
&ctxp->bah, BCRYPT_MD4_ALGORITHM, NULL, 0))) {
win32err("BCryptOpenAlgorithmProvider");
};
if (0 > (ctxp->st =
BCryptGetProperty(ctxp->bah, BCRYPT_OBJECT_LENGTH,
(unsigned char *) &ctxp->cbhashobj,
sizeof(DWORD), &ctxp->cbdata, 0))) {
win32err("BCryptGetProperty1");
};
if (0
== (ctxp->pbhashobj =
HeapAlloc(GetProcessHeap(), 0, ctxp->cbhashobj))) {
win32err("HeapAlloc1");
};
if (0 > (ctxp->st = BCryptGetProperty(
ctxp->bah, BCRYPT_HASH_LENGTH, (PBYTE) &ctxp->cbhash,
sizeof(DWORD), &ctxp->cbdata, 0))) {
win32err("BCryptGetProperty2");
}
if (0
== (ctxp->pbhash =
HeapAlloc(GetProcessHeap(), 0, ctxp->cbhash))) {
win32err("HeapAlloc2\n");
}
if (0 > BCryptCreateHash(ctxp->bah, &ctxp->bhh, ctxp->pbhashobj,
ctxp->cbhashobj, NULL, 0, 0)) {
win32err("BCryptCreateHash");
}
break;
case 'u': /* HASH_UPDATE(ctxp, ptr, len) */
if (0 > (ctxp->st = BCryptHashData(ctxp->bhh, p, d, 0))) {
win32err("BCryptHashData");
}
break;
case 'f': /* HASH_FINISH(ctxp) */
if (0 > BCryptFinishHash(ctxp->bhh, ctxp->pbhash, ctxp->cbhash, 0)) {
win32err("BCryptFinishHash");
}
break;
case 'c': /* HASH_CLEANUP(ctxp) */
if (ctxp->bah) {
BCryptCloseAlgorithmProvider(ctxp->bah, 0);
}
if (ctxp->bhh) {
BCryptDestroyHash(ctxp->bhh);
}
if (ctxp->pbhashobj) {
HeapFree(GetProcessHeap(), 0, ctxp->pbhashobj);
}
if (ctxp->pbhash) {
HeapFree(GetProcessHeap(), 0, ctxp->pbhash);
}
break;
case 's': /* HASH_RESULT_SIZE(ctxp) */
return ctxp->cbhash;
case 'r': /* HASH_RESULT(ctxp, resp) */
*(unsigned char **)p = ctxp->pbhash;
break;
case 'b': /* HASH_BINFILE(NULL,&binfile,0) */
// XXX This buffer should be allocated, not static (and freed in
// HASH_CLEANUP).
// NB: assumes !longPathAware in manifest (Win10+)
{
static char binfile[MAX_PATH];
DWORD rv = GetModuleFileNameA(NULL, binfile, sizeof(binfile));
if (rv == 0 || rv == sizeof(binfile))
return 1;
#ifdef BETA
printf("FILE '%s'\n", binfile);
#endif
*(unsigned char **) p = (unsigned char *) binfile;
return 0;
}
}
return 0; /* ok */
error:
raw_printf("WIN32 function %s failed: status=%" PRIx64 "\n",
errname, (uint64)ctxp->st);
return 1; /* fail */
}
#undef win32err
#include <shellapi.h>
#define MAX_SYM_SIZE 100
#ifdef __GNUC__
// gcc can't generate .pdb files. llvm can almost do it.
// For these platforms, use github/ianlancetaylor/libbacktrace.
// XXX this doesn't work yet - we get correct addresses but no symbol info
// XXX so still needs cleanup
// XXX no mark (overflow held to last valid segment) handling yet
#include <backtrace.h>
struct userstate {
int error_count;
int good_count;
char *out;
int outsize;
int maxframes;
} userstate;
//backtrace_full_callback
static int
btfcb_fn(void *us0, uintptr_t pc, const char *filename,
int lineno, const char *fnname){
struct userstate *us = us0;
//XXX generate a stack frame line
printf("C: pc=%llx f=%s line=%d fn=%s\n",pc,filename,lineno,fnname);
us->good_count++;
return 0;
}
//backtrace_error_callback
static void
btecb_fn(void *us0, const char *msg, int errnum){
struct userstate *us = us0;
us->error_count++;
if(errnum < 0){
printf("E1: M=%s e=%d\n",msg,errnum);
// XXX save error message
} else {
printf("E2: M=%s e=%d\n",msg,errnum);
// errnum is an errno
//XXX save error message with strerror
}
}
int
win32_cr_gettrace(int maxframes, char *out, int outsize){
userstate.error_count = 0;
userstate.good_count = 0;
userstate.out = out;
userstate.outsize = outsize;
userstate.maxframes = maxframes;
static char binfile[MAX_PATH];// assumes !longPathAware in manifest (Win10+)
DWORD rv = GetModuleFileNameA(NULL, binfile, sizeof(binfile));
struct backtrace_state *state
= backtrace_create_state(binfile, 0, btecb_fn, &userstate);
if(!state) return userstate.error_count + userstate.good_count;
rv=backtrace_full(state, 0, btfcb_fn, btecb_fn, &userstate);
printf("rv=%d\n",rv);
// XXX rv not checked
// XXX this API leaks its memory; there is no free function
return userstate.error_count + userstate.good_count;
}
#else
// Use win32 API with Visual Studio (and probably MSVC).
#include <dbghelp.h>
int
win32_cr_gettrace(int maxframes, char *out, int outsize){
char *mark = out;
void *frames[200]; // XXX why does VS fail var array? wrong C std?
int x;
int tmp;
#define BSIZE (MAX_SYM_SIZE+50)
char buf[BSIZE];
HANDLE me = GetCurrentProcess();
SetLastError(0);
// XXX may need to pass the binary's dir
//XXX check for different flags
if(!SymInitialize(me, NULL, TRUE)){
snprintf(buf, BSIZE, "no stack trace: SymInitialize: %d\n",
GetLastError());
return 1;
}
int fcount = CaptureStackBackTrace(0, maxframes,frames,NULL);
if(!fcount)goto finish;
char symbol_info_space[sizeof(SYMBOL_INFO)+MAX_SYM_SIZE];
SYMBOL_INFO *si = (SYMBOL_INFO *)symbol_info_space;
si->MaxNameLen = MAX_SYM_SIZE;
si->SizeOfStruct = sizeof(SYMBOL_INFO);
for(x=0;x<fcount;x++){
DWORD64 disp64 =0 ;
DWORD64 adr = (DWORD64)(frames[x]);
if(!adr) break;
if(SymFromAddr(me, adr, &disp64, si)){
//printf("A %x\n",GetLastError());fflush(stdout);
tmp = snprintf(buf, BSIZE, "%d %p %s+%lld\n",
x, frames[x], &si->Name[0], (long long int)disp64);
if(swr_add_uricoded(buf, &out, &outsize, mark))
goto finish;
#if 1
// XXX does this block do anything useful?
DWORD disp = (DWORD) disp64;
IMAGEHLP_LINE ihl;
ihl.SizeOfStruct = sizeof(IMAGEHLP_LINE);
if (SymGetLineFromAddr(me, adr, &disp, &ihl)) {
printf("L=%d\n", ihl.LineNumber);
} else {
// 7e/1e7 - no info. May need to call SymLoadModule if we need those addrs
// BUT probably system code, so we don't care - experiment
// printf("SGLFA failed: $%08x\n", GetLastError());
}
//XXXnow format the line
#endif
} else {
// Error 487 (invalid address) seems to mean
// "I can't find any info for this address".
tmp = snprintf(buf, BSIZE, "%d %p (error %d)\n",
x, frames[x], GetLastError());
if(swr_add_uricoded(buf, &out, &outsize, mark))
goto finish;
}
if(tmp < 0 || tmp >= outsize){ // XXX is test now wrong?
//printf("FAIL tmp=%d\n",tmp);
fcount = x+1;
goto finish;
}
mark = out;
}
finish:
SymCleanup(me);
return fcount; // XXX if output truncated, fcount could be wrong
}
#endif
int *
win32_cr_shellexecute(const char *url){
//XXX Docs say to do this, but has so many caveats I'm going to try skipping it.
//CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
int *rv = (int*)ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
return rv;
}
#endif /* CRASHREPORT */
#endif /* WIN32 */
/*windsys.c*/