add stacktrace, improve assert, improve debugbreak
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,6 +5,8 @@ multimedia.h
|
||||
playground.py
|
||||
ui_notes.txt
|
||||
|
||||
l.log
|
||||
|
||||
build/
|
||||
|
||||
*.wasm
|
||||
|
||||
@@ -39,9 +39,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
b32 run_server = false;
|
||||
b32 core_test_target = false;
|
||||
b32 win32_target = true;
|
||||
b32 win32_target = false;
|
||||
b32 standalone_w32_target = false;
|
||||
b32 wasm_target = false;
|
||||
b32 wasm_target = true;
|
||||
|
||||
if (run_server) {
|
||||
os_systemf("start /D ..\\package ..\\package\\run_server.bat");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// automatically generated using: C:\dev\wasm\src/app/app.meta.c
|
||||
// automatically generated using: D:\dev\wasm\src/app/app.meta.c
|
||||
|
||||
type_t type__app_key_t = { type_kind_enum, s8_const_lit("app_key_t"), sizeof(app_key_t),
|
||||
.members = (type_member_t[]){
|
||||
@@ -228,7 +228,7 @@ app_key_t w32_map_wparam_to_app_key(WPARAM wparam) {
|
||||
default: {return app_key_null;} break;
|
||||
}
|
||||
}
|
||||
#endif/*C:\dev\wasm\src/app/app.meta.c(135)*/
|
||||
#endif/*D:\dev\wasm\src/app/app.meta.c(135)*/
|
||||
type_t type__app_mouse_button_t = { type_kind_enum, s8_const_lit("app_mouse_button_t"), sizeof(app_mouse_button_t),
|
||||
.members = (type_member_t[]){
|
||||
{.name = s8_const_lit("app_mouse_button_null"), .value = app_mouse_button_null},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// automatically generated using: C:\dev\wasm\src/app/app.meta.c
|
||||
// automatically generated using: D:\dev\wasm\src/app/app.meta.c
|
||||
typedef enum {
|
||||
app_key_null,
|
||||
app_key_1,
|
||||
@@ -71,7 +71,7 @@ app_key_page_up,
|
||||
app_key_page_down,
|
||||
app_key_count,
|
||||
} app_key_t;
|
||||
/*C:\dev\wasm\src/app/app.meta.c(135)*/
|
||||
/*D:\dev\wasm\src/app/app.meta.c(135)*/
|
||||
typedef enum {
|
||||
app_mouse_button_null,
|
||||
app_mouse_button_left,
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#define B_STACKTRACE_IMPL
|
||||
#include "stacktrace.h"
|
||||
#include "core_platform_win32.c"
|
||||
#else
|
||||
#include <math.h>
|
||||
@@ -17,6 +20,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define B_STACKTRACE_IMPL
|
||||
#include "stacktrace.h"
|
||||
//:unix_debug_break
|
||||
//static void os_unix_sigtrap(int signum) { signal(SIGTRAP, SIG_DFL); }
|
||||
#include "core_platform_unix.c"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -106,9 +106,9 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
#define STACK_CAP(stack) (lengthof((stack).data))
|
||||
#define STACK_EMPTY(stack) ((stack).len == 0)
|
||||
#define STACK_FULL(stack) ((stack).len == STACK_CAP(stack))
|
||||
#define STACK_PUSH(stack, ...) (assert(!STACK_FULL(stack)), (stack).data[(stack).len++] = __VA_ARGS__)
|
||||
#define STACK_POP(stack) (assert(!STACK_EMPTY(stack)), (stack).data[--(stack).len])
|
||||
#define STACK_TOP(stack) (assert(!STACK_EMPTY(stack)), (stack).data[((stack).len-1)])
|
||||
#define STACK_PUSH(stack, ...) (assert_expr(!STACK_FULL(stack)), (stack).data[(stack).len++] = __VA_ARGS__)
|
||||
#define STACK_POP(stack) (assert_expr(!STACK_EMPTY(stack)), (stack).data[--(stack).len])
|
||||
#define STACK_TOP(stack) (assert_expr(!STACK_EMPTY(stack)), (stack).data[((stack).len-1)])
|
||||
|
||||
#define STRINGIFY_(S) #S
|
||||
#define STRINGIFY(S) STRINGIFY_(S)
|
||||
@@ -141,11 +141,14 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#define debug__break() __debugbreak()
|
||||
#define debug__break() (IsDebuggerPresent() && (__debugbreak(), 1))
|
||||
#else
|
||||
#define debug__break() __builtin_trap()
|
||||
//:unix_debug_break
|
||||
// https://github.com/r-lyeh/tinybits/blob/master/tinyassert.c
|
||||
// #define debug__break() (signal(SIGTRAP, break_handler_), raise(SIGTRAP))
|
||||
#endif
|
||||
#define debug_break() (debug__break(), 0)
|
||||
#define debug_break() (debug__break(), 1)
|
||||
|
||||
#if PLATFORM_WASM
|
||||
#define gb_thread
|
||||
@@ -164,7 +167,7 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
// Single linked list Queue
|
||||
#define SLLQ_APPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert((n)->next == NULL); \
|
||||
assert_expr((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
@@ -175,7 +178,7 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
|
||||
#define SLLQ_PREPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert((n)->next == NULL); \
|
||||
assert_expr((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
@@ -217,8 +220,8 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
// Doubly linked list Queue
|
||||
#define DLLQ_APPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
assert_expr((node)->next == NULL); \
|
||||
assert_expr((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
@@ -231,8 +234,8 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
|
||||
#define DLLQ_PREPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
assert_expr((node)->next == NULL); \
|
||||
assert_expr((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
@@ -248,7 +251,7 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
#define DLLQ_REMOVE_EX(first, last, node, next, prev) \
|
||||
do { \
|
||||
if ((first) == (last)) { \
|
||||
assert((node) == (first)); \
|
||||
assert_expr((node) == (first)); \
|
||||
(first) = (last) = 0; \
|
||||
} else if ((last) == (node)) { \
|
||||
(last) = (last)->prev; \
|
||||
@@ -270,8 +273,8 @@ union convert_f32_i32_t { f32 f; i32 i; };
|
||||
// Doubly linked list Stack
|
||||
#define DLLS_PUSH_EX(first, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
assert_expr((node)->next == NULL); \
|
||||
assert_expr((node)->prev == NULL); \
|
||||
(node)->next = (first); \
|
||||
if ((first)) \
|
||||
(first)->prev = (node); \
|
||||
|
||||
@@ -26,9 +26,11 @@ fn void default_log_proc(log_level_t level, s8_t file_and_line, s8_t string);
|
||||
fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...);
|
||||
|
||||
#if PLATFORM_DEBUG_ASSERT
|
||||
#define assert(x) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x "\n"), debug_break()))
|
||||
#define assert_expr(x) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x "\n"), debug_break()))
|
||||
#define assert(x) do { static int once = 1; for (;once;once=0) assert_expr(x); } while(0)
|
||||
#else
|
||||
#define assert(x) (void)(x)
|
||||
#define assert_expr(x) (void)(x)
|
||||
#define assert(x) do { (void)(x); } while(0)
|
||||
#endif
|
||||
#define not_implemented assert(!"not implemented!")
|
||||
#define invalid_codepath assert(!"invalid code path!")
|
||||
|
||||
@@ -33,7 +33,29 @@ fn f64 os_parse_float(char *str) {
|
||||
return strtod(str, NULL);
|
||||
}
|
||||
|
||||
fn void os_unix_crash_handler(int signal, siginfo_t* info, void* context) {
|
||||
context; // unused
|
||||
printf("signal: %d", signal);
|
||||
if (signal == SIGSEGV) {
|
||||
printf(" at addr: %p", info->si_addr);
|
||||
}
|
||||
puts("");
|
||||
puts(b_stacktrace_get_string());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fn void os_unix_register_crash_handler() {
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = os_unix_crash_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGABRT, &sa, NULL);
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
tcx->temp = ma_create(ma_default_reserve_size);
|
||||
ma_init(&tcx->perm, ma_default_reserve_size);
|
||||
os_unix_register_crash_handler();
|
||||
}
|
||||
@@ -34,7 +34,19 @@ fn f64 os_parse_float(char *str) {
|
||||
return strtod(str, NULL);
|
||||
}
|
||||
|
||||
fn void os_win32_crash_handler(int signal) {
|
||||
printf("signal: %d\n", signal);
|
||||
puts(b_stacktrace_get_string());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fn void os_win32_register_crash_handler() {
|
||||
signal(SIGSEGV, os_win32_crash_handler);
|
||||
signal(SIGABRT, os_win32_crash_handler);
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
tcx->temp = ma_create(ma_default_reserve_size);
|
||||
ma_init(&tcx->perm, ma_default_reserve_size);
|
||||
os_win32_register_crash_handler();
|
||||
}
|
||||
412
src/core/stacktrace.h
Normal file
412
src/core/stacktrace.h
Normal file
@@ -0,0 +1,412 @@
|
||||
#if !defined(B_STACKTRACE_INCLUDED)
|
||||
#define B_STACKTRACE_INCLUDED (1)
|
||||
/*
|
||||
b_stacktrace v0.21 -- a cross-platform stack-trace generator
|
||||
SPDX-License-Identifier: MIT
|
||||
URL: https://github.com/iboB/b_stacktrace
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
#define B_STACKTRACE_IMPL before including b_stacktrace.h in *one* C or C++
|
||||
file to create the implementation
|
||||
|
||||
#include "b_stacktrace.h" to get access to the following functions:
|
||||
|
||||
char* b_stacktrace_get_string();
|
||||
Returns a human-readable stack-trace string from the point of view of the
|
||||
caller.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
|
||||
b_stacktrace_handle b_stacktrace_get();
|
||||
Returns a stack-trace handle from the point of view of the caller which
|
||||
can be expanded to a string via b_stacktrace_to_string.
|
||||
The handle is allocated with `malloc` and needs to be freed with `free`
|
||||
|
||||
b_stacktrace_to_string(b_stacktrace_handle stacktrace);
|
||||
Converts a stack-trace handle to a human-readable string.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
|
||||
|
||||
Config
|
||||
======
|
||||
|
||||
#define B_STACKTRACE_API to custom export symbols to export the library
|
||||
functions from a shared lib
|
||||
|
||||
Revision History
|
||||
================
|
||||
|
||||
* 0.21 (2022-12-20) Fixed typo
|
||||
* 0.20 (2022-12-18) Beta.
|
||||
Expanded interface
|
||||
Minor fixes
|
||||
* 0.10 (2020-12-07) Initial public release. Alpha version
|
||||
|
||||
MIT License
|
||||
===========
|
||||
|
||||
Copyright (c) 2020-2023 Borislav Stanimirov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#if !defined(B_STACKTRACE_API)
|
||||
#define B_STACKTRACE_API extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
A stacktrace handle
|
||||
*/
|
||||
typedef struct b_stacktrace_tag* b_stacktrace_handle;
|
||||
|
||||
/*
|
||||
Returns a stack-trace handle from the point of view of the caller which
|
||||
can be expanded to a string via b_stacktrace_to_string.
|
||||
The handle is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
B_STACKTRACE_API b_stacktrace_handle b_stacktrace_get();
|
||||
|
||||
/*
|
||||
Converts a stack-trace handle to a human-readable string.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
B_STACKTRACE_API char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
|
||||
|
||||
/*
|
||||
Returns a human-readable stack-trace string from the point of view of the
|
||||
caller.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
B_STACKTRACE_API char* b_stacktrace_get_string(void);
|
||||
|
||||
/* version */
|
||||
#define B_STACKTRACE_VER_MAJOR 0
|
||||
#define B_STACKTRACE_VER_MINOR 20
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(B_STACKTRACE_IMPL)
|
||||
|
||||
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct print_buf {
|
||||
char* buf;
|
||||
int pos;
|
||||
int size;
|
||||
} print_buf;
|
||||
|
||||
static print_buf buf_init(void) {
|
||||
print_buf ret = {
|
||||
(char*) malloc(1024),
|
||||
0,
|
||||
1024
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void buf_printf(print_buf* b, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const int len = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
va_end(args);
|
||||
|
||||
const int new_end = b->pos + len;
|
||||
|
||||
if (new_end > b->size) {
|
||||
while (new_end > b->size) b->size *= 2;
|
||||
b->buf = (char*)realloc(b->buf, b->size);
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
b->pos += vsnprintf(b->buf + b->pos, len, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char* b_stacktrace_get_string(void) {
|
||||
b_stacktrace_handle h = b_stacktrace_get();
|
||||
char* ret = b_stacktrace_to_string(h);
|
||||
free(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define B_STACKTRACE_MAX_DEPTH 1024
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <DbgHelp.h>
|
||||
|
||||
#pragma comment(lib, "DbgHelp.lib")
|
||||
|
||||
#define B_STACKTRACE_ERROR_FLAG ((DWORD64)1 << 63)
|
||||
|
||||
typedef struct b_stacktrace_entry {
|
||||
DWORD64 AddrPC_Offset;
|
||||
DWORD64 AddrReturn_Offset;
|
||||
} b_stacktrace_entry;
|
||||
|
||||
static int SymInitialize_called = 0;
|
||||
|
||||
b_stacktrace_handle b_stacktrace_get(void) {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
CONTEXT context;
|
||||
STACKFRAME64 frame; /* in/out stackframe */
|
||||
DWORD imageType;
|
||||
b_stacktrace_entry* ret = (b_stacktrace_entry*)malloc(B_STACKTRACE_MAX_DEPTH * sizeof(b_stacktrace_entry));
|
||||
int i = 0;
|
||||
|
||||
if (!SymInitialize_called) {
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
SymInitialize_called = 1;
|
||||
}
|
||||
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
#ifdef _M_IX86
|
||||
imageType = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_X64
|
||||
imageType = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rsp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Rsp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_IA64
|
||||
imageType = IMAGE_FILE_MACHINE_IA64;
|
||||
frame.AddrPC.Offset = context.StIIP;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.IntSp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrBStore.Offset = context.RsBSP;
|
||||
frame.AddrBStore.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.IntSp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#else
|
||||
#error "Platform not supported!"
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
b_stacktrace_entry* cur = ret + i++;
|
||||
if (i == B_STACKTRACE_MAX_DEPTH) {
|
||||
cur->AddrPC_Offset = 0;
|
||||
cur->AddrReturn_Offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!StackWalk64(imageType, process, thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
|
||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
||||
cur->AddrReturn_Offset = B_STACKTRACE_ERROR_FLAG; /* mark error */
|
||||
cur->AddrReturn_Offset |= GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
||||
cur->AddrReturn_Offset = frame.AddrReturn.Offset;
|
||||
|
||||
if (frame.AddrReturn.Offset == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (b_stacktrace_handle)(ret);
|
||||
}
|
||||
|
||||
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
||||
const b_stacktrace_entry* entries = (b_stacktrace_entry*)h;
|
||||
int i = 0;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
print_buf out = buf_init();
|
||||
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + 1024);
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->MaxNameLength = 1024;
|
||||
|
||||
while (1) {
|
||||
IMAGEHLP_LINE64 lineData;
|
||||
DWORD lineOffset = 0;
|
||||
DWORD64 symOffset = 0;
|
||||
const b_stacktrace_entry* cur = entries + i++;
|
||||
|
||||
if (cur->AddrReturn_Offset & B_STACKTRACE_ERROR_FLAG) {
|
||||
DWORD error = cur->AddrReturn_Offset & 0xFFFFFFFF;
|
||||
buf_printf(&out, "StackWalk64 error: %d @ %p\n", error, cur->AddrPC_Offset);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur->AddrPC_Offset == cur->AddrReturn_Offset) {
|
||||
buf_printf(&out, "Stack overflow @ %p\n", cur->AddrPC_Offset);
|
||||
break;
|
||||
}
|
||||
|
||||
SymGetLineFromAddr64(process, cur->AddrPC_Offset, &lineOffset, &lineData);
|
||||
buf_printf(&out, "%s(%d): ", lineData.FileName, lineData.LineNumber);
|
||||
|
||||
if (SymGetSymFromAddr64(process, cur->AddrPC_Offset, &symOffset, symbol)) {
|
||||
buf_printf(&out, "%s\n", symbol->Name);
|
||||
}
|
||||
else {
|
||||
buf_printf(&out, " Unkown symbol @ %p\n", cur->AddrPC_Offset);
|
||||
}
|
||||
|
||||
if (cur->AddrReturn_Offset == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(symbol);
|
||||
return out.buf;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef struct b_stacktrace {
|
||||
void* trace[B_STACKTRACE_MAX_DEPTH];
|
||||
int trace_size;
|
||||
} b_stacktrace;
|
||||
|
||||
b_stacktrace_handle b_stacktrace_get(void) {
|
||||
b_stacktrace* ret = (b_stacktrace*)malloc(sizeof(b_stacktrace));
|
||||
ret->trace_size = backtrace(ret->trace, B_STACKTRACE_MAX_DEPTH);
|
||||
return (b_stacktrace_handle)(ret);
|
||||
}
|
||||
|
||||
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
||||
const b_stacktrace* stacktrace = (b_stacktrace*)h;
|
||||
char** messages = backtrace_symbols(stacktrace->trace, stacktrace->trace_size);
|
||||
print_buf out = buf_init();
|
||||
*out.buf = 0;
|
||||
|
||||
for (int i = 0; i < stacktrace->trace_size; ++i) {
|
||||
buf_printf(&out, "%s\n", messages[i]);
|
||||
}
|
||||
|
||||
free(messages);
|
||||
return out.buf;
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct b_stacktrace {
|
||||
void* trace[B_STACKTRACE_MAX_DEPTH];
|
||||
int trace_size;
|
||||
} b_stacktrace;
|
||||
|
||||
b_stacktrace_handle b_stacktrace_get(void) {
|
||||
b_stacktrace* ret = (b_stacktrace*)malloc(sizeof(b_stacktrace));
|
||||
ret->trace_size = backtrace(ret->trace, B_STACKTRACE_MAX_DEPTH);
|
||||
return (b_stacktrace_handle)(ret);
|
||||
}
|
||||
|
||||
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
||||
const b_stacktrace* stacktrace = (b_stacktrace*)h;
|
||||
char** messages = backtrace_symbols(stacktrace->trace, stacktrace->trace_size);
|
||||
print_buf out = buf_init();
|
||||
|
||||
for (int i = 0; i < stacktrace->trace_size; ++i) {
|
||||
void* tracei = stacktrace->trace[i];
|
||||
char* msg = messages[i];
|
||||
|
||||
/* calculate load offset */
|
||||
Dl_info info;
|
||||
dladdr(tracei, &info);
|
||||
if (info.dli_fbase == (void*)0x400000) {
|
||||
/* address from executable, so don't offset */
|
||||
info.dli_fbase = NULL;
|
||||
}
|
||||
|
||||
while (*msg && *msg != '(') ++msg;
|
||||
*msg = 0;
|
||||
|
||||
{
|
||||
char cmd[1024];
|
||||
char line[2048];
|
||||
|
||||
FILE* fp;
|
||||
snprintf(cmd, 1024, "addr2line -e %s -f -C -p %p 2>/dev/null", messages[i], (void*)((char*)tracei - (char*)info.dli_fbase));
|
||||
|
||||
fp = popen(cmd, "r");
|
||||
if (!fp) {
|
||||
buf_printf(&out, "Failed to generate trace further...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
buf_printf(&out, "%s: ", messages[i]);
|
||||
if (strstr(line, "?? ")) {
|
||||
/* just output address if nothing can be found */
|
||||
buf_printf(&out, "%p\n", tracei);
|
||||
}
|
||||
else {
|
||||
buf_printf(&out, "%s", line);
|
||||
}
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
free(messages);
|
||||
return out.buf;
|
||||
}
|
||||
|
||||
#else
|
||||
/* noop implementation */
|
||||
char* b_stacktrace_get_string(void) {
|
||||
print_buf out = buf_init();
|
||||
buf_printf("b_stacktrace: unsupported platform\n");
|
||||
return out.buf;
|
||||
}
|
||||
#endif /* platform */
|
||||
|
||||
#endif /* B_STACKTRACE_IMPL */
|
||||
#endif /* B_STACKTRACE_INCLUDED */
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define STBTT_cos(x) (f64_cos(x))
|
||||
#define STBTT_acos(x) (f64_acos(x))
|
||||
#define STBTT_fabs(x) (f64_abs(x))
|
||||
#define STBTT_assert(x) (assert(x))
|
||||
#define STBTT_assert(x) assert(x)
|
||||
#define STBTT_malloc(x,u) (ma_push_size(tcx->temp, x))
|
||||
#define STBTT_free(x,u)
|
||||
#define STBTT_strlen(x) (str_len(x))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// automatically generated using: C:\dev\wasm\src/render/render.meta.c
|
||||
// automatically generated using: D:\dev\wasm\src/render/render.meta.c
|
||||
gb_read_only u8 main_font_data[] = {
|
||||
0,1,0,0,0,16,1,0,0,4,0,0,71,68,69,70,9,171,18,85,0,0,2,40,0,0,1,242,71,80,79,83,196,118,81,155,0,0,24,140,0,0,22,52,71,83,85,66,112,248,190,150,0,0,222,16,0,0,83,202,79,83,47,50,
|
||||
138,149,152,224,0,0,1,200,0,0,0,96,83,84,65,84,121,145,108,221,0,0,1,96,0,0,0,46,99,109,97,112,147,243,132,151,0,0,75,136,0,0,65,218,103,97,115,112,0,0,0,16,0,0,1,20,0,0,0,8,103,108,121,102,
|
||||
|
||||
@@ -92,7 +92,7 @@ fn b32 rn_reload_font_atlas(rn_font_t *font, s8_t font_data, rn_atlas_t *atlas,
|
||||
i32 xadvance, left_side_bearing;
|
||||
stbtt_GetCodepointHMetrics(&stb_font, ascii_symbol, &xadvance, &left_side_bearing);
|
||||
|
||||
rn_glyph_t glyph = {};
|
||||
rn_glyph_t glyph = {0};
|
||||
glyph.atlas_bounding_box = rn_pack_bitmap(atlas, bitmap, width, height);
|
||||
glyph.size = (v2f32_t){(f32)width, (f32)height};
|
||||
glyph.offset = (v2f32_t){(f32)xoff, (f32)yoff};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fn rn_shader_t rn_create_shader(char *glsl_vshader, char *glsl_fshader) {
|
||||
rn_shader_t result = {};
|
||||
rn_shader_t result = {0};
|
||||
result.vshader = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader);
|
||||
result.fshader = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader);
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ fn void test_s8(void) {
|
||||
assert(s8_are_equal(s0, s8_lit("23456789")));
|
||||
assert(s8_are_equal(s1, s8_lit("01")));
|
||||
}
|
||||
|
||||
ma_destroy(arena);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// automatically generated using: C:\dev\wasm\src/ui/ui.meta.c
|
||||
// automatically generated using: D:\dev\wasm\src/ui/ui.meta.c
|
||||
|
||||
type_t type__ui_color_t = { type_kind_enum, s8_const_lit("ui_color_t"), sizeof(ui_color_t),
|
||||
.members = (type_member_t[]){
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// automatically generated using: C:\dev\wasm\src/ui/ui.meta.c
|
||||
// automatically generated using: D:\dev\wasm\src/ui/ui.meta.c
|
||||
typedef enum {
|
||||
ui_color_rect,
|
||||
ui_color_rect_hot,
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "app/app.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
|
||||
#include "core/core.c"
|
||||
#include "os/os.c"
|
||||
#include "app/app.c"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// automatically generated using: C:\dev\wasm\src/wasm_app/wasm_app.meta.c
|
||||
// automatically generated using: D:\dev\wasm\src/wasm_app/wasm_app.meta.c
|
||||
gb f32 font_size = 30;
|
||||
gb f32 _font_size = 30;
|
||||
gb_read_only mt_tweak_t tweak_table[] = {
|
||||
|
||||
Reference in New Issue
Block a user