mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-02 03:58:11 +00:00
move to codebase-defined entry point style, with basic command line argument parsing, capture, thread-ctx, and other boilerplate deduplicated in the base layer's entry point definition
This commit is contained in:
@@ -813,7 +813,7 @@ lnx_safe_call_sig_handler(int){
|
||||
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
|
||||
|
||||
internal void
|
||||
os_init(int argc, char **argv)
|
||||
os_init(void)
|
||||
{
|
||||
// NOTE(allen): Initialize linux layer mutex
|
||||
{
|
||||
|
||||
@@ -67,19 +67,6 @@ os_string_list_from_argcv(Arena *arena, int argc, char **argv)
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Helpers (Helper, Implemented Once)
|
||||
|
||||
internal void
|
||||
os_relaunch_self(void){
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
OS_LaunchOptions opts = {0};
|
||||
opts.cmd_line = os_get_command_line_arguments();
|
||||
opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Initial);
|
||||
os_launch_process(&opts, 0);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
||||
|
||||
|
||||
+12
-7
@@ -165,11 +165,6 @@ internal String8 os_string_from_system_path(Arena *arena, OS_SystemPath path);
|
||||
|
||||
internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Helpers (Helper, Implemented Once)
|
||||
|
||||
internal void os_relaunch_self(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
||||
|
||||
@@ -204,7 +199,7 @@ internal void os_condition_variable_broadcast(OS_Handle cv);
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
|
||||
|
||||
internal void os_init(int argc, char **argv);
|
||||
internal void os_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS)
|
||||
@@ -234,7 +229,6 @@ internal U64 os_logical_core_count(void);
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Process & Thread Info (Implemented Per-OS)
|
||||
|
||||
internal String8List os_get_command_line_arguments(void);
|
||||
internal S32 os_get_pid(void);
|
||||
internal S32 os_get_tid(void);
|
||||
internal String8List os_get_environment(void);
|
||||
@@ -370,4 +364,15 @@ internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *f
|
||||
internal OS_Guid os_make_guid(void);
|
||||
internal String8 os_string_from_guid(Arena *arena, OS_Guid guid);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Entry Points (Implemented Per-OS)
|
||||
|
||||
// NOTE(rjf): The implementation of `os_core` will define low-level entry
|
||||
// points if BUILD_ENTRY_DEFINING_UNIT is defined to 1. These will call
|
||||
// into the standard codebase program entry points, named "entry_point".
|
||||
|
||||
#if BUILD_ENTRY_DEFINING_UNIT
|
||||
internal void entry_point(CmdLine *cmdline);
|
||||
#endif
|
||||
|
||||
#endif // OS_CORE_H
|
||||
|
||||
@@ -185,7 +185,8 @@ w32_thread_base(void *ptr){
|
||||
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
|
||||
|
||||
internal void
|
||||
os_init(int argc, char **argv){
|
||||
os_init(void)
|
||||
{
|
||||
// Load Fancy Memory Functions
|
||||
{
|
||||
HMODULE module = LoadLibraryA("kernel32.dll");
|
||||
@@ -214,9 +215,6 @@ os_init(int argc, char **argv){
|
||||
// Setup initial path
|
||||
w32_initial_path = os_string_from_system_path(w32_perm_arena, OS_SystemPath_Current);
|
||||
|
||||
// Setup command line arguments
|
||||
w32_cmd_line_args = os_string_list_from_argcv(w32_perm_arena, argc, argv);
|
||||
|
||||
// rjf: setup environment variables
|
||||
{
|
||||
CHAR *this_proc_env = GetEnvironmentStrings();
|
||||
@@ -470,12 +468,6 @@ os_logical_core_count(void)
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Process Info (Implemented Per-OS)
|
||||
|
||||
internal String8List
|
||||
os_get_command_line_arguments(void)
|
||||
{
|
||||
return w32_cmd_line_args;
|
||||
}
|
||||
|
||||
internal S32
|
||||
os_get_pid(void){
|
||||
DWORD id = GetCurrentProcessId();
|
||||
@@ -1555,7 +1547,8 @@ os_make_guid(void)
|
||||
OS_Guid result; MemoryZeroStruct(&result);
|
||||
UUID uuid;
|
||||
RPC_STATUS rpc_status = UuidCreate(&uuid);
|
||||
if (rpc_status == RPC_S_OK) {
|
||||
if(rpc_status == RPC_S_OK)
|
||||
{
|
||||
result.data1 = uuid.Data1;
|
||||
result.data2 = uuid.Data2;
|
||||
result.data3 = uuid.Data3;
|
||||
@@ -1564,3 +1557,244 @@ os_make_guid(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Entry Points (Implemented Per-OS)
|
||||
|
||||
#include <dbghelp.h>
|
||||
#undef OS_WINDOWS // shlwapi uses its own OS_WINDOWS include inside
|
||||
#include <shlwapi.h>
|
||||
|
||||
internal B32 win32_g_is_quiet = 0;
|
||||
|
||||
internal HRESULT WINAPI
|
||||
win32_dialog_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, LONG_PTR data)
|
||||
{
|
||||
if(msg == TDN_HYPERLINK_CLICKED)
|
||||
{
|
||||
ShellExecuteW(NULL, L"open", (LPWSTR)lparam, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
internal LONG WINAPI
|
||||
win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs)
|
||||
{
|
||||
if(win32_g_is_quiet)
|
||||
{
|
||||
ExitProcess(1);
|
||||
}
|
||||
|
||||
static volatile LONG first = 0;
|
||||
if(InterlockedCompareExchange(&first, 1, 0) != 0)
|
||||
{
|
||||
// prevent failures in other threads to popup same message box
|
||||
// this handler just shows first thread that crashes
|
||||
// we are terminating afterwards anyway
|
||||
for (;;) Sleep(1000);
|
||||
}
|
||||
|
||||
WCHAR buffer[4096] = {0};
|
||||
int buflen = 0;
|
||||
|
||||
DWORD exception_code = exception_ptrs->ExceptionRecord->ExceptionCode;
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"A fatal exception (code 0x%x) occurred. The process is terminating.\n", exception_code);
|
||||
|
||||
// load dbghelp dynamically just in case if it is missing
|
||||
HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
|
||||
if(dbghelp)
|
||||
{
|
||||
DWORD (WINAPI *dbg_SymSetOptions)(DWORD SymOptions);
|
||||
BOOL (WINAPI *dbg_SymInitializeW)(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess);
|
||||
BOOL (WINAPI *dbg_StackWalk64)(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
|
||||
PVOID (WINAPI *dbg_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
|
||||
DWORD64 (WINAPI *dbg_SymGetModuleBase64)(HANDLE hProcess, DWORD64 qwAddr);
|
||||
BOOL (WINAPI *dbg_SymFromAddrW)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFOW Symbol);
|
||||
BOOL (WINAPI *dbg_SymGetLineFromAddrW64)(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line);
|
||||
BOOL (WINAPI *dbg_SymGetModuleInfoW64)(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULEW64 ModuleInfo);
|
||||
|
||||
*(FARPROC*)&dbg_SymSetOptions = GetProcAddress(dbghelp, "SymSetOptions");
|
||||
*(FARPROC*)&dbg_SymInitializeW = GetProcAddress(dbghelp, "SymInitializeW");
|
||||
*(FARPROC*)&dbg_StackWalk64 = GetProcAddress(dbghelp, "StackWalk64");
|
||||
*(FARPROC*)&dbg_SymFunctionTableAccess64 = GetProcAddress(dbghelp, "SymFunctionTableAccess64");
|
||||
*(FARPROC*)&dbg_SymGetModuleBase64 = GetProcAddress(dbghelp, "SymGetModuleBase64");
|
||||
*(FARPROC*)&dbg_SymFromAddrW = GetProcAddress(dbghelp, "SymFromAddrW");
|
||||
*(FARPROC*)&dbg_SymGetLineFromAddrW64 = GetProcAddress(dbghelp, "SymGetLineFromAddrW64");
|
||||
*(FARPROC*)&dbg_SymGetModuleInfoW64 = GetProcAddress(dbghelp, "SymGetModuleInfoW64");
|
||||
|
||||
if(dbg_SymSetOptions && dbg_SymInitializeW && dbg_StackWalk64 && dbg_SymFunctionTableAccess64 && dbg_SymGetModuleBase64 && dbg_SymFromAddrW && dbg_SymGetLineFromAddrW64 && dbg_SymGetModuleInfoW64)
|
||||
{
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
CONTEXT* context = exception_ptrs->ContextRecord;
|
||||
|
||||
dbg_SymSetOptions(SYMOPT_EXACT_SYMBOLS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
|
||||
if(dbg_SymInitializeW(process, L"", TRUE))
|
||||
{
|
||||
// check that raddbg.pdb file is good
|
||||
B32 raddbg_pdb_valid = 0;
|
||||
{
|
||||
IMAGEHLP_MODULEW64 module = {0};
|
||||
module.SizeOfStruct = sizeof(module);
|
||||
if(dbg_SymGetModuleInfoW64(process, (DWORD64)&win32_exception_filter, &module))
|
||||
{
|
||||
raddbg_pdb_valid = (module.SymType == SymPdb);
|
||||
}
|
||||
}
|
||||
|
||||
if(!raddbg_pdb_valid)
|
||||
{
|
||||
buflen += wnsprintfW(buffer + buflen, sizeof(buffer) - buflen,
|
||||
L"\nThe PDB debug information file for this executable is not valid or was not found. Please rebuild binary to get call stack.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
STACKFRAME64 frame = {0};
|
||||
DWORD image_type;
|
||||
#if defined(_M_AMD64)
|
||||
image_type = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context->Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context->Rbp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context->Rsp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif defined(_M_ARM64)
|
||||
image_type = IMAGE_FILE_MACHINE_ARM64;
|
||||
frame.AddrPC.Offset = context->Pc;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context->Fp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context->Sp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#else
|
||||
# error Architecture not supported!
|
||||
#endif
|
||||
|
||||
for(U32 idx=0; ;idx++)
|
||||
{
|
||||
const U32 max_frames = 32;
|
||||
if(idx == max_frames)
|
||||
{
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"...");
|
||||
break;
|
||||
}
|
||||
|
||||
if(!dbg_StackWalk64(image_type, process, thread, &frame, context, 0, dbg_SymFunctionTableAccess64, dbg_SymGetModuleBase64, 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
U64 address = frame.AddrPC.Offset;
|
||||
if(address == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(idx==0)
|
||||
{
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen,
|
||||
L"\nPress Ctrl+C to copy this text to clipboard, then create a new issue in\n"
|
||||
L"<a href=\"%S\">%S</a>\n\n", BUILD_ISSUES_LINK_STRING_LITERAL, BUILD_ISSUES_LINK_STRING_LITERAL);
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"Call stack:\n");
|
||||
}
|
||||
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"%u. [0x%I64x]", idx + 1, address);
|
||||
|
||||
struct {
|
||||
SYMBOL_INFOW info;
|
||||
WCHAR name[MAX_SYM_NAME];
|
||||
} symbol = {0};
|
||||
|
||||
symbol.info.SizeOfStruct = sizeof(symbol.info);
|
||||
symbol.info.MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
DWORD64 displacement = 0;
|
||||
if(dbg_SymFromAddrW(process, address, &displacement, &symbol.info))
|
||||
{
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s +%u", symbol.info.Name, (DWORD)displacement);
|
||||
|
||||
IMAGEHLP_LINEW64 line = {0};
|
||||
line.SizeOfStruct = sizeof(line);
|
||||
|
||||
DWORD line_displacement = 0;
|
||||
if(dbg_SymGetLineFromAddrW64(process, address, &line_displacement, &line))
|
||||
{
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L", %s line %u", PathFindFileNameW(line.FileName), line.LineNumber);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IMAGEHLP_MODULEW64 module = {0};
|
||||
module.SizeOfStruct = sizeof(module);
|
||||
if(dbg_SymGetModuleInfoW64(process, address, &module))
|
||||
{
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s", module.ModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nVersion: %S%S", BUILD_VERSION_STRING_LITERAL, BUILD_GIT_HASH_STRING_LITERAL_APPEND);
|
||||
|
||||
TASKDIALOGCONFIG dialog = {0};
|
||||
dialog.cbSize = sizeof(dialog);
|
||||
dialog.dwFlags = TDF_SIZE_TO_CONTENT | TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
dialog.pszMainIcon = TD_ERROR_ICON;
|
||||
dialog.dwCommonButtons = TDCBF_CLOSE_BUTTON;
|
||||
dialog.pszWindowTitle = L"Fatal Exception";
|
||||
dialog.pszContent = buffer;
|
||||
dialog.pfCallback = &win32_dialog_callback;
|
||||
TaskDialogIndirect(&dialog, 0, 0, 0);
|
||||
|
||||
ExitProcess(1);
|
||||
}
|
||||
|
||||
#undef OS_WINDOWS // shlwapi uses its own OS_WINDOWS include inside
|
||||
#define OS_WINDOWS 1
|
||||
|
||||
#if BUILD_CONSOLE_INTERFACE
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
SetUnhandledExceptionFilter(&win32_exception_filter);
|
||||
for(int i = 0; i < argc; i += 1)
|
||||
{
|
||||
String8 arg8 = str8_cstring(argv[i]);
|
||||
if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
win32_g_is_quiet = 1;
|
||||
}
|
||||
}
|
||||
main_thread_base_entry_point(entry_point, argv, (U64)argc);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||
{
|
||||
SetUnhandledExceptionFilter(&win32_exception_filter);
|
||||
Arena *args_arena = arena_alloc__sized(KB(64), KB(64));
|
||||
WCHAR *command_line = GetCommandLineW();
|
||||
int argc = 0;
|
||||
WCHAR **argv_16 = CommandLineToArgvW(command_line, &argc);
|
||||
char **argv = push_array(args_arena, char *, argc);
|
||||
for(int i = 0; i < argc; i += 1)
|
||||
{
|
||||
String16 arg16 = str16_cstring((U16 *)argv_16[i]);
|
||||
String8 arg8 = str8_from_16(args_arena, arg16);
|
||||
if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
win32_g_is_quiet = 1;
|
||||
}
|
||||
argv[i] = (char *)arg8.str;
|
||||
}
|
||||
main_thread_base_entry_point(entry_point, argv, (U64)argc);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user