5942: Support unicode with ExcHndl, use upstream module offsets, handle errors r=def- a=Robyt3

Update Dr. Mingw (ExcHndl) to 0.9.8.

Use the new `ExcHndlSetLogFileNameW` function to set the exception log file name using wide characters, to support paths containing unicode.

It's not necessary to call `ExcHndlInit` explicitly after loading `exchndl.dll`, as the `DllMain` will already initialize the exception handler when the DLL is loaded. Module offsets are supported by upstream ExcHndl now, so we don't need to provide our own version that supplies the module offset to `ExcHndlInit` anymore. Upstream ExcHndl will also resolve the source code lines for addresses automatically, when the executable is build with debug information.

Handle the cases that the exception handling module cannot be loaded and that the `ExcHndlSetLogFileNameW` function cannot be found in the module.

Update `scripts/parse_drmingw.sh`:

- Parse both old and new module offsets.
- Use tabs instead of spaces consistently.
- Reset the ANSI color after printing colored messages.

Closes #5877.

Needs https://github.com/ddnet/ddnet-libs/pull/34.

Example crash logs:

- [crash_debug_old.RTP.txt](https://github.com/ddnet/ddnet/files/9768008/crash_debug_old.RTP.txt)
- [crash_debug_new.RTP.txt](https://github.com/ddnet/ddnet/files/9768011/crash_debug_new.RTP.txt)
- [crash_release_old.RTP.txt](https://github.com/ddnet/ddnet/files/9768010/crash_release_old.RTP.txt)
- [crash_release_new.RTP.txt](https://github.com/ddnet/ddnet/files/9768009/crash_release_new.RTP.txt)

## Checklist

- [X] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
bors[bot] 2022-10-12 21:44:43 +00:00 committed by GitHub
commit bd3b4f2d50
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 27 deletions

@ -1 +1 @@
Subproject commit 52bddda25778af9c3a6579bf75f8242e17e12c25 Subproject commit aa673564095d83e60db51e40f39f3f2b53d61a20

View file

@ -1,29 +1,37 @@
#!/bin/bash #!/bin/bash
if [ -z ${1+x} ]; then if [ -z ${1+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass executable file (full path)" printf "\e[31m%s\e[30m\n" "Did not pass executable file (full path)"
printf "\e[31m%s\e[30m\n" "Usage: $0 <executable> <crash_log>" printf "\e[31m%s\e[30m\n" "Usage: $0 <executable> <crash_log>"
exit 1 echo -en "\e[0m"
exit 1
fi fi
if [ -z ${2+x} ]; then if [ -z ${2+x} ]; then
printf "\e[31m%s\e[30m\n" "Did not pass crash log file (full path)" printf "\e[31m%s\e[30m\n" "Did not pass crash log file (full path)"
printf "\e[31m%s\e[30m\n" "Usage: $0 <executable> <crash_log>" printf "\e[31m%s\e[30m\n" "Usage: $0 <executable> <crash_log>"
exit 1 echo -en "\e[0m"
exit 1
fi fi
TMP_OFFSET=$(grep -E -o "\(with offset [0-9A-F]*\)" "$2" | grep -E -o "[A-F0-9]*") TMP_OFFSET=$(grep -E -o "\(with offset [0-9A-F]+\)" "$2" | grep -E -o "[A-F0-9]*")
if [ -z "$TMP_OFFSET" ]; then
TMP_OFFSET=$(grep -E -o "^[0-9A-F]+-[0-9A-F]+ .+\.exe$" "$2" | grep -E -o "^[A-F0-9]+")
if [ -z "$TMP_OFFSET" ]; then
printf "\e[31m%s\e[30m\n" "Module offset not found; addresses will be absolute"
echo -en "\e[0m"
fi
fi
ADDR_PC_REGEX='[0-9A-F]+ [0-9A-F]+ [0-9A-F]+ [0-9A-F]+' ADDR_PC_REGEX='[0-9A-F]+ [0-9A-F]+ [0-9A-F]+ [0-9A-F]+'
while read -r line while read -r line
do do
if [[ $line =~ $ADDR_PC_REGEX ]] if [[ $line =~ $ADDR_PC_REGEX ]]
then then
TMP_ADDR=$(echo "$line" | grep -E -o -m 1 "[A-F0-9]+ " | head -1) TMP_ADDR=$(echo "$line" | grep -E -o -m 1 "[A-F0-9]+ " | head -1)
ADDR_BASE=$(winedump -f "$1" | grep -E -o "image base[ ]*0x[0-9A-Fa-f]*" | grep -E -o "[0-9A-Fa-f]+" | tail -1) ADDR_BASE=$(winedump -f "$1" | grep -E -o "image base[ ]*0x[0-9A-Fa-f]*" | grep -E -o "[0-9A-Fa-f]+" | tail -1)
REAL_ADDR=$(printf '%X\n' "$(((0x$TMP_ADDR-0x$TMP_OFFSET)+0x$ADDR_BASE))") REAL_ADDR=$(printf '%X\n' "$(((0x$TMP_ADDR-0x$TMP_OFFSET)+0x$ADDR_BASE))")
echo "Parsing address: $REAL_ADDR (img base: $ADDR_BASE)" echo "Parsing address: $REAL_ADDR (img base: $ADDR_BASE)"
addr2line -e "$1" "$REAL_ADDR" addr2line -e "$1" "$REAL_ADDR"
fi fi
done < "$2" done < "$2"

View file

@ -4215,20 +4215,11 @@ static HMODULE exception_handling_module = nullptr;
void init_exception_handler() void init_exception_handler()
{ {
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
exception_handling_module = LoadLibraryA("exchndl.dll"); const char *module_name = "exchndl.dll";
if(exception_handling_module != nullptr) exception_handling_module = LoadLibraryA(module_name);
if(exception_handling_module == nullptr)
{ {
// Intentional dbg_msg("exception_handling", "failed to load exception handling library '%s' (error %ld)", module_name, GetLastError());
#ifdef __MINGW32__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
auto exc_hndl_init = (void APIENTRY (*)(void *))GetProcAddress(exception_handling_module, "ExcHndlInit");
#ifdef __MINGW32__
#pragma GCC diagnostic pop
#endif
void *exception_handling_offset = (void *)GetModuleHandle(NULL);
exc_hndl_init(exception_handling_offset);
} }
#else #else
#error exception handling not implemented #error exception handling not implemented
@ -4240,16 +4231,22 @@ void set_exception_handler_log_file(const char *log_file_path)
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
if(exception_handling_module != nullptr) if(exception_handling_module != nullptr)
{ {
WCHAR wBuffer[IO_MAX_PATH_LENGTH];
MultiByteToWideChar(CP_UTF8, 0, log_file_path, -1, wBuffer, std::size(wBuffer));
// Intentional // Intentional
#ifdef __MINGW32__ #ifdef __MINGW32__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
#endif #endif
auto exception_log_file_path_func = (BOOL APIENTRY(*)(const char *))(GetProcAddress(exception_handling_module, "ExcHndlSetLogFileNameA")); const char *function_name = "ExcHndlSetLogFileNameW";
auto exception_log_file_path_func = (BOOL APIENTRY(*)(const WCHAR *))(GetProcAddress(exception_handling_module, function_name));
#ifdef __MINGW32__ #ifdef __MINGW32__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
exception_log_file_path_func(log_file_path); if(exception_log_file_path_func == nullptr)
dbg_msg("exception_handling", "could not find function '%s' in exception handling library (error %ld)", function_name, GetLastError());
else
exception_log_file_path_func(wBuffer);
} }
#else #else
#error exception handling not implemented #error exception handling not implemented