From 91c5989a7d3838eab36a2d7b0b8bf4ae930f36af Mon Sep 17 00:00:00 2001 From: doyle Date: Thu, 31 Aug 2023 01:03:48 +1000 Subject: [PATCH] dqn: Implement stack trace for windows --- Misc/dqn_unit_tests.cpp | 108 +------ _clang-format | 504 +++++++++++++++++++++++++++++--- dqn.h | 6 +- dqn_containers.h | 2 +- dqn_debug.cpp | 147 +++++++++- dqn_debug.h | 54 +++- dqn_external.cpp | 9 - dqn_external.h | 365 +---------------------- dqn_helpers.cpp | 4 + dqn_win32.h | 627 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1279 insertions(+), 547 deletions(-) create mode 100644 dqn_win32.h diff --git a/Misc/dqn_unit_tests.cpp b/Misc/dqn_unit_tests.cpp index 52a3aad..be9960e 100644 --- a/Misc/dqn_unit_tests.cpp +++ b/Misc/dqn_unit_tests.cpp @@ -1847,112 +1847,20 @@ static void Dqn_Test_RunSuite() dqn_library->log_callback = prev_log_callback; } -#define WIN32_LEAN_AND_MEAN -#include -#include // STACKFRAME64, ... -#include // CONTEXT -#pragma comment(lib, "DbgHelp.lib") - -// extern "C" -// { -// /*HANDLE*/ void * __stdcall GetCurrentProcess(void); -// /*HANDLE*/ void * __stdcall GetCurrentThread(void); -// } - -void DumpStackTrace() -{ - #if !defined(_M_X64) - #error "Platform is not implemented" - #endif - - CONTEXT context; - RtlCaptureContext(&context); - - STACKFRAME64 frame = {}; - 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; - - void *thread = GetCurrentThread(); - static Dqn_TicketMutex mutex = {}; - Dqn_TicketMutex_Begin(&mutex); - - void *process = GetCurrentProcess(); - static bool init = false; - if (!init) { - SymInitialize(process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/); - SymSetOptions(SYMOPT_LOAD_LINES); - init = 1; - } - - for (;;) { - if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, - process, - thread, - &frame, - &context, - nullptr /*ReadMemoryRoutine*/, - SymFunctionTableAccess64, - SymGetModuleBase64, - nullptr /*TrnaslateAddress*/)) { - break; - } - - if (frame.AddrPC.Offset == frame.AddrReturn.Offset) { - // TODO(doyle): Recursion - } - - if (frame.AddrPC.Offset == 0) { - break; - // TODO(doyle): Invalid program counter - } else { - - // NOTE: Get file+line ================================================================= - - IMAGEHLP_LINE64 line = {}; - line.SizeOfStruct = sizeof(line); - DWORD line_displacement = 0; - - if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &line_displacement, &line)) { - printf("%s(%lu): ", line.FileName, line.LineNumber); - } else { - DWORD error = GetLastError(); - printf("SymFromAddr returned error : %lu\n", error); - } - - // NOTE: Get function name ============================================================ - - char buffer[sizeof(SYMBOL_INFO) + 1024] = {}; - SYMBOL_INFO *symbol = new (buffer) SYMBOL_INFO; - symbol->SizeOfStruct = sizeof(*symbol); - symbol->MaxNameLen = 1024; - uint64_t symbol_displacement = 0; // Offset to the beginning of the symbol to the address - - if (SymFromAddr(process, frame.AddrPC.Offset, &symbol_displacement, symbol)) { - printf("%.*s\n", DQN_CAST(int)symbol->NameLen, symbol->Name); - } else { - DWORD error = GetLastError(); - printf("SymFromAddr returned error : %lu\n", error); - } - - } - } - Dqn_TicketMutex_End(&mutex); -} - #if defined(DQN_TEST_WITH_MAIN) int main(int argc, char *argv[]) { (void)argv; (void)argc; - printf("%s\n\n", b_stacktrace_get_string()); - DumpStackTrace(); - return 1; + Dqn_Library_Init(); + + Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); + Dqn_StackTraceFrames stack_trace = Dqn_StackTrace_GetFrames(scratch.arena, 128 /*limit*/); + DQN_FOR_UINDEX (index, stack_trace.size) { + Dqn_StackTraceFrame frame = stack_trace.data[index]; + Dqn_Print_LnF("%.*s(%I64u): %.*s", DQN_STRING_FMT(frame.file_name), frame.line_number, DQN_STRING_FMT(frame.function_name)); + } Dqn_Test_RunSuite(); return 0; } #endif - diff --git a/_clang-format b/_clang-format index e460667..4e5604a 100644 --- a/_clang-format +++ b/_clang-format @@ -1,45 +1,459 @@ -{ - ColumnLimit: 120, - TabWidth: 4, - IndentWidth: 4, # 1 tab - BreakBeforeBraces: Allman, - PointerBindsToType: false, - ### - AlwaysBreakAfterDefinitionReturnType: false, - AlwaysBreakTemplateDeclarations: true, - AlwaysBreakBeforeMultilineStrings: true, - IndentFunctionDeclarationAfterType: false, - # - AccessModifierOffset: -4, # 1 tab - AlignAfterOpenBracket: true, - AlignConsecutiveAssignments: true, - AlignTrailingComments: true, - # - AllowAllParametersOfDeclarationOnNextLine: true, - AllowShortBlocksOnASingleLine: false, - AllowShortIfStatementsOnASingleLine: true, - AllowShortLoopsOnASingleLine: false, - # - BinPackArguments: false, - BinPackParameters: false, - # - BreakConstructorInitializersBeforeComma: true, - ConstructorInitializerIndentWidth: 0, - # - IndentCaseLabels: true, - # - MaxEmptyLinesToKeep: 1, - NamespaceIndentation: None, - # - SpaceBeforeAssignmentOperators: true, - SpaceInEmptyParentheses: false, - SpacesBeforeTrailingComments: 1, - SpacesInAngles: false, - SpacesInCStyleCastParentheses: false, - SpacesInParentheses: false, - SpacesInSquareBrackets: false, - # - Cpp11BracedListStyle: true, - Standard: Cpp11, - # -} +--- +IndentWidth: 4 +TabWidth: 4 +--- +Language: Cpp + +# Align parameters on the open bracket, e.g.: +# someLongFunction(argument1, +# argument2); +AlignAfterOpenBracket: Align + +# Align array column and left justify the columns e.g.: +# struct test demo[] = +# { +# {56, 23, "hello"}, +# {-1, 93463, "world"}, +# {7, 5, "!!" } +# }; +AlignArrayOfStructures: Left + +# Align assignments on consecutive lines. This will result in formattings like: +# +# int a = 1; +# int somelongname = 2; +# double c = 3; +# +# int d = 3; +# /* A comment. */ +# double e = 4; +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveBitFields: Consecutive +AlignConsecutiveDeclarations: Consecutive +AlignConsecutiveMacros: Consecutive + +# Align escaped newlines as far left as possible. +# #define A \ +# int aaaa; \ +# int b; \ +# int dddddddddd; +AlignEscapedNewlines: Left + +# Horizontally align operands of binary and ternary expressions. +# Specifically, this aligns operands of a single expression that needs to be +# split over multiple lines, e.g.: +# +# int aaa = bbbbbbbbbbbbbbb + +# ccccccccccccccc; +AlignOperands: Align + +# true: false: +# int a; // My comment a vs. int a; // My comment a +# int b = 2; // comment b int b = 2; // comment about b +AlignTrailingComments: true + +# If the function declaration doesn’t fit on a line, allow putting all +# parameters of a function declaration onto the next line even if +# BinPackParameters is false. +# +# true: +# void myFunction( +# int a, int b, int c, int d, int e); +# +# false: +# void myFunction(int a, +# int b, +# int c, +# int d, +# int e); +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never # "while (true) { continue; }" can be put on a single line. + +# If true, short case labels will be contracted to a single line. +# +# true: false: +# switch (a) { vs. switch (a) { +# case 1: x = 1; break; case 1: +# case 2: return; x = 1; +# } break; +# case 2: +# return; +# } +AllowShortCaseLabelsOnASingleLine: true +AllowShortEnumsOnASingleLine: true # enum { A, B } myEnum; + +# Only merge functions defined inside a class. Implies “empty”. +# +# class Foo { +# void f() { foo(); } +# }; +# void f() { +# foo(); +# } +# void f() {} +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false + +# Only merge empty lambdas. +# +# auto lambda = [](int a) {} +# auto lambda2 = [](int a) { +# return a; +# }; +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false + +# true: false: +# aaaa = vs. aaaa = "bbbb" +# "bbbb" "cccc"; +# "cccc"; +AlwaysBreakBeforeMultilineStrings: true + +# Force break after template declaration only when the following declaration +# spans multiple lines. +# +# template T foo() { +# } +# template +# T foo(int aaaaaaaaaaaaaaaaaaaaa, +# int bbbbbbbbbbbbbbbbbbbbb) { +# } +AlwaysBreakTemplateDeclarations: MultiLine + +# If false, a function call’s arguments will either be all on the same line or +# will have one line each. +# +# true: +# void f() { +# f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa, +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); +# } +# +# false: +# void f() { +# f(aaaaaaaaaaaaaaaaaaaa, +# aaaaaaaaaaaaaaaaaaaa, +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); +# } +BinPackArguments: false +BinPackParameters: false # As BinPackArguments but for function definition parameters + +# Add space after the : only (space may be added before if needed for +# AlignConsecutiveBitFields). +# +# unsigned bf: 2; +BitFieldColonSpacing: After + +# LooooooooooongType loooooooooooooooooooooongVariable = +# someLooooooooooooooooongFunction(); +# +# bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > +# ccccccccccccccccccccccccccccccccccccccccc; +BreakBeforeBinaryOperators: None + +# Always attach braces to surrounding context, but break before braces on +# function, namespace and class definitions. +BreakBeforeBraces: Linux + +# true: +# template +# concept ... +# +# false: +# template concept ... +BreakBeforeConceptDeclarations: false + +# true: +# veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription +# ? firstValue +# : SecondValueVeryVeryVeryVeryLong; +# +# false: +# veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ? +# firstValue : +# SecondValueVeryVeryVeryVeryLong; +BreakBeforeTernaryOperators: true + +# Break constructor initializers before the colon and commas, and align the +# commas with the colon. +# +# Constructor() +# : initializer1() +# , initializer2() +BreakConstructorInitializers: BeforeComma + +# Break inheritance list only after the commas. +# +# class Foo : Base1, +# Base2 +# {}; +BreakInheritanceList: AfterComma + +# true: +# const char* x = "veryVeryVeryVeryVeryVe" +# "ryVeryVeryVeryVeryVery" +# "VeryLongString"; +BreakStringLiterals: true +ColumnLimit: 100 + +# false: +# namespace Foo { +# namespace Bar { +# } +# } +CompactNamespaces: false + +# true: false: +# vector x{1, 2, 3, 4}; vs. vector x{ 1, 2, 3, 4 }; +# vector x{{}, {}, {}, {}}; vector x{ {}, {}, {}, {} }; +# f(MyMap[{composite, key}]); f(MyMap[{ composite, key }]); +# new int[3]{1, 2, 3}; new int[3]{ 1, 2, 3 }; +Cpp11BracedListStyle: true + +# Analyze the formatted file for the most used line ending (\r\n or \n). UseCRLF +# is only used as a fallback if none can be derived. +DeriveLineEnding: true +DerivePointerAlignment: true # As per DeriveLineEnding except for pointers and references + +# Add empty line only when access modifier starts a new logical block. Logical +# block is a group of one or more member fields or functions. +# +# struct foo { +# private: +# int i; +# +# protected: +# int j; +# /* comment */ +# public: +# foo() {} +# +# private: +# protected: +# }; +EmptyLineBeforeAccessModifier: LogicalBlock + +# true: false: +# namespace a { vs. namespace a { +# foo(); foo(); +# bar(); bar(); +# } // namespace a } +FixNamespaceComments: true + +# false: true: +# class C { vs. class C { +# class D { class D { +# void bar(); void bar(); +# protected: protected: +# D(); D(); +# }; }; +# public: public: +# C(); C(); +# }; }; +# void foo() { void foo() { +# return 1; return 1; +# } } +IndentAccessModifiers: false + +# false: true: +# switch (fool) { vs. switch (fool) { +# case 1: { case 1: +# bar(); { +# } break; bar(); +# default: { } +# plop(); break; +# } default: +# } { +# plop(); +# } +# } +IndentCaseBlocks: false + +# false: true: +# switch (fool) { vs. switch (fool) { +# case 1: case 1: +# bar(); bar(); +# break; break; +# default: default: +# plop(); plop(); +# } } +IndentCaseLabels: true + +# extern "C" { +# void foo(); +# } +IndentExternBlock: NoIndent + +# Indents directives before the hash. +# +# #if FOO +# #if BAR +# #include +# #endif +# #endif +IndentPPDirectives: BeforeHash + +# true: false: +# if (foo) { vs. if (foo) { +# bar(); +# bar(); } +# } +KeepEmptyLinesAtTheStartOfBlocks: false + +# The maximum number of consecutive empty lines to keep. +# +# MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0 +# int f() { int f() { +# int = 1; int i = 1; +# i = foo(); +# i = foo(); return i; +# } +# return i; +# } +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None + +# Put all constructor initializers on the current line if they fit. Otherwise, +# put each one on its own line. +# +# Constructor() : a(), b() +# +# Constructor() +# : aaaaaaaaaaaaaaaaaaaa(), +# bbbbbbbbbbbbbbbbbbbb(), +# ddddddddddddd() +PackConstructorInitializers: CurrentLine +PointerAlignment: Right + +# false: +# // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information +# /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ +# +# true: +# // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of +# // information +# /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of +# * information */ +ReflowComments: true + +# false: true: +# +# if (isa(D)) { vs. if (isa(D)) +# handleFunctionDecl(D); handleFunctionDecl(D); +# } else if (isa(D)) { else if (isa(D)) +# handleVarDecl(D); handleVarDecl(D); +# } +# +# if (isa(D)) { vs. if (isa(D)) { +# for (auto *A : D.attrs()) { for (auto *A : D.attrs()) +# if (shouldProcessAttr(A)) { if (shouldProcessAttr(A)) +# handleAttr(A); handleAttr(A); +# } } +# } +# } +# +# if (isa(D)) { vs. if (isa(D)) +# for (auto *A : D.attrs()) { for (auto *A : D.attrs()) +# handleAttr(A); handleAttr(A); +# } +# } +# +# if (auto *D = (T)(D)) { vs. if (auto *D = (T)(D)) { +# if (shouldProcess(D)) { if (shouldProcess(D)) +# handleVarDecl(D); handleVarDecl(D); +# } else { else +# markAsIgnored(D); markAsIgnored(D); +# } } +# } +# +# if (a) { vs. if (a) +# b(); b(); +# } else { else if (c) +# if (c) { d(); +# d(); else +# } else { e(); +# e(); +# } +# } +RemoveBracesLLVM: true + +# Never v.s. Always +# #include #include +# struct Foo { +# int a, b, c; struct Foo { +# }; int a, b, c; +# namespace Ns { }; +# class Bar { +# public: namespace Ns { +# struct Foobar { class Bar { +# int a; public: +# int b; struct Foobar { +# }; int a; +# private: int b; +# int t; }; +# int method1() { +# // ... private: +# } int t; +# enum List { +# ITEM1, int method1() { +# ITEM2 // ... +# }; } +# template +# int method2(T x) { enum List { +# // ... ITEM1, +# } ITEM2 +# int i, j, k; }; +# int method3(int par) { +# // ... template +# } int method2(T x) { +# }; // ... +# class C {}; } +# } +# int i, j, k; +# +# int method3(int par) { +# // ... +# } +# }; +# +# class C {}; +# } +SeparateDefinitionBlocks: Always + +# true: false: +# int a = 5; vs. int a= 5; +# a += 42; a+= 42; +SpaceBeforeAssignmentOperators: true + +# Put a space before opening parentheses only after control statement keywords +# (for/if/while...). +# +# void f() { +# if (true) { +# f(); +# } +# } +SpaceBeforeParens: ControlStatements +SpacesBeforeTrailingComments: 1 + +# static_cast(arg); +# std::function fct; +SpacesInAngles: Never + +Standard: Auto + +# Macros which are ignored in front of a statement, as if they were an +# attribute. So that they are not parsed as identifier, for example for Qts +# emit. +# unsigned char data = 'x'; +# emit signal(data); // This is parsed as variable declaration. +# +# vs. +# +# unsigned char data = 'x'; +# emit signal(data); // Now it's fine again. +StatementAttributeLikeMacros: [emit] +--- diff --git a/dqn.h b/dqn.h index 4331805..9f1f296 100644 --- a/dqn.h +++ b/dqn.h @@ -169,6 +169,7 @@ // [$BSTK] b_stacktrace | | Generating call stacktraces // [$OS_H] OS Headers | | Headers from the operating system // [$STBS] stb_sprintf | | Portable sprintf +#include "dqn_win32.h" #include "dqn_external.h" // NOTE: Additional Configuration @@ -211,11 +212,6 @@ // // DQN_MEMSET_BYTE // -// - Override the stack trace dump functionality on invocation of this macro. -// Currently this is only used in asserts. -// -// DQN_DUMP_STACK_TRACE -// // - Define this macro to enable emory leak tracking when requesting memory // from the OS via this library. For example calls to Dqn_VMem_Reserve or // DQN_ALLOC are recorded to the leak table. diff --git a/dqn_containers.h b/dqn_containers.h index 66e8668..28d13d8 100644 --- a/dqn_containers.h +++ b/dqn_containers.h @@ -939,7 +939,7 @@ DQN_API template void Dqn_FArray_Clear(Dqn_FArray DQN_API Dqn_List Dqn_List_InitWithArena(Dqn_Arena *arena, Dqn_usize chunk_size) +template DQN_API Dqn_List Dqn_List_Init(Dqn_Arena *arena, Dqn_usize chunk_size) { Dqn_List result = {}; result.arena = arena; diff --git a/dqn_debug.cpp b/dqn_debug.cpp index 88ab58b..363370f 100644 --- a/dqn_debug.cpp +++ b/dqn_debug.cpp @@ -1,5 +1,5 @@ // NOTE: [$ASAN] Dqn_Asan ========================================================================== === -void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) +DQN_API void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) { #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) __asan_poison_memory_region(ptr, size); @@ -12,7 +12,7 @@ void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) #endif } -void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) +DQN_API void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) { #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) __asan_unpoison_memory_region(ptr, size); @@ -24,22 +24,145 @@ void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) #endif } -// NOTE: [$DEBG] Dqn_Debug ========================================================================= -DQN_API Dqn_String8 Dqn_Debug_CleanStackTrace(Dqn_String8 stack_trace) +DQN_API Dqn_StackTraceWalkResult Dqn_StackTrace_Walk(Dqn_Arena *arena, uint16_t limit) { - // NOTE: Remove the stacktrace's library invocations from the stack trace - // which just adds noise to the actual trace we want to look at, e.g: - // - // dqn\b_stacktrace.h(198): b_stacktrace_get - // dqn\b_stacktrace.h(156): b_stacktrace_get_string + Dqn_StackTraceWalkResult result = {}; + #if defined(DQN_OS_WIN32) + if (!arena) + return result; - Dqn_String8BinarySplitResult split_line0 = Dqn_String8_BinarySplit(stack_trace, DQN_STRING8("\n")); - Dqn_String8BinarySplitResult split_line1 = Dqn_String8_BinarySplit(split_line0.rhs, DQN_STRING8("\n")); + static Dqn_TicketMutex mutex = {}; + Dqn_TicketMutex_Begin(&mutex); - Dqn_String8 result = split_line1.rhs; + HANDLE thread = GetCurrentThread(); + result.process = GetCurrentProcess(); + + for (static bool init = false; !init; init = true) { + SymSetOptions(SYMOPT_LOAD_LINES); + if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) { + Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); + Dqn_WinError error = Dqn_Win_LastError(scratch.arena); + Dqn_Log_ErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DQN_STRING_FMT(error.msg)); + } + } + + CONTEXT context; + RtlCaptureContext(&context); + + STACKFRAME64 frame = {}; + 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; + + Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena); + Dqn_List raw_frames = Dqn_List_Init(scratch.arena, 32 /*chunk size*/); + + while (raw_frames.count < limit) { + if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, + result.process, + thread, + &frame, + &context, + nullptr /*ReadMemoryRoutine*/, + SymFunctionTableAccess64, + SymGetModuleBase64, + nullptr /*TranslateAddress*/)) { + break; + } + + // NOTE: It might be useful one day to use frame.AddrReturn.Offset. + // If AddrPC.Offset == AddrReturn.Offset then we can detect recursion. + Dqn_List_Add(&raw_frames, frame.AddrPC.Offset); + } + Dqn_TicketMutex_End(&mutex); + + result.base_addr = Dqn_Arena_NewArray(arena, uint64_t, raw_frames.count, Dqn_ZeroMem_No); + for (Dqn_ListChunk *chunk = raw_frames.head; chunk; chunk = chunk->next) { + DQN_MEMCPY(result.base_addr + result.size, chunk->data, sizeof(*chunk->data) * chunk->count); + result.size += DQN_CAST(uint16_t)chunk->count; + } + #else + (void)limit; (void)arena; + #endif return result; } +DQN_API bool Dqn_StackTrace_WalkResultIterate(Dqn_StackTraceWalkResultIterator *it, Dqn_StackTraceWalkResult *walk) +{ + bool result = false; + if (!it || !walk || !walk->base_addr || !walk->process) + return result; + + if (it->index >= walk->size) + return false; + + result = true; + it->raw_frame.process = walk->process; + it->raw_frame.base_addr = walk->base_addr[it->index++]; + return result; +} + +DQN_API Dqn_StackTraceFrame Dqn_StackTrace_RawFrameToFrame(Dqn_Arena *arena, Dqn_StackTraceRawFrame raw_frame) +{ + #if defined(DQN_OS_WIN32) + // NOTE: Get line+filename ===================================================================== + + // TODO: Why does zero-initialising this with `line = {};` cause + // SymGetLineFromAddr64 function to fail once we are at + // __scrt_commain_main_seh and hit BaseThreadInitThunk frame? The + // line and file number are still valid in the result which we use, so, + // we silently ignore this error. + IMAGEHLP_LINEW64 line; + line.SizeOfStruct = sizeof(line); + DWORD line_displacement = 0; + SymGetLineFromAddrW64(raw_frame.process, raw_frame.base_addr, &line_displacement, &line); + + // NOTE: Get function name ===================================================================== + + alignas(SYMBOL_INFOW) char buffer[sizeof(SYMBOL_INFOW) + (MAX_SYM_NAME * sizeof(wchar_t))] = {}; + SYMBOL_INFOW *symbol = DQN_CAST(SYMBOL_INFOW *)buffer; + symbol->SizeOfStruct = sizeof(*symbol); + symbol->MaxNameLen = sizeof(buffer) - sizeof(*symbol); + + uint64_t symbol_displacement = 0; // Offset to the beginning of the symbol to the address + SymFromAddrW(raw_frame.process, raw_frame.base_addr, &symbol_displacement, symbol); + + // NOTE: Construct result ====================================================================== + + Dqn_String16 file_name16 = Dqn_String16{line.FileName, Dqn_CString16_Size(line.FileName)}; + Dqn_String16 function_name16 = Dqn_String16{symbol->Name, symbol->NameLen}; + + Dqn_StackTraceFrame result = {}; + result.address = raw_frame.base_addr; + result.line_number = line.LineNumber; + result.file_name = Dqn_Win_String16ToString8(arena, file_name16); + result.function_name = Dqn_Win_String16ToString8(arena, function_name16); + #else + Dqn_StackTraceFrame result = {}; + #endif + return result; +} + +DQN_API Dqn_StackTraceFrames Dqn_StackTrace_GetFrames(Dqn_Arena *arena, uint16_t limit) +{ + Dqn_StackTraceFrames result = {}; + Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena); + Dqn_StackTraceWalkResult walk = Dqn_StackTrace_Walk(scratch.arena, limit); + + if (!walk.size) + return result; + + result.data = Dqn_Arena_NewArray(arena, Dqn_StackTraceFrame, walk.size, Dqn_ZeroMem_No); + for (Dqn_StackTraceWalkResultIterator it = {}; Dqn_StackTrace_WalkResultIterate(&it, &walk); ) { + result.data[result.size++] = Dqn_StackTrace_RawFrameToFrame(arena, it.raw_frame); + } + return result; +} + +// NOTE: [$DEBG] Dqn_Debug ========================================================================= #if defined(DQN_LEAK_TRACING) DQN_API void Dqn_Debug_TrackAlloc_(Dqn_String8 stack_trace, void *ptr, Dqn_usize size, bool leak_permitted) { diff --git a/dqn_debug.h b/dqn_debug.h index 77eda87..552bb7d 100644 --- a/dqn_debug.h +++ b/dqn_debug.h @@ -20,14 +20,9 @@ #define DQN_MEMSET_BYTE 0 #endif +// TODO(doyle): Use our new stacktrace library #if !defined(DQN_DUMP_STACK_TRACE) - #define DQN_DUMP_STACK_TRACE \ - do { \ - Dqn_String8 stack_trace_ = Dqn_String8_InitCString8(b_stacktrace_get_string()); \ - Dqn_String8 clean_stack_trace_ = Dqn_Debug_CleanStackTrace(stack_trace_); \ - Dqn_Print_StdF(Dqn_PrintStd_Err, "%.*s", DQN_STRING_FMT(clean_stack_trace_)); \ - free(stack_trace_.data); \ - } while (0) + #define DQN_DUMP_STACK_TRACE #endif #if !defined(DQN_ASAN_POISON) @@ -57,8 +52,47 @@ static_assert(Dqn_IsPowerOfTwoAligned(DQN_ASAN_POISON_GUARD_SIZE, DQN_ASAN_POISO #include #endif -void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size); -void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size); +DQN_API void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size); +DQN_API void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size); + +// NOTE: [$STKT] Dqn_StackTrace ==================================================================== +struct Dqn_StackTraceFrame +{ + uint64_t address; + uint64_t line_number; + Dqn_String8 file_name; + Dqn_String8 function_name; +}; + +struct Dqn_StackTraceRawFrame +{ + void *process; + uint64_t base_addr; +}; + +struct Dqn_StackTraceWalkResult +{ + void *process; + uint64_t *base_addr; + uint16_t size; +}; + +struct Dqn_StackTraceWalkResultIterator +{ + Dqn_StackTraceRawFrame raw_frame; + uint16_t index; +}; + +struct Dqn_StackTraceFrames +{ + Dqn_StackTraceFrame *data; + uint16_t size; +}; + +DQN_API Dqn_StackTraceWalkResult Dqn_StackTrace_Walk (Dqn_Arena *arena, uint16_t limit); +DQN_API bool Dqn_StackTrace_WalkResultIterate(Dqn_StackTraceWalkResultIterator *it, Dqn_StackTraceWalkResult *walk); +DQN_API Dqn_StackTraceFrames Dqn_StackTrace_GetFrames (Dqn_Arena *arena, uint16_t limit); +DQN_API Dqn_StackTraceFrame Dqn_StackTrace_RawFrameToFrame (Dqn_Arena *arena, Dqn_StackTraceRawFrame raw_frame); // NOTE: [$CALL] Dqn_CallSite ====================================================================== struct Dqn_CallSite @@ -93,8 +127,6 @@ static_assert(sizeof(Dqn_AllocRecord) == 48, "memory tracking can get expensive. Enforce that there is no " "unexpected padding."); -DQN_API Dqn_String8 Dqn_Debug_CleanStackTrace(Dqn_String8 stack_trace); - #if defined(DQN_LEAK_TRACING) #define Dqn_Debug_TrackAlloc(ptr, size, leak_permitted) Dqn_Debug_TrackAlloc_ (Dqn_String8_InitCString8(b_stacktrace_get_string()), ptr, size, leak_permitted) #define Dqn_Debug_TrackDealloc(ptr) Dqn_Debug_TrackDealloc_(Dqn_String8_InitCString8(b_stacktrace_get_string()), ptr) diff --git a/dqn_external.cpp b/dqn_external.cpp index a410b99..5a6890d 100644 --- a/dqn_external.cpp +++ b/dqn_external.cpp @@ -1,12 +1,3 @@ -// NOTE: [$BSTK] b_stacktrace ====================================================================== -DQN_MSVC_WARNING_PUSH -DQN_MSVC_WARNING_DISABLE(6308) // b_stacktrace.h|147 'realloc' might return null pointer: assigning null pointer to 'b->buf', which is passed as an argument to 'realloc', will cause the original memory block to be leaked. -DQN_MSVC_WARNING_DISABLE(6011) // b_stacktrace.h|244 Dereferencing NULL pointer 'cur'. : Lines: 183, 184, 185, 186, 187, 188, 189, 191, 196, 198, 208, 209, 210, 211, 212, 213, 214, 229, 230, 231, 237, 244 -DQN_MSVC_WARNING_DISABLE(6387) // b_stacktrace.h|284 'symbol' could be '0'.: Lines: 256, 257, 258, 259, 260, 261, 262, 264, 265, 266, 267, 268, 270, 276, 281, 282, 284 -#define B_STACKTRACE_IMPL -#include "b_stacktrace.h" -DQN_MSVC_WARNING_POP - // NOTE: [$STBS] stb_sprintf ======================================================================= #if !defined(DQN_STB_SPRINTF_HEADER_ONLY) #define STB_SPRINTF_IMPLEMENTATION diff --git a/dqn_external.h b/dqn_external.h index 8ea1654..58325b6 100644 --- a/dqn_external.h +++ b/dqn_external.h @@ -1,368 +1,5 @@ -// NOTE: [$BSTK] b_stacktrace ====================================================================== -#if defined(DQN_OS_WIN32) - #define DQN_NO_WIN32_MIN_HEADER - #define WIN32_MEAN_AND_LEAN - #include - #include -#endif - -#define B_STACKTRACE_API static -#include "b_stacktrace.h" - // NOTE: [$OS_H] OS Headers ======================================================================== -#if defined(DQN_OS_WIN32) - #pragma comment(lib, "bcrypt") - #pragma comment(lib, "wininet") - - #if defined(DQN_NO_WIN32_MIN_HEADER) - #include // Dqn_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc - #include // Dqn_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc - #if !defined(DQN_NO_WINNET) - DQN_MSVC_WARNING_PUSH - DQN_MSVC_WARNING_DISABLE(6553) // wininet.h|940 warning| The annotation for function 'InternetConnectA' on _Param_(8) does not apply to a value type. - #include // Dqn_Win_Net -> InternetConnect ... etc - DQN_MSVC_WARNING_POP - #endif // DQN_NO_WINNET - #elif !defined(_INC_WINDOWS) - DQN_MSVC_WARNING_PUSH - DQN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union - #define MAX_PATH 260 - - // NOTE: Wait/Synchronization - #define INFINITE 0xFFFFFFFF // Infinite timeout - - // NOTE: FormatMessageA - #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 - #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 - #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 - #define MAKELANGID(p, s) ((((unsigned short )(s)) << 10) | (unsigned short )(p)) - #define SUBLANG_DEFAULT 0x01 // user default - #define LANG_NEUTRAL 0x00 - - // NOTE: MultiByteToWideChar - #define CP_UTF8 65001 // UTF-8 translation - - // NOTE: VirtualAlloc - // NOTE: Allocation Type - #define MEM_RESERVE 0x00002000 - #define MEM_COMMIT 0x00001000 - #define MEM_DECOMMIT 0x00004000 - #define MEM_RELEASE 0x00008000 - - // NOTE: Protect - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_GUARD 0x100 - - // NOTE: FindFirstFile - #define INVALID_HANDLE_VALUE ((void *)(long *)-1) - #define INVALID_FILE_ATTRIBUTES ((unsigned long)-1) - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 - #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_HIDDEN 0x00000002 - - // NOTE: GetModuleFileNameW - #define ERROR_INSUFFICIENT_BUFFER 122L - - // NOTE: MoveFile - #define MOVEFILE_REPLACE_EXISTING 0x00000001 - #define MOVEFILE_COPY_ALLOWED 0x00000002 - - // NOTE: Wininet - typedef unsigned short INTERNET_PORT; - #define INTERNET_OPEN_TYPE_PRECONFIG 0 // use registry configuration - #define INTERNET_DEFAULT_HTTPS_PORT 443 // HTTPS - #define INTERNET_SERVICE_HTTP 3 - #define INTERNET_OPTION_USER_AGENT 41 - #define INTERNET_FLAG_NO_AUTH 0x00040000 // no automatic authentication handling - #define INTERNET_FLAG_SECURE 0x00800000 // use PCT/SSL if applicable (HTTP) - - // NOTE: CreateFile - #define GENERIC_READ (0x80000000L) - #define GENERIC_WRITE (0x40000000L) - #define GENERIC_EXECUTE (0x20000000L) - #define GENERIC_ALL (0x10000000L) - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - #define FILE_APPEND_DATA 4 - - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - - #define STD_INPUT_HANDLE ((unsigned long)-10) - #define STD_OUTPUT_HANDLE ((unsigned long)-11) - #define STD_ERROR_HANDLE ((unsigned long)-12) - - #define INVALID_FILE_SIZE ((unsigned long)0xFFFFFFFF) - - #define HTTP_QUERY_RAW_HEADERS 21 - #define HTTP_QUERY_RAW_HEADERS_CRLF 22 - - // NOTE: HttpAddRequestHeadersA - #define HTTP_ADDREQ_FLAG_ADD_IF_NEW 0x10000000 - #define HTTP_ADDREQ_FLAG_ADD 0x20000000 - #define HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA 0x40000000 - #define HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON 0x01000000 - #define HTTP_ADDREQ_FLAG_COALESCE HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA - #define HTTP_ADDREQ_FLAG_REPLACE 0x80000000 - - #define SW_MAXIMIZED 3 - #define SW_SHOW 5 - - typedef enum PROCESS_DPI_AWARENESS { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 - } PROCESS_DPI_AWARENESS; - - #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void *)-4) - - typedef union { - struct { - unsigned long LowPart; - unsigned long HighPart; - } DUMMYSTRUCTNAME; - struct { - unsigned long LowPart; - unsigned long HighPart; - } u; - uint64_t QuadPart; - } ULARGE_INTEGER; - - typedef struct - { - unsigned long dwLowDateTime; - unsigned long dwHighDateTime; - } FILETIME; - - typedef struct - { - unsigned long dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - unsigned long nFileSizeHigh; - unsigned long nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA; - - typedef enum - { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - - typedef struct { - unsigned long nLength; - void *lpSecurityDescriptor; - bool bInheritHandle; - } SECURITY_ATTRIBUTES; - - typedef struct { - long left; - long top; - long right; - long bottom; - } RECT, *PRECT, *NPRECT, *LPRECT; - - typedef struct { - union { - unsigned long dwOemId; // Obsolete field...do not use - struct { - uint16_t wProcessorArchitecture; - uint16_t wReserved; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - unsigned long dwPageSize; - void *lpMinimumApplicationAddress; - void *lpMaximumApplicationAddress; - unsigned long *dwActiveProcessorMask; - unsigned long dwNumberOfProcessors; - unsigned long dwProcessorType; - unsigned long dwAllocationGranularity; - uint16_t wProcessorLevel; - uint16_t wProcessorRevision; - } SYSTEM_INFO; - - typedef struct { - unsigned short wYear; - unsigned short wMonth; - unsigned short wDayOfWeek; - unsigned short wDay; - unsigned short wHour; - unsigned short wMinute; - unsigned short wSecond; - unsigned short wMilliseconds; - } SYSTEMTIME; - - typedef struct { - unsigned long dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - unsigned long nFileSizeHigh; - unsigned long nFileSizeLow; - unsigned long dwReserved0; - unsigned long dwReserved1; - wchar_t cFileName[MAX_PATH]; - wchar_t cAlternateFileName[14]; - #ifdef _MAC - unsigned long dwFileType; - unsigned long dwCreatorType; - unsigned short wFinderFlags; - #endif - } WIN32_FIND_DATAW; - - typedef enum { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel, - } FINDEX_INFO_LEVELS; - - typedef enum { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - - typedef enum { - INTERNET_SCHEME_PARTIAL = -2, - INTERNET_SCHEME_UNKNOWN = -1, - INTERNET_SCHEME_DEFAULT = 0, - INTERNET_SCHEME_FTP, - INTERNET_SCHEME_GOPHER, - INTERNET_SCHEME_HTTP, - INTERNET_SCHEME_HTTPS, - INTERNET_SCHEME_FILE, - INTERNET_SCHEME_NEWS, - INTERNET_SCHEME_MAILTO, - INTERNET_SCHEME_SOCKS, - INTERNET_SCHEME_JAVASCRIPT, - INTERNET_SCHEME_VBSCRIPT, - INTERNET_SCHEME_RES, - INTERNET_SCHEME_FIRST = INTERNET_SCHEME_FTP, - INTERNET_SCHEME_LAST = INTERNET_SCHEME_RES - } INTERNET_SCHEME; - - typedef struct { - unsigned long dwStructSize; // size of this structure. Used in version check - char *lpszScheme; // pointer to scheme name - unsigned long dwSchemeLength; // length of scheme name - INTERNET_SCHEME nScheme; // enumerated scheme type (if known) - char *lpszHostName; // pointer to host name - unsigned long dwHostNameLength; // length of host name - INTERNET_PORT nPort; // converted port number - char *lpszUserName; // pointer to user name - unsigned long dwUserNameLength; // length of user name - char *lpszPassword; // pointer to password - unsigned long dwPasswordLength; // length of password - char *lpszUrlPath; // pointer to URL-path - unsigned long dwUrlPathLength; // length of URL-path - char *lpszExtraInfo; // pointer to extra information (e.g. ?foo or #foo) - unsigned long dwExtraInfoLength; // length of extra information - } URL_COMPONENTSA; - - typedef void * HMODULE; - typedef union { - struct { - unsigned long LowPart; - long HighPart; - }; - struct { - unsigned long LowPart; - long HighPart; - } u; - uint64_t QuadPart; - } LARGE_INTEGER; - - extern "C" - { - /*BOOL*/ int __stdcall CreateDirectoryW (wchar_t const *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); - /*BOOL*/ int __stdcall RemoveDirectoryW (wchar_t const *lpPathName); - /*DWORD*/ unsigned long __stdcall GetCurrentDirectoryW (unsigned long nBufferLength, wchar_t *lpBuffer); - - /*BOOL*/ int __stdcall FindNextFileW (void *hFindFile, WIN32_FIND_DATAW *lpFindFileData); - /*HANDLE*/ void * __stdcall FindFirstFileExW (wchar_t const *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, void *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, void *lpSearchFilter, unsigned long dwAdditionalFlags); - /*DWORD*/ unsigned long __stdcall GetFileAttributesExW (wchar_t const *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, WIN32_FILE_ATTRIBUTE_DATA *lpFileInformation); - /*BOOL*/ int __stdcall GetFileSizeEx (void *hFile, LARGE_INTEGER *lpFileSize); - - /*BOOL*/ int __stdcall MoveFileExW (wchar_t const *lpExistingFileName, wchar_t const *lpNewFileName, unsigned long dwFlags); - /*BOOL*/ int __stdcall CopyFileW (wchar_t const *lpExistingFileName, wchar_t const *lpNewFileName, int bFailIfExists); - /*BOOL*/ int __stdcall DeleteFileW (wchar_t const *lpExistingFileName); - /*HANDLE*/ void * __stdcall CreateFileW (wchar_t const *lpFileName, unsigned long dwDesiredAccess, unsigned long dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, unsigned long dwCreationDisposition, unsigned long dwFlagsAndAttributes, void *hTemplateFile); - /*BOOL*/ int __stdcall ReadFile (void *hFile, void *lpBuffer, unsigned long nNumberOfBytesToRead, unsigned long *lpNumberOfBytesRead, struct OVERLAPPED *lpOverlapped); - /*BOOL*/ int __stdcall WriteFile (void *hFile, void const *lpBuffer, unsigned long nNumberOfBytesToWrite, unsigned long *lpNumberOfBytesWritten, struct OVERLAPPED *lpOverlapped); - /*BOOL*/ int __stdcall CloseHandle (void *hObject); - - /*BOOL*/ int __stdcall WriteConsoleA (void *hConsoleOutput, const char *lpBuffer, unsigned long nNumberOfCharsToWrite, unsigned long *lpNumberOfCharsWritten, void *lpReserved); - /*BOOL*/ int __stdcall AllocConsole (); - /*BOOL*/ int __stdcall FreeConsole (); - /*BOOL*/ int __stdcall AttachConsole (unsigned long dwProcessId); - /*HANDLE*/ void * __stdcall GetStdHandle (unsigned long nStdHandle); - /*BOOL*/ int __stdcall GetConsoleMode (void *hConsoleHandle, unsigned long *lpMode); - - /*HMODULE*/ void * __stdcall LoadLibraryA (char const *lpFileName); - /*BOOL*/ int __stdcall FreeLibrary (void *hModule); - /*FARPROC*/ void * __stdcall GetProcAddress (void *hModule, char const *lpProcName); - - /*BOOL*/ int __stdcall GetWindowRect (void *hWnd, RECT *lpRect); - /*BOOL*/ int __stdcall SetWindowPos (void *hWnd, void *hWndInsertAfter, int X, int Y, int cx, int cy, unsigned int uFlags); - - /*DWORD*/ unsigned long __stdcall GetWindowModuleFileNameA (void *hwnd, char *pszFileName, unsigned int cchFileNameMax); - /*HMODULE*/ void * __stdcall GetModuleHandleA (char const *lpModuleName); - /*DWORD*/ unsigned long __stdcall GetModuleFileNameW (void *hModule, wchar_t *lpFilename, unsigned long nSize); - - /*DWORD*/ unsigned long __stdcall WaitForSingleObject (void *hHandle, unsigned long dwMilliseconds); - - /*BOOL*/ int __stdcall QueryPerformanceCounter (LARGE_INTEGER *lpPerformanceCount); - /*BOOL*/ int __stdcall QueryPerformanceFrequency (LARGE_INTEGER *lpFrequency); - - /*HANDLE*/ void * __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, size_t dwStackSize, unsigned long (*lpStartAddress)(void *), void *lpParameter, unsigned long dwCreationFlags, unsigned long *lpThreadId); - /*HANDLE*/ void * __stdcall CreateSemaphoreA (SECURITY_ATTRIBUTES *lpSecurityAttributes, long lInitialCount, long lMaxCount, char *lpName); - /*BOOL*/ int __stdcall ReleaseSemaphore (void *semaphore, long lReleaseCount, long *lpPreviousCount); - void __stdcall Sleep (unsigned long dwMilliseconds); - /*DWORD*/ unsigned long __stdcall GetCurrentThreadId (); - - void * __stdcall VirtualAlloc (void *lpAddress, size_t dwSize, unsigned long flAllocationType, unsigned long flProtect); - /*BOOL*/ int __stdcall VirtualProtect (void *lpAddress, size_t dwSize, unsigned long flNewProtect, unsigned long *lpflOldProtect); - /*BOOL*/ int __stdcall VirtualFree (void *lpAddress, size_t dwSize, unsigned long dwFreeType); - - void __stdcall GetSystemInfo (SYSTEM_INFO *system_info); - void __stdcall GetSystemTime (SYSTEMTIME *lpSystemTime); - void __stdcall GetSystemTimeAsFileTime (FILETIME *lpFileTime); - void __stdcall GetLocalTime (SYSTEMTIME *lpSystemTime); - - /*DWORD*/ unsigned long __stdcall FormatMessageA (unsigned long dwFlags, void *lpSource, unsigned long dwMessageId, unsigned long dwLanguageId, char *lpBuffer, unsigned long nSize, va_list *Arguments); - /*DWORD*/ unsigned long __stdcall GetLastError (); - - int __stdcall MultiByteToWideChar (unsigned int CodePage, unsigned long dwFlags, char const *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); - int __stdcall WideCharToMultiByte (unsigned int CodePage, unsigned long dwFlags, wchar_t const *lpWideCharStr, int cchWideChar, char *lpMultiByteStr, int cbMultiByte, char const *lpDefaultChar, bool *lpUsedDefaultChar); - - /*NTSTATUS*/ long __stdcall BCryptOpenAlgorithmProvider(void *phAlgorithm, wchar_t const *pszAlgId, wchar_t const *pszImplementation, unsigned long dwFlags); - /*NTSTATUS*/ long __stdcall BCryptGenRandom (void *hAlgorithm, unsigned char *pbBuffer, unsigned long cbBuffer, unsigned long dwFlags); - - /*BOOLAPI*/ int __stdcall InternetCrackUrlA (char const *lpszUrl, unsigned long dwUrlLength, unsigned long dwFlags, URL_COMPONENTSA *lpUrlComponents); - /*HANDLE*/ void * __stdcall InternetOpenA (char const *lpszAgent, unsigned long dwAccessType, char const *lpszProxy, char const *lpszProxyBypass, unsigned long dwFlags); - /*HANDLE*/ void * __stdcall InternetConnectA (void *hInternet, char const *lpszServerName, INTERNET_PORT nServerPort, char const *lpszUserName, char const *lpszPassword, unsigned long dwService, unsigned long dwFlags, unsigned long *dwContext); - /*BOOLAPI*/ int __stdcall InternetSetOptionA (void *hInternet, unsigned long dwOption, void *lpBuffer, unsigned long dwBufferLength); - /*BOOLAPI*/ int __stdcall InternetReadFile (void *hFile, void *lpBuffer, unsigned long dwNumberOfBytesToRead, unsigned long *lpdwNumberOfBytesRead); - /*BOOLAPI*/ int __stdcall InternetCloseHandle (void *hInternet); - /*HANDLE*/ void * __stdcall HttpOpenRequestA (void *hConnect, char const *lpszVerb, char const *lpszObjectName, char const *lpszVersion, char const *lpszReferrer, char const **lplpszAcceptTypes, unsigned long dwFlags, unsigned long *dwContext); - /*BOOLAPI*/ int __stdcall HttpSendRequestA (void *hRequest, char const *lpszHeaders, unsigned long dwHeadersLength, void *lpOptional, unsigned long dwOptionalLength); - /*BOOLAPI*/ int __stdcall HttpAddRequestHeadersA (void *hRequest, char const *lpszHeaders, unsigned long dwHeadersLength, unsigned long dwModifiers); - /*BOOL*/ int __stdcall HttpQueryInfoA (void *hRequest, unsigned long dwInfoLevel, void *lpBuffer, unsigned long *lpdwBufferLength, unsigned long *lpdwIndex); - - /*HINSTANCE*/ void * __stdcall ShellExecuteA (void *hwnd, char const *lpOperation, char const *lpFile, char const *lpParameters, char const *lpDirectory, int nShowCmd); - /*BOOL*/ int __stdcall ShowWindow (void *hWnd, int nCmdShow); - } - DQN_MSVC_WARNING_POP - #endif // !defined(_INC_WINDOWS) -#elif defined(DQN_OS_UNIX) +#if defined(DQN_OS_UNIX) #include // errno #include // O_RDONLY ... etc #include // FICLONE diff --git a/dqn_helpers.cpp b/dqn_helpers.cpp index e4b7f3e..82466cf 100644 --- a/dqn_helpers.cpp +++ b/dqn_helpers.cpp @@ -844,10 +844,12 @@ DQN_API Dqn_Library *Dqn_Library_Init() Dqn_Log_DebugF("Dqn Library initialised:\n"); Dqn_Print_StdLnF(Dqn_PrintStd_Err, " OS Page Size/Alloc Granularity: %$$_I32u/%$$_I32u", result->os_page_size, result->os_alloc_granularity); + #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) if (DQN_ASAN_POISON) { Dqn_Print_StdLnF(Dqn_PrintStd_Err, " ASAN manual poisoning%s", DQN_ASAN_VET_POISON ? " (+vet sanity checks)" : ""); Dqn_Print_StdLnF(Dqn_PrintStd_Err, " ASAN poison guard size: %$$_I32u", DQN_ASAN_POISON_GUARD_SIZE); } + #endif #if defined(DQN_LEAK_TRACING) Dqn_Print_StdLnF(Dqn_PrintStd_Err, " Allocation leak tracing"); @@ -857,6 +859,8 @@ DQN_API Dqn_Library *Dqn_Library_Init() Dqn_Print_StdLnF(Dqn_PrintStd_Err, " TSC profiler available"); #endif + // TODO(doyle): Add stacktrace feature log + Dqn_Print_StdLnF(Dqn_PrintStd_Err, ""); return result; } diff --git a/dqn_win32.h b/dqn_win32.h new file mode 100644 index 0000000..b1076a3 --- /dev/null +++ b/dqn_win32.h @@ -0,0 +1,627 @@ +#if defined(DQN_OS_WIN32) +#pragma comment(lib, "bcrypt") +#pragma comment(lib, "wininet") +#pragma comment(lib, "dbghelp") + +#if defined(DQN_NO_WIN32_MIN_HEADER) + #include // Dqn_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc + #include // Dqn_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc + #if !defined(DQN_NO_WINNET) + DQN_MSVC_WARNING_PUSH + DQN_MSVC_WARNING_DISABLE(6553) // wininet.h|940 warning| The annotation for function 'InternetConnectA' on _Param_(8) does not apply to a value type. + #include // Dqn_Win_Net -> InternetConnect ... etc + DQN_MSVC_WARNING_POP + #endif // DQN_NO_WINNET +#elif !defined(_INC_WINDOWS) + DQN_MSVC_WARNING_PUSH + DQN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union + + // NOTE: Windows typedefs ====================================================================== + typedef unsigned long DWORD; + typedef unsigned __int64 DWORD64; + typedef int BOOL; + typedef char CHAR; + typedef void* HANDLE; + typedef unsigned long ULONG; + typedef unsigned __int64 ULONG64; + typedef wchar_t WCHAR; + + // NOTE: Windows Defines ======================================================================= + #define MAX_PATH 260 + + // NOTE: Wait/Synchronization ================================================================== + #define INFINITE 0xFFFFFFFF // Infinite timeout + + // NOTE: FormatMessageA ======================================================================== + #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 + #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 + #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 + #define MAKELANGID(p, s) ((((unsigned short )(s)) << 10) | (unsigned short )(p)) + #define SUBLANG_DEFAULT 0x01 // user default + #define LANG_NEUTRAL 0x00 + + // NOTE: MultiByteToWideChar + #define CP_UTF8 65001 // UTF-8 translation + + // NOTE: VirtualAlloc ========================================================================== + // NOTE: Allocation Type + #define MEM_RESERVE 0x00002000 + #define MEM_COMMIT 0x00001000 + #define MEM_DECOMMIT 0x00004000 + #define MEM_RELEASE 0x00008000 + + // NOTE: Protect + #define PAGE_NOACCESS 0x01 + #define PAGE_READONLY 0x02 + #define PAGE_READWRITE 0x04 + #define PAGE_GUARD 0x100 + + // NOTE: FindFirstFile ========================================================================= + #define INVALID_HANDLE_VALUE ((void *)(long *)-1) + #define INVALID_FILE_ATTRIBUTES ((unsigned long)-1) + #define FILE_ATTRIBUTE_NORMAL 0x00000080 + #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 + #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 + #define FILE_ATTRIBUTE_READONLY 0x00000001 + #define FILE_ATTRIBUTE_HIDDEN 0x00000002 + + // NOTE: GetModuleFileNameW ==================================================================== + #define ERROR_INSUFFICIENT_BUFFER 122L + + // NOTE: MoveFile ============================================================================== + #define MOVEFILE_REPLACE_EXISTING 0x00000001 + #define MOVEFILE_COPY_ALLOWED 0x00000002 + + // NOTE: Wininet =============================================================================== + typedef unsigned short INTERNET_PORT; + #define INTERNET_OPEN_TYPE_PRECONFIG 0 // use registry configuration + #define INTERNET_DEFAULT_HTTPS_PORT 443 // HTTPS + #define INTERNET_SERVICE_HTTP 3 + #define INTERNET_OPTION_USER_AGENT 41 + #define INTERNET_FLAG_NO_AUTH 0x00040000 // no automatic authentication handling + #define INTERNET_FLAG_SECURE 0x00800000 // use PCT/SSL if applicable (HTTP) + + // NOTE: CreateFile ============================================================================ + #define GENERIC_READ (0x80000000L) + #define GENERIC_WRITE (0x40000000L) + #define GENERIC_EXECUTE (0x20000000L) + #define GENERIC_ALL (0x10000000L) + #define FILE_ATTRIBUTE_NORMAL 0x00000080 + #define FILE_APPEND_DATA 4 + + #define CREATE_NEW 1 + #define CREATE_ALWAYS 2 + #define OPEN_EXISTING 3 + #define OPEN_ALWAYS 4 + #define TRUNCATE_EXISTING 5 + + #define STD_INPUT_HANDLE ((unsigned long)-10) + #define STD_OUTPUT_HANDLE ((unsigned long)-11) + #define STD_ERROR_HANDLE ((unsigned long)-12) + + #define INVALID_FILE_SIZE ((unsigned long)0xFFFFFFFF) + + #define HTTP_QUERY_RAW_HEADERS 21 + #define HTTP_QUERY_RAW_HEADERS_CRLF 22 + + // NOTE: HttpAddRequestHeadersA ================================================================ + #define HTTP_ADDREQ_FLAG_ADD_IF_NEW 0x10000000 + #define HTTP_ADDREQ_FLAG_ADD 0x20000000 + #define HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA 0x40000000 + #define HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON 0x01000000 + #define HTTP_ADDREQ_FLAG_COALESCE HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA + #define HTTP_ADDREQ_FLAG_REPLACE 0x80000000 + + #define SW_MAXIMIZED 3 + #define SW_SHOW 5 + + // NOTE: Windows Structs ======================================================================= + typedef enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 + } PROCESS_DPI_AWARENESS; + + #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void *)-4) + + typedef union { + struct { + unsigned long LowPart; + unsigned long HighPart; + } DUMMYSTRUCTNAME; + struct { + unsigned long LowPart; + unsigned long HighPart; + } u; + uint64_t QuadPart; + } ULARGE_INTEGER; + + typedef struct + { + unsigned long dwLowDateTime; + unsigned long dwHighDateTime; + } FILETIME; + + typedef struct + { + unsigned long dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + unsigned long nFileSizeHigh; + unsigned long nFileSizeLow; + } WIN32_FILE_ATTRIBUTE_DATA; + + typedef enum + { + GetFileExInfoStandard, + GetFileExMaxInfoLevel + } GET_FILEEX_INFO_LEVELS; + + typedef struct { + unsigned long nLength; + void *lpSecurityDescriptor; + bool bInheritHandle; + } SECURITY_ATTRIBUTES; + + typedef struct { + long left; + long top; + long right; + long bottom; + } RECT, *PRECT, *NPRECT, *LPRECT; + + typedef struct { + union { + unsigned long dwOemId; // Obsolete field...do not use + struct { + uint16_t wProcessorArchitecture; + uint16_t wReserved; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + unsigned long dwPageSize; + void *lpMinimumApplicationAddress; + void *lpMaximumApplicationAddress; + unsigned long *dwActiveProcessorMask; + unsigned long dwNumberOfProcessors; + unsigned long dwProcessorType; + unsigned long dwAllocationGranularity; + uint16_t wProcessorLevel; + uint16_t wProcessorRevision; + } SYSTEM_INFO; + + typedef struct { + unsigned short wYear; + unsigned short wMonth; + unsigned short wDayOfWeek; + unsigned short wDay; + unsigned short wHour; + unsigned short wMinute; + unsigned short wSecond; + unsigned short wMilliseconds; + } SYSTEMTIME; + + typedef struct { + unsigned long dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + unsigned long nFileSizeHigh; + unsigned long nFileSizeLow; + unsigned long dwReserved0; + unsigned long dwReserved1; + wchar_t cFileName[MAX_PATH]; + wchar_t cAlternateFileName[14]; + #ifdef _MAC + unsigned long dwFileType; + unsigned long dwCreatorType; + unsigned short wFinderFlags; + #endif + } WIN32_FIND_DATAW; + + typedef enum { + FindExInfoStandard, + FindExInfoBasic, + FindExInfoMaxInfoLevel, + } FINDEX_INFO_LEVELS; + + typedef enum { + FindExSearchNameMatch, + FindExSearchLimitToDirectories, + FindExSearchLimitToDevices, + FindExSearchMaxSearchOp + } FINDEX_SEARCH_OPS; + + typedef enum { + INTERNET_SCHEME_PARTIAL = -2, + INTERNET_SCHEME_UNKNOWN = -1, + INTERNET_SCHEME_DEFAULT = 0, + INTERNET_SCHEME_FTP, + INTERNET_SCHEME_GOPHER, + INTERNET_SCHEME_HTTP, + INTERNET_SCHEME_HTTPS, + INTERNET_SCHEME_FILE, + INTERNET_SCHEME_NEWS, + INTERNET_SCHEME_MAILTO, + INTERNET_SCHEME_SOCKS, + INTERNET_SCHEME_JAVASCRIPT, + INTERNET_SCHEME_VBSCRIPT, + INTERNET_SCHEME_RES, + INTERNET_SCHEME_FIRST = INTERNET_SCHEME_FTP, + INTERNET_SCHEME_LAST = INTERNET_SCHEME_RES + } INTERNET_SCHEME; + + typedef struct { + unsigned long dwStructSize; // size of this structure. Used in version check + char *lpszScheme; // pointer to scheme name + unsigned long dwSchemeLength; // length of scheme name + INTERNET_SCHEME nScheme; // enumerated scheme type (if known) + char *lpszHostName; // pointer to host name + unsigned long dwHostNameLength; // length of host name + INTERNET_PORT nPort; // converted port number + char *lpszUserName; // pointer to user name + unsigned long dwUserNameLength; // length of user name + char *lpszPassword; // pointer to password + unsigned long dwPasswordLength; // length of password + char *lpszUrlPath; // pointer to URL-path + unsigned long dwUrlPathLength; // length of URL-path + char *lpszExtraInfo; // pointer to extra information (e.g. ?foo or #foo) + unsigned long dwExtraInfoLength; // length of extra information + } URL_COMPONENTSA; + + typedef void * HMODULE; + typedef union { + struct { + unsigned long LowPart; + long HighPart; + }; + struct { + unsigned long LowPart; + long HighPart; + } u; + uint64_t QuadPart; + } LARGE_INTEGER; + + // NOTE: minwinddef.h ========================================================================== + typedef unsigned long DWORD; + typedef int BOOL; + typedef int INT; + typedef unsigned int UINT; + typedef unsigned short WORD; + typedef unsigned char BYTE; + + // NOTE: winnt.h Typedefs ====================================================================== + typedef void VOID; + typedef __int64 LONGLONG; + typedef unsigned __int64 ULONGLONG; + + // NOTE: winnt.h Structs ======================================================================= + typedef struct __declspec(align(16)) _M128A { + ULONGLONG Low; + LONGLONG High; + } M128A, *PM128A; + + typedef struct __declspec(align(16)) _XSAVE_FORMAT { + WORD ControlWord; + WORD StatusWord; + BYTE TagWord; + BYTE Reserved1; + WORD ErrorOpcode; + DWORD ErrorOffset; + WORD ErrorSelector; + WORD Reserved2; + DWORD DataOffset; + WORD DataSelector; + WORD Reserved3; + DWORD MxCsr; + DWORD MxCsr_Mask; + M128A FloatRegisters[8]; + #if defined(_WIN64) + M128A XmmRegisters[16]; + BYTE Reserved4[96]; + #else + M128A XmmRegisters[8]; + BYTE Reserved4[224]; + #endif + } XSAVE_FORMAT, *PXSAVE_FORMAT; + typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; + + typedef struct __declspec(align(16)) _CONTEXT { + DWORD64 P1Home; + DWORD64 P2Home; + DWORD64 P3Home; + DWORD64 P4Home; + DWORD64 P5Home; + DWORD64 P6Home; + DWORD ContextFlags; + DWORD MxCsr; + WORD SegCs; + WORD SegDs; + WORD SegEs; + WORD SegFs; + WORD SegGs; + WORD SegSs; + DWORD EFlags; + DWORD64 Dr0; + DWORD64 Dr1; + DWORD64 Dr2; + DWORD64 Dr3; + DWORD64 Dr6; + DWORD64 Dr7; + DWORD64 Rax; + DWORD64 Rcx; + DWORD64 Rdx; + DWORD64 Rbx; + DWORD64 Rsp; + DWORD64 Rbp; + DWORD64 Rsi; + DWORD64 Rdi; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 Rip; + + union { + XMM_SAVE_AREA32 FltSave; + + struct { + M128A Header[2]; + M128A Legacy[8]; + M128A Xmm0; + M128A Xmm1; + M128A Xmm2; + M128A Xmm3; + M128A Xmm4; + M128A Xmm5; + M128A Xmm6; + M128A Xmm7; + M128A Xmm8; + M128A Xmm9; + M128A Xmm10; + M128A Xmm11; + M128A Xmm12; + M128A Xmm13; + M128A Xmm14; + M128A Xmm15; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + + M128A VectorRegister[26]; + DWORD64 VectorControl; + DWORD64 DebugControl; + DWORD64 LastBranchToRip; + DWORD64 LastBranchFromRip; + DWORD64 LastExceptionToRip; + DWORD64 LastExceptionFromRip; + } CONTEXT; + + // NOTE: winnt.h Defines ======================================================================= + #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) + + extern "C" + { + VOID __declspec(dllimport) __stdcall RtlCaptureContext(CONTEXT *ContextRecord); + HANDLE __declspec(dllimport) __stdcall GetCurrentProcess(void); + HANDLE __declspec(dllimport) __stdcall GetCurrentThread(void); + DWORD __declspec(dllimport) __stdcall SymSetOptions(DWORD SymOptions); + BOOL __declspec(dllimport) __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); + } + + // NOTE: DbgHelp.h ============================================================================= + + // NOTE: DbgHelp.h Defines ===================================================================== + #define SYMOPT_CASE_INSENSITIVE 0x00000001 + #define SYMOPT_UNDNAME 0x00000002 + #define SYMOPT_DEFERRED_LOADS 0x00000004 + #define SYMOPT_NO_CPP 0x00000008 + #define SYMOPT_LOAD_LINES 0x00000010 + #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 + #define SYMOPT_LOAD_ANYTHING 0x00000040 + #define SYMOPT_IGNORE_CVREC 0x00000080 + #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 + #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 + #define SYMOPT_EXACT_SYMBOLS 0x00000400 + #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 + #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 + #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 + #define SYMOPT_PUBLICS_ONLY 0x00004000 + #define SYMOPT_NO_PUBLICS 0x00008000 + #define SYMOPT_AUTO_PUBLICS 0x00010000 + #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 + #define SYMOPT_SECURE 0x00040000 + #define SYMOPT_NO_PROMPTS 0x00080000 + #define SYMOPT_OVERWRITE 0x00100000 + #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 + #define SYMOPT_FLAT_DIRECTORY 0x00400000 + #define SYMOPT_FAVOR_COMPRESSED 0x00800000 + #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 + #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 + #define SYMOPT_READONLY_CACHE 0x04000000 + #define SYMOPT_SYMPATH_LAST 0x08000000 + #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 + #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 + #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 + #define SYMOPT_DEBUG 0x80000000 + + #define MAX_SYM_NAME 2000 + + // NOTE: DbgHelp.h Structs ===================================================================== + typedef enum { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat + } ADDRESS_MODE; + + typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; + } ADDRESS64, *LPADDRESS64; + + + typedef struct _KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 KiUserExceptionDispatcher; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD BuildVersion; + DWORD RetpolineStubFunctionTableSize; + DWORD64 RetpolineStubFunctionTable; + DWORD RetpolineStubOffset; + DWORD RetpolineStubSize; + DWORD64 Reserved0[2]; + } KDHELP64, *PKDHELP64; + + typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; // program counter + ADDRESS64 AddrReturn; // return address + ADDRESS64 AddrFrame; // frame pointer + ADDRESS64 AddrStack; // stack pointer + ADDRESS64 AddrBStore; // backing store pointer + VOID *FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD64 Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD64 Reserved[3]; + KDHELP64 KdHelp; + } STACKFRAME64; + + typedef struct _IMAGEHLP_LINEW64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + VOID *Key; // internal + DWORD LineNumber; // line number in file + WCHAR *FileName; // full filename + DWORD64 Address; // first instruction of line + } IMAGEHLP_LINEW64; + + typedef struct _SYMBOL_INFOW { + ULONG SizeOfStruct; + ULONG TypeIndex; // Type Index of symbol + ULONG64 Reserved[2]; + ULONG Index; + ULONG Size; + ULONG64 ModBase; // Base Address of module comtaining this symbol + ULONG Flags; + ULONG64 Value; // Value of symbol, ValuePresent should be 1 + ULONG64 Address; // Address of symbol including base address of module + ULONG Register; // register holding value or pointer to value + ULONG Scope; // scope of the symbol + ULONG Tag; // pdb classification + ULONG NameLen; // Actual length of name + ULONG MaxNameLen; + WCHAR Name[1]; // Name of symbol + } SYMBOL_INFOW; + + // NOTE: DbgHelp.h Typedefs ==================================================================== + typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); + typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); + typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); + typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); + + // NOTE: DbgHelp.h Funtions ==================================================================== + extern "C" + { + __declspec(dllimport) BOOL __stdcall StackWalk64(DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); + __declspec(dllimport) BOOL __stdcall SymFromAddrW(HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); + __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); + __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); + __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64(HANDLE hProcess, DWORD64 qwAddr); + }; + + // NOTE: Windows.h =============================================================================== + extern "C" + { + /*BOOL*/ int __stdcall CreateDirectoryW (wchar_t const *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); + /*BOOL*/ int __stdcall RemoveDirectoryW (wchar_t const *lpPathName); + /*DWORD*/ unsigned long __stdcall GetCurrentDirectoryW (unsigned long nBufferLength, wchar_t *lpBuffer); + + /*BOOL*/ int __stdcall FindNextFileW (void *hFindFile, WIN32_FIND_DATAW *lpFindFileData); + /*HANDLE*/ void * __stdcall FindFirstFileExW (wchar_t const *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, void *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, void *lpSearchFilter, unsigned long dwAdditionalFlags); + /*DWORD*/ unsigned long __stdcall GetFileAttributesExW (wchar_t const *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, WIN32_FILE_ATTRIBUTE_DATA *lpFileInformation); + /*BOOL*/ int __stdcall GetFileSizeEx (void *hFile, LARGE_INTEGER *lpFileSize); + + /*BOOL*/ int __stdcall MoveFileExW (wchar_t const *lpExistingFileName, wchar_t const *lpNewFileName, unsigned long dwFlags); + /*BOOL*/ int __stdcall CopyFileW (wchar_t const *lpExistingFileName, wchar_t const *lpNewFileName, int bFailIfExists); + /*BOOL*/ int __stdcall DeleteFileW (wchar_t const *lpExistingFileName); + /*HANDLE*/ void * __stdcall CreateFileW (wchar_t const *lpFileName, unsigned long dwDesiredAccess, unsigned long dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, unsigned long dwCreationDisposition, unsigned long dwFlagsAndAttributes, void *hTemplateFile); + /*BOOL*/ int __stdcall ReadFile (void *hFile, void *lpBuffer, unsigned long nNumberOfBytesToRead, unsigned long *lpNumberOfBytesRead, struct OVERLAPPED *lpOverlapped); + /*BOOL*/ int __stdcall WriteFile (void *hFile, void const *lpBuffer, unsigned long nNumberOfBytesToWrite, unsigned long *lpNumberOfBytesWritten, struct OVERLAPPED *lpOverlapped); + /*BOOL*/ int __stdcall CloseHandle (void *hObject); + + /*BOOL*/ int __stdcall WriteConsoleA (void *hConsoleOutput, const char *lpBuffer, unsigned long nNumberOfCharsToWrite, unsigned long *lpNumberOfCharsWritten, void *lpReserved); + /*BOOL*/ int __stdcall AllocConsole (); + /*BOOL*/ int __stdcall FreeConsole (); + /*BOOL*/ int __stdcall AttachConsole (unsigned long dwProcessId); + /*HANDLE*/ void * __stdcall GetStdHandle (unsigned long nStdHandle); + /*BOOL*/ int __stdcall GetConsoleMode (void *hConsoleHandle, unsigned long *lpMode); + + /*HMODULE*/ void * __stdcall LoadLibraryA (char const *lpFileName); + /*BOOL*/ int __stdcall FreeLibrary (void *hModule); + /*FARPROC*/ void * __stdcall GetProcAddress (void *hModule, char const *lpProcName); + + /*BOOL*/ int __stdcall GetWindowRect (void *hWnd, RECT *lpRect); + /*BOOL*/ int __stdcall SetWindowPos (void *hWnd, void *hWndInsertAfter, int X, int Y, int cx, int cy, unsigned int uFlags); + + /*DWORD*/ unsigned long __stdcall GetWindowModuleFileNameA (void *hwnd, char *pszFileName, unsigned int cchFileNameMax); + /*HMODULE*/ void * __stdcall GetModuleHandleA (char const *lpModuleName); + /*DWORD*/ unsigned long __stdcall GetModuleFileNameW (void *hModule, wchar_t *lpFilename, unsigned long nSize); + + /*DWORD*/ unsigned long __stdcall WaitForSingleObject (void *hHandle, unsigned long dwMilliseconds); + + /*BOOL*/ int __stdcall QueryPerformanceCounter (LARGE_INTEGER *lpPerformanceCount); + /*BOOL*/ int __stdcall QueryPerformanceFrequency (LARGE_INTEGER *lpFrequency); + + /*HANDLE*/ void * __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, size_t dwStackSize, unsigned long (*lpStartAddress)(void *), void *lpParameter, unsigned long dwCreationFlags, unsigned long *lpThreadId); + /*HANDLE*/ void * __stdcall CreateSemaphoreA (SECURITY_ATTRIBUTES *lpSecurityAttributes, long lInitialCount, long lMaxCount, char *lpName); + /*BOOL*/ int __stdcall ReleaseSemaphore (void *semaphore, long lReleaseCount, long *lpPreviousCount); + void __stdcall Sleep (unsigned long dwMilliseconds); + /*DWORD*/ unsigned long __stdcall GetCurrentThreadId (); + + void * __stdcall VirtualAlloc (void *lpAddress, size_t dwSize, unsigned long flAllocationType, unsigned long flProtect); + /*BOOL*/ int __stdcall VirtualProtect (void *lpAddress, size_t dwSize, unsigned long flNewProtect, unsigned long *lpflOldProtect); + /*BOOL*/ int __stdcall VirtualFree (void *lpAddress, size_t dwSize, unsigned long dwFreeType); + + void __stdcall GetSystemInfo (SYSTEM_INFO *system_info); + void __stdcall GetSystemTime (SYSTEMTIME *lpSystemTime); + void __stdcall GetSystemTimeAsFileTime (FILETIME *lpFileTime); + void __stdcall GetLocalTime (SYSTEMTIME *lpSystemTime); + + /*DWORD*/ unsigned long __stdcall FormatMessageA (unsigned long dwFlags, void *lpSource, unsigned long dwMessageId, unsigned long dwLanguageId, char *lpBuffer, unsigned long nSize, va_list *Arguments); + /*DWORD*/ unsigned long __stdcall GetLastError (); + + int __stdcall MultiByteToWideChar (unsigned int CodePage, unsigned long dwFlags, char const *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); + int __stdcall WideCharToMultiByte (unsigned int CodePage, unsigned long dwFlags, wchar_t const *lpWideCharStr, int cchWideChar, char *lpMultiByteStr, int cbMultiByte, char const *lpDefaultChar, bool *lpUsedDefaultChar); + + /*NTSTATUS*/ long __stdcall BCryptOpenAlgorithmProvider(void *phAlgorithm, wchar_t const *pszAlgId, wchar_t const *pszImplementation, unsigned long dwFlags); + /*NTSTATUS*/ long __stdcall BCryptGenRandom (void *hAlgorithm, unsigned char *pbBuffer, unsigned long cbBuffer, unsigned long dwFlags); + + /*BOOLAPI*/ int __stdcall InternetCrackUrlA (char const *lpszUrl, unsigned long dwUrlLength, unsigned long dwFlags, URL_COMPONENTSA *lpUrlComponents); + /*HANDLE*/ void * __stdcall InternetOpenA (char const *lpszAgent, unsigned long dwAccessType, char const *lpszProxy, char const *lpszProxyBypass, unsigned long dwFlags); + /*HANDLE*/ void * __stdcall InternetConnectA (void *hInternet, char const *lpszServerName, INTERNET_PORT nServerPort, char const *lpszUserName, char const *lpszPassword, unsigned long dwService, unsigned long dwFlags, unsigned long *dwContext); + /*BOOLAPI*/ int __stdcall InternetSetOptionA (void *hInternet, unsigned long dwOption, void *lpBuffer, unsigned long dwBufferLength); + /*BOOLAPI*/ int __stdcall InternetReadFile (void *hFile, void *lpBuffer, unsigned long dwNumberOfBytesToRead, unsigned long *lpdwNumberOfBytesRead); + /*BOOLAPI*/ int __stdcall InternetCloseHandle (void *hInternet); + /*HANDLE*/ void * __stdcall HttpOpenRequestA (void *hConnect, char const *lpszVerb, char const *lpszObjectName, char const *lpszVersion, char const *lpszReferrer, char const **lplpszAcceptTypes, unsigned long dwFlags, unsigned long *dwContext); + /*BOOLAPI*/ int __stdcall HttpSendRequestA (void *hRequest, char const *lpszHeaders, unsigned long dwHeadersLength, void *lpOptional, unsigned long dwOptionalLength); + /*BOOLAPI*/ int __stdcall HttpAddRequestHeadersA (void *hRequest, char const *lpszHeaders, unsigned long dwHeadersLength, unsigned long dwModifiers); + /*BOOL*/ int __stdcall HttpQueryInfoA (void *hRequest, unsigned long dwInfoLevel, void *lpBuffer, unsigned long *lpdwBufferLength, unsigned long *lpdwIndex); + + /*HINSTANCE*/ void * __stdcall ShellExecuteA (void *hwnd, char const *lpOperation, char const *lpFile, char const *lpParameters, char const *lpDirectory, int nShowCmd); + /*BOOL*/ int __stdcall ShowWindow (void *hWnd, int nCmdShow); + } + DQN_MSVC_WARNING_POP +#endif // !defined(_INC_WINDOWS) +#endif /// defined(DQN_OS_WIN32)