dqn: Implement stack trace for windows

This commit is contained in:
doyle 2023-08-31 01:03:48 +10:00
parent 0028e9ca62
commit 91c5989a7d
10 changed files with 1279 additions and 547 deletions

View File

@ -1847,112 +1847,20 @@ static void Dqn_Test_RunSuite()
dqn_library->log_callback = prev_log_callback;
}
#define WIN32_LEAN_AND_MEAN
#include <TlHelp32.h>
#include <DbgHelp.h> // STACKFRAME64, ...
#include <winnt.h> // 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

View File

@ -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 doesnt 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 <typename T> T foo() {
# }
# template <typename T>
# T foo(int aaaaaaaaaaaaaaaaaaaaa,
# int bbbbbbbbbbbbbbbbbbbbb) {
# }
AlwaysBreakTemplateDeclarations: MultiLine
# If false, a function calls 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<typename T>
# concept ...
#
# false:
# template<typename T> 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<int> x{1, 2, 3, 4}; vs. vector<int> x{ 1, 2, 3, 4 };
# vector<T> x{{}, {}, {}, {}}; vector<T> 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 <foo>
# #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<FunctionDecl>(D)) { vs. if (isa<FunctionDecl>(D))
# handleFunctionDecl(D); handleFunctionDecl(D);
# } else if (isa<VarDecl>(D)) { else if (isa<VarDecl>(D))
# handleVarDecl(D); handleVarDecl(D);
# }
#
# if (isa<VarDecl>(D)) { vs. if (isa<VarDecl>(D)) {
# for (auto *A : D.attrs()) { for (auto *A : D.attrs())
# if (shouldProcessAttr(A)) { if (shouldProcessAttr(A))
# handleAttr(A); handleAttr(A);
# } }
# }
# }
#
# if (isa<FunctionDecl>(D)) { vs. if (isa<FunctionDecl>(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 <cstring> #include <cstring>
# 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<typename T>
# int method2(T x) { enum List {
# // ... ITEM1,
# } ITEM2
# int i, j, k; };
# int method3(int par) {
# // ... template<typename T>
# } 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<int>(arg);
# std::function<void(int)> 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]
---

6
dqn.h
View File

@ -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.

View File

@ -939,7 +939,7 @@ DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear(Dqn_FArray<T, N
#if !defined(DQN_NO_LIST)
// NOTE: [$LIST] Dqn_List ==========================================================================
template <typename T> DQN_API Dqn_List<T> Dqn_List_InitWithArena(Dqn_Arena *arena, Dqn_usize chunk_size)
template <typename T> DQN_API Dqn_List<T> Dqn_List_Init(Dqn_Arena *arena, Dqn_usize chunk_size)
{
Dqn_List<T> result = {};
result.arena = arena;

View File

@ -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<uint64_t> raw_frames = Dqn_List_Init<uint64_t>(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<uint64_t> *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)
{

View File

@ -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 <sanitizer/asan_interface.h>
#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)

View File

@ -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

View File

@ -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 <Windows.h>
#include <shellscalingapi.h>
#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 <bcrypt.h> // Dqn_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc
#include <shellapi.h> // 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 <wininet.h> // 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.h> // errno
#include <fcntl.h> // O_RDONLY ... etc
#include <linux/fs.h> // FICLONE

View File

@ -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;
}

627
dqn_win32.h Normal file
View File

@ -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 <bcrypt.h> // Dqn_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc
#include <shellapi.h> // 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 <wininet.h> // 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,<