diff --git a/src/torture/dbg_tests/mule.cpp b/src/torture/dbg_tests/mule.cpp new file mode 100644 index 00000000..e81a9d52 --- /dev/null +++ b/src/torture/dbg_tests/mule.cpp @@ -0,0 +1,3673 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/// test: { +/// windows: { +/// skip: "" +/// compile: "/Z7 /c /I%SRC% /EHsc mule_main.cpp mule_inline.cpp" +/// compile: "/Z7 /c /I%SRC% mule_c.c" +/// compile: "/Z7 /c /O2 mule_o2.cpp" +/// compile: "/Z7 /c mule_module.cpp" +/// link: "/DEBUG:FULL /out:mule_main.exe mule_main.obj mule_inline.obj mule_c.obj mule_o2.obj" +/// link: "/DEBUG:FULL /DLL mule_module.obj" +/// launch: "mule_main.exe" +/// } +/// } + +/// file: "mule_c.h" + +void c_type_coverage_eval_tests(void); +void c_type_with_bitfield_usage(void); + +/// file: "mule_c.c" + +/* +* Program to run in debugger organized to provide tests for +* single threaded stepping, breakpoints, evaluation. +*/ + +//////////////////////////////// +// NOTE(allen): Complex Types + +#include + +void +c_type_coverage_eval_tests(void){ +#if _WIN32 + _Fcomplex x = _FCbuild(0.f, 1.f); + _Dcomplex y = _Cbuild(0.f, -1.f); + +#else + float complex x = 0.f + 1.f*I; + double complex y = 0.0 - 1.0*I; + +#endif +} + +//////////////////////////////// +// NOTE(allen): Reuse Type Names From Another Module + +#include + +typedef struct Basics{ + double a; + float b; + unsigned long long c; + long long d; + unsigned int e; + int f; + unsigned short g; + short h; + unsigned char i; + char j; + + int z; +} Basics; + +typedef struct Basics_Stdint{ + double x1; + float x2; + uint64_t x3; + int64_t x4; + uint32_t x5; + int32_t x6; + uint16_t x7; + int16_t x8; + uint8_t x9; + int8_t x0; +} Basics_Stdint; + +typedef struct Pair{ + int i; + float f; +} Pair; + +void +c_versions_of_same_types(void){ + Basics basics = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, }; + Basics_Stdint basics_stdint = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, }; + Pair memory_[] = { + {100, 1.f}, + {101, 2.f}, + {102, 4.f}, + {103, 8.f}, + {104, 16.f}, + {105, 32.f}, + }; + + int x = memory_[3].i + basics.f; +} + +//////////////////////////////// +//~ NOTE(rjf): Bitfields + +typedef struct TypeWithBitfield TypeWithBitfield; +struct TypeWithBitfield +{ + int v : 14; + int w : 4; + int x : 32; + int y : 4; + int z : 10; +}; + +typedef struct BitfieldType64 BitfieldType64; +struct BitfieldType64 +{ + uint64_t size : 63; + uint64_t is_free : 1; +}; + +static int mut_xarray[4] = {100, 101, 102, 103}; +static float mut_farray[4] = {100.5f, 101.5f, 102.5f, 103.5f}; + +void +c_type_with_bitfield_usage(void) +{ + TypeWithBitfield b = {0}; + b.v = 100; + b.w = 6; + b.x = 434512; + b.y = 7; + b.z = 12; + int x = (b.v + b.x); + int y = (b.y - b.z); + int z = (b.w) + 5; + BitfieldType64 b64 = {0}; + b64.size = 524288; + b64.is_free = 1; + int abc = mut_xarray[0]; + mut_xarray[0] += 1; + abc += mut_xarray[0]; + abc += mut_xarray[1]; + abc += mut_xarray[2]; + float f = mut_farray[0] + mut_farray[1] + mut_farray[2] + mut_farray[3]; + int w = 0; +} + +/// file: "inline_body.cpp" + +bias = (bias^x)&7; +x -= bias; +x *= 2; +x *= x; +x += bias; + +/// file: "mule_inline.cpp" + +/* +** Make sure we have an inlined function +*/ + +#if defined(_MSC_VER) +# define FORCE_INLINE __forceinline +#elif defined(__clang__) || defined(__GNUC__) +# define FORCE_INLINE __attribute__((always_inline)) +#else +# error need force inline for this compiler +#endif + +//////////////////////////////// +// NOTE(allen): Inline Stepping + +unsigned int fixed_frac_bits = 5; +static unsigned int bias = 7; + +static FORCE_INLINE unsigned int +fixed_mul(unsigned int a, unsigned int b){ + unsigned int c = (((a - bias)*(b - bias)) >> fixed_frac_bits) + bias; + return(c); +} + +static FORCE_INLINE unsigned int +multi_file_inlinesite(unsigned int x){ + // force compiler to generate annotations for code that's inside another file +#include "inline_body.cpp" + return x >> fixed_frac_bits; +} + +static unsigned int test_value = 0; + +unsigned int +inline_stepping_tests(void){ + bias = 15; + + // NOTE(nick): Interesting that CL does not generate inline site symbols in order of apperance here unlike clang. + + // CL: + // BinaryAnnotations: CodeLengthAndCodeOffset d 0 + // BinaryAnnotation Length: 4 bytes (1 bytes padding) + // + // Clang: + // BinaryAnnotations: LineOffset 1 CodeLength d + // BinaryAnnotation Length: 4 bytes (0 bytes padding) + unsigned int x = fixed_mul(5001, 7121); + + // CL: + // BinaryAnnotations: CodeOffsetAndLineOffset d File 0 CodeOffsetAndLineOffset 22 LineOffset 1e + // CodeLengthAndCodeOffset 2 3 + // BinaryAnnotation Length: 12 bytes (1 bytes padding) + // + // Clang: + // BinaryAnnotations: File 18 LineOffset ffffffe6 CodeOffset d CodeOffsetAndLineOffset 22 + // File 0 LineOffset 1e CodeOffset 3 CodeLength 2 + // BinaryAnnotation Length: 16 bytes (0 bytes padding) + unsigned int z = multi_file_inlinesite(x); + return(z); +} + +/// file: "mule_o2.cpp" + +static int important_s32 = 0; +static float important_f32 = 0; + +#if _WIN32 +#include +#endif + +static void +do_something_with_intermediate_values(void) +{ + static int another_important_s32 = 0; + static float another_important_f32 = 0; + + another_important_s32 = (int)important_f32; + another_important_f32 = (float)important_s32; + +#if _WIN32 + char buffer[256] = "Hello, World!\n"; + buffer[0] += important_s32 + another_important_s32; + buffer[1] += (int)another_important_f32 * important_f32; + OutputDebugStringA(buffer); +#endif +} + +static void +store_important_s32(int *ptr) +{ + important_s32 = *ptr; +} + +static void +store_important_f32(float *ptr) +{ + important_f32 = *ptr; +} + +void +optimized_build_eval_tests(void) +{ + int simple_sum = 0; + for(int i = 0; i < 10000; i += 1) + { + simple_sum += i; + } + store_important_s32(&simple_sum); + + do_something_with_intermediate_values(); + + static struct {float x, y;} vec2s[] = + { + { 10.f, 76.f }, + { 40.f, 50.f }, + { -230.f, 20.f }, + { 27.f, 27.f }, + { 57.f, -57.f }, + { -37.f, 97.f }, + { 99.f, 67.f }, + { 99.f, 37.f }, + { 99.f, 57.f }, + }; + { + struct{float x, y;}sum = {0}; + int count = sizeof(vec2s)/sizeof(vec2s[0]); + for(int i = 0; i < count; i += 1) + { + sum.x += vec2s[i].x; + sum.y += vec2s[i].y; + } + struct{float x, y;}avg = {sum.x/count, sum.y/count}; + float f32 = avg.x * avg.y; + store_important_f32(&f32); + } + + do_something_with_intermediate_values(); + + int factorial = 1; + for(int i = 10; i > 0; i -= 1) + { + factorial *= i; + } + store_important_s32(&factorial); + + do_something_with_intermediate_values(); +} + +//////////////////////////////// +// NOTE(allen): Struct Parameters Eval + +struct OptimizedBasics{ + char a; + unsigned char b; + short c; + unsigned short d; + int e; + unsigned int f; + long long g; + unsigned long long h; + float i; + double j; +}; + +static void +optimized_struct_parameter_helper(int *ptr, OptimizedBasics basics) +{ + basics.a += *ptr; + basics.a += 1; + basics.a += 1; +} + +void +optimized_struct_parameters_eval_tests(void) +{ + int x = 10; + OptimizedBasics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + optimized_struct_parameter_helper(&x, basics); +} + +/// file: "mule_main.cpp" + +/* +** Program to run in debugger organized to provide tests for +** stepping, breakpoints, evaluation, cross-module calls. +*/ + +#define EvalTest(expr, match) + +#if _WIN32 && _DEBUG +#pragma comment(linker, "/nodefaultlib:libcmt") +#pragma comment(lib, "libcmtd") +#endif + +#include +#include +#include +#include +#if !_WIN32 +# define RADDBG_MARKUP_STUBS +#endif +#define RADDBG_MARKUP_IMPLEMENTATION +#include "lib_raddbg_markup/raddbg_markup.h" + +//////////////////////////////// +// NOTE(allen): System For DLL Testing + +typedef void TestFunction(void); + +static void mule_init(void); +static TestFunction* mule_get_module_function(char *name); + +#if _WIN32 + +#include + +HMODULE mule_dll = 0; + +static void +mule_init(void){ + mule_dll = LoadLibraryA("mule_module.dll"); +} + +static TestFunction* +mule_get_module_function(char *name){ + TestFunction *result = (TestFunction*)GetProcAddress(mule_dll, name); + return(result); +} + +#else + +static void +mule_init(void){ + // TODO(allen): implement +} + +static TestFunction* +mule_get_module_function(char *name){ + // TODO(allen): implement + return(0); +} + +#endif + + +//////////////////////////////// +// NOTE(nick): Entry Point + +int +mule_main(int argc, char **argv); + +#if _WIN32 +#include +#include +int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){ + int argc = __argc; + char **argv = __argv; + int result = mule_main(argc, argv); + return(result); +} +#else +int main(int argc, char **argv){ + return(mule_main(argc, argv)); +} +#endif + +//////////////////////////////// +// NOTE(nick): BSS section test + +#if defined(__clang__) +# pragma clang section bss="muleBSS" +#elif defined(_MSC_VER) +// NOTE(nick): clang-cl is borken it allocates memory and sets Initialized Flag on the seciton. +// This is was reported by Jeff => https://bugs.llvm.org/show_bug.cgi?id=47939 +// +// This is still unresolved, last checked Sep 11, 2023. +# pragma bss_seg("muleBSS") +#else +# error "bss not defined" +#endif +char global_variable_in_bss[4096*10000]; + +//////////////////////////////// +// NOTE(allen): Inline Stepping (Built In Separate Unit) + +extern unsigned int fixed_frac_bits; +unsigned int inline_stepping_tests(void); + + +//////////////////////////////// +// NOTE(rjf): -O2 Optimized Code (Built In Separate Unit) + +void optimized_build_eval_tests(void); +void optimized_struct_parameters_eval_tests(void); + +//////////////////////////////// +// NOTE(allen): Type Coverage Eval + +#include + +struct Basics +{ + char a; + unsigned char b; + short c; + unsigned short d; + int e; + unsigned int f; + long long g; + unsigned long long h; + float i; + double j; + int z; +}; + +struct Basics_Stdint +{ + int8_t a; + uint8_t b; + int16_t c; + uint16_t d; + int32_t e; + uint32_t f; + int64_t g; + uint64_t h; + float i; + double j; +}; + +struct Pair +{ + int x; + float y; +}; + +struct Fixed_Array +{ + Pair pairs[10]; + int count; +}; + +struct Dynamic_Array +{ + Pair *pairs; + int count; +}; +raddbg_type_view(Dynamic_Array, slice($)); + +template +struct TemplatedDynamicArray +{ + T *v; + int count; +}; +raddbg_type_view(TemplatedDynamicArray, rows($, count, array(v, count))); + +template +struct OpaqueTemplatedDynamicArray +{ + void *v; + int count; +}; +raddbg_type_view(OpaqueTemplatedDynamicArray, array(cast(type *)v, count)); + +struct Struct_With_Embedded_Arrays +{ + int x; + float y; + Pair pairs[10]; + char z; +}; + +typedef unsigned int Custom_Index_Type; + +typedef void Function_No_Params_Type(void); +typedef void Function_Few_Params_Type(Pair *pairs, int count, Function_No_Params_Type *no_params_type); + +static Function_No_Params_Type *ty_no_params = 0; +static Function_Few_Params_Type *ty_few_params = 0; + +struct Callback{ + Function_Few_Params_Type *few_params; + Function_No_Params_Type *no_params; + Pair pair; +}; + +union Vector_R2 +{ + struct + { + float x; + float y; + }; + float v[2]; +}; +raddbg_type_view(Vector_R2, rows($, x, y)); + +typedef union Matrix4x4F32 Matrix4x4F32; +union Matrix4x4F32 +{ + float elements[4][4]; +}; +raddbg_type_view(Matrix4x4F32, columns($.elements, $[0], $[1], $[2], $[3])); + +union PackedF16 +{ + uint16_t v; + struct + { + uint16_t mantissa : 10; + uint16_t exponent : 5; + uint16_t sign : 1; + }; +}; +raddbg_type_view(PackedF16, + exponent == 0 ? (0.00006103515625f*mantissa/1024.f) : + (exponent == 31 && mantissa == 0 && sign == 1) ? "-infinity" : + (exponent == 31 && mantissa == 0 && sign == 1) ? "+infinity" : + (exponent == 31) ? "NaN" : + (exponent < 15) ? (1.f/(1<<(15 - exponent)) * (sign * -2 + 1.f) * (1.f + mantissa/1024.f)) : + (exponent > 15) ? ((1<<(exponent-15)) * (sign * -2 + 1.f) * (1.f + mantissa/1024.f)) : + ((sign * -2 + 1) * 1.f + mantissa/1024.f)); + +enum Kind +{ + Kind_Negative = -1, + Kind_None, + Kind_First, + Kind_Second, + Kind_Third, + Kind_Fourth, + Kind_COUNT, +}; + +enum Flag +{ + Flag_None = 0, + Flag_First = 1, + Flag_Second = 2, + Flag_Third = 4, + Flag_Fourth = 8, + Flag_AllMoreNarrow = 0xFF, + Flag_AllNarrow = 0xFFFF, + Flag_All = 0xFFFFFFFF, +}; + +struct Has_Enums +{ + Kind kind; + Flag flags; +}; + +struct Discriminated_Union +{ + Kind kind; + union + { + struct + { + int x; + int y; + Vector_R2 vector; + } first; + Pair second; + struct + { + Function_Few_Params_Type *few_params; + Pair pairs[4]; + } third; + struct + { + Kind sub_kind; + Flag flags; + } fourth; + }; +}; +raddbg_type_view(Discriminated_Union, + kind == Kind.First ? first : + kind == Kind.Second ? second : + kind == Kind.Third ? third : + kind == Kind.Fourth ? fourth : + $); + +struct Crazy_Union +{ + Kind kind; + union + { + struct + { + int first_and_third__x; + int first_and_third__y; + int first_and_third__z; + } first_and_third; + struct + { + char *second__name; + Pair second__pairs[16]; + } second; + }; + union + { + struct + { + char *first__name; + int first__x; + } first; + struct + { + char *third__name; + Function_Few_Params_Type *third__few_params; + } third; + }; +}; +raddbg_type_view(Crazy_Union, + kind == Kind.First ? rows($, first_and_third, first) : + kind == Kind.Second ? rows($, second) : + kind == Kind.Third ? rows($, first_and_third, third) : + kind == Kind.Fourth ? kind : + $); + +struct Linked_List{ + Linked_List *next; + Linked_List *prev; + int x; +}; + +enum{ + Anonymous_A, + Anonymous_B, + Anonymous_C, + Anonymous_D, +}; + +typedef uint32_t SizedKind; +enum SizedKindEnum +{ + SizedKind_A, + SizedKind_B, + SizedKind_C, + SizedKind_D, +}; + +typedef Kind Alias1; +typedef Flag Alias2; +typedef Has_Enums Alias3; +typedef Discriminated_Union Alias4; + +struct Has_A_Pre_Forward_Reference{ + struct Gets_Referenced_Forwardly *pointer; +}; + +struct Gets_Referenced_Forwardly{ + int x; + int y; +}; + +struct Has_A_Post_Forward_Reference{ + struct Gets_Referenced_Forwardly value; +}; + +struct TypeWithMemberFunction +{ + int x; + int y; + int z; + char *name; + __declspec(noinline) void SetInfo(int _x, int _y, char *_name) + { + x = _x; + y = _y; + z = 0; + name = _name; + OutputDebugStringA("setting info\n"); + } +}; + +static void +no_params1(void){ + +} + +static void +few_params1(Pair *pairs, int count, Function_No_Params_Type *no_params_type){ + +} + +// +// NOTE(rjf): this doesn't work because MSVC - despite GENERATING DEBUG INFO +// FOR THE MyByte TYPEDEF - does not actually *reference* this typedef +// anywhere, and instead treats all `MyByte *`s as `char *`s, thus completely +// eliminating the point of the typedef and view. :( +// +typedef char MyByte; +raddbg_type_view(MyByte *, no_string($)); + +static void +variadic_params(char *fmt, ...) +{ + int x = 0; +} + +static void +type_coverage_eval_tests(void) +{ + Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + Basics_Stdint basics_stdint = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + + uint32_t a = (1<<31); + int32_t b = (1<<31); + + uint32_t abcd = 0xaabbccdd; + int64_t abcd64 = (int64_t)abcd; + + char string[] = "Hello World!"; + char longer_text[] = + "Suppose there was some text\n" + "With multiple lines in it\r\n" + "\t> What ways might it be rendered?\n" + "\t> How would it deal with line endings?\r\n"; + wchar_t a_wide_string[] = + L"This is a string, but instead of being encoded in a stream of bytes,\n" + L"it is encoded in a stream of 2-byte packages!\n"; + char some_data_with_a_string[] = + { + 'H', 'e', 'l', 'l', 'o', 27, 27, 2, 27, 125, + }; + struct SomeDataStructured + { + char data[4]; + }; + SomeDataStructured *some_data = (SomeDataStructured *)&some_data_with_a_string[0]; + char *string_ptr = &string[0]; + + const char *const_string = "Hello, World!"; + const char const_string_array[] = "Hello, World!"; + const char *const const_ptr_const_string = "Hello, World!"; + + MyByte *non_string_byte_ptr = "Hello, World!"; + + void *pointer = &basics; + Basics *pointer_to_basics = &basics; + Basics **pointer_to_pointer_to_basics = &pointer_to_basics; + + Fixed_Array fixed = + { + { + { 3, 4.f}, + { 5, 6.f}, + { 7, 8.f}, + { 9, 10.f}, + {11, 12.f}, + {13, 14.f}, + {15, 16.f}, + {17, 18.f}, + {19, 20.f}, + }, + 9 + }; + Pair memory_[] = + { + {100, 1.f}, + {101, 2.f}, + {102, 4.f}, + {103, 8.f}, + {104, 16.f}, + {105, 32.f}, + }; + Dynamic_Array dynamic = + { + memory_, + 6 + }; + EvalTest(dynamic[0].i, 100); EvalTest(dynamic[0].f, 1.f); + EvalTest(dynamic[1].i, 101); EvalTest(dynamic[1].f, 2.f); + EvalTest(dynamic[2].i, 102); EvalTest(dynamic[2].f, 4.f); + + TemplatedDynamicArray templated_dynamic = {dynamic.pairs, dynamic.count}; + TemplatedDynamicArray templated_dynamics[] = + { + {dynamic.pairs, dynamic.count}, + {dynamic.pairs, dynamic.count}, + {dynamic.pairs, dynamic.count}, + {dynamic.pairs, dynamic.count}, + {dynamic.pairs, dynamic.count}, + }; + + OpaqueTemplatedDynamicArray otd = {dynamic.pairs, dynamic.count}; + + raddbg_pin(columns(sequence(6), fixed.pairs[$], memory_[$])); + raddbg_pin(basics); + raddbg_pin(fixed); + raddbg_pin(pointer); + raddbg_pin(dynamic); + + Struct_With_Embedded_Arrays swea = {0}; + { + swea.x = 4; + swea.y = 23.5f; + swea.pairs[0].x = 100; + swea.pairs[0].y = 123.f; + swea.pairs[2].x = 300; + swea.pairs[2].y = 323.f; + swea.pairs[5].x = 600; + swea.pairs[5].y = 623.f; + swea.z = 'z'; + } + + Struct_With_Embedded_Arrays *swea_ptr = &swea; + int access_via_ptr_member = swea_ptr->x; + + Custom_Index_Type custom_index = 42; + Custom_Index_Type more_custom_indices[] = { + 04,13,22,31,40 + }; + + Function_No_Params_Type *ptr_no_params = no_params1; + Function_No_Params_Type **ptr_ptr_no_params = &ptr_no_params; + Function_Few_Params_Type *ptr_few_params = few_params1; + Function_Few_Params_Type **ptr_ptr_few_params = &ptr_few_params; + Callback callback = {few_params1, no_params1, {1, 2.f}}; + + Matrix4x4F32 matrix = + { + { + {1.f, 0.f, 0.f, 0.f}, + {0.f, 1.f, 0.f, 0.f}, + {0.f, 0.f, 1.f, 0.f}, + {0.f, 0.f, 0.f, 1.f}, + } + }; + + Vector_R2 vector = {1.f, 2.f}; + + Has_Enums has_enums = {(Kind)4, (Flag)7}; + + struct EnumBitfields + { + Kind k1 : 4; + Kind k2 : 3; + Kind k3 : 1; + Kind k4 : 16; + }; + + EnumBitfields enum_bitfields = {}; + enum_bitfields.k1 = Kind_First; + enum_bitfields.k2 = Kind_Second; + enum_bitfields.k3 = Kind_None; + enum_bitfields.k4 = Kind_Fourth; + + Crazy_Union crazy_union = {}; + + crazy_union.kind = Kind_First; + crazy_union.kind = Kind_Second; + crazy_union.kind = Kind_Third; + crazy_union.kind = Kind_Fourth; + + Discriminated_Union discriminated_union = {}; + + discriminated_union.kind = Kind_First; + discriminated_union.first.x = 16; + discriminated_union.first.y = 8; + discriminated_union.first.vector.x = 4.f; + discriminated_union.first.vector.y = 2.f; + + discriminated_union.kind = Kind_Second; + discriminated_union.second.x = 123; + discriminated_union.second.y = 3.14f; + + discriminated_union.kind = Kind_Third; + discriminated_union.third.few_params = few_params1; + discriminated_union.third.pairs[0] = memory_[0]; + discriminated_union.third.pairs[1] = memory_[1]; + discriminated_union.third.pairs[2] = memory_[2]; + discriminated_union.third.pairs[3] = memory_[3]; + + discriminated_union.kind = Kind_Fourth; + discriminated_union.fourth.sub_kind = Kind_First; + discriminated_union.fourth.flags = (Flag)7; + + Linked_List list = {&list, &list, 0}; + + struct SLLNode + { + SLLNode *next; + SLLNode *the_real_next_ptr; + int x; + }; + SLLNode node6 = {0, 0, 6}; + SLLNode node5 = {0, &node6, 5}; + SLLNode node4 = {0, &node5, 4}; + SLLNode node3 = {0, &node4, 3}; + SLLNode node2 = {0, &node3, 2}; + SLLNode node1 = {0, &node2, 1}; + raddbg_pin(list(node1, the_real_next_ptr)); + + node6.next = &node1; + + Alias1 a1 = has_enums.kind; + Alias2 a2 = has_enums.flags; + Alias3 a3 = has_enums; + Alias4 a4 = discriminated_union; + + Has_A_Pre_Forward_Reference r1 = {0}; + Has_A_Post_Forward_Reference r2 = {0}; + + Basics &basics_ref = basics; + const Basics *basics_const_ptr = &basics; + const Basics &basics_const_ref = basics; + + union + { + int x; + char y[4]; + } integer_slicing = {123456789}; + + typedef struct stks + { + void *left; + size_t len; + } stks; + stks stks_test[256] = {0}; + stks *stks_first = &stks_test[0]; + stks *stks_ptr = stks_first + 8; + + TypeWithMemberFunction twmf = {0}; + twmf.SetInfo(123, 456, "foobar"); + + TestFunction *function = mule_get_module_function("dll_type_eval_tests"); + function(); + + int abc = 0; + for(int i = 0; i < 1000; i += 1) + { + if(i == 500) + { + abc+= 1; + } + int a = i + abc; + int b = a*5; + } + + char *names[] = + { + "samwise gamgee", "mithrandir", "grima wormtongue", "theodred", "theoden", "eomer", "eowyn", + "arwen", "sauron", "baggins", "proudfoot", "hardbottle", "bag end", "hobbiton", + "bree", "imladris", "isengard", "moria", "mount doom", "helm's deep", "bracegirdle", + "buckleberry ferry", "amun sul", "frodo", "bilbo", "buckland", "fangorn", "elrond", + "numenor", "treebeard", "shadowfax", "brego", "erod", "azufel", "dunedain", + "saruman", "aragorn", "gandalf", "meriadoc brandybuck", "peregrine took", "faramir", "boromir", + "ecthelion", "denethor", "mithrandil", "isildur", "haldir", "elessar", "elendil", + "dead marsh", "rohan", "gondor", "anarion", "earendil", "cirith ungol", "minas morghul", + "minas tirith", "barad-dur", "rivendell", "pellenor", "ithilien", "anduril", "narsil", + "edoras", "mordor", "osgiliath", + }; + + for(int i = 0; i < sizeof(names)/sizeof(names[0]); i += 1) + { + OutputDebugStringA(names[i]); + OutputDebugStringA("\n"); + } + + if(1) + { + OutputDebugStringA("this is inside a branch!\n"); + OutputDebugStringA("foo"); + OutputDebugStringA("bar"); + OutputDebugStringA("baz"); + } + + const int32_t x1 = 3; + const int32_t y1 = -10; + const int32_t z1 = x1 + y1; + + std::string small_cplusplus_string = "smallstr"; + std::string cplusplus_string = "This is a C++ string!"; + + std::vector int_vector; + int_vector.push_back(1); + int_vector.push_back(2); + int_vector.push_back(3); + int_vector.push_back(4); + int_vector.push_back(5); + int_vector.push_back(6); + int_vector.push_back(7); + + std::unordered_map people = + { + {"Peter", 1}, + {"Oliver", 2}, + {"Jack", 3}, + }; + + std::vector *pint_vector = &int_vector; + std::vector &rint_vector = int_vector; + + std::vector dynamic_array_vector; + dynamic_array_vector.push_back(dynamic); + dynamic_array_vector.push_back(dynamic); + dynamic_array_vector.push_back(dynamic); + dynamic_array_vector.push_back(dynamic); + + SizedKind sized_kind = SizedKind_C; + + variadic_params("foo", 123, 456); + + int x = (int)(Anonymous_D); +} + +//////////////////////////////// +// NOTE(allen): Mutating Variables Eval + +static const int con_some_constant = 4; +static const float con_some_constant_f = 0.04f; + +static int mut_x = 0; +static int mut_y; +static int mut_xarray[4] = {0, 1, 2, 3}; +static int *mut_xptr; + +static float mut_f = 0; +static float mut_g; +static float mut_farray[4] = {0.5f, 1.5f, 2.5f, 3.5f}; +static float *mut_fptr; + +static float mut_arrayarray[3][3]; + +static Linked_List mut_link; + +static void +mutate_in_function(int *array, int count){ + for (int i = 0; i < count; i += 1){ + array[i] += 1; + } + + for (int i = 0; i < 4; i += 1){ + mut_farray[i] += 1.f; + } +} + +static void +mutating_variables_eval_tests(void){ + //////////////////////////////// + // NOTE(allen): Basics + + int array_literal[10] = { + 10, 20, 30, 40, 50, 60, 70, 80, 90, + }; + + Basics struct_literal = { + -1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001, + }; + + array_literal[0] = struct_literal.e = 9; + + int x = mut_x; + int y = x + 10 + con_some_constant; + mut_y = y; + mut_xarray[0] += 0; + mut_xarray[1] += x; + mut_xarray[2] += y; + mut_xarray[3] += x + y; + + mut_xptr = &mut_xarray[2]; + + *mut_xptr -= (y - x)/2; + *(mut_xptr - 1) += 11; + + float f = mut_f + .333f + con_some_constant_f; + float g = f + 10.1f; + mut_g = g; + mut_farray[0] += 0.000001f; + mut_farray[1] += f; + mut_farray[2] += g; + mut_farray[3] += f + g; + + mut_fptr = &mut_farray[3]; + + *mut_fptr -= (g - f)*0.5f; + *(mut_fptr - 1) += 1.f; + + float a = 0.777f; + for (int i = 0; i < 3; i += 1){ + float b = a*a - 1.f; + for (int j = 0; j < 3; j += 1){ + mut_arrayarray[i][j] = b; + b += 0.111f; + } + a += 0.333f; + } + + //////////////////////////////// + // NOTE(allen): Changes in functions + + mutate_in_function(array_literal, 10); + + mutate_in_function(array_literal, 10); + + //////////////////////////////// + // NOTE(allen): Changes through pointers + + Basics basic = struct_literal; + Basics advanced = struct_literal; + + Basics *struct_pointer = &basic; + + basic.a += 1; + advanced.a += 1; + struct_pointer->a += 1; + + struct_pointer = &advanced; + + basic.b += 1; + advanced.b += 1; + struct_pointer->b += 1; + + Linked_List links[5]; + for (int i = 0; i < 5; i += 1){ + links[i].next = &links[i + 1]; + links[i].prev = &links[i - 1]; + links[i].x = i; + } + links[0].prev = 0; + links[4].next = &mut_link; + mut_link.prev = &links[4]; + mut_link.next = 0; + mut_link.x = 1000; + + Linked_List *link_ptr = links; + + link_ptr = link_ptr->next; + + link_ptr = &links[4]; + link_ptr = &mut_link; + + Linked_List sentinel = {0}; + sentinel.x = -1; + sentinel.next = &links[0]; + links[0].prev = &sentinel; + sentinel.prev = &mut_link; + mut_link.next = &sentinel; + + link_ptr = &sentinel; +} + +//////////////////////////////// +// NOTE(allen): Global Eval + +struct NestedNodeInner{ + unsigned int small0; + unsigned int small1; + unsigned int big0; + unsigned int big1; +}; + +struct NestedNodeOuter{ + NestedNodeOuter *next; + NestedNodeInner *inner_nodes; + unsigned int inner_node_count; +}; + +static void +nested_types_eval_tests(void){ + // doing some setup + NestedNodeOuter *outer1 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + NestedNodeOuter *outer2 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + NestedNodeOuter *outer3 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + + outer1->next = outer2; + outer2->next = outer3; + outer3->next = 0; + + outer1->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer1->inner_node_count = 10; + + outer2->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer2->inner_node_count = 10; + + outer3->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer3->inner_node_count = 10; + + for (unsigned int i = 0; i < 10; i += 1){ + outer1->inner_nodes[i].small0 = i; + outer1->inner_nodes[i].small1 = 2*i; + outer1->inner_nodes[i].big0 = 0xFFFFFF + 0xF*i; + outer1->inner_nodes[i].big1 = 0xFFFFFF + 0xFF*i; + + outer2->inner_nodes[i].small0 = 1 + i; + outer2->inner_nodes[i].small1 = 3*i; + outer2->inner_nodes[i].big0 = 0x1000000 + 0x10*i; + outer2->inner_nodes[i].big1 = 0x1000000 + 0x101*i; + + outer3->inner_nodes[i].small0 = 2 + i; + outer3->inner_nodes[i].small1 = 4*i; + outer3->inner_nodes[i].big0 = 0x8000000 + 0xF0*i; + outer3->inner_nodes[i].big1 = 0x8000000 + 0xF0F*i; + } + + // okay eval it here + int x = 0; +} + +//////////////////////////////// +// NOTE(rjf): Struct Parameters Eval + +static void +struct_parameter_helper(Basics basics) +{ + basics.a += 1; + basics.a += 1; + basics.a += 1; +} + +static void +struct_parameters_eval_tests(void) +{ + Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + struct_parameter_helper(basics); +} + +//////////////////////////////// +// NOTE(allen): Global Eval + +static int g_abc = 100; +static float g_xyz = 21.f; +static Alias1 g_kind = Kind_First; + +static void +complicated_global_mutation(int *x){ + *x = (int)g_xyz; +} + +static void +cross_unit_global_mutation(void){ + fixed_frac_bits = 10; +} + +static int +function_with_duplicate_local_statics(void) +{ + static char *l_abc = "foobar"; + static int l_xyz = 123; + static Kind l_kind = Kind_First; + int x = l_xyz + (int)(int64_t)(l_abc); + return x; +} + +static void +global_eval_tests(void) +{ + g_abc = 11*11; + g_xyz = (float)g_abc - 21.f; + + int z = g_abc; + complicated_global_mutation(&z); + + complicated_global_mutation(&g_abc); + + if (g_kind == Kind_First){ + g_abc -= 1; + g_kind = Kind_None; + } + + cross_unit_global_mutation(); + + static int l_abc = 200; + static float l_xyz = 42.f; + static Alias1 l_kind = Kind_Second; + + l_abc = g_abc*2; + l_xyz = g_xyz*2; + l_kind = (Alias1)(g_kind + 1); + + function_with_duplicate_local_statics(); +} + +//////////////////////////////// +// NOTE(allen): Return Eval + +static int +complicated_return_expression(void){ + int x = 171717; + return((x % 13) <= 5?(x % 19)*11:(x - 500)%200); +} + +static void +return_eval_tests(void){ + complicated_return_expression(); +} + +//////////////////////////////// +// NOTE(allen): TLS Eval + +#if _WIN32 +# define thread_var __declspec(thread) +#else +# define thread_var __thread +#endif + +thread_var int tls_a = 100; +thread_var int tls_b = 999; + +static void +tls_eval_tests(void){ + tls_a = (tls_a + tls_b)/2; + tls_b = tls_b - tls_a; + + TestFunction *dll_tls_eval_test = mule_get_module_function("dll_tls_eval_test"); + if (dll_tls_eval_test != 0){ + dll_tls_eval_test(); + } +} + +//////////////////////////////// +// NOTE(allen): Complicated Type Coverage Eval + +struct Complicated_Type_Members{ + int x600[2][2][2][2]; + int *x601[2][2][2][2]; + int (*x602)[2][2][2][2]; + int (*x603[2])[2][2][2]; + int (*(*x604[2])[2])[2][2]; + int (*(*(*x605[2])[2])[2])[2]; + + int (*x33[2])(void); + int (*x34[3])(void); + int (*x35[2][2])(void); + + int (*(*z33)(void))[2]; + int (*(*z34)(void))[3]; + int (*(*z35)(void))[2][2]; + + int (*(*f2)(void))(void); + int (*(*(*f3)(void))(void))(void); + int (*(*f4)(int))(void); + int (*(*f5)(void))(int); + int (*(*f6)(int))(int); + int (*(*(*f7_growing)(char))(short))(int); + int (*(*(*f7_shrinking)(int))(short))(char); +}; + +static void +complicated_type_coverage_tests(void){ + Complicated_Type_Members m = {0}; + + int x1 = {0}; + int *x2 = {0}; + int **x3 = {0}; + + int x4a[2] = {0}; + int *x4[2] = {0}; + int x5a[3] = {0}; + int *x5[3] = {0}; + int *x6[2][2] = {0}; + int (*x7)[2] = {0}; + int (*x8)[3] = {0}; + int (*x9)[2][2] = {0}; + + int x600[2][2][2][2] = {0}; + int *x601[2][2][2][2] = {0}; + int (*x602)[2][2][2][2] = {0}; + int (*x603[2])[2][2][2] = {0}; + int (*(*x604[2])[2])[2][2] = {0}; + int (*(*(*x605[2])[2])[2])[2] = {0}; + + int x606_growing [2][3][4][5] = {0}; + int x606_shrinking[5][4][3][2] = {0}; + + int (*(*(*x607_growing [2])[3])[4])[5] = {0}; + int (*(*(*x607_shrinking[5])[4])[3])[2] = {0}; + + int **x10[2] = {0}; + int **x11[3] = {0}; + int **x12[2][2] = {0}; + int *(*x13)[2] = {0}; + int *(*x14)[3] = {0}; + int *(*x15)[2][2] = {0}; + int **x16[2] = {0}; + int **x17[3] = {0}; + int **x18[2][2] = {0}; + + int (*y1[2])[2] = {0}; + int (*y2[3])[2] = {0}; + int (*y3[2][2])[2] = {0}; + int (*y4[2])[3] = {0}; + int (*y5[3])[3] = {0}; + int (*y6[2][2])[3] = {0}; + int (*y7[2])[2][2] = {0}; + int (*y8[3])[2][2] = {0}; + int (*y9[2][2])[2][2] = {0}; + + int (*x19)(void) = {0}; + int (*x20)(int) = {0}; + int (*x21)(int, int) = {0}; + int (*x22)(int*, int) = {0}; + int (*x23)(int**, int) = {0}; + int (*x24)(int**, int*) = {0}; + int (*x25)(int**, int**) = {0}; + + int *(*x26)(void) = {0}; + int *(*x27)(int) = {0}; + int *(*x28)(int, int) = {0}; + int *(*x29)(int*, int) = {0}; + int *(*x30)(int**, int) = {0}; + int *(*x31)(int**, int*) = {0}; + int *(*x32)(int**, int**) = {0}; + + int (*x33[2])(void) = {0}; + int (*x34[3])(void) = {0}; + int (*x35[2][2])(void) = {0}; + + int (*x36[2])(int) = {0}; + int (*x37[3])(int) = {0}; + int (*x38[2][2])(int) = {0}; + + int (*x39[2])(int, int) = {0}; + int (*x40[3])(int, int) = {0}; + int (*x41[2][2])(int, int) = {0}; + + int (*x42[2])(int*, int) = {0}; + int (*x43[3])(int*, int) = {0}; + int (*x44[2][2])(int*, int) = {0}; + + int (*x45[2])(int**, int) = {0}; + int (*x46[3])(int**, int) = {0}; + int (*x47[2][2])(int**, int) = {0}; + + int (*x48[2])(int**, int*) = {0}; + int (*x49[3])(int**, int*) = {0}; + int (*x50[2][2])(int**, int*) = {0}; + + int (*x51[2])(int**, int**) = {0}; + int (*x52[3])(int**, int**) = {0}; + int (*x53[2][2])(int**, int**) = {0}; + + int (*(*z33)(void))[2] = {0}; + int (*(*z34)(void))[3] = {0}; + int (*(*z35)(void))[2][2] = {0}; + + int (*(*z36)(int))[2] = {0}; + int (*(*z37)(int))[3] = {0}; + int (*(*z38)(int))[2][2] = {0}; + + int (*(*z39)(int, int))[2] = {0}; + int (*(*z40)(int, int))[3] = {0}; + int (*(*z41)(int, int))[2][2] = {0}; + + int (*(*z42)(int*, int))[2] = {0}; + int (*(*z43)(int*, int))[3] = {0}; + int (*(*z44)(int*, int))[2][2] = {0}; + + int (*(*z45)(int**, int))[2] = {0}; + int (*(*z46)(int**, int))[3] = {0}; + int (*(*z47)(int**, int))[2][2] = {0}; + + int (*(*z48)(int**, int*))[2] = {0}; + int (*(*z49)(int**, int*))[3] = {0}; + int (*(*z50)(int**, int*))[2][2] = {0}; + + int (*(*z51)(int**, int**))[2] = {0}; + int (*(*z52)(int**, int**))[3] = {0}; + int (*(*z53)(int**, int**))[2][2] = {0}; + + int (*(*z303[2])(void)) = {0}; + int (*(*z304[3])(void)) = {0}; + int (*(*z305[2][2])(void)) = {0}; + + int (*(*z306[2])(int)) = {0}; + int (*(*z307[3])(int)) = {0}; + int (*(*z308[2][2])(int)) = {0}; + + int (*(*z309[2])(int, int)) = {0}; + int (*(*z400[3])(int, int)) = {0}; + int (*(*z401[2][2])(int, int)) = {0}; + + int (*(*z402[2])(int*, int)) = {0}; + int (*(*z403[3])(int*, int)) = {0}; + int (*(*z404[2][2])(int*, int)) = {0}; + + int (*(*z405[2])(int**, int)) = {0}; + int (*(*z406[3])(int**, int)) = {0}; + int (*(*z407[2][2])(int**, int)) = {0}; + + int (*(*z408[2])(int**, int*)) = {0}; + int (*(*z409[3])(int**, int*)) = {0}; + int (*(*z500[2][2])(int**, int*)) = {0}; + + int (*(*z501[2])(int**, int**)) = {0}; + int (*(*z502[3])(int**, int**)) = {0}; + int (*(*z503[2][2])(int**, int**)) = {0}; + + int (*(*f2)(void))(void) = {0}; + int (*(*(*f3)(void))(void))(void) = {0}; + int (*(*f4)(int))(void) = {0}; + int (*(*f5)(void))(int) = {0}; + int (*(*f6)(int))(int) = {0}; + int (*(*(*f7_growing)(char))(short))(int) = {0}; + int (*(*(*f7_shrinking)(int))(short))(char) = {0}; + + int (*f8)(int (*)(void)) = {0}; + int (*f9)(void (*)(int)) = {0}; + void (*f10)(int (*)(int)) = {0}; + int (*f11)(int, int (*)(void)) = {0}; + int (*f12)(int (*)(void), int) = {0}; + int (*f13)(int (*)(void), int (*)(void)) = {0}; + + int (*f14)(int (*)(void)) = {0}; + int (*f15)(int (*)(int (*)(void))) = {0}; + int (*f16)(int (*)(int (*)(int (*)(void)))) = {0}; + int (*f17)(int (*)(int (*)(int (*)(int (*)(void))))) = {0}; + + int (*f18)(int (*)(void)) = {0}; + int (*f19)(int (*(*)(void))(void)) = {0}; + int (*f20)(int (*(*(*)(void))(void))(void)) = {0}; + int (*f21)(int (*(*(*(*)(void))(void))(void))(void)) = {0}; + + int (*(*(*(*f22)(void))(void))(void))(void) = {0}; + int (*(*(*(*f23)(int [2]))(void))(void))(void) = {0}; + int (*(*(*(*f24)(int *[2]))(int [3]))(void))(void) = {0}; + int (*(*(*(*f25)(int (*)[2]))(int *[3]))(int [4]))(void) = {0}; + int (*(*(*(*f26)(int **(**)[2]))(int (*)[3]))(int *[4]))(int [5]) = {0}; + + int x = 0; +} + +//////////////////////////////// +// NOTE(allen): Extended Type Coverage Eval + +template +struct Template_Example{ + X x; + int y; +}; + +template +struct Template_Example2{ + X x; + Y y; +}; + +template +struct Template_Example3{ + X x; + Y y; + Template_Example3(X x, Y y) + { + this->x = x; + this->y = y; + } + ~Template_Example3() + { + int x = 2; + int y = 5; + int z = x + y; + } +}; + +struct SingleInheritanceBase +{ + int x; + int y; +}; + +struct SingleInheritanceDerived : SingleInheritanceBase +{ + int z; + int w; +}; + +struct Has_Members{ + int a; + int b; + uint64_t c; + uint64_t d; + Basics bas; + + int w(void){ return a; } + int x(void){ return b; } + uint64_t y(void){ return c; } + uint64_t z(void){ return d; } + Basics bas_f(void){ return bas; } +}; + +struct Has_Static_Members{ + int a; + int b; + static uint64_t c; + static uint64_t d; + + int w(void){ return a; } + int x(void){ return b; } + static uint64_t y(void){ return c; } + static uint64_t z(void){ return d; } +}; + +uint64_t Has_Static_Members::c = 0; +uint64_t Has_Static_Members::d = 0; + +struct Pointer_To_Member{ + int Has_Members::*member_ptr_int; + uint64_t Has_Members::*member_ptr_u64; + Basics Has_Members::*member_ptr_bas; + + int (Has_Members::*method_ptr_int)(void); + uint64_t (Has_Members::*method_ptr_u64)(void); + Basics (Has_Members::*method_ptr_bas)(void); +}; + +struct Has_Sub_Types{ + struct Sub_Type1{ + int x; + int y; + }; + + struct Sub_Type2{ + float x; + float y; + }; + + Sub_Type1 a; + Sub_Type2 b; +}; + +struct Conflicting_Type_Names{ + struct Sub_Type1{ + uint64_t z; + }; + + struct Sub_Type2{ + int64_t z; + }; + + Sub_Type1 a; + Sub_Type2 b; +}; + +struct Has_Private_Sub_Types{ + Has_Private_Sub_Types(char x1, char y1, + float x2, int y2, + int x3, float y3){ + this->a.x = x1; + this->a.y = y1; + this->b.x = x2; + this->b.y = y2; + this->c.x = x3; + this->c.y = y3; + } + + struct Public_Sub_Type{ + char x; + char y; + }; + Public_Sub_Type a; + + protected: + struct Protected_Sub_Type{ + float x; + int y; + }; + Protected_Sub_Type b; + + private: + struct Private_Sub_Type{ + int x; + float y; + }; + Private_Sub_Type c; +}; + +struct Vtable_Parent{ + virtual void a_virtual_function(void) = 0; + virtual void b_virtual_function(void) = 0; + virtual void c_virtual_function(void) = 0; + + void a_virtual_function(int r){ + for (int i = 0; i < r; i += 1){ + a_virtual_function(); + } + } +}; + +struct Vtable_Child : Vtable_Parent{ + int x; + int y; + + Vtable_Child(int a, int b){ + x = a; + y = b; + } + virtual void a_virtual_function(void){ + x = 0; + }; + virtual void b_virtual_function(void){ + y = 0; + }; + virtual void c_virtual_function(void){ + x = y; + }; +}; + +struct Vinheritance_Base{ + int x; + int y; + + virtual void a_virtual_function(void){ + x = 0; + }; + virtual void b_virtual_function(void){ + y = 0; + }; + virtual void x_virtual_function(void){ + y = x; + }; +}; + +struct Vinheritance_MidLeft : virtual Vinheritance_Base{ + float left; + + virtual void c1_virtual_function(void){ + left = 0; + }; + virtual void c2_virtual_function(void){ + left = 0; + }; +}; + +struct Vinheritance_MidRight : virtual Vinheritance_Base{ + float right; + + virtual void d_virtual_function(void){ + right = 0; + }; +}; + +struct Vinheritance_Child : Vinheritance_MidLeft, Vinheritance_MidRight{ + char *name; + + virtual void a_virtual_function(void){ + x = 1; + }; + virtual void c1_virtual_function(void){ + left = 1; + }; +}; + +struct Minheritance_Base{ + int x; + int y; +}; + +struct Minheritance_MidLeft : Minheritance_Base{ + float left; +}; + +struct Minheritance_MidRight : Minheritance_Base{ + float right; +}; + +struct Minheritance_Child : Minheritance_MidLeft, Minheritance_MidRight{ + char *name; +}; + +struct Pure +{ + virtual ~Pure() = default; + virtual void Foo() = 0; +}; + +struct PureChild : Pure +{ + virtual ~PureChild() = default; + virtual void Foo() {a += 1;} + double a = 0; +}; + +struct Base +{ + int x; + int y; + int z; + Base(){x = 1; y = 2; z = 3;} + virtual ~Base() = default; + virtual void Foo() = 0; +}; + +struct Derived : Base +{ + int r; + int g; + int b; + int a; + virtual ~Derived() = default; + virtual void Foo() + { + x += 1; + y += 1; + y += 1; + z += 1; + z += 1; + z += 1; + a += 1; + a += 1; + a += 1; + a += 1; + } +}; + +struct DerivedA : Base +{ + float a; + float b; + DerivedA() {a = 123.f; b = 123.f;} + virtual void Foo() {a += 1;} + virtual ~DerivedA() = default; +}; + +struct DerivedB : Base +{ + double c; + double d; + DerivedB() {c = 123.0; d = 123.0;} + virtual void Foo() {c += 1;} + virtual ~DerivedB() = default; +}; + +struct NonVirtualBase +{ + int x; + int y; + int z; +}; + +struct NonVirtualDerived : NonVirtualBase +{ + int r; + int g; + int b; + int a; +}; + +struct OverloadedMethods{ + int x; + int cool_method(void){ + return(x); + } + int cool_method(int z){ + int r = x; + x = z; + return(r); + } + void cool_method(int y, int z){ + if (x < z){ + x = y; + } + else{ + x = z; + } + } +}; + +struct HasStaticConstMembers +{ + int a; + int b; + static int c; + static int d; + static const int e = 789; + static const int f = 101112; +}; + +int HasStaticConstMembers::c = 123; +int HasStaticConstMembers::d = 456; + +struct Has_A_Constructor{ + int n; + int d; + Has_A_Constructor(int a, int b){ + int gcd = 1; + { + int x = a; + int y = b; + if (x < y){ + y = a; + x = b; + } + for (;y > 0;){ + int z = x%y; + x = y; + y = z; + } + gcd = x; + } + n = a/gcd; + d = b/gcd; + } + + static int N; + static int D; + ~Has_A_Constructor(){ + int m = N*d + n*D; + int e = d*D; + N = m; + D = d; + } +}; + +int Has_A_Constructor::N = 0; +int Has_A_Constructor::D = 1; + +struct Constructor_Gotcha_Test{ + int x; + int y; + void Constructor_Gotcha(void){ + x = y = 0; + } +}; + +struct Has_A_Friend{ + friend struct Modifies_Other; + int get_x(void){ return x; } + int get_y(void){ return y; } + + private: + int x; + int y; +}; + +struct Modifies_Other{ + int x; + int y; + + void talk_to_friend(Has_A_Friend *other){ + other->x = y; + other->y = x; + } +}; + +namespace UserNamespace{ + namespace SubA{ + struct Foo{ + int x; + int y; + }; + }; + namespace SubB{ + struct Foo{ + float u; + float v; + }; + }; + + SubA::Foo foo_a = {10, 20}; + SubB::Foo foo_b = {0.1f, 0.05f}; + + static void namespaced_function(void){ + foo_a.x = (int)(foo_a.y*foo_b.u); + foo_b.v = (float)(foo_a.x*foo_b.v); + } +}; + +static void +call_with_pass_by_reference(int &x){ + x += 1; +} + +static void +call_with_pass_by_const_reference(const int &x){ + int y = x; +} + +static void +extended_type_coverage_eval_tests(void){ + //////////////////////////////// + // NOTE(allen): Extensions to base type system. + { + int x = 0; + const int *x_ptr = &x; + int *const x_cptr = &x; + + call_with_pass_by_reference(x); + + call_with_pass_by_const_reference(x); + } + + //////////////////////////////// + // NOTE(allen): Extensions to user defined types + { + Template_Example temp_f = {1.f, 2}; + Template_Example temp_v = {(void*)&temp_f, 2}; + Template_Example > temp_tf = {temp_f, 2}; + Template_Example2 temp_if = {2, 1.f}; + Template_Example3 temp3_if(2, 1.f); + Template_Example3 temp3_vi((void *)&temp3_if, 1.f); + Template_Example3> temp3_itif(123, temp_if); + + SingleInheritanceDerived sid; + sid.x = 123; + sid.y = 456; + sid.z = 789; + sid.w = 999; + + Pointer_To_Member pointer_to_member = { + &Has_Members::a, &Has_Members::c, &Has_Members::bas, + &Has_Members::x, &Has_Members::z, &Has_Members::bas_f, + }; + + Has_Static_Members has_static_members = { 10, 20 }; + Has_Static_Members::c = 100; + Has_Static_Members::d = 110; + has_static_members.x(); + has_static_members.y(); + has_static_members.z(); + has_static_members.w(); + + Has_Sub_Types has_sub_types = { + {100, 200}, + {.1f, .2f}, + }; + + Conflicting_Type_Names conflicting_type_names = { + {10}, {-20}, + }; + + Has_Private_Sub_Types has_private_sub_types(1, 2, 4, 8, 16, 32); + + Vtable_Child vtable_child(1, 2); + vtable_child.a_virtual_function(); + + Vinheritance_Child vinheritance_child; + vinheritance_child.name = "foobar"; + vinheritance_child.left = 10.5f; + vinheritance_child.right = 13.0f; + vinheritance_child.x = -1; + vinheritance_child.y = -1; + + Minheritance_Child minheritance_child; + minheritance_child.name = "foobar"; + minheritance_child.left = 10.5f; + minheritance_child.right = 13.0f; + minheritance_child.Minheritance_MidLeft::x = -1; + minheritance_child.Minheritance_MidLeft::y = -1; + minheritance_child.Minheritance_MidRight::x = +1; + minheritance_child.Minheritance_MidRight::y = +1; + + Pure *child = new PureChild(); + child->Foo(); + child->Foo(); + child->Foo(); + delete child; + + Base *derived = new Derived(); + derived->Foo(); + derived->Foo(); + derived->Foo(); + delete derived; + + NonVirtualBase *non_virtual_derived = new NonVirtualDerived(); + non_virtual_derived->x += 1; + non_virtual_derived->x += 1; + non_virtual_derived->x += 1; + + std::unique_ptr ridiculous_cplusplus_base_class = std::make_unique(); + + std::vector> ridiculous_cplusplus_array; + for(int i = 0; i < 1024; i += 1) + { + if((i & 1) == 1) + { + ridiculous_cplusplus_array.push_back(std::make_unique()); + } + else + { + ridiculous_cplusplus_array.push_back(std::make_unique()); + } + } + + Base *base_array[1024] = {0}; + for(int i = 0; i < sizeof(base_array)/sizeof(base_array[0]); i += 1) + { + if((i & 1) == 1) + { + base_array[i] = new DerivedA(); + } + else + { + base_array[i] = new DerivedB(); + } + } + + OverloadedMethods overloaded_methods; + { + overloaded_methods.x = 0; + int a = overloaded_methods.cool_method(); + overloaded_methods.cool_method(-10, 100); + int b = overloaded_methods.cool_method(100); + overloaded_methods.cool_method(b*2, a*2); + int c = overloaded_methods.cool_method(a + b); + int z = c; + } + + Has_A_Constructor construct_me(360, 25); + + Has_A_Friend has_a_friend; + + Modifies_Other modifies_other; + modifies_other.x = 57; + modifies_other.y = 66; + + modifies_other.talk_to_friend(&has_a_friend); + + int x = has_a_friend.get_x(); + int y = has_a_friend.get_y(); + int z = x; + + HasStaticConstMembers static_const_members = {0}; + static_const_members.a = 123 + HasStaticConstMembers::c * HasStaticConstMembers::e; + static_const_members.b = 456 + HasStaticConstMembers::d * HasStaticConstMembers::f; + } + + //////////////////////////////// + // NOTE(allen): Namespaces + { + UserNamespace::namespaced_function(); + } +} + +//////////////////////////////// +//~ rjf: Templated Function Eval Tests + +typedef struct TemplateArg TemplateArg; +struct TemplateArg +{ + int x; + int y; + int z; + float a; + float b; + float c; + char *name; +}; + +template static T +templated_factorial(T t) +{ + T result = t; + if(t > 1) + { + result *= templated_factorial(t-1); + } + return result; +} + +template static T +compute_template_arg_info(T t) +{ + int sum = t.x + t.y + t.z; + int size = sizeof(t); + float sum_f = t.a + t.b + t.c; + OutputDebugStringA(t.name); + return t; +} + +static void +templated_function_eval_tests(void) +{ + int int_factorial = templated_factorial(10); + float float_factorial = templated_factorial(10); + TemplateArg arg = {1, 2, 3, 4.f, 5.f, 6.f, "my template arg"}; + compute_template_arg_info(arg); + int x = 0; +} + +//////////////////////////////// +//~ NOTE(allen): C Type Coverage + +extern "C"{ +#include "mule_c.h" +} + +//////////////////////////////// +//~ rjf: Basic Inline Line Info Tests + +#if defined(_MSC_VER) +# define FORCE_INLINE __forceinline +#elif defined(__clang__) +# define FORCE_INLINE __attribute__((always_inline)) +#else +# error need force inline for this compiler +#endif + +static FORCE_INLINE void +basic_inlinee(int inlinee_param_x, int inlinee_param_y, int inlinee_param_z) +{ + OutputDebugStringA("A\n"); + OutputDebugStringA("B\n"); + OutputDebugStringA("C\n"); + OutputDebugStringA("D\n"); +} + +static void +basic_inline_tests(void) +{ + OutputDebugStringA("{\n"); + basic_inlinee(12, 34, 56); + OutputDebugStringA("}\n"); +} + +//////////////////////////////// +//~ rjf: Fancy Visualization Eval Tests + +struct PackedBits +{ + unsigned char b1 : 1; + unsigned char b2 : 1; + unsigned char b3 : 1; + unsigned char b4 : 1; + unsigned char b5 : 1; + unsigned char b6 : 1; +}; +raddbg_type_view(unsigned char : 1, bool($)); + +struct Bitmap +{ + unsigned char *base; + int width; + int height; +}; +raddbg_type_view(Bitmap, bitmap(base, width, height)); + +static unsigned int +mule_bswap_u32(unsigned int x) +{ + unsigned int result = (((x & 0xFF000000) >> 24) | + ((x & 0x00FF0000) >> 8) | + ((x & 0x0000FF00) << 8) | + ((x & 0x000000FF) << 24)); + return result; +} + +static void +fancy_viz_eval_tests(void) +{ + //- rjf: windows -> GetLastError +#if _WIN32 + DWORD error_code = 0; + SetLastError(1234); + error_code = GetLastError(); + SetLastError(4567); + error_code = GetLastError(); + (void)error_code; +#endif + + //- rjf: booleans (checkboxes) + bool bool1 = 0; raddbg_pin(bool1); + bool bool2 = 1; raddbg_pin(bool2); + bool bool3 = 0; raddbg_pin(bool3); + PackedBits packed_bits = {}; + packed_bits.b1 = 1; + packed_bits.b3 = 1; + packed_bits.b5 = 1; + + //- rjf: sliders + float slide1 = 500.f; raddbg_pin(range1(slide1, 0, 1000)); + double slide2 = 0.75; raddbg_pin(range1(slide2, 0, 1.0)); + int slide3 = 25; raddbg_pin(range1(slide3, 0, 100)); + + //- rjf: colors + float example_color_4f32[4] = {1.00f, 0.85f, 0.25f, 1.00f}; + unsigned int example_color_u32 = 0xff6f30ff; + struct {float r, g, b, a;} example_color_struct = {0.50f, 0.95f, 0.75f, 1.00f}; + int x0 = 0; + raddbg_pin(color(example_color_4f32)); + raddbg_pin(color(example_color_u32)); + raddbg_pin(color(example_color_struct)); + + //- rjf: multiline text + char *long_string = ("This is an example of some very long text with line breaks\n" + "in it. This is a very common kind of data which is inspected\n" + "in the debugger while programming, and it is often a pain\n" + "when it is poorly supported.\n"); + char *code_string = ("#include \n" + "\n" + "int main(int argc, char**argv)\n" + "{\n" + " printf(\"Hello, World!\\n\");\n" + " return 0;\n" + "}\n\n"); + int x1 = 0; + raddbg_pin(text(long_string)); + raddbg_pin(text(code_string, lang=c)); + raddbg_pin(disasm(fancy_viz_eval_tests)); + + //- rjf: programmatic memory annotations + void *some_block_of_memory = malloc(256); + memset(some_block_of_memory, 0x27, 256); + raddbg_annotate_vaddr_range(some_block_of_memory, 256, "test memory annotation"); + + //- rjf: half-floats + PackedF16 f16s[] = + { + {0x0001}, // ~0.000000059604645 + {0x03ff}, // ~0.000060975552 + {0x0400}, // ~0.00006103515625 + {0x3555}, // ~0.33325195 + {0x3bff}, // ~0.99951172 + {0x3c00}, // 1 + {0x3c01}, // 1.00097656 + {0x7bff}, // 65504, + {0x7c00}, // +inf + {0xfc00}, // -inf + }; + + //- rjf: table index lookups + struct + { + char *name; + int x; + int y; + int z; + } + nodes[] = + { + {"---", 1, 7, 3}, + {"---", 5, 4, 2}, + {"second", 12, 41, 22}, + {"---", 8, 9, 1}, + {"---", 1, 1, 1}, + {"first", 50, 50, 50}, + {"fourth", 7, 7, 7}, + {"---", 7, 12, 1}, + {"third", 27, 43, 41}, + {"---", 2, 17, 50}, + }; + int node_indices[] = + { + 5, 2, 8, 6 + }; + raddbg_pin(columns(node_indices, nodes[$])); + + //- rjf: bitmaps + unsigned int background_color = 0x00000000; + unsigned int main_color = 0xff2424ff; + unsigned int shine_color = 0xff5693ff; + unsigned int shadow_color = 0xff238faf; + unsigned int bg = mule_bswap_u32(background_color); + unsigned int cl = mule_bswap_u32(main_color); + unsigned int sn = mule_bswap_u32(shine_color); + unsigned int sh = mule_bswap_u32(shadow_color); + unsigned int pixels[] = + { + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, cl, cl, bg, cl, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, cl, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, cl, sn, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, sh, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, sh, cl, cl, cl, sh, sh, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, sh, sh, sh, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + }; + raddbg_pin(bitmap(pixels, 18, 18)); + for(int i = 0; i < sizeof(pixels)/sizeof(pixels[0]); i += 1) + { + unsigned int r = pixels[i]&0x000000ff; + unsigned int a = pixels[i]&0xff000000; + pixels[i] = pixels[i]>>8; + pixels[i] &= ~0xffff0000; + pixels[i] |= (r<<16); + pixels[i] |= (a); + } + for(int i = 0; i < sizeof(pixels)/sizeof(pixels[0]); i += 1) + { + unsigned int r = pixels[i]&0x000000ff; + unsigned int a = pixels[i]&0xff000000; + pixels[i] = pixels[i]>>8; + pixels[i] &= ~0xffff0000; + pixels[i] |= (r<<16); + pixels[i] |= (a); + } + for(int i = 0; i < sizeof(pixels)/sizeof(pixels[0]); i += 1) + { + unsigned int r = pixels[i]&0x000000ff; + unsigned int a = pixels[i]&0xff000000; + pixels[i] = pixels[i]>>8; + pixels[i] &= ~0xffff0000; + pixels[i] |= (r<<16); + pixels[i] |= (a); + } + int x2 = 0; + + //- rjf: type-viewed bitmaps + Bitmap foo = {(unsigned char *)&pixels[0], 18, 18}; + raddbg_pin(foo); + + //- rjf: name collisions with debugger rules + Function_Few_Params_Type *raw = 0; + char *text = "some_important_text_here\n"; + Bitmap bitmap = foo; + int x3 = 0; + + //- rjf: 3D geometry + float vertex_data[] = // pos.x, pos.y, pos.z, nor.x, nor.y, nor.z, tex.u, tex.v, col.r, col.g, col.b, ... + { + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 2.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 2.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 8.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 8.0f, 0.973f, 0.480f, 0.002f, + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 2.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 2.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 8.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 8.0f, 0.612f, 0.000f, 0.069f, + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 2.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 2.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 8.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 8.0f, 0.000f, 0.254f, 0.637f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 2.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 2.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 8.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 8.0f, 0.001f, 0.447f, 0.067f, + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + }; + unsigned int index_data[] = + { + 0, 1, 9, 9, 8, 0, 1, 2, 5, 5, 4, 1, 6, 7, 10, 10, 9, 6, 2, 3, 11, 11, 10, 2, + 12, 13, 21, 21, 20, 12, 13, 14, 17, 17, 16, 13, 18, 19, 22, 22, 21, 18, 14, 15, 23, 23, 22, 14, + 24, 25, 33, 33, 32, 24, 25, 26, 29, 29, 28, 25, 30, 31, 34, 34, 33, 30, 26, 27, 35, 35, 34, 26, + 36, 37, 45, 45, 44, 36, 37, 38, 41, 41, 40, 37, 42, 43, 46, 46, 45, 42, 38, 39, 47, 47, 46, 38, + 48, 49, 57, 57, 56, 48, 49, 50, 53, 53, 52, 49, 54, 55, 58, 58, 57, 54, 50, 51, 59, 59, 58, 50, + 60, 61, 69, 69, 68, 60, 61, 62, 65, 65, 64, 61, 66, 67, 70, 70, 69, 66, 62, 63, 71, 71, 70, 62, + 72, 73, 74, 74, 75, 72, 76, 77, 78, 78, 79, 76, 80, 81, 82, 82, 83, 80, 84, 85, 86, 86, 87, 84, + 88, 89, 90, 90, 91, 88, 92, 93, 94, 94, 95, 92, 96, 97, 98, 98, 99, 96, 100, 101, 102, 102, 103, 100, + 104, 105, 106, 106, 107, 104, 108, 109, 110, 110, 111, 108, 112, 113, 114, 114, 115, 112, 116, 117, 118, 118, 119, 116, + 120, 121, 122, 122, 123, 120, 124, 125, 126, 126, 127, 124, 128, 129, 130, 130, 131, 128, 132, 133, 134, 134, 135, 132, + 136, 137, 138, 138, 139, 136, 140, 141, 142, 142, 143, 140, 144, 145, 146, 146, 147, 144, 148, 149, 150, 150, 151, 148, + 152, 153, 154, 154, 155, 152, 156, 157, 158, 158, 159, 156, 160, 161, 162, 162, 163, 160, 164, 165, 166, 166, 167, 164, + }; + int count = (sizeof index_data/4); + float *vtx = vertex_data; + int vtx_size = sizeof vertex_data; + raddbg_pin(geo3d(index_data, count = count, vtx = vtx, vtx_size = vtx_size)); + int x4 = 0; +} + +//////////////////////////////// +//~ rjf: Markup Tests + +static void +markup_tests(void) +{ + int x = 0; + raddbg_add_breakpoint(&x, sizeof(x), 0, 1, 0); + for(int i = 0; i < 10000; i += 1) + { + if(i == 5000) + { + x += 1; + } + } + raddbg_remove_breakpoint(&x, sizeof(x), 0, 1, 0); +} + +//////////////////////////////// +//~ NOTE(allen): Function Overload Resolution + +static int +overloaded_function(float y){ + int r = (int)(y + 0.5f); + return(r); +} + +static int +overloaded_function(float y, int x){ + int r = overloaded_function(y) + x; + return(r); +} + +static int +overloaded_function(int x){ + float y = (float)x; + int r = overloaded_function(y, 1); + return(r); +} + +//////////////////////////////// +// NOTE(allen): Control Flow Stepping + +static void +control_flow_stepping_tests(void){ + { + int a = 1; + if (a < 1){ /// 1000: { run_to_line at step_over } + a += 1; + } + if (a < 2){ /// 1001: { at step_over } + a += 2; /// 1002: { at step_over } + } + } + + { + int a = 1; /// 1003: { at step_over } + if (a < 1) /// 1004: { at step_over } + { + a += 1; + } + if (a < 2) /// 1005: { at step_over } + { + a += 2; /// 1006: { at step_over } + } + } + + { + int a = 1; /// 1007: { at step_over } + if (a < 1) /// 1008: { at step_over } + a += 1; + if (a < 2) /// 1009: { at step_over } + a += 2; /// 1010: { at step_over } + } + + { + int a = 1; /// 1011: { at step_over } + int b = 2; /// 1012: { at step_over } + if (a <= b){ /// 1013: { at step_over } + if (a == b){ /// 1014: { at step_over } + b += 1; + } + else{ + a += 1; /// 1015: { at } + } + } + else{ + if (a%2){ + a = b; + } + else{ + a = b - 1; + } + } + } + + { + int a = 1; /// 1016: { run_to_line at step_over } + int b = 2; /// 1017: { at step_over } + if (a <= b) + { + if (a == b) /// 1018: { at step_over } + { + b += 1; + } + else + { + a += 1; /// 1019: { at } + } + } + else + { + if (a%2) + { + a = b; + } + else + { + a = b - 1; + } + } + } + + { + int a = 1; /// 1020: { run_to_line at step_over } + int b = 2; /// 1021: { at step_over } + if (a <= b) /// 1022: { at step_over } + if (a == b) /// 1023: { at step_over } + b += 1; + else + a += 1; /// 1024: { at step_over } + else + if (a%2) + a = b; + else + a = b - 1; + } + + { + int x = 0; /// 1025: { at step_over } + for (int i = 0; i < 10; i += 1){ /// 1026: { at step_over } + x += i; /// 1027: { at step_over } + } + } + + { + int x = 0; // 1028: { run_to_line at } + for (int i = 0; i < 10; i += 1) + { + x += i; + } + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) + x += i; + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) x += i; + } + + { + int a = 1; + for (;a < 10;){ + switch (a){ + case 0: case 1: case 2: + { + a += 2; + }break; + + default: + case 4: + case 5: + { + a += 1; + }break; + + case 6: a += 1; break; + case 7: a += 1; + case 8: + case 9: a += 1; + } + } + } + + { + int i = 0; + while (i < 5){ + i += 1; + } + + while (i < 10) + { + i += 1; + } + + while (i < 15) + i += 1; + + while (i < 20) i += 1; + } + + { + int i = 0; + do + { + i += 1; + } while (i < 10); + } + + { + int i = 17; + + check_again: + if (i <= 1) goto done; + if ((i&1) == 0) goto even_case; + + // odd_case: + i = 3*i + 1; + + even_case: + i /= 2; + goto check_again; + + done:; + } + + { + int x = 15; + label_same_line:; x -= 1; if(x > 0) { goto label_same_line; } else { goto end_label_same_line; } + } + end_label_same_line:; +} + +//////////////////////////////// +// NOTE(allen): Indirect Call/Jump Stepping Tests + +typedef int FunctionType(int); + +static int +function_foo(int a){ + if (a < 1){ + a += 1; + } + if (a < 2){ + a += 2; + } + return(a); +} + +static int +function_bar(int x){ + for (int i = 0; i < 10; i += 1){ + x += i; + } + return(x); +} + + +static void +indirect_call_jump_stepping_tests(void){ + int z = 1; + FunctionType *ptr = function_foo; + z = ptr(z); + if ((z & 1) == 0){ + ptr = function_bar; + } + z = ptr(z); + + switch (z&7){ + case 0: + { + z += 2; + ptr = function_bar; + }break; + + case 1: + { + z += 1; + ptr = function_bar; + }break; + + case 2: + { + z *= 2; + ptr = function_bar; + }break; + + case 3: + { + z -= 10; + ptr = function_foo; + }break; + + case 4: + { + z -= 5; + ptr = function_foo; + }break; + + case 5: + { + z = z ^ 0x10; + ptr = function_foo; + }break; + + case 6: + { + z = z & ~0x10; + ptr = function_foo; + }break; + + case 7: + { + z = z | 0x10; + ptr = function_foo; + }break; + } + + z = ptr(z); +} + +//////////////////////////////// +// NOTE(rjf): alloca (Variable-Width Stack Changes) Stepping Tests + +static void +alloca_stepping_tests(void) +{ + int x = 1; + int y = 3; + int z = 5; + +#if _WIN32 + int *mem = (int *)_alloca((x+y+z)*sizeof(int)); + mem[0] = x; + mem[1] = y; + mem[2] = z; +#else + int *mem = (int *)__builtin_alloca((x+y+z)*sizeof(int)); + mem[0] = x; + mem[1] = y; + mem[2] = z; +#endif +} + +//////////////////////////////// +// NOTE(allen): Overloaded Line Stepping + +static int +function_get_integer(void){ + return(1); +} + +static void +function_with_multiple_parameters(int x, int y){ + x += y; +} + +static int +recursive_single_line(int x){ return(x <= 1?0:x + recursive_single_line(x/2)); } + +static int shared_1(int x) { return(x); } static int shared_2(int x) { return(1 + shared_1(x)); } + +static void +overloaded_line_stepping_tests(void){ + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + + recursive_single_line(50); + recursive_single_line(50); + recursive_single_line(50); + + shared_2(5); + shared_2(5); + shared_2(5); + + function_get_integer(); shared_1(1); shared_1(2); + + if ((shared_2(10) && shared_2(-1)) || + shared_2(function_get_integer())){ + int x = 0; + } + else{ + int y = 0; + } +} + +//////////////////////////////// +// NOTE(allen): Long Jump Stepping + +#include + +static jmp_buf global_jump_buffer; +static int global_jump_x; + +static void +long_jump_from_function(void){ + int spin = 0; + for (; spin < 5; spin += 1); + longjmp(global_jump_buffer, 2); + global_jump_x = spin; +} + +static void +long_jump_wrapped_in_function(void){ + global_jump_x = 0; + int val = setjmp(global_jump_buffer); + if (val == 0){ + global_jump_x = 1; + longjmp(global_jump_buffer, 1); + } + else if (val == 1){ + if (global_jump_x == 1){ + global_jump_x = 2; + long_jump_from_function(); + } + } + else if (val == 2){ + global_jump_x = 3; + } +} + +static void +long_jump_stepping_tests(void){ + + long_jump_wrapped_in_function(); + + long_jump_wrapped_in_function(); + + long_jump_wrapped_in_function(); + +} + +//////////////////////////////// +// NOTE(allen): Recursion Stepping + +static int +recursive_call(int x){ + if (x <= 1){ + return(x); + } + + int r1 = recursive_call(x - 1); + int r2 = recursive_call(x - 2); + return(r1 + r2); +} + +static int +tail_recursive_call(int x, int m){ + if (x <= 1){ + return(m); + } + return(tail_recursive_call(x - 1, x*m)); +} + +static void +recursion_stepping_tests(void){ + + recursive_call(4); + + recursive_call(4); + + tail_recursive_call(5, 1); + + tail_recursive_call(5, 1); + +} + +//////////////////////////////// +// NOTE(rjf): Thread Stepping + +#if _WIN32 +DWORD thread_step_thread(void *p) +{ + int x = 0; + for(int i = 0; i < 100000; i += 1) + { + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + x += 1; + } + return 0; +} +#endif + +void thread_stepping_tests(void) +{ +#if _WIN32 + HANDLE h[8] = {0}; + for(int i = 0; i < sizeof(h)/sizeof(h[0]); i += 1) + { + DWORD id = 0; + h[i] = CreateThread(0, 0, thread_step_thread, 0, CREATE_SUSPENDED, &id); + raddbg_thread_id_name(id, "thread_step_thread_%i", i); + raddbg_thread_id_color_u32(id, 0xff9f23ff); + } + for(int i = 0; i < sizeof(h)/sizeof(h[0]); i += 1) + { + ResumeThread(h[i]); + } + for(int i = 0; i < sizeof(h)/sizeof(h[0]); i += 1) + { + WaitForSingleObject(h[i], INFINITE); + } +#endif +} + +//////////////////////////////// +// NOTE(rjf): Debug Strings + +static void +debug_string_tests(void) +{ + for(int i = 0; i < 100; i += 1) + { + printf("here is a number: %i\n", i); + fflush(stdout); + } +#if _WIN32 + for(int i = 0; i < 100; i += 1) + { + OutputDebugStringA("Hello, World!\n"); + } + char message[65409+1]; + memset(&message[0], '=', sizeof(message)); + for(int i = 1; i < sizeof(message); i += 128) + { + message[i] = '\n'; + } + message[sizeof(message) - 1] = 0; + OutputDebugStringA(message); +#endif +} + +//////////////////////////////// +//~ rjf: Thread Name Test + +#if _WIN32 +DWORD dummy_thread(void *p) +{ + Sleep(10); + return 0; +} +#endif + +static void +thread_name_tests(void) +{ +#if _WIN32 + DWORD id = 0; + HANDLE h = CreateThread(0, 0, dummy_thread, 0, CREATE_SUSPENDED, &id); + raddbg_thread_id_name(id, "dummy_thread"); + raddbg_thread_id_color_u32(id, 0xff1f23ff); + ResumeThread(h); + WaitForSingleObject(h, INFINITE); +#endif +} + +//////////////////////////////// +//~ rjf: Interrupt Stepping Tests + +#include + +static void +interrupt_stepping_tests(void) +{ + __debugbreak(); + __debugbreak(); + __debugbreak(); + __debugbreak(); + for(int i = 0; i < 1000; i += 1) + { + if(i == 999) + { + __debugbreak(); + } + } + for(int i = 0; i < 1000; i += 1) + { + if(i == 999) + { + assert(0); + } + } + int x = 0; +} + +//////////////////////////////// +//~ rjf: JIT Stepping Tests + +static void +jit_stepping_tests(void) +{ + OutputDebugString("A\n"); + VOID *code = VirtualAlloc(0, 0x1000, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); + *((uint32_t*)code) = 0xC39090CC; + ((void (__fastcall *)()) code)(); + OutputDebugString("B\n"); +} + +//////////////////////////////// +// NOTE(allen): Exception Stepping + +static void +exception_filter_test(void) +{ + __try + { + RaiseException(0xc0000095, 0, 0, 0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + OutputDebugStringA("did an exception\n"); + } +} + +int *global_null_read_pointer = 0; +static void +trip(void){ + *global_null_read_pointer = 0; +} + +static void +cpp_exception_in_function(void){ + int v = 0; + try{ + throw 1; + } + catch (...){ + v = 1; + } +} + +static void +cpp_throw_in_function(void){ + throw 1; +} + +static void +win32_exception_in_function(void){ +#if _WIN32 + int v = 0; + __try{ + trip(); + v = 1; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + v = 2; + } + + v = 3; + __try{ + trip(); + v = 4; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + v = 5; + } +#endif +} + +static void +cpp_recursive_exception(int x){ + try{ + if (x > 1){ + throw 1; + } + } + catch (...){ + x -= 1; + cpp_recursive_exception(x); + x += 1; + } +} + +static void +win32_recursive_exception(int x){ +#if _WIN32 + __try{ + if (x > 1){ + throw 1; + } + } + __except (EXCEPTION_EXECUTE_HANDLER){ + x -= 1; + win32_recursive_exception(x); + x += 1; + } +#endif +} + +static void +exception_stepping_tests(void){ + { + int v = 0; + try{ + throw 1; + } + catch (...){ + v = 1; + } + } + + { + int v = 0; + try{ + cpp_throw_in_function(); + } + catch (...){ + v = 1; + } + } + + cpp_exception_in_function(); + cpp_exception_in_function(); + +#if _WIN32 + win32_exception_in_function(); + win32_exception_in_function(); +#endif + + // NOTE(allen): Exception in catch tests + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + try{ + v = 2; + throw 2; + } + catch (...){ + v = 3; + } + } + } + + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + cpp_exception_in_function(); + } + } + +#if _WIN32 + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + win32_exception_in_function(); + } + } +#endif + + cpp_recursive_exception(4); + cpp_recursive_exception(4); + cpp_recursive_exception(4); + +#if _WIN32 + win32_recursive_exception(4); + win32_recursive_exception(4); + win32_recursive_exception(4); +#endif + + // NOTE(allen): Try in try tests + { + int v = 0; + try{ + try{ + v = 1; + throw 1; + } + catch (...){ + v = 2; + } + throw 2; + } + catch (...){ + v = 3; + } + } + + { + int v = 0; + try{ + try{ + v = 1; + cpp_throw_in_function(); + } + catch (...){ + v = 2; + } + throw 2; + } + catch (...){ + v = 3; + } + } + + { + int v = 0; + try{ + cpp_exception_in_function(); + throw 2; + } + catch (...){ + v = 3; + } + } + +#if _WIN32 + { + int v = 0; + try{ + win32_exception_in_function(); + throw 2; + } + catch (...){ + v = 3; + } + } +#endif + +} + +typedef void (*callback_t)(int a); +static void +dynamic_step_test(void){ +#if _WIN32 +#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( _M_AMD64 ) + void *page = VirtualAlloc(0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); + char *ptr = (char*)page; + *ptr++ = 0x51; // push rcx + *ptr++ = 0x59; // pop rcx + *ptr++ = 0xC3; // ret + callback_t cb = (callback_t)page; + cb(1); +#endif +#endif +} + +//////////////////////////////// + +raddbg_entry_point(mule_main); + +int +mule_main(int argc, char** argv) +{ //// 1: { run_to_line at } + + raddbg_thread_name("mule_main_thread"); + raddbg_thread_color_rgba(0.4f, 0.9f, 0.2f, 1); + if(raddbg_is_attached()) + { + raddbg_log("raddbg is attached!\n"); + } + + mule_init(); + + // NOTE(allen): Stepping Tests + control_flow_stepping_tests(); + + // NOTE(allen): Eval Tests + type_coverage_eval_tests(); + + mutating_variables_eval_tests(); + + nested_types_eval_tests(); + + struct_parameters_eval_tests(); + + global_eval_tests(); + + return_eval_tests(); + + tls_eval_tests(); + + complicated_type_coverage_tests(); + + extended_type_coverage_eval_tests(); + + templated_function_eval_tests(); + + c_type_coverage_eval_tests(); + + c_type_with_bitfield_usage(); + + optimized_build_eval_tests(); + + optimized_struct_parameters_eval_tests(); + + fancy_viz_eval_tests(); + + exception_filter_test(); + + markup_tests(); + + indirect_call_jump_stepping_tests(); + + alloca_stepping_tests(); + + basic_inline_tests(); + + inline_stepping_tests(); + + overloaded_line_stepping_tests(); + + overloaded_function(100); + + dynamic_step_test(); + + long_jump_stepping_tests(); + + recursion_stepping_tests(); + + thread_stepping_tests(); + + debug_string_tests(); + + thread_name_tests(); + + jit_stepping_tests(); + + interrupt_stepping_tests(); + + exception_stepping_tests(); + + return(0); +} + +/// file: "mule_module.cpp" + +#if _WIN32 +#define export_function extern "C" __declspec(dllexport) +#else +#define export_function extern "C" +#endif + +#if _WIN32 +# define thread_var __declspec(thread) +#else +# define thread_var __thread +#endif + +typedef struct OnlyInModule OnlyInModule; +struct OnlyInModule +{ + int x; + int y; + int z; + char *name; +}; + +typedef struct Basics Basics; +struct Basics +{ + int a; + int b; + int c; + int d; +}; + +static OnlyInModule only_in_module_global = +{ + 1, 2, 3, "foobar", +}; + +thread_var float tls_a = 1.015625f; +thread_var int tls_b = -100; + +export_function void +dll_tls_eval_test(void) +{ + tls_a *= 1.5f; + tls_b *= -2; + only_in_module_global.x += 1; + only_in_module_global.y += 2; + only_in_module_global.z += 3; +} + +export_function void +dll_type_eval_tests(void) +{ + Basics basics1 = {1, 2, 3, 4}; + Basics basics2 = {4, 5, 6, 7}; + OnlyInModule only_in_module = {123, 456, 789, "this type is only in the module!"}; + int x = 0; + (void)x; +} + diff --git a/src/torture/torture.c b/src/torture/torture.c index 385ab907..4cda5a7b 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -8,6 +8,7 @@ global String8 g_out = str8_lit_comp("torture_artifacts"); global B32 g_verbose; global B32 g_redirect_stdout = 1; global B32 g_stop_on_first_fail_or_crash = 1; +global B32 g_build_only = 0; global String8 g_test_data; // tests @@ -1091,6 +1092,7 @@ t_help(void) fprintf(stderr, " -linker: Path to PE/COFF linker\n"); fprintf(stderr, " -print_stdout Print to console stdout and stderr of a run\n"); fprintf(stderr, " -out: Directory path for test outputs (default \"%.*s\")\n", str8_varg(g_out)); + fprintf(stderr, " -build_only Build debugger harness without running the tests\n"); fprintf(stderr, " -verbose Enable verbose mode\n"); fprintf(stderr, " -help Print help menu and exit\n"); fprintf(stderr, "\nInputs are wildcard expressions. Prefix with ! to skip matches, or + to force-run matches.\n"); @@ -1249,6 +1251,7 @@ t_entry_point(CmdLine *cmdline) g_verbose = cmd_line_has_flag(cmdline, str8_lit("verbose")); g_redirect_stdout = !cmd_line_has_flag(cmdline, str8_lit("print_stdout")); g_stop_on_first_fail_or_crash = !cmd_line_has_flag(cmdline, str8_lit("keep_going")); + g_build_only = cmd_line_has_flag(cmdline, str8_lit("build_only")); g_output_arena = arena_alloc(); // default options when running under debugger @@ -1285,13 +1288,34 @@ t_entry_point(CmdLine *cmdline) make_directory(g_out); if (!folder_path_exists(g_out)) { fprintf(stderr, "ERROR: unable to create output directory \"%.*s\"\n", str8_varg(g_out)); - abort_self(1); + goto exit; } // // Clean up output from previous run // delete_file_at_path(g_stdout_file_name); + + // + // Check tools + // + String8 tools[] = { + t_raddbg_path(), + t_radbin_path(), + t_radlink_path(), + t_clang_path(), +#if OS_WINDOWS + t_cl_path(), +#elif OS_LINUX + t_gcc_path(), +#endif + }; + for EachElement(i, tools) { + if ( ! file_path_exists(tools[i])) { + fprintf(stderr, "ERROR: failed to find tool \"%.*s\"\n", str8_varg(tools[i])); + goto exit; + } + } // // Run tests diff --git a/src/torture/torture_d2r.c b/src/torture/torture_d2r.c index 0fc26099..8d30e9d9 100644 --- a/src/torture/torture_d2r.c +++ b/src/torture/torture_d2r.c @@ -281,7 +281,7 @@ SKIP(d2r_line_table) for EachElement(i, test_table) { for EachIndex(k, test_table[i].line_size) { String8 cmdl = str8f(arena, "-voff2line -voff:0x%llx %S", test_table[i].voff + k, t_make_file_path(arena, str8_lit("a.rdi"))); - t_invoke_radbin(cmdl.str); + t_invoke_radbin((char *)cmdl.str); if (g_last_exit_code != 0) { t_errorf("radbin exited with %llu on \"%S\"\n", (unsigned long long)g_last_exit_code, cmdl); diff --git a/src/torture/torture_dbg.c b/src/torture/torture_dbg.c index e92c6e51..7dfb7036 100644 --- a/src/torture/torture_dbg.c +++ b/src/torture/torture_dbg.c @@ -4,25 +4,10 @@ #define T_Dbg_DefaultTimeout TIMEOUT_SEC(5) extern B32 g_stop_on_first_fail_or_crash; +extern B32 g_build_only; //////////////////////////////// -internal void -t_find_line_and_col(String8 source, MD_Node *n, U64 *line_out, U64 *col_out) -{ - U64 line = 1; - U64 col = 1; - for (U64 cursor = 0; cursor < source.size && cursor < n->src_offset; cursor += 1) { - if (source.str[cursor] == '\n') { - line += 1; - col = 0; - } - col += 1; - } - if (line_out) { *line_out = line; } - if (col_out) { *col_out = col; } -} - internal void t_errorf_md(String8 file_name, String8 source, MD_Node *n, char *fmt, ...) { @@ -30,22 +15,16 @@ t_errorf_md(String8 file_name, String8 source, MD_Node *n, char *fmt, ...) va_list args; va_start(args, fmt); String8 result = push_str8fv(scratch.arena, fmt, args); - U64 line = 0, col = 0; - t_find_line_and_col(source, n, &line, &col); - t_errorf("ERROR: %S:%llu%llu: %S\n", file_name, (unsigned long long)line, (unsigned long long)col, result); + TxtPt pt = mg_txt_pt_from_string_off(source, n->src_offset); + t_errorf("ERROR: %S:%llu%llu: %S\n", file_name, (unsigned long long)pt.line, (unsigned long long)pt.column, result); va_end(args); scratch_end(scratch); } //////////////////////////////// -// Debugger IPC Replies +// IPC Controller -typedef struct -{ - MD_ParseResult parse; - MD_Node *root; - MD_Node *msg; -} T_IpcReply; +internal U32 g_dbg_pid; internal B32 t_ipc_parse_string(MD_Node *node, String8 child_name, String8 *out) @@ -75,7 +54,6 @@ t_ipc_parse_u32(MD_Node *node, String8 child_name, U32 *out) return 0; } -#define t_ipc_parse_int(n, c, ptr) t_ipc_parse_int_(n, c, sizeof(*ptr), ptr) internal B32 t_ipc_parse_int_(MD_Node *node, String8 child_name, U64 out_size, void *out) { @@ -112,18 +90,12 @@ t_ipc_parse_b32(MD_Node *node, String8 child_name, B32 *out) return is_ok; } -//////////////////////////////// -// IPC Controller - -internal U32 g_dbg_pid; - internal B32 t_dbg_send_cmd(String8 cmd, U64 timeout_us, Arena *reply_arena, MD_ParseResult *reply_out) { Temp scratch = scratch_begin(&reply_arena, 1); B32 is_sent = 0; - // send command String8 cmdline = str8f(scratch.arena, "--gen_crash_dump --ipc --pid:%u %S", g_dbg_pid, cmd); if (t_invoke(t_raddbg_path(), cmdline, timeout_us) == 0) { goto exit; } @@ -186,7 +158,7 @@ t_dbg_state(Arena *arena, U64 timeout_us) // send status request MD_ParseResult reply = {0}; - if ( ! t_dbg_send_cmd(str8_lit("state"), timeout_us, arena ? arena : scratch.arena, &reply)) { goto exit; } + if ( ! t_dbg_send_cmd(str8_lit("state"), timeout_us, arena, &reply)) { goto exit; } // parse reply MD_Node *state_md = md_child_from_string(reply.root, str8_lit("state"), 0); @@ -221,13 +193,14 @@ t_dbg_src_line(Arena *arena, U64 vaddr, T_DbgLineArray *lines_out, U64 timeout_u typedef struct Node { struct Node *next; T_DbgLine v; } Node; Node *first_line = 0, *last_line = 0; U64 line_count = 0; + for MD_EachNode(n, lines_md->first) { T_DbgLine line = {0}; - if ( ! t_ipc_parse_string(n, str8_lit("file_path"), &line.file_path)) { t_infof("INFO: 'lines' is missing 'file_path'\n"); goto exit; } - if ( ! t_ipc_parse_int(n, str8_lit("line_num"), &line.line_num)) { t_infof("INFO: 'lines' is missing 'line_num'\n"); goto exit; } - if ( ! t_ipc_parse_int(n, str8_lit("column_num"), &line.column_num)) { t_infof("INFO: 'lines' is missing 'column_num'\n"); goto exit; } - if ( ! t_ipc_parse_int(n, str8_lit("voff_range_min"), &line.voff_range.min)) { t_infof("INFO: 'lines' is missing 'voff_range_min'\n"); goto exit; } - if ( ! t_ipc_parse_int(n, str8_lit("voff_range_max"), &line.voff_range.max)) { t_infof("INFO: 'lines' is missing 'voff_range_max'\n"); goto exit; } + if ( ! t_ipc_parse_string(n, str8_lit("file_path"), &line.file_path)) { t_infof("INFO: 'lines' is missing 'file_path'\n"); goto exit; } + if ( ! t_ipc_parse_int (n, str8_lit("line_num"), &line.pt.line)) { t_infof("INFO: 'lines' is missing 'line_num'\n"); goto exit; } + if ( ! t_ipc_parse_int (n, str8_lit("column_num"), &line.pt.column)) { t_infof("INFO: 'lines' is missing 'column_num'\n"); goto exit; } + if ( ! t_ipc_parse_int (n, str8_lit("voff_range_min"), &line.voff_range.min)) { t_infof("INFO: 'lines' is missing 'voff_range_min'\n"); goto exit; } + if ( ! t_ipc_parse_int (n, str8_lit("voff_range_max"), &line.voff_range.max)) { t_infof("INFO: 'lines' is missing 'voff_range_max'\n"); goto exit; } Node *n = push_array(scratch.arena, Node, 1); n->v = line; @@ -276,32 +249,44 @@ t_dbg_send_cmd_and_wait_stop(String8 cmd, U64 timeout_us) Temp scratch = scratch_begin(0,0); B32 is_stopped = 0; - // snapshot status - T_DbgState *status_before = t_dbg_state(scratch.arena, max_U64); - if (status_before == 0) { Assert(0 && "failed to snapshot status"); goto exit; } + // snapshot state + T_DbgState *state_before = t_dbg_state(scratch.arena, max_U64); + if (state_before == 0) { + t_errorf("ERROR: failed to snapshot state\n"); + goto exit; + } // send command - if (t_dbg_send_cmd(cmd, max_U64, 0, 0) == 0) { Assert(0 && "failed to the command"); goto exit; } + if (t_dbg_send_cmd(cmd, max_U64, 0, 0) == 0) { + t_errorf("ERROR: failed to send command \"%S\"", cmd); + goto exit; + } // wait for debugger to stop U64 t = ENDT_US(timeout_us); for (;;) { - // query debugger status - T_DbgState *status = t_dbg_state(scratch.arena, t); - if (status == 0) { Assert(0 && "failed to acquire debugger status"); goto exit; } + // query debugger state + T_DbgState *state = t_dbg_state(scratch.arena, t); + if (state == 0) { + t_errorf("ERROR: failed to fetch debugger state\n"); + goto exit; + } // did state change? -> break - if (!status->running && status->run_gen != status_before->run_gen) { + if (!state->running && state->run_gen != state_before->run_gen) { is_stopped = 1; break; } // "solve" the wait problem - if (now_time_us() >= t) { Assert(0 && "timeout"); goto exit; } + if (now_time_us() >= t) { + t_errorf("ERROR: command \"%S\" hit timeout\n", cmd); + goto exit; + } sleep_ms(10); } - //--- Status --------------------- + //--- state --------------------- if (0 && is_stopped) { T_DbgState *state = t_dbg_state(scratch.arena, T_Dbg_DefaultTimeout); @@ -315,10 +300,16 @@ t_dbg_send_cmd_and_wait_stop(String8 cmd, U64 timeout_us) String8 sp = t_dbg_value_from_exprf(scratch.arena, "hex(reg:rsp)"); T_DbgState *last_stop = t_dbg_state(scratch.arena, T_Dbg_DefaultTimeout); - AssertAlways(last_stop); + if ( ! last_stop) { + t_errorf("ERROR: debugger state fetch failed\n"); + goto exit; + } T_DbgLineArray lines = {0}; - AssertAlways(t_dbg_src_line(scratch.arena, last_stop->ip_vaddr, &lines, T_Dbg_DefaultTimeout)); + if ( ! t_dbg_src_line(scratch.arena, last_stop->ip_vaddr, &lines, T_Dbg_DefaultTimeout)) { + t_errorf("ERROR: failed t map IP(0x%llx) to a source location\n", last_stop->ip_vaddr); + goto exit; + } t_infof("------------------------------------------------------------------------------------------------------------------------\n"); t_infof(" Process: %.*s [%.*s] (Active: %.*s)\n", str8_varg(process_id), str8_varg(process_label), str8_varg(process_active)); @@ -330,8 +321,8 @@ t_dbg_send_cmd_and_wait_stop(String8 cmd, U64 timeout_us) for EachIndex(i, lines.count) { t_infof(" {\n"); t_infof(" File Path: %.*s\n", str8_varg(lines.v[i].file_path)); - t_infof(" Line: %lld\n", (long long)lines.v[i].line_num); - t_infof(" Column: %lld\n", (long long)lines.v[i].column_num); + t_infof(" Line: %lld\n", (long long)lines.v[i].pt.line); + t_infof(" Column: %lld\n", (long long)lines.v[i].pt.column); t_infof(" }\n"); } fflush(stdout); @@ -348,13 +339,27 @@ t_dbg_ping(U64 timeout_us) { Temp scratch = scratch_begin(0,0); T_DbgState *state = t_dbg_state(scratch.arena, timeout_us); - B32 did_reply = state != 0; scratch_end(scratch); - return did_reply; + return state != 0; +} + +internal B32 +t_dbg_bp_add_line(String8 file, U64 line) +{ + return t_dbg_send_cmdf(0,0,0, "add_breakpoint \"%S\":%llu", file, line); +} + +internal B32 +t_dbg_bp_add_func(String8 func_name) +{ + return t_dbg_send_cmdf(0,0,0, "add_function_breakpoint %S", func_name); +} + +internal B32 +t_dbg_bp_add_addr(U64 addr) +{ + return t_dbg_send_cmdf(0,0,0, "add_address_breakpoint 0x%llx", addr); } -internal B32 t_dbg_bp_add_line(String8 file, U64 line) { return t_dbg_send_cmdf(0,0,0, "add_breakpoint \"%S\":%llu", file, line); } -internal B32 t_dbg_bp_add_func(String8 func_name) { return t_dbg_send_cmdf(0,0,0, "add_function_breakpoint %S", func_name); } -internal B32 t_dbg_bp_add_addr(U64 addr) { return t_dbg_send_cmdf(0,0,0, "add_address_breakpoint 0x%llx", addr); } internal B32 t_dbg_launch(String8 cmdline, U64 timeout_us) @@ -374,7 +379,10 @@ t_dbg_launch(String8 cmdline, U64 timeout_us) .cmd_line = lnk_arg_list_parse_windows_rules(scratch.arena, cmdline), }; Process dbg_handle = process_launch(&launch_opts); - if (process_match(dbg_handle, process_zero())) { AssertAlways(0 && "failed to launch debugger"); goto exit; } + if (process_match(dbg_handle, process_zero())) { + t_errorf("ERROR: failed to launch debugger with this CMDL: %S\n", cmdline); + goto exit; + } #if OS_WINDOWS // cache debugger PID @@ -396,7 +404,10 @@ t_dbg_launch(String8 cmdline, U64 timeout_us) if (dbg_ready) { break; } // "solve" the wait problem - if (now_time_us() >= t) { Assert(0 && "timeout"); break; } + if (now_time_us() >= t) { + t_errorf("ERROR: failed to launch debugger, because operation timed out\n"); + break; + } sleep_ms(10); } @@ -415,10 +426,10 @@ t_dbg_eval(Arena *arena, String8 expr, T_Eval *eval_out) B32 is_ok = t_dbg_send_cmd(cmd, T_Dbg_DefaultTimeout, arena, &reply); T_Eval e = {0}; - if ( ! t_ipc_parse_string(reply.root, str8_lit("expr"), &e.expr)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: expr\n"); Assert(0); goto exit; } - if ( ! t_ipc_parse_string(reply.root, str8_lit("value"), &e.value)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: value\n"); Assert(0); goto exit; } - if ( ! t_ipc_parse_string(reply.root, str8_lit("type"), &e.type)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: type\n"); Assert(0); goto exit; } - if ( ! t_ipc_parse_string(reply.root, str8_lit("error"), &e.error)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: error\n"); Assert(0); goto exit; } + if ( ! t_ipc_parse_string(reply.root, str8_lit("expr"), &e.expr)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: expr\n"); goto exit; } + if ( ! t_ipc_parse_string(reply.root, str8_lit("value"), &e.value)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: value\n"); goto exit; } + if ( ! t_ipc_parse_string(reply.root, str8_lit("type"), &e.type)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: type\n"); goto exit; } + if ( ! t_ipc_parse_string(reply.root, str8_lit("error"), &e.error)) { t_errorf_md(str8_lit("IPC"), str8_zero(), reply.root, "ERROR: failed to parse reply member: error\n"); goto exit; } if (eval_out) { *eval_out = e; } exit:; @@ -465,146 +476,213 @@ t_dbg_script_cmd_kind_from_string(String8 cmd) } internal B32 -t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source, T_DbgScript *script_out) +t_dbg_parse_script(Arena *arena, String8 file_path, String8 source, T_DbgScript *script_out) { Temp scratch = scratch_begin(&arena, 1); + B32 is_ok = 0; - + T_DbgScript script = { .file_path = push_str8_copy(arena, file_path) }; - // scrape MD comment tokens out of source while preserving original source offsets - MD_TokenArray script_tokens = {0}; - { - MD_TokenizeResult source_tokens = md_tokenize_from_text(scratch.arena, source); - MD_TokenChunkList script_token_chunks = {0}; - for EachIndex(token_idx, source_tokens.tokens.count) { - MD_Token token = source_tokens.tokens.v[token_idx]; - if (token.flags & MD_TokenFlag_Comment) { - String8 token_string = str8_substr(source, token.range); - String8 comment = str8_skip_chop_whitespace(token_string); - String8 prefix = str8_lit("///"); - if (str8_matchi(str8_prefix(comment, prefix.size), prefix)) { - String8 script_part = str8_skip(comment, prefix.size); - U64 script_part_base_off = (U64)(script_part.str - source.str); - MD_TokenizeResult script_part_tokenize = md_tokenize_from_text(scratch.arena, script_part); - for EachIndex(script_token_idx, script_part_tokenize.tokens.count) { - MD_Token script_token = script_part_tokenize.tokens.v[script_token_idx]; - script_token.range.min += script_part_base_off; - script_token.range.max += script_part_base_off; - md_token_chunk_list_push(scratch.arena, &script_token_chunks, 4096, script_token); - } - MD_Token newline_token = md_token_make(r1u64(token.range.max, token.range.max), MD_TokenFlag_Newline); - md_token_chunk_list_push(scratch.arena, &script_token_chunks, 4096, newline_token); - } + // parse out mdesk out of the comments + MD_TokenizeResult source_tokens = md_tokenize_from_text(scratch.arena, source); + MD_TokenChunkList annot_chunks = {0}; + for EachIndex(token_idx, source_tokens.tokens.count) { + MD_Token source_token = source_tokens.tokens.v[token_idx]; + + // skip non-comment tokens + if (~source_token.flags & MD_TokenFlag_Comment) { continue; } + + // read token string + String8 source_token_string = str8_substr(source, source_token.range); + + if (str8_match_wildcard(source_token_string, str8_lit("*///*"), 0)) { + + // drop comment prefix + String8 raw_annots = str8_skip(str8_skip_chop_whitespace(source_token_string), 3); + + // parse annotations + MD_TokenizeResult annot_parse = md_tokenize_from_text(scratch.arena, raw_annots); + + for EachIndex(i, annot_parse.tokens.count) { + MD_Token annot_token = annot_parse.tokens.v[i]; + + // adjust token range so they point back into the source file + annot_token.range = shift_1u64(annot_token.range, (U64)(raw_annots.str - source.str)); + + // append annotation token + md_token_chunk_list_push(scratch.arena, &annot_chunks, 4096, annot_token); } + + // append new line token + MD_Token newline_token = md_token_make(r1u64(source_token.range.max, source_token.range.max), MD_TokenFlag_Newline); + md_token_chunk_list_push(scratch.arena, &annot_chunks, 4096, newline_token); } - script_tokens = md_token_array_from_chunk_list(scratch.arena, &script_token_chunks); } - - // script tokens -> mdesk tree - MD_ParseResult script_parse = md_parse_from_text_tokens(scratch.arena, file_path, source, script_tokens); - AssertAlways(script_parse.msgs.worst_message_kind < MD_MsgKind_Error); - - // test - { - MD_Node *test = script_parse.root->first; - AssertAlways( ! md_node_is_nil(test)); - if (str8_matchi(test->string, str8_lit("test"))) { - for MD_EachNode(n, test->first) { - OperatingSystem os = operating_system_from_string(n->string); - AssertAlways(os != OperatingSystem_Null); - - for MD_EachNode(field, n->first) { - T_DbgScriptDirectiveKind kind = T_DbgScriptDirectiveKind_Null; - if (str8_matchi(field->string, str8_lit("compile"))) { kind = T_DbgScriptDirectiveKind_Compile; } - else if (str8_matchi(field->string, str8_lit("link"))) { kind = T_DbgScriptDirectiveKind_Link; } - else if (str8_matchi(field->string, str8_lit("launch"))) { kind = T_DbgScriptDirectiveKind_Launch; } - else if (str8_matchi(field->string, str8_lit("skip"))) { kind = T_DbgScriptDirectiveKind_Skip; } - if (kind == T_DbgScriptDirectiveKind_Null) { - t_errorf_md(file_path, source, n, "unknown field in test header \"%S\"\n", field->string); - goto exit; - } + // script annotations -> mdesk tree + MD_TokenArray annot_tokens = md_token_array_from_chunk_list(scratch.arena, &annot_chunks); + MD_ParseResult script_parse = md_parse_from_text_tokens(scratch.arena, file_path, source, annot_tokens); - T_DbgScriptDirective *dir = push_array(arena, T_DbgScriptDirective, 1); - dir->kind = kind; - t_find_line_and_col(source, field, &dir->line, 0); - - if (field->flags & MD_NodeFlag_HasBraceLeft) { - if (kind == T_DbgScriptDirectiveKind_Compile) { - for MD_EachNode(sub_field, field->first) { - if (str8_matchi(sub_field->string, str8_lit("cc"))) { - MD_Node *cc = sub_field->first; - if (cc->flags & MD_NodeFlag_StringLiteral) { - if (str8_matchi(cc->string, str8_lit("clang"))) { dir->compile.cc = T_Compiler_Clang; } - else if (str8_matchi(cc->string, str8_lit("cl"))) { dir->compile.cc = T_Compiler_Cl; } - else { - t_errorf_md(file_path, source, cc, "unknown compiler name: \"%S\"\n", sub_field->string); - goto exit; - } - } else { - t_errorf_md(file_path, source, sub_field, "value of CC must be a string literal e.g. CC: \"clang\"\n"); - goto exit; - } - } else if (str8_matchi(sub_field->string, str8_lit("args"))) { - MD_Node *args = sub_field->first; - if (args->flags & MD_NodeFlag_StringLiteral) { - dir->args = str8_copy(arena, args->string); - } else { - t_errorf_md(file_path, source, args, "value of ARGS must be a string literal\n"); - goto exit; - } - } else { - t_errorf_md(file_path, source, sub_field, "unknown field \"%S\"\n", sub_field->string); - goto exit; - } - } - } - } else { - if (md_node_is_nil(field->first)) { - t_errorf_md(file_path, source, field, "missing value on field %S\n", field->string); - goto exit; - } - if ( ! md_node_is_nil(field->first->next)) { - t_errorf_md(file_path, source, field, "field %S accepts only one value\n", field->string); - goto exit; - } - if (~field->first->flags & MD_NodeFlag_StringLiteral) { - t_errorf_md(file_path, source, field, "field %S accepts only strings\n", field->string); - goto exit; - } - dir->args = str8_copy(arena, field->first->string); - } - - T_DbgScriptDirectiveList *list = &script.directives[os][kind]; - SLLQueuePush(list->first, list->last, dir); - list->count += 1; - } + // was parse ok? -> error + if (script_parse.msgs.worst_message_kind >= MD_MsgKind_Error) { + t_errorf("ERROR: cannot tokenize mdesk file: \"%S\"\n", file_path); + for EachNode(msg, MD_Msg, script_parse.msgs.first) { + String8 msg_kind_string = {0}; + switch(msg->kind) + { + default:{}break; + case MD_MsgKind_Note: {msg_kind_string = str8_lit("note");}break; + case MD_MsgKind_Warning: {msg_kind_string = str8_lit("warning");}break; + case MD_MsgKind_Error: {msg_kind_string = str8_lit("error");}break; + case MD_MsgKind_FatalError: {msg_kind_string = str8_lit("fatal error");}break; } - } else { + TxtPt pt = mg_txt_pt_from_string_off(source, msg->node->src_offset); + String8 loc = push_str8f(scratch.arena, "%S:%I64d:%I64d", file_path, pt.line, pt.column); + t_errorf(" [%S] %S: %S\n", msg_kind_string, loc, msg->string); + } + goto exit; + } + + // @test: + { + // first child node of the root must be a test header + MD_Node *test = script_parse.root->first; + + // is node test? -> error + if ( ! str8_matchi(test->string, str8_lit("test"))) { t_errorf("ERROR: %S: missing test header\n", file_path); goto exit; } - } - - // file - { - MD_NodePtrList files = {0}; - for MD_EachNode(n, script_parse.root->first->next) { - if (str8_matchi(n->string, str8_lit("file"))) { - AssertAlways( ! md_node_is_nil(n->first)); - if ( ! md_node_is_nil(n->first->next) || ! (n->first->flags & MD_NodeFlag_StringLiteral)) { - U32 line = 0; - for EachIndex(idx, n->first->src_offset) { line += (source.str[idx] == '\n'); } - t_errorf_md(file_path, source, n, "value of the 'file' must be a string, (e.g. file: \"main.c\")\n", file_path, line); + for MD_EachNode(n, test->first) { + OperatingSystem os = operating_system_from_string(n->string); + + // is OS string correct? -> error + if (os == OperatingSystem_Null && n->string.size > 0) { + t_errorf_md(file_path, source, n, "test is defined for unknown os: \"%S\"\n", n->string); + goto exit; + } + + for MD_EachNode(field, n->first) { + // define table for mapping string to a directive kind + struct { + T_DbgScriptDirectiveKind kind; + String8 string; + } dir_string_map[] = { + #define X(q,w) { T_DbgScriptDirectiveKind_##q, str8_lit(w) }, + T_DbgScriptDirectiveKind_XList + #undef X + }; + + // string -> directive + T_DbgScriptDirectiveKind kind = T_DbgScriptDirectiveKind_Null; + for EachElement(i, dir_string_map) { + if (str8_matchi(field->string, dir_string_map[i].string)) { + kind = dir_string_map[i].kind; + break; + } + } + + // was directive found? -> error + if (kind == T_DbgScriptDirectiveKind_Null) { + t_errorf_md(file_path, source, n, "unknown field in test header \"%S\"\n", field->string); goto exit; } + // alloc directive node + T_DbgScriptDirective *dir = push_array(arena, T_DbgScriptDirective, 1); + dir->kind = kind; + dir->pt = mg_txt_pt_from_string_off(source, field->src_offset); + + // TODO: collapse + if (field->flags & MD_NodeFlag_HasBraceLeft) { + // walk each sub-field of the MD node, and find nodes for the directive + if (kind == T_DbgScriptDirectiveKind_Compile) { + for MD_EachNode(sub_field, field->first) { + // compiler override + if (str8_matchi(sub_field->string, str8_lit("cc"))) { + MD_Node *cc = sub_field->first; + if (~cc->flags & MD_NodeFlag_StringLiteral) { + t_errorf_md(file_path, source, sub_field, "value of CC must be a string literal e.g. CC: \"clang\"\n"); + goto exit; + } + + if (str8_matchi(cc->string, str8_lit("clang"))) { dir->compile.cc = T_Compiler_Clang; } + else if (str8_matchi(cc->string, str8_lit("cl"))) { dir->compile.cc = T_Compiler_Cl; } + else { + t_errorf_md(file_path, source, cc, "unknown compiler name: \"%S\"\n", sub_field->string); + goto exit; + } + } + // commnad line for the compiler + else if (str8_matchi(sub_field->string, str8_lit("args"))) { + MD_Node *args = sub_field->first; + if (~args->flags & MD_NodeFlag_StringLiteral) { + t_errorf_md(file_path, source, args, "value of ARGS must be a string literal\n"); + goto exit; + } + dir->args = str8_copy(arena, args->string); + } + // unknown field + else { + t_errorf_md(file_path, source, sub_field, "unknown field \"%S\"\n", sub_field->string); + goto exit; + } + } + } + } + // MD node is a string + else { + // is value present? -> error + if (md_node_is_nil(field->first)) { + t_errorf_md(file_path, source, field, "missing value on field %S\n", field->string); + goto exit; + } + + // more than one node? -> error + if ( ! md_node_is_nil(field->first->next)) { + t_errorf_md(file_path, source, field, "field %S accepts only one value\n", field->string); + goto exit; + } + + // node is not a string literal? -> error + if (~field->first->flags & MD_NodeFlag_StringLiteral) { + t_errorf_md(file_path, source, field, "field %S accepts only strings\n", field->string); + goto exit; + } + + // copy string from MD node + dir->args = str8_copy(arena, field->first->string); + } + + // append new directive + T_DbgScriptDirectiveList *list = &script.directives[os][kind]; + SLLQueuePush(list->first, list->last, dir); + list->count += 1; + } + } + } + + // @file: + { + // collect file nodes + MD_NodePtrList files = {0}; + for MD_EachNode(n, script_parse.root->first->next) { + if (str8_matchi(n->string, str8_lit("file"))) { + + // is file value a string? -> error + if ( ! md_node_is_nil(n->first->next) || ! (n->first->flags & MD_NodeFlag_StringLiteral)) { + t_errorf_md(file_path, source, n, "value of the 'file' must be a string, (e.g. file: \"main.c\")\n"); + goto exit; + } + + // append file node md_node_ptr_list_push(scratch.arena, &files, n); } } + // no nodes? -> treat whole file as a script if (files.count == 0) { MD_Node *whole_file = push_array(scratch.arena, MD_Node, 1); whole_file->first = push_array(scratch.arena, MD_Node, 1); @@ -618,77 +696,106 @@ t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source, T_DbgS for EachNode(n_ptr, MD_NodePtrNode, files.first) { MD_Node *n = n_ptr->v; + // get file name + String8 file_name = n->first->string; + + // was file seen? -> error + MD_Node *is_declared = hash_map_search_string_raw(&files_hm, file_name); + if (is_declared) { + TxtPt pt = mg_txt_pt_from_string_off(source, is_declared->src_offset); + t_errorf_md(file_path, source, n, "file %S is already declared at line %llu", file_name, pt.line); + goto exit; + } + hash_map_push_string_raw(scratch.arena, &files_hm, file_name, n); + + // file ends at EOF or before the next file directive U64 src_opl = source.size; if (n_ptr->next) { src_opl = n_ptr->next->v->src_offset; } + // sub-string the source file String8 sub_source = str8_substr(source, r1u64(n->src_offset, src_opl)); U64 file_min = str8_find_needle(sub_source, 0, str8_lit("\n"), 0) + 1; U64 file_max = str8_find_needle_reverse(sub_source, 0, str8_lit("\n"), 0); sub_source = str8_substr(sub_source, r1u64(file_min, file_max)); + // append new file node T_DbgScriptFile *file = push_array(arena, T_DbgScriptFile, 1); - file->path = t_make_file_path(arena, n->first->string); + file->path = t_make_file_path(arena, file_name); file->source = sub_source; - t_find_line_and_col(source, n, &file->line, 0); + file->pt = mg_txt_pt_from_string_off(source, n->src_offset); SLLQueuePush(script.files.first, script.files.last, file); script.files.count += 1; - - hash_map_push_raw_raw(scratch.arena, &files_hm, n, file); } } - // programs + // @program: { - HashMap hm = {0}; // + HashMap hm = {0}; // (U64, T_DbgScriptProgram) for MD_EachNode(n, script_parse.root->first->next) { + // find order number nodes U64 order = 0; - if (try_u64_from_str8_c_rules(n->string, &order)) { - T_DbgScriptFile *file = 0; - for (file = script.files.first; file != 0; file = file->next) { - if (file->source.str <= n->string.str && n->string.str < (file->source.str + file->source.size)) { - break; - } + if ( ! try_u64_from_str8_c_rules(n->string, &order)) { + continue; + } + + // correlate MD node to the script file + T_DbgScriptFile *file = 0; + for (file = script.files.first; file != 0; file = file->next) { + if (file->source.str <= n->string.str && n->string.str < (file->source.str + file->source.size)) { + break; } - AssertAlways(file != 0); + } + + // found file? -> error + if (file == 0) { + t_errorf_md(file_path, source, n, "failed to correlate MD node to the script source file\n"); + goto exit; + } + + // is order number unique? -> error + T_DbgScriptProgram *p = hash_map_search_u64_raw(&hm, order); + if (p) { + t_errorf_md(file_path, source, n, "duplicate order number %llu found, previous defined at %llu\n", order, p->pt.line); + goto exit; + } + + // alloc & fill out program + p = push_array(arena, T_DbgScriptProgram, 1); + p->pt = mg_txt_pt_from_string_off(source, n->src_offset); + p->order = order; + p->os = OperatingSystem_CURRENT; + p->file = file; + hash_map_push_u64_raw(scratch.arena, &hm, order, p); + + for MD_EachNode(cmd_n, n->first) { + // alloc & fill out command + T_DbgScriptCmd *cmd = push_array(arena, T_DbgScriptCmd, 1); + cmd->kind = t_dbg_script_cmd_kind_from_string(cmd_n->string); + cmd->pt = mg_txt_pt_from_string_off(source, n->src_offset); + SLLQueuePush(p->first, p->last, cmd); + p->count += 1; - T_DbgScriptProgram *p = hash_map_search_u64_raw(&hm, order); - if (p == 0) { - p = push_array(arena, T_DbgScriptProgram, 1); - t_find_line_and_col(source, n, &p->line, 0); - p->order = order; - p->os = OperatingSystem_CURRENT; - p->file = file; - hash_map_push_u64_raw(scratch.arena, &hm, order, p); - } else { - t_errorf("ERROR: duplicate order number %llu found on line %llu\n", (unsigned long long)order, (unsigned long long)p->line); - } - - for MD_EachNode(cmd_n, n->first) { - // push new cmd - T_DbgScriptCmd *cmd = push_array(arena, T_DbgScriptCmd, 1); - cmd->kind = t_dbg_script_cmd_kind_from_string(cmd_n->string); - t_find_line_and_col(source, n, &cmd->line_num, &cmd->col_num); - Assert(cmd->kind != T_DbgScriptCmdKind_Null); - SLLQueuePush(p->first, p->last, cmd); - p->count += 1; - - // parse cmd args - MD_Node *cmd_arg = cmd_n->first; - if ( ! md_node_is_nil(cmd_arg)) { - if (cmd->kind == T_DbgScriptCmdKind_At) { - AssertAlways(try_s64_from_str8_c_rules(cmd_arg->string, &cmd->at.delta)); - } else if (cmd->kind == T_DbgScriptCmdKind_Eval) { - NotImplemented; - } else if (cmd->kind == T_DbgScriptCmdKind_Breakpoint) { - NotImplemented; - } + // parse cmd args + MD_Node *cmd_arg = cmd_n->first; + + if (md_node_is_nil(cmd_arg)) { continue; } + + if (cmd->kind == T_DbgScriptCmdKind_At) { + if ( ! try_s64_from_str8_c_rules(cmd_arg->string, &cmd->at_delta)) { + t_errorf_md(file_path, source, cmd_arg, "failed to parse \"%S\"", cmd_arg->string); + goto exit; } + } else if (cmd->kind == T_DbgScriptCmdKind_Eval) { + t_errorf_md(file_path, source, cmd_arg, "TODO: Eval\n"); + } else if (cmd->kind == T_DbgScriptCmdKind_Breakpoint) { + t_errorf_md(file_path, source, cmd_arg, "TODO: Breakpoint\n"); } } } + // extract commands and sort based on order number script.program_count = hm.count; script.programs = values_from_hash_map_raw(arena, &hm); radsort(script.programs, script.program_count, t_dbg_script_program_is_before); @@ -696,9 +803,7 @@ t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source, T_DbgS is_ok = 1; exit:; - if (script_out) { - *script_out = script; - } + if (script_out) { *script_out = script; } scratch_end(scratch); return is_ok; } @@ -715,7 +820,7 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) if (program->os == OperatingSystem_CURRENT) { for EachNode(cmd, T_DbgScriptCmd, program->first) { - t_infof("[%llu] Command: %S:%llu %S\n", program->order, script->file_path, (unsigned long long)cmd->line_num, t_string_from_dbg_script_cmd_kind(cmd->kind)); + t_infof("[%llu] Command: %S:%llu %S\n", program->order, script->file_path, cmd->pt.line, t_string_from_dbg_script_cmd_kind(cmd->kind)); switch (cmd->kind) { case T_DbgScriptCmdKind_Null: break; @@ -731,9 +836,12 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) case T_DbgScriptCmdKind_Breakpoint: NotImplemented; break; case T_DbgScriptCmdKind_ClearBreakpoints: t_dbg_send_cmdf(0,0,0, "clear_breakpoints"); break; case T_DbgScriptCmdKind_Run: t_dbg_send_cmd(str8_lit("run"), timeout_us, 0, 0); break; + case T_DbgScriptCmdKind_RunToLine: { + U64 line = cmd->pt.line - program->file->pt.line; + t_dbg_send_cmd_and_wait_stop(str8f(scratch.arena, "run_to_line \"%S:%llu\"", program->file->path, line), timeout_us); + } break; case T_DbgScriptCmdKind_At: { - // TODO: debugger does not populate eval cache with registers before first frame, - // so this racy, for now use lower level option + // TODO: debugger does not populate eval cache with registers before first frame -- for now use lower level option #if 0 U64 ip = u64_from_str8(t_dbg_value_from_exprf(scratch.arena, "reg:rip"), 10); if (ip == 0) { @@ -743,7 +851,7 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) #else T_DbgState *temp_status = t_dbg_state(scratch.arena, T_Dbg_DefaultTimeout); if (temp_status == 0) { - t_errorf("ERROR: %S:%llu: failed to query IP\n", script->file_path, (unsigned long long)cmd->line_num); + t_errorf("ERROR: %S:%llu: failed to query IP\n", script->file_path, cmd->pt.line); goto exit; } U64 ip = temp_status->ip; @@ -752,29 +860,29 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) // map IP -> source location T_DbgLineArray lines = {0}; if (t_dbg_src_line(scratch.arena, ip, &lines, T_Dbg_DefaultTimeout) == 0) { - t_errorf("ERROR: %S:%llu: IP (0x%llx) does not map to a source line\n", script->file_path, (unsigned long long)cmd->line_num, (unsigned long long)ip); + t_errorf("ERROR: %S:%llu: IP (0x%llx) does not map to a source line\n", script->file_path, cmd->pt.line, ip); goto exit; } // compute line where debugger must be - S64 at_line_s64 = (S64)(program->line - program->file->line) + cmd->at.delta; + S64 at_line_s64 = (S64)(program->pt.line - program->file->pt.line) + cmd->at_delta; U64 at_line_u64 = at_line_s64 >= 0 ? (U64)at_line_s64 : 0; AssertAlways(at_line_u64 > 0); if (lines.count == 0) { - t_errorf("ERROR: %S:%llu:%llu: no source location maps for vaddr: 0x%llx\n", script->file_path, (unsigned long long)cmd->line_num, (unsigned long long)cmd->col_num, (unsigned long long)ip); + t_errorf("ERROR: %S:%llu:%llu: no source location maps for vaddr: 0x%llx\n", script->file_path, cmd->pt.line, cmd->pt.column, ip); goto exit; } // match expected vs current debugger locations for EachIndex(i, lines.count) { - B32 mismatch = lines.v[i].line_num != at_line_u64 || + B32 mismatch = lines.v[i].pt.line != at_line_u64 || !str8_match(lines.v[i].file_path, program->file->path, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive); if (mismatch) { - t_errorf("ERROR: %S:%llu: location check did not pass:\n", script->file_path, (unsigned long long)cmd->line_num); - t_errorf(" Expected: %S:%llu\n", program->file->path, (unsigned long long)at_line_u64); - t_errorf(" Got : %S:%llu\n", lines.v[i].file_path, (unsigned long long)lines.v[i].line_num); - t_errorf(" IP : 0x%llx\n", (unsigned long long)ip); + t_errorf("ERROR: %S:%llu: location check did not pass:\n", script->file_path, cmd->pt.line); + t_errorf(" Expected: %S:%llu\n", program->file->path, at_line_u64); + t_errorf(" Got : %S:%llu\n", lines.v[i].file_path, lines.v[i].pt.line); + t_errorf(" IP : 0x%llx\n", ip); goto exit; } } @@ -796,11 +904,6 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) internal T_RunSig(dbg_script_runner) { - if ( ! file_path_exists(t_raddbg_path())) { - t_errorf("ERROR: failed to find debugger \"%S\"\n", t_raddbg_path()); - T_Ok(0); - } - // read source file String8 source = data_from_file_path(arena, user_data); if (source.size == 0) { @@ -810,7 +913,7 @@ T_RunSig(dbg_script_runner) // source -> script T_DbgScript script = {0}; - if ( ! t_dbg_script_from_source(arena, user_data, source, &script)) { + if ( ! t_dbg_parse_script(arena, user_data, source, &script)) { result_out->status = T_RunStatus_Fail; goto exit; } @@ -818,20 +921,16 @@ T_RunSig(dbg_script_runner) // write source files to test folder for EachNode(file, T_DbgScriptFile, script.files.first) { if (write_data_to_file_path(file->path, file->source) == 0) { - t_errorf("ERROR: %S:%llu: failed to write: \"%S\"\n", user_data, (unsigned long long)file->line, file->path); + t_errorf("ERROR: %S:%llu: failed to write: \"%S\"\n", user_data, file->pt.line, file->path); T_Ok(0); } } - if (script.directives[OperatingSystem_CURRENT][T_DbgScriptDirectiveKind_Skip].count) { - result_out->status = T_RunStatus_Skip; - goto exit; - } - // compiler vars HashTable *script_vars = hash_table_init(arena, 1000); hash_table_push_path_string(arena, script_vars, str8_lit("FILE"), user_data); hash_table_push_path_string(arena, script_vars, str8_lit("CWD"), g_wdir); + hash_table_push_path_string(arena, script_vars, str8_lit("SRC"), t_src_path()); // run compilers for EachNode(directive, T_DbgScriptDirective, script.directives[OperatingSystem_CURRENT][T_DbgScriptDirectiveKind_Compile].first) { @@ -867,7 +966,7 @@ T_RunSig(dbg_script_runner) if (compiler == T_Compiler_Cl) { g_output = str8_skip(g_output, str8_chop_line(&g_output).size); } // file name print if (g_last_exit_code) { - t_errorf("ERROR: %S:%llu: %S\n", script.file_path, (unsigned long long)directive->line, g_errors); + t_errorf("ERROR: %S:%llu: %S\n", script.file_path, (unsigned long long)directive->pt.line, g_errors); if (g_stop_on_first_fail_or_crash) { T_Ok(0); } @@ -883,11 +982,17 @@ T_RunSig(dbg_script_runner) T_Ok(0); } if (g_last_exit_code != 0) { - t_errorf("ERROR: %S:%llu: %S\n", script.file_path, (unsigned long long)directive->line, g_errors); + t_errorf("ERROR: %S:%llu: %S\n", script.file_path, (unsigned long long)directive->pt.line, g_errors); T_Ok(0); } } - + + // is skip flag set? -> exit + if (g_build_only || script.directives[OperatingSystem_CURRENT][T_DbgScriptDirectiveKind_Skip].count) { + result_out->status = T_RunStatus_Skip; + goto exit; + } + // launch targets for EachNode(directive, T_DbgScriptDirective, script.directives[OperatingSystem_CURRENT][T_DbgScriptDirectiveKind_Launch].first) { String8 expanded_args = lnk_expand_env_vars_windows(arena, script_vars, directive->args); diff --git a/src/torture/torture_dbg.h b/src/torture/torture_dbg.h index 39e73b05..c1aac25a 100644 --- a/src/torture/torture_dbg.h +++ b/src/torture/torture_dbg.h @@ -3,121 +3,6 @@ #pragma once -//////////////////////////////// -// Dbg Script - -typedef struct T_DbgScriptFile -{ - struct T_DbgScriptFile *next; - String8 path; - String8 source; - U64 line; -} T_DbgScriptFile; - -typedef struct -{ - U64 count; - T_DbgScriptFile *first; - T_DbgScriptFile *last; -} T_DbgScriptFileList; - -#define T_DbgScriptCmdKind_XList \ - X(Breakpoint, "bp") \ - X(ClearBreakpoints, "bp_clear") \ - X(Run, "run") \ - X(Halt, "halt") \ - X(StepOver, "step_over") \ - X(StepInto, "step_into") \ - X(StepOut, "step_out") \ - X(StepOverInst, "step_over_inst") \ - X(StepIntoInst, "step_over_inst") \ - X(StepOverLine, "step_over_line") \ - X(StepIntoLine, "step_into_line") \ - X(KillAll, "kll_all") \ - X(At, "at") \ - X(Eval, "eval") - -typedef enum -{ - T_DbgScriptCmdKind_Null, -#define X(n,...) T_DbgScriptCmdKind_##n, - T_DbgScriptCmdKind_XList -#undef X - T_DbgScriptCmdKind_Count -} T_DbgScriptCmdKind; - -typedef struct T_DbgScriptCmd -{ - struct T_DbgScriptCmd *next; - T_DbgScriptCmdKind kind; - U64 line_num; - U64 col_num; - union { - struct { - S64 delta; - } at; - }; -} T_DbgScriptCmd; - -typedef struct T_DbgScriptProgram -{ - U64 line; - U64 order; - OperatingSystem os; - T_DbgScriptFile *file; - U64 count; - T_DbgScriptCmd *first; - T_DbgScriptCmd *last; - struct T_DbgScriptProgram *next; -} T_DbgScriptProgram; - -typedef struct -{ - U64 count; - T_DbgScriptProgram *first; - T_DbgScriptProgram *last; -} T_DbgScriptProgramList; - -typedef enum -{ - T_DbgScriptDirectiveKind_Null, - T_DbgScriptDirectiveKind_Compile, - T_DbgScriptDirectiveKind_Link, - T_DbgScriptDirectiveKind_Launch, - T_DbgScriptDirectiveKind_Skip, - T_DbgScriptDirectiveKind_Count, -} T_DbgScriptDirectiveKind; - -typedef struct T_DbgScriptDirective -{ - struct T_DbgScriptDirective *next; - T_DbgScriptDirectiveKind kind; - U64 line; - String8 args; - union { - struct { - T_Compiler cc; - } compile; - }; -} T_DbgScriptDirective; - -typedef struct -{ - U64 count; - T_DbgScriptDirective *first; - T_DbgScriptDirective *last; -} T_DbgScriptDirectiveList; - -typedef struct -{ - String8 file_path; - T_DbgScriptDirectiveList directives[OperatingSystem_COUNT][T_DbgScriptDirectiveKind_Count]; - T_DbgScriptFileList files; - U64 program_count; - T_DbgScriptProgram **programs; - B32 skip; -} T_DbgScript; - //////////////////////////////// // IPC Controller @@ -146,8 +31,7 @@ typedef struct typedef struct { String8 file_path; - U64 line_num; - U64 column_num; + TxtPt pt; Rng1U64 voff_range; } T_DbgLine; @@ -168,25 +52,154 @@ typedef struct //////////////////////////////// // Dbg Script -internal void t_dbg_register_script_tests(Arena *arena, String8 folder_path); -internal B32 t_dbg_run_script(Arena *arena, T_DbgScript *script, U64 timeout_us); +#define T_DbgScriptCmdKind_XList \ + X(Breakpoint, "bp") \ + X(ClearBreakpoints, "bp_clear") \ + X(Halt, "halt") \ + X(Run, "run") \ + X(RunToLine, "run_to_line") \ + X(StepOver, "step_over") \ + X(StepInto, "step_into") \ + X(StepOut, "step_out") \ + X(StepOverInst, "step_over_inst") \ + X(StepIntoInst, "step_over_inst") \ + X(StepOverLine, "step_over_line") \ + X(StepIntoLine, "step_into_line") \ + X(KillAll, "kll_all") \ + X(At, "at") \ + X(Eval, "eval") + +typedef enum +{ + T_DbgScriptCmdKind_Null, +#define X(n,...) T_DbgScriptCmdKind_##n, + T_DbgScriptCmdKind_XList +#undef X + T_DbgScriptCmdKind_Count +} T_DbgScriptCmdKind; + +#define T_DbgScriptDirectiveKind_XList \ + X(Compile, "compile") \ + X(Link, "link") \ + X(Launch, "launch") \ + X(Skip, "skip") + +typedef enum +{ + T_DbgScriptDirectiveKind_Null, +#define X(q,w) T_DbgScriptDirectiveKind_##q, + T_DbgScriptDirectiveKind_XList +#undef X + T_DbgScriptDirectiveKind_Count, +} T_DbgScriptDirectiveKind; + +typedef struct T_DbgScriptFile +{ + struct T_DbgScriptFile *next; + String8 path; + String8 source; + TxtPt pt; +} T_DbgScriptFile; + +typedef struct +{ + U64 count; + T_DbgScriptFile *first; + T_DbgScriptFile *last; +} T_DbgScriptFileList; + +typedef struct T_DbgScriptCmd +{ + struct T_DbgScriptCmd *next; + T_DbgScriptCmdKind kind; + TxtPt pt; + S64 at_delta; +} T_DbgScriptCmd; + +typedef struct T_DbgScriptProgram +{ + TxtPt pt; + U64 order; + OperatingSystem os; + T_DbgScriptFile *file; + U64 count; + T_DbgScriptCmd *first; + T_DbgScriptCmd *last; + struct T_DbgScriptProgram *next; +} T_DbgScriptProgram; + +typedef struct +{ + U64 count; + T_DbgScriptProgram *first; + T_DbgScriptProgram *last; +} T_DbgScriptProgramList; + +typedef struct T_DbgScriptDirective +{ + struct T_DbgScriptDirective *next; + T_DbgScriptDirectiveKind kind; + TxtPt pt; + String8 args; + union { + struct { + T_Compiler cc; + } compile; + }; +} T_DbgScriptDirective; + +typedef struct +{ + U64 count; + T_DbgScriptDirective *first; + T_DbgScriptDirective *last; +} T_DbgScriptDirectiveList; + +typedef struct +{ + String8 file_path; + T_DbgScriptDirectiveList directives[OperatingSystem_COUNT][T_DbgScriptDirectiveKind_Count]; + T_DbgScriptFileList files; + U64 program_count; + T_DbgScriptProgram **programs; + B32 skip; +} T_DbgScript; + //////////////////////////////// -// Dbg Tester +// IPC Controller -internal B32 t_dbg_ping (U64 timeout_us); -internal B32 t_dbg_run (U64 timeout_us); -internal B32 t_dbg_kill_all (U64 timeout_us); -internal B32 t_dbg_halt (U64 timeout_us); -internal B32 t_dbg_step_over (U64 timeout_us); -internal B32 t_dbg_step_into (U64 timeout_us); -internal B32 t_dbg_step_out (U64 timeout_us); -internal B32 t_dbg_step_over_inst(U64 timeout_us); -internal B32 t_dbg_step_into_inst(U64 timeout_us); -internal B32 t_dbg_step_over_line(U64 timeout_us); -internal B32 t_dbg_step_into_line(U64 timeout_us); -internal B32 t_dbg_launch(String8 cmdline, U64 timeout_us); -internal B32 t_dbg_eval(Arena *arena, String8 expr, T_Eval *eval_out); -// TODO: need a source location query in eval -internal B32 t_dbg_src_line(Arena *arena, U64 vaddr, T_DbgLineArray *lines, U64 timeout_us); +// error helper +internal void t_errorf_md(String8 file_name, String8 source, MD_Node *n, char *fmt, ...); + +// reply parse helpers +internal B32 t_ipc_parse_string(MD_Node *node, String8 child_name, String8 *out); +internal B32 t_ipc_parse_u32(MD_Node *node, String8 child_name, U32 *out); +internal B32 t_ipc_parse_int_(MD_Node *node, String8 child_name, U64 out_size, void *out); +internal B32 t_ipc_parse_b32(MD_Node *node, String8 child_name, B32 *out); +#define t_ipc_parse_int(n, c, ptr) t_ipc_parse_int_(n, c, sizeof(*ptr), ptr) + +// debugger commands +internal B32 t_dbg_send_cmd(String8 cmd, U64 timeout_us, Arena *reply_arena, MD_ParseResult *reply_out); +internal B32 t_dbg_send_cmdf(U64 timeout_us, Arena *reply_arena, MD_ParseResult *reply_out, char *fmt, ...); +internal T_DbgState * t_dbg_state(Arena *arena, U64 timeout_us); +internal B32 t_dbg_src_line(Arena *arena, U64 vaddr, T_DbgLineArray *lines_out, U64 timeout_us); +internal String8 t_dbg_value_from_expr(Arena *arena, String8 expr); +internal String8 t_dbg_value_from_exprf(Arena *arena, char *fmt, ...); +internal B32 t_dbg_send_cmd_and_wait_stop(String8 cmd, U64 timeout_us); +internal B32 t_dbg_ping(U64 timeout_us); +internal B32 t_dbg_bp_add_line(String8 file, U64 line); +internal B32 t_dbg_bp_add_func(String8 func_name); +internal B32 t_dbg_bp_add_addr(U64 addr); +internal B32 t_dbg_launch(String8 cmdline, U64 timeout_us); +internal B32 t_dbg_eval(Arena *arena, String8 expr, T_Eval *eval_out); + +//////////////////////////////// +// Dbg Script + +internal String8 t_string_from_dbg_script_cmd_kind(T_DbgScriptCmdKind v); +internal T_DbgScriptCmdKind t_dbg_script_cmd_kind_from_string(String8 cmd); +internal B32 t_dbg_parse_script(Arena *arena, String8 file_path, String8 source, T_DbgScript *script_out); +internal B32 t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us); +internal void t_dbg_register_script_tests(Arena *arena, String8 folder_path); diff --git a/src/torture/torture_main.c b/src/torture/torture_main.c index f6f505b9..6745399c 100644 --- a/src/torture/torture_main.c +++ b/src/torture/torture_main.c @@ -30,6 +30,7 @@ #include "minidump/minidump.h" #include "minidump/minidump_parse.h" #include "mdesk/mdesk.h" +#include "metagen/metagen.h" #include "window_manager/window_manager_inc.h" #include "config/config_inc.h" #include "content/content.h" @@ -107,6 +108,7 @@ #include "minidump/minidump.c" #include "minidump/minidump_parse.c" #include "mdesk/mdesk.c" +#include "metagen/metagen.c" #include "window_manager/window_manager_inc.c" #include "config/config_inc.c" #include "content/content.c"