Merge remote-tracking branch 'EpicGamesExt/master'

# Conflicts:
#	.gitignore
This commit is contained in:
ed
2026-06-23 20:12:24 -04:00
503 changed files with 143836 additions and 120896 deletions
+7
View File
@@ -1 +1,8 @@
*.sh text=auto eol=lf
src/lib_rdi/rdi.h text=auto eol=lf
src/lib_rdi/rdi.c text=auto eol=lf
*.meta.* text=auto eol=lf
*.exe filter=lfs diff=lfs merge=lfs -text
*.pdb filter=lfs diff=lfs merge=lfs -text
*.elf filter=lfs diff=lfs merge=lfs -text
*.rdi filter=lfs diff=lfs merge=lfs -text
+117 -18
View File
@@ -8,7 +8,45 @@ on:
paths-ignore:
- '**.md'
env:
TORTURE_FLAGS: "--gen_crash_dump"
jobs:
build-ubuntu-24-04:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
target:
- raddbg
- raddbg_non_graphical
- radlink
- radbin
- torture
compiler:
- clang-22
# TODO: - gcc
mode:
- debug
- release
steps:
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: Install Dependencies
shell: bash
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
sudo apt-get update
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
- name: build
shell: bash
run: |
CC="${{ matrix.compiler }}" ./build.sh "${{ matrix.target }}" "${{ matrix.mode }}"
build-windows-2022:
runs-on: windows-2022
strategy:
@@ -18,6 +56,7 @@ jobs:
- raddbg
- radlink
- radbin
- mule_main
compiler:
- msvc
- clang
@@ -25,28 +64,88 @@ jobs:
- debug
- release
steps:
- name: checkout
uses: actions/checkout@v2
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: build (vs 2022)
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
call build meta "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
run-torture:
runs-on: windows-2022
run-ubuntu-24-04:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
compiler:
- clang-22
# TODO: - gcc
mode:
- debug
# TODO: - release
steps:
# - name: Install ASAN
# shell: cmd
# run: |
# "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" modify --installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" --quiet --force --norestart --add Microsoft.VisualStudio.Component.VC.ASAN
- name: checkout
uses: actions/checkout@v2
- name: run-torture
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: Install Dependencies
shell: bash
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
sudo apt-get update
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
# crash callstack symbolizer depends on LLVM
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
- name: Run
shell: bash
run: |
CC="${{ matrix.compiler }}" ./run_tests.sh clang "${{ matrix.mode }}" -- \* $TORTURE_FLAGS
- name: Upload Artifacts
if: failure()
uses: actions/upload-artifact@v7
with:
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
path: |
build/*.core
build/*.exe
build/*.pdb
build/torture_artifacts/**
if-no-files-found: ignore
run-windows-2022:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
compiler:
- msvc
- clang
mode:
- debug
- release
steps:
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: Run
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build radlink asan debug no_meta || exit /b 1
call build torture debug no_meta || exit /b 1
cd build
torture -l:radlink || exit /b 1
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
call run_tests.bat ${{ matrix.compiler }} ${{ matrix.mode }} -- * %TORTURE_FLAGS% || exit /b 1
- name: Upload Artifacts
if: failure()
uses: actions/upload-artifact@v7
with:
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
path: |
build/*.dmp
build/*.exe
build/*.pdb
build/torture_artifacts/**
if-no-files-found: ignore
+2 -1
View File
@@ -1,4 +1,5 @@
/build/
/local/
*~
.vscode/settings.json
.vs
tags
+245
View File
@@ -1,3 +1,248 @@
# v0.9.27-alpha
## Debugger Changes
- Fixed an issue which would rarely cause steps to take a long time.
- Drastically improved memory usage of PDB -> RDI conversion for some
workloads, notably PDBs with many small compilation units.
- Added the ability to disambiguate symbol names by module name, debug info
name, or compilation unit name in expressions. This can be done using the
usual syntax, e.g. `my_module.dll!foo`, or `my_unit.obj!foo`. `:` can also be
used instead of `!`.
- Added the ability to redirect debug string output to any label on a
per-target basis. Those labels can then be evaluated in any watch window or
text visualizer. By default, all targets write to `output`, which is
automatically visualized by an `Output` tab. But if you want different
targets to route their debug output to different buffers, you can name the
buffers differently, and then view those in separate text views.
- Added a `Run To Name` command.
- Added an `Auto Load Last Project` setting, which will automatically load the
most recently loaded project on startup (the old behavior pre-0.9.26). This
setting is off by default.
- Added right-click menus for watch expressions, to easily find them in a
memory view, or to break when their value changes.
- Added preliminary support for symbol servers. First, the debugger can attempt
to download debug info for any module via the `Download Module Debug Info`
command (also accessible by right-clicking a module). Second, the debugger
can be configured to automatically do this for all modules which don't have
debug info via the `Auto Download Debug Info` setting. The local cache path
and server URLs used by the debugger for downloading symbols are parsed from
the `_NT_SYMBOL_PATH` environment variable. If that environment variable is
not configured, then it falls back to the defaults of `C:/SymbolCache` and
`https://msdl.microsoft.com/download/symbols`.
- Adjusted the default dark theme.
- Made several UI visual improvements.
- Fixed a few issues relating to offline symbol evaluation (evaluation of
symbols in debug info when not debugging); this was sometimes preventing
function listers (e.g. used in `Go To Name`) from working when not debugging.
- Fixed the debugger's snap-to-code-location rule when a `Disassembly` tab is
occupying the same panel as source code tabs. Previously, the debugger would
overly aggressively switch back to source code tabs. Now, it should respect
the preference of disassembly correctly.
- Improved the stability of the step-over-line operation. Our stepping
algorithm would sometimes cause spurious (and rarely, non-spurious)
access violation exceptions when a thread would try to execute at address
`0x38f`. This most regularly surfaced when an exception on one thread (like a
breakpoint being hit) would interrupt stepping on another thread. This has
been resolved, and stepping in such scenarios should be much more reliable.
- Fixed some crashes in the PDB -> RDI converter. (#792, #803)
- Fixed a bug which was sometimes causing a step-over operation to resume the
process without catching the target thread after its step completed. (#804)
- Adjusted evaluation visualizations to include fully qualified symbol names.
(#809)
## Linker Changes
- /OPT:REF Fixed a race in the dead-code-elimination pass where the linker
sometimes erroneously removed live sections.
- Fixed a bug where the linker emitted relocations for empty COFF resource entries,
which lead to "relocating against symbol that is in a removed section" errors.
- Added the /RAD_TYPE_SERVER switch to run the type-dedup pass on object files,
producing RRT files that can be passed back on the next link to improve
linking speed.
# v0.9.26-alpha
## Debugger Changes
- Added scope ending visualizations to the text view, to display the header of
a scope at the closing position of the scope. This can be turned off via the
`Cursor Scope End Annotations` setting.
- Added the ability to evaluate `autos`, which is a collection of expressions
that the debugger determines refer to symbols which are being (or about to
be) changed by the selected thread.
- Added source-inline and disassembly-inline visualization of auto expressions.
This can be turned off via the `Show Auto Watches In Source / Disassembly`
setting.
- Added the ability to evaluate local static variables unambiguously, when the
same name is used for multiple local static variables, even when outside the
function containing the local static. This can be done by namespacing the
variable name with the containing function, either using a `::` or `.`
operator. (#359)
- Added a setting, `Transient Tabs`, to disable transient tabs being opened,
when the debugger automatically snaps to new code locations.
- Added a setting, `Display Pointer Addresses Before Contents`, to always
force the debugger to show pointer addresses before attempting to visualize
to what the pointer points.
- Adjusted the `Step Out` command to perform scope-granularity stepping, rather
than only being function-frame-granularity. This uses scope information found
in debug info to step out of scopes when possible, rather than always exiting
the current function frame. This makes the command much more useful for
stepping through larger functions with several scopes of larger work, or for
stepping out of loops. (#746)
- Adjusted the debugger's user & project configuration file behavior to be less
idiosyncratic with other programs. Project files are no longer auto-loaded
based on the project last loaded during the previous debugger runtime.
Creating a new user or project also does not immediately require choosing a
path for the file; these can later be specified using the respective `Save`
commands. (#743)
- Adjusted the debugger to automatically set the current path when loading a
project file. (#743)
- Added syntax highlighting and tab-completion for view identifiers in
watch expressions.
- Added more in-debugger documentation for views and their arguments, when
written in a watch expression.
- Moved configuration data previously treated as project data to being user
data, tagged with the associated project. This includes loaded debug info and
breakpoints. The effect of this is that project files are much easier to
check into source control (they do not change in spurious ways for other
users on a project), but project-related user configuration will still be
correctly filtered based on whatever project is loaded.
- Improved the debugger's behavior with respect to keeping previously-loaded
debug info around. Now, when the debugger begins a new debugging session, it
will unload all loaded debug info, and it will only reload debug info that is
actively found to be needed by debuggees. This preserves the debugger's
ability to use debug info without debugging for features like
go-to-definition and type evaluation, but it stops the debugger from keeping
old and unneeded debug info loaded indefinitely (until it is manually
unloaded). (#711)
- Adjusted recent project visualization to include the name of the project,
specified with the `Project Name` setting.
- Renamed `Switch` to `Open Source File From Debug Info`, to better represent
the command's functionality.
- Adjusted file path evaluation visualization to include the full path to the
containing folder, when it is not obvious from context (for instance, if the
file evaluation is a child evaluation of a folder evaluation, the containing
folder path is not shown; if the file path is evaluated standalone, as it is
in the lister generated for the `Open Source File From Debug Info` command,
then the containing folder path is shown).
- Improved visualization of unmapped addresses in the memory view. Now, instead
of bytes at these addresses being displayed as `0` with a special background,
they are displayed as `x`, and the annotations for these addresses (displayed
at the bottom of the memory view, for the cursor's cell) explicitly label
them as being unmapped.
- Improved visualization of unmapped addresses in watch expressions. Now,
instead of only being colored differently with evaluations reading as zeroed
memory, the value will explicitly label addresses as unmapped when possible.
- Fixed a leak which most notably manifested during rapid creation/destruction
of new threads. (#780)
- Fixed a leak related to debugger's config state. This was difficult to
reproduce, but it may fix leaks experienced after running the debugger for an
extended period of time.
- Fixed a bug where cross-module evaluations would resolve to incorrect
addresses, due to using the incorrect module's base virtual address. This was
also causing broken behavior sometimes in the `Go To Name` lister, and
other similar UIs.
- Fixed a bug where panels without tabs were unnecessarily keeping the debugger
UI awake in some cases.
- Fixed a bug preventing hover evaluation from working on indexing expressions.
(#707)
- Replaced the DWARF -> RDI converter with a new multithreaded version, which
should execute much faster on larger DWARF debug info, and produce much
smaller RDI output, due to the addition of type deduplication.
- Introduced structured namespaces to RDI, which structurally encode namespace
hierarchies for debug info symbols, instead of this information being
implicitly baked using language-specific conventions into symbol names. This
is used to deduplicate repeated namespace prefixes from symbol names, leading
to a smaller string footprint for generated RDIs. Symbols now only store
their partially-qualified name. For example, for a C++ symbol `A::B::C`, the
symbol itself will store its name as `C`, but it will also record its
container as being `B`. `B`, then, will record its container as being `A`.
This allows users of RDI to dynamically construct the fully-qualified name as
needed, and it allows for more reliable and language-agnostic usage of
partially-qualified symbol names.
- Adjusted the debugger to not rely on `SynchronizationBarrier` functions on
Windows when they're not available (pre-Windows-8). (#739)
## Linker Changes
- Implemented /DEBUG:GHASH
- Fixed an issue where an import thunk or import address could be linked from
the currently searched library instead of the library where the first import
reference was found. For example, if the first pass finds the import thunk in
foo.lib and the second pass resolves symbol to the import address in bar.lib,
the linker now always linkes the import thunk and import address members from
the library where the first reference was found.
- /OPT:REF: Fixed an issue with garbage collection of associated sections and
weak symbols that led linker to remove live sections.
- /OPT:REF Added relocation batching to reduce contention on the global
reference list during garbage collection.
# v0.9.25-alpha
## Debugger Changes
- Added a dedicated cursor address bar to the memory view. This can be focused
with the keyboard with the `Focus Menu` command. By default, this command is
bound to `Alt + D`, but if you have existing configuration, you may need to
bind it yourself manually (this can be done in the palette). This address bar
accepts any expression, and controls the cursor's address. All other
configuration options are still available in the memory view settings.
- Added "Peek Types" to the memory view. These control the set of types which
are used to interpret bytes at the cursor. Options exist for basic cases,
like integers and floats, but the view also supports entering a list of
full type expressions, which can include user-defined types like structures.
- Added annotations for members of structure variables to the memory view.
- Added a dedicated zoom setting for the memory view.
- Added a setting for automatically determining the number of columns in the
memory view based on the available space.
- Fixed many bugs and improved visuals in the memory view. (#690)
- Fixed the debugger incorrectly evaluating pointer casts of registers in
register space, rather than promoting them to process address space
evaluations. This fixes cases where expressions like `(int *)rax` were not
evaluating correctly. (#659)
- Fixed the debugger incorrectly requiring multiple step operations when source
lines mapped to multiple discontiguous ranges of instructions. This most
notably showed up with certain styles of `for`-loops, especially with Clang
and other non-C/C++ languages, and function prologues in non-C/C++ languages.
- Fixed the debugger treating the `foo, x` fastpath for `hex(foo)` differently
than `hex(foo)`, in that the hexadecimal setting was not being inherited.
- Fixed the debugger leaking debug info conversion process handles. This
addresses cases where the debugger was preventing stale debug info from being
updated, after a rebuild. (#736)
- Fixed the debugger not correctly using target-embedded markup data. (#702)
- Fixed the debugger not showing full call stacks when the top instruction
pointer is located at a 0 address.
- Fixed integer casts producing incorrect values. (#754)
- Fixed the PDB -> RDI converter's interpretation of certain empty argument
lists in function types in PDB. This fixes some cases where local variables
were being interpreted as parameters, which resulted in incorrect evaluation
results. (#751)
- Fixed several crashes and instabilities. (#735)
- Added a dedicated settings button to the focused tab. This opens the same
menu as right-clicking the tab, but this makes this menu (and thus all
options for all tabs and views) more discoverable.
- Added optional cursor trails, to visualize cursor motion. Can be turned off
by toggling the `Cursor Trail` setting.
- Added project names. When set, this name is used for displaying the project
instead of the project filename in the UI and window titles.
- Adjusted the rules for explicit file location finding commands (like
`Switch`, or `Switch To Partner File`), such that they prefer creating new
non-transient tabs, even if the target file is found within an existing
transient tab.
- Adjusted the source code context menu to activate commands with a single
press, rather than the usual double click behavior from general palettes.
## Linker Changes
- Optimized debug info generation to reduce memory usage in large links by 25%.
- Fixed a determinism issue that caused linker to write unreliable debug info.
- Fixed over-reservetaion of PDB pages, reducing the PDB size.
- Implemented /INFERASANLIBS
- Implemented /WHOLEARCHIVE
- Implemented /PDBSTRIPPED
- Set correct defaults for unload and bind import tables.
# v0.9.24-alpha
## Debugger Changes
+35 -18
View File
@@ -24,6 +24,7 @@ cd /D "%~dp0"
:: Below is a list of all possible non-target command line options:
::
:: - `asan`: enable address sanitizer
:: - `ubsan`: enable undefined-behavior sanitizer
:: - `telemetry`: enable RAD telemetry profiling support
:: - `spall`: enable spall profiling support
@@ -35,14 +36,15 @@ if "%debug%"=="1" set release=0 && echo [debug mode]
if "%release%"=="1" set debug=0 && echo [release mode]
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
if "%clang%"=="1" set msvc=0 && echo [clang compile]
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
:: --- Unpack Command Line Build Arguments ------------------------------------
set auto_compile_flags=
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
if "%ubsan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=undefined && echo [ubsan enabled]
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info]
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
@@ -66,21 +68,22 @@ if "%pgo%"=="1" (
)
:: --- Compile/Link Line Definitions ------------------------------------------
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /Zc:preprocessor
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf
set cl_out= /out:
set cl_obj_out= /Fo:
set cl_linker=
set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 -msha
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf
set clang_common= -mcx16 -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 -D_DEBUG %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 -DNDEBUG %clang_common% %auto_compile_flags%
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:noicf
set clang_out= -o
set clang_obj_out= -o
set clang_linker= -Xlinker
:: --- Per-Build Settings -----------------------------------------------------
set link_dll=-DLL
set link_icon=logo.res
if "%msvc%"=="1" set linker=%cl_linker%
if "%clang%"=="1" set linker=%clang_linker%
@@ -92,16 +95,20 @@ if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
if "%msvc%"=="1" set rc=call rc
if "%clang%"=="1" set rc=call llvm-rc
if "%msvc%"=="1" set link_dll=/link /DLL
if "%clang%"=="1" set link_dll=-Xlinker -DLL
:: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug%
if "%msvc%"=="1" set compile_release=%cl_release%
if "%msvc%"=="1" set compile_link=%cl_link%
if "%msvc%"=="1" set out=%cl_out%
if "%msvc%"=="1" set obj_out=%cl_obj_out%
if "%clang%"=="1" set compile_debug=%clang_debug%
if "%clang%"=="1" set compile_release=%clang_release%
if "%clang%"=="1" set compile_link=%clang_link%
if "%clang%"=="1" set out=%clang_out%
if "%clang%"=="1" set obj_out=%clang_obj_out%
if "%debug%"=="1" set compile=%compile_debug%
if "%release%"=="1" set compile=%compile_release%
@@ -119,32 +126,37 @@ for /f %%i in ('call git describe --always --dirty') do set compile=%compile%
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
:: --- Build & Run Metaprogram ------------------------------------------------
pushd build
if "%meta%"=="1" (
echo [doing metagen]
pushd build
echo [building metagen]
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
metagen.exe || exit /b 1
popd
)
if "%no_meta%"=="" if exist metagen.exe (
echo [running metagen]
metagen.exe || exit /b 1
)
popd
:: --- Build Everything (@build_targets) --------------------------------------
pushd build
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
if "%raddbg_non_graphical%"=="1" set didbuild=1 && %compile% -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg_non_graphical.exe || exit /b 1
if "%com_shim%"=="1" set didbuild=1 && %compile% ..\src\com_shim\com_shim_main.c %compile_link% %out%com_shim.exe || exit /b 1
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
if "%eval_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\eval_scratch.c %compile_link% %out%eval_scratch.exe || exit /b 1
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp %obj_out%mule_inline.obj && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp %obj_out%mule_o2.obj && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture.c %compile_link% %out%torture.exe || exit /b1
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture_main.c %compile_link% %out%torture.exe || exit /b1
if "%dwarf_expr_test%"=="1" set didbuild=1 && %compile% ..\src\torture\dwarf_expr_test.c %compile_link% %out%dwarf_expr_test.exe || exit /b1
if "%unit_sizes_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\scratch\unit_sizes_from_pdb.c %compile_link% %out%unit_sizes_from_pdb.exe || exit /b1
if "%mule_peb_trample%"=="1" (
set didbuild=1
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
@@ -155,6 +167,11 @@ if "%mule_peb_trample%"=="1" (
)
popd
:: --- Set Up Debugger Com Shim -----------------------------------------------
pushd build
if "%raddbg_com_shim%"=="1" copy /y com_shim.exe raddbg.com
popd
:: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" (
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
@@ -165,7 +182,7 @@ if "%didbuild%"=="" (
if "%pgo_run%"=="1" (
if "%radlink%"=="1" (
pushd local\lyra_pgo
call %~dp0build\radlink @lyra.rsp /rad_alt_pch_dir:%~dp0local\lyra_pgo || exit /b 1
call %~dp0build\radlink @lyra.rsp || exit /b 1
popd
)
goto restart
Regular → Executable
+42 -46
View File
@@ -4,78 +4,74 @@ cd "$(dirname "$0")"
# --- Unpack Arguments --------------------------------------------------------
for arg in "$@"; do declare $arg='1'; done
if [ ! -v gcc ]; then clang=1; fi
if [ ! -v release ]; then debug=1; fi
if [ -v debug ]; then echo "[debug mode]"; fi
if [ -v release ]; then echo "[release mode]"; fi
if [ -v clang ]; then compiler="${CC:-clang}"; echo "[clang compile]"; fi
if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
if [[ "$#" == "0" ]]; then raddbg='1'; fi
# --- Unpack Command Line Build Arguments -------------------------------------
auto_compile_flags=''
cc_sanitize=""
if [[ "${asan:-0}" == "1" ]]; then
echo "[asan enabled]"
cc_sanitize="-fsanitize=address"
fi
# --- Get Current Git Commit Id -----------------------------------------------
git_hash=$(git describe --always --dirty)
git_hash_full=$(git rev-parse HEAD)
# --- Compile/Link Line Definitions -------------------------------------------
clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
clang_link="-lpthread -lm -lrt -ldl"
clang_out="-o"
gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
gcc_link="-lpthread -lm -lrt -ldl"
gcc_out="-o"
cc_cflags_gcc=""
cc_cflags_clang=${cc_sanitize}" -fdiagnostics-absolute-paths -Wno-for-loop-analysis -Wno-incompatible-pointer-types-discards-qualifiers -Wno-initializer-overrides -Wno-compare-distinct-pointer-types -Wno-single-bit-bitfield-constant-conversion -Wno-deprecated-declarations -Wno-writable-strings -Wno-unknown-warning-option -Wno-deprecated-register -Wno-unused-local-typedef -msse2"
cc_common="-mcx16 -I../src/ -I../local/ -D_GNU_SOURCE -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wall -Wno-missing-braces -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-value -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
cc_debug="-g -O0 -DBUILD_DEBUG=1 ${cc_common}"
cc_release="-g -O2 -DBUILD_DEBUG=0 ${cc_common}"
cc_link="-lpthread -lm -lrt -ldl"
# --- Per-Build Settings ------------------------------------------------------
link_dll="-fPIC"
link_os_gfx="-lX11 -lXext"
link_render="-lGL -lEGL"
link_font_provider="-lfreetype"
cc_link_dll="-fPIC"
# --- External Libraries ------------------------------------------------------
# sudo apt install -y pkg-config libfreetype6-dev libx11-dev libxext-dev libgl-dev libegl-dev
if [[ -x "$(command -v pkg-config)" ]]; then
cc_font_provider="$(pkg-config --cflags --libs freetype2)"
cc_os_gfx="$(pkg-config --cflags --libs x11 xext)"
cc_render="$(pkg-config --cflags --libs gl egl)"
else
cc_font_provider="-I/usr/include/freetype2 -lfreetype"
cc_os_gfx="-lX11 -lXext"
cc_render="-lGL -lEGL"
fi
# --- Choose Compile/Link Lines -----------------------------------------------
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
if [ -v gcc ]; then compile_release="$gcc_release"; fi
if [ -v gcc ]; then compile_link="$gcc_link"; fi
if [ -v gcc ]; then out="$gcc_out"; fi
if [ -v clang ]; then compile_debug="$clang_debug"; fi
if [ -v clang ]; then compile_release="$clang_release"; fi
if [ -v clang ]; then compile_link="$clang_link"; fi
if [ -v clang ]; then out="$clang_out"; fi
if [ -v debug ]; then compile="$compile_debug"; fi
if [ -v release ]; then compile="$compile_release"; fi
if [[ "${gcc:-0}" == "1" ]]; then compiler="${CC:-gcc} $cc_cflags_gcc"; echo "[gcc compile]";
elif [[ "${clang:-1}" == "1" ]]; then compiler="${CC:-clang} $cc_cflags_clang"; echo "[clang compile]";
fi
if [[ "${release:-0}" == "1" ]]; then echo "[release mode]"; compile="$compiler $cc_release";
elif [[ "${debug:-1}" == "1" ]]; then echo "[debug mode]"; compile="$compiler $cc_debug";
fi
# --- Prep Directories --------------------------------------------------------
mkdir -p build
mkdir -p local
mkdir -p build local
# --- Build & Run Metaprogram -------------------------------------------------
if [ -v no_meta ]; then echo "[skipping metagen]"; fi
if [ ! -v no_meta ]
if [[ "${no_meta:-0}" == "0" ]]
then
echo "[building metagen]"
cd build
$compile_debug ../src/metagen/metagen_main.c $compile_link $out metagen
$compiler $cc_debug ../src/metagen/metagen_main.c $cc_link -o metagen
./metagen
cd ..
fi
# --- Build Everything (@build_targets) ---------------------------------------
cd build
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $link_font_provider $out raddbg; fi
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
if [ -v rdi_breakpad_from_pdb ]; then didbuild=1 && $compile ../src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c $compile_link $out rdi_breakpad_from_pdb; fi
if [ -v ryan_scratch ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $link_render $link_font_provider $out ryan_scratch; fi
if [[ "${raddbg:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg; fi
if [[ "${raddbg_non_graphical:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg_non_graphical; fi
if [[ "${radbin:-0}" == "1" ]]; then didbuild=1 && $compile ../src/radbin/radbin_main.c $cc_link -o radbin; fi
if [[ "${radlink:-0}" == "1" ]]; then didbuild=1 && $compile ../src/linker/lnk.c $cc_link -o radlink; fi
if [[ "${torture:-0}" == "1" ]]; then didbuild=1 && $compile ../src/torture/torture_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o torture; fi
cd ..
# --- Warn On No Builds -------------------------------------------------------
if [ ! -v didbuild ]
if [[ "${didbuild:-0}" == "0" ]]
then
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh rdi_from_pdb\`."
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh radlink\`."
exit 1
fi
+93
View File
@@ -0,0 +1,93 @@
{
"version": "0.2.1",
"defaults": {},
"configurations": [
{
"type": "cppdbg",
"name": "launch - torture",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "build/",
"program": "torture",
"args": [ "d2r_checksums" ],
"stopAtEntry": false,
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "-gdb-set follow-fork-mode parent" },
{ "text": "-gdb-set detach-on-fork on" },
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
},
{
"type": "cppdbg",
"name": "launch - radbin",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "build/",
"program": "radbin",
"args": [ "-voff2line", "-voff:0x1000", "torture_artifacts/d2r_line_table/a.rdi" ],
"stopAtEntry": false,
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "-gdb-set follow-fork-mode parent" },
{ "text": "-gdb-set detach-on-fork on" },
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
},
{
"type": "cppdbg",
"name": "launch - radlink",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "/mnt/c/devel/raddebugger/build/torture_artifacts/debug_p_sig_mismatch",
"program": "/mnt/c/devel/raddebugger/build/radlink",
"args": [ "/subsystem:console", "/entry:entry", "/out:a.exe", "/debug:full", "a.obj", "b.obj", "entry.obj" ],
"stopAtEntry": false,
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
},
{
"type": "cppdbg",
"name": "launch - raddbg",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "build/",
"program": "/mnt/c/devel/raddebugger/build/raddbg",
//"processId": "65821",
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
}
]
}
File diff suppressed because it is too large Load Diff
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_DUMP_H
#define DWARF_DUMP_H
typedef enum
{
DW_DumperCacheFlag_InfoRanges = (1 << 0),
DW_DumperCacheFlag_CuArr = (1 << 1),
DW_DumperCacheFlag_LineVmMap = (1 << 2),
DW_DumperCacheFlag_TagTrees = (1 << 3),
} DW_DumperCacheFlags;
typedef struct DW_Dumper
{
Arena *arena;
Arch arch;
B32 is_relaxed;
B32 is_verbose;
DW_Raw *input;
DW_DumperCacheFlags cache_flags;
struct {
Rng1U64Array info_ranges;
DW_CompUnit *cu_arr;
HashTable *line_vm_map;
DW_TagTree *tag_trees;
} cache;
} DW_Dumper;
#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper)
typedef DW_PRINTER(DW_Printer);
////////////////////////////////
// cache
internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper);
internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper);
internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper);
internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper);
////////////////////////////////
//~ rjf: Stringification Helpers
internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program);
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa);
internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row);
#if 0
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx);
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch);
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges);
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input);
#endif
////////////////////////////////
//~ rjf: Dump Entry Point
internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose);
#endif // DWARF_DUMP_H
File diff suppressed because it is too large Load Diff
+233
View File
@@ -0,0 +1,233 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_EXPR_H
#define DWARF_EXPR_H
////////////////////////////////
// evaluator
#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512)
#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512)
#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64)
#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr)
typedef enum
{
DW_ExprValueType_Generic,
DW_ExprValueType_U8,
DW_ExprValueType_U16,
DW_ExprValueType_U32,
DW_ExprValueType_U64,
DW_ExprValueType_U128,
DW_ExprValueType_U256,
DW_ExprValueType_U512,
DW_ExprValueType_S8,
DW_ExprValueType_S16,
DW_ExprValueType_S32,
DW_ExprValueType_S64,
DW_ExprValueType_S128,
DW_ExprValueType_S256,
DW_ExprValueType_S512,
DW_ExprValueType_F32,
DW_ExprValueType_F64,
DW_ExprValueType_Addr,
DW_ExprValueType_Implicit,
DW_ExprValueType_Bool,
} DW_ExprValueType;
typedef S8 DW_ExprBool;
typedef struct DW_ExprValue
{
DW_ExprValueType type;
Rng1U64Array ranges;
U64 *offsets;
union {
U8 u8;
U16 u16;
U32 u32;
U64 u64;
U128 u128;
U256 u256;
U512 u512;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
F32 f32;
F64 f64;
U64 addr;
DW_ExprBool boolean;
String8 implicit;
String8 generic;
};
} DW_ExprValue;
typedef struct DW_ExprValueNode
{
DW_ExprValue v;
struct DW_ExprValueNode *next;
} DW_ExprValueNode;
typedef enum
{
DW_PieceKind_Null,
DW_PieceKind_Value,
DW_PieceKind_Undefined,
} DW_PieceKind;
typedef struct DW_Piece
{
DW_PieceKind kind;
U64 bit_size;
U8 *value;
} DW_Piece;
typedef struct DW_PieceNode
{
DW_Piece v;
struct DW_PieceNode *next;
} DW_PieceNode;
typedef struct DW_PieceList
{
U64 count;
DW_PieceNode *first;
DW_PieceNode *last;
} DW_PieceList;
typedef struct DW_ExprStack
{
U64 count;
DW_ExprValueNode *top;
} DW_ExprStack;
typedef enum
{
DW_ExprEvalResult_Fail,
DW_ExprEvalResult_Ok,
DW_ExprEvalResult_Maybe,
DW_ExprEvalResult_ExecOpLimitReached,
} DW_ExprEvalResult;
////////////////////////////////
// encoder
typedef enum
{
DW_ExprEncType_Null,
DW_ExprEncType_Op,
DW_ExprEncType_U8,
DW_ExprEncType_U16,
DW_ExprEncType_U32,
DW_ExprEncType_U64,
DW_ExprEncType_S8,
DW_ExprEncType_S16,
DW_ExprEncType_S32,
DW_ExprEncType_S64,
DW_ExprEncType_ULEB128,
DW_ExprEncType_SLEB128,
DW_ExprEncType_Addr,
DW_ExprEncType_Block,
DW_ExprEncType_DwarfUInt,
DW_ExprEncType_Label,
DW_ExprEncType_DeclLabel,
} DW_ExprEncType;
typedef struct DW_ExprEnc
{
DW_ExprEncType type;
union {
DW_ExprOp op;
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
U64 addr;
String8 block;
String8 label;
};
} DW_ExprEnc;
#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v }
#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v }
#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v }
#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v }
#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v }
#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v }
#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v }
#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v }
#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v }
#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v }
#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v }
#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v }
#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v }
#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v }
#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) }
#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) }
////////////////////////////////
// pieces
internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v);
// size -> type
internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size);
// type -> size
internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k);
// typer
internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type);
// arithmetic operators
internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs);
// comparison operators
internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs);
// bitwise operators
internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs);
// unary operators
internal DW_ExprValue dw_expr_abs(DW_ExprValue value);
internal DW_ExprValue dw_expr_neg(DW_ExprValue value);
internal DW_ExprValue dw_expr_not(DW_ExprValue value);
// stack
internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value);
internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size);
internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack);
internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack);
internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx);
// value helpers
internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v);
// evaluator
internal DW_ExprEvalResult dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls_base, U64 op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out);
#endif //DWARF_EXPR_H
File diff suppressed because it is too large Load Diff
+528
View File
@@ -0,0 +1,528 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_PARSE_H
#define DWARF_PARSE_H
typedef struct DW_Section
{
String8 name;
String8 data;
B32 is_dwo;
} DW_Section;
typedef struct DW_Raw
{
DW_Section sec[DW_Section_COUNT];
DW_Section sup[DW_Section_COUNT];
} DW_Raw;
typedef struct DW_ListUnit
{
DW_Version version;
U64 address_size;
U64 segment_selector_size;
U64 entry_size;
String8 entries;
} DW_ListUnit;
typedef struct DW_ListUnitInput
{
U64 addr_count;
U64 str_offset_count;
U64 rnglist_count;
U64 loclist_count;
Rng1U64Array addr_ranges;
Rng1U64Array str_offset_ranges;
Rng1U64Array rnglist_ranges;
Rng1U64Array loclist_ranges;
DW_ListUnit *addrs;
DW_ListUnit *str_offsets;
DW_ListUnit *rnglists;
DW_ListUnit *loclists;
} DW_ListUnitInput;
typedef struct DW_AbbrevTableEntry
{
U64 id;
U64 off;
} DW_AbbrevTableEntry;
typedef struct DW_AbbrevTable DW_AbbrevTable;
struct DW_AbbrevTable
{
U64 count;
DW_AbbrevTableEntry *entries;
};
typedef enum DW_AbbrevKind
{
DW_Abbrev_Null,
DW_Abbrev_Tag,
DW_Abbrev_Attrib,
DW_Abbrev_AttribSequenceEnd,
DW_Abbrev_DIEBegin,
DW_Abbrev_DIEEnd,
} DW_AbbrevKind;
typedef U32 DW_AbbrevFlags;
enum
{
DW_AbbrevFlag_HasImplicitConst = (1 << 0),
DW_AbbrevFlag_HasChildren = (1 << 1),
};
typedef struct DW_Abbrev
{
DW_AbbrevKind kind;
U64 sub_kind;
U64 id;
S64 implicit_const;
DW_AbbrevFlags flags;
} DW_Abbrev;
typedef struct DW_Attrib
{
U64 info_off;
U64 abbrev_off;
U64 abbrev_id;
DW_AttribKind attrib_kind;
DW_Form form;
} DW_Attrib;
typedef struct DW_AttribNode
{
struct DW_AttribNode *next;
DW_Attrib v;
} DW_AttribNode;
typedef struct DW_AttribList
{
DW_AttribNode *first;
DW_AttribNode *last;
U64 count;
} DW_AttribList;
typedef U8 DW_TagSpare;
typedef struct DW_Tag
{
B32 has_children;
U64 abbrev_id;
DW_TagKind kind;
DW_AttribList attribs;
U64 info_off;
DW_TagSpare v;
} DW_Tag;
typedef struct DW_TagNode
{
DW_Tag tag;
struct DW_TagNode *sibling;
struct DW_TagNode *first_child;
struct DW_TagNode *last_child;
} DW_TagNode;
typedef struct DW_Loc
{
Rng1U64 range;
String8 expr;
} DW_Loc;
typedef struct DW_LocNode
{
DW_Loc v;
struct DW_LocNode *next;
} DW_LocNode;
typedef struct DW_LocList
{
U64 count;
DW_LocNode *first;
DW_LocNode *last;
} DW_LocList;
typedef struct DW_CompUnit
{
B32 relaxed;
DW_Ext ext;
DW_CompUnitKind kind;
DW_Version version;
DW_Format format;
U64 address_size;
U64 abbrev_off;
Rng1U64 info_range;
U64 first_tag_info_off;
DW_AbbrevTable abbrev_table;
DW_ListUnit *addr_lu;
DW_ListUnit *str_offsets_lu;
DW_ListUnit *rnglists_lu;
DW_ListUnit *loclists_lu;
U64 low_pc;
U64 dwo_id;
DW_Tag tag;
HashTable *tag_ht;
} DW_CompUnit;
typedef struct DW_TagTree
{
DW_TagNode *root;
U64 tag_count;
} DW_TagTree;
////////////////////////////////
typedef struct DW_LineFile
{
String8 path;
U64 dir_idx;
U64 time_stamp;
U64 size;
U128 md5;
String8 source;
} DW_LineFile;
typedef struct DW_LineFileNode
{
struct DW_LineFileNode *next;
DW_LineFile file;
} DW_LineFileNode;
typedef struct DW_LineFileList
{
U64 node_count;
DW_LineFileNode *first;
DW_LineFileNode *last;
} DW_LineFileList;
typedef struct DW_LineFileArray
{
U64 count;
DW_LineFile *v;
} DW_LineFileArray;
typedef struct DW_LineVMHeader
{
U64 unit_length;
DW_Version version;
U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str.
U8 segment_selector_size;
U64 header_length;
U8 min_inst_len;
U8 max_ops_for_inst;
U8 default_is_stmt;
S8 line_base;
U8 line_range;
U8 opcode_base;
U64 num_opcode_lens;
U8 *opcode_lens;
U64 line_program_off;
String8Array dir_table;
DW_LineFileArray file_table;
} DW_LineVMHeader;
typedef struct DW_LineVMState
{
U64 address; // Address of a machine instruction.
U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction.
// Line table doesn't contain full path to a file, instead
// DWARF encodes path as two indices. First index will point into a directory
// table, and second points into a file name table.
U64 file_index;
U64 line;
U64 column;
B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint.
B32 basic_block; // Indicates that the "address" is inside a basic block.
// Indicates that "address" points to place where function starts.
// Usually prologue is the place where compiler emits instructions to
// prepare stack for a function.
B32 prologue_end;
B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack.
U64 isa; // Instruction set that is used.
U64 discriminator; // Arbitrary id that indicates to which block these instructions belong.
B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows.
} DW_LineVMState;
typedef struct DW_LineVM
{
Arena *arena;
U64 cursor;
String8 program;
DW_LineVMHeader header;
B32 new_line;
B32 new_seq;
B32 skip_opcode;
DW_LineVMState state;
U64 advance;
U64 opcode_off;
DW_StdOpcode opcode;
DW_ExtOpcode ext_opcode;
U64 ext_length;
U64 line_advance;
U64 addr_advance;
HashTable *ext_file_ht;
struct {
union {
String8 string;
U64 u64;
S64 s64;
};
} operands[4];
String8 error;
} DW_LineVM;
////////////////////////////////
// .debug_pubnames and .debug_pubtypes
typedef struct DW_PubStringsBucket
{
struct DW_PubStringsBucket *next;
String8 string;
U64 info_off;
U64 cu_info_off;
} DW_PubStringsBucket;
typedef struct DW_PubStringsTable
{
U64 size;
DW_PubStringsBucket **buckets;
} DW_PubStringsTable;
typedef struct DW_Reference
{
DW_CompUnit *cu;
U64 info_off; // global .debug_info offset
} DW_Reference;
////////////////////////////////
//~ Expression
typedef union DW_ExprOperand
{
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
String8 block;
} DW_ExprOperand;
typedef struct DW_ExprInst
{
DW_ExprOp opcode;
DW_ExprOperand *operands;
U64 size;
struct DW_ExprInst *next;
struct DW_ExprInst *prev;
} DW_ExprInst;
typedef struct DW_Expr
{
U64 count;
DW_ExprInst *first;
DW_ExprInst *last;
} DW_Expr;
////////////////////////////////
// .debug_frame
typedef struct DW_CIE
{
String8 insts;
String8 aug_string;
String8 aug_data;
U64 code_align_factor;
S64 data_align_factor;
U64 ret_addr_reg;
U64 ext[4];
DW_Format format;
U8 version;
U8 address_size;
U8 segment_selector_size;
} DW_CIE;
typedef struct DW_FDE
{
DW_Format format;
U64 cie_pointer;
Rng1U64 pc_range;
String8 insts;
} DW_FDE;
typedef union DW_CFA_Operand
{
U64 u64;
S64 s64;
String8 block;
} DW_CFA_Operand;
typedef enum
{
DW_CFA_ParseErrorCode_NewInst,
DW_CFA_ParseErrorCode_End,
DW_CFA_ParseErrorCode_OutOfData
} DW_CFA_ParseErrorCode;
typedef struct DW_CFA_Inst
{
DW_CFA_Opcode opcode;
DW_CFA_Operand operands[DW_CFA_OperandMax];
} DW_CFA_Inst;
typedef struct DW_CFA_InstNode
{
DW_CFA_Inst v;
struct DW_CFA_InstNode *next;
} DW_CFA_InstNode;
typedef struct DW_CFA_InstList
{
U64 count;
DW_CFA_InstNode *first;
DW_CFA_InstNode *last;
} DW_CFA_InstList;
#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out)
typedef DW_DECODE_PTR(DW_DecodePtr);
// hasher
internal U64 dw_hash_from_string(String8 string);
// deserial helpers
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out);
internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out);
internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data);
internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data);
// list units
internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out);
internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input);
internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index);
internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index);
// abbrev table
internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base);
internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id);
// form and tag
internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out);
internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out);
internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out);
// attrib interp
internal U64 dw_interp_sec_offset(DW_Form form);
internal String8 dw_interp_exprloc (DW_Form form);
internal U128 dw_interp_const_u128(DW_Form form);
internal U64 dw_interp_const_u64 (DW_Form form);
internal U32 dw_interp_const_u32 (DW_Form form);
internal S64 dw_interp_const_s64 (DW_Form form);
internal S32 dw_interp_const_s32 (DW_Form form);
internal B32 dw_interp_flag (DW_Form form);
internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form);
internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form);
internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form);
internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form);
internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind);
internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
// compile unit
internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed);
internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu);
internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree);
internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off);
// line VM
internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out);
internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu);
internal void dw_line_vm_release(DW_LineVM *vm);
internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance);
internal B32 dw_line_vm_step(DW_LineVM *vm);
internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx);
internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file);
// helper for .debug_pubtypes and .debug_pubnames
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind);
// expression
internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data);
// debug frame
internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n);
internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v);
internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out);
internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out);
internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out);
internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out);
internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out);
internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
#endif // DWARF_PARSE_H
+373
View File
@@ -0,0 +1,373 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal DW_CFI_Row *
dw_make_cfi_row(Arena *arena, U64 reg_count)
{
DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1);
row->regs = push_array(arena, DW_CFI_Register, reg_count);
for EachIndex(reg_idx, reg_count) {
row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue;
}
return row;
}
internal void
dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count)
{
dst->cfa = src->cfa;
MemoryCopyTyped(dst->regs, src->regs, reg_count);
}
internal DW_CFI_Row *
dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count)
{
DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count);
dw_memcpy_cfi_row(new_row, row, reg_count);
return new_row;
}
internal DW_CFI_Unwind *
dw_cfi_unwind_init(Arena *arena,
Arch arch,
DW_CIE *cie,
DW_FDE *fde,
DW_DecodePtr *decode_ptr_func,
void *decode_ptr_ud)
{
Temp scratch = scratch_begin(&arena, 1);
DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1);
uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->cie = cie;
uw->fde = fde;
uw->pc = fde->pc_range.min;
uw->arch = arch;
uw->reg_count = dw_reg_count_from_arch(arch);
// setup initial register rules
DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->row = dw_make_cfi_row(arena, uw->reg_count);
uw->curr_inst = initial_insts.first;
if (!dw_cfi_next_row(arena, uw)) {
AssertAlways(0 && "unable to interpret initial row instructions");
}
// make first row from initial rules
uw->initial_row = uw->row;
uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count);
uw->curr_inst = uw->insts.first;
scratch_end(scratch);
return uw;
}
internal B32
dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw)
{
B32 is_row_valid = 0;
DW_CFA_InstNode *row_inst = uw->curr_inst;
// skip leading nops
while (uw->curr_inst) {
if (uw->curr_inst->v.opcode != DW_CFA_Nop) {
break;
}
uw->curr_inst = uw->curr_inst->next;
}
while (uw->curr_inst) {
DW_CFA_Inst *inst = &uw->curr_inst->v;
// validate register operands
DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode);
U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode);
for EachIndex(operand_idx, operand_count) {
if (operand_types[operand_idx] == DW_CFA_OperandType_Register) {
if (inst->operands[operand_idx].u64 >= uw->reg_count) {
goto exit;
}
}
}
switch (inst->opcode) {
// Row Creation Instructions
case DW_CFA_SetLoc: {
uw->pc = inst->operands[0].u64;
} break;
case DW_CFA_AdvanceLoc:
case DW_CFA_AdvanceLoc1:
case DW_CFA_AdvanceLoc2:
case DW_CFA_AdvanceLoc4: {
uw->pc += inst->operands[0].u64;
} break;
// CFA Definition Instructions
case DW_CFA_DefCfa:
case DW_CFA_DefCfaSf: {
U64 reg = inst->operands[0].u64;
S64 off = inst->operands[1].s64;
uw->row->cfa.rule = DW_CFA_Rule_RegOff;
uw->row->cfa.reg = reg;
uw->row->cfa.off = off;
} break;
case DW_CFA_DefCfaRegister: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
U64 reg = inst->operands[0].u64;
uw->row->cfa.reg = reg;
} break;
case DW_CFA_DefCfaOffset:
case DW_CFA_DefCfaOffsetSf: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
uw->row->cfa.off = inst->operands[0].s64;
} break;
case DW_CFA_DefCfaExpr: {
uw->row->cfa.rule = DW_CFA_Rule_Expression;
uw->row->cfa.expr = inst->operands[0].block;
} break;
// Register Rule Instructions
case DW_CFA_Undefined: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined;
} break;
case DW_CFA_SameValue: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue;
} break;
case DW_CFA_Offset:
case DW_CFA_OffsetExt:
case DW_CFA_OffsetExtSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_ValOffset:
case DW_CFA_ValOffsetSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Register: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Expr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_ValExpr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_Restore:
case DW_CFA_RestoreExt: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg] = uw->initial_row->regs[reg];
} break;
// Row State Instructions
case DW_CFA_RememberState: {
DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count);
SLLStackPush(uw->row, new_row);
} break;
case DW_CFA_RestoreState: {
if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops
DW_CFI_Row *free_row = uw->row;
SLLStackPop(uw->row);
SLLStackPush(uw->free_rows, free_row);
} break;
case DW_CFA_Nop: {} break;
default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode
}
uw->curr_inst = uw->curr_inst->next;
if (uw->curr_inst) {
if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; }
}
}
is_row_valid = row_inst != 0;
exit:;
return is_row_valid;
}
internal DW_CFI_Row *
dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc)
{
Temp scratch = scratch_begin(&arena, 1);
B32 is_row_found = 0;
U64 reg_count = dw_reg_count_from_arch(arch);
DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx);
DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count);
U64 prev_pc = uw->pc;
while (dw_cfi_next_row(scratch.arena, uw)) {
if (prev_pc <= pc && pc < uw->pc) {
is_row_found = 1;
break;
}
dw_memcpy_cfi_row(row, uw->row, uw->reg_count);
prev_pc = uw->pc;
}
// handle last row
if (!is_row_found) {
if (contains_1u64(fde->pc_range, pc)) {
row = uw->row;
is_row_found = 1;
}
}
// copy out final row
DW_CFI_Row *result = 0;
if (is_row_found) {
result = dw_copy_cfi_row(arena, row, reg_count);
}
scratch_end(scratch);
return result;
}
internal MachineOpResult
dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out)
{
MachineOpResult unwind_status = MachineOpResult_Fail;
ARCH_Info *arch_info = arch_info_from_arch(arch);
switch(row->cfa.rule)
{
case DW_CFA_Rule_Null:{}break;
case DW_CFA_Rule_RegOff:
{
// TODO: report error (invalid register read)
U64 cfa_reg_value = 0;
U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg);
AssertAlways(reg_size <= sizeof(cfa_reg_value));
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value))
{
break;
}
*cfa_out = cfa_reg_value + row->cfa.off;
unwind_status = MachineOpResult_Ok;
}break;
case DW_CFA_Rule_Expression:
{
Temp scratch = scratch_begin(0,0);
DW_ExprValue value = {0};
DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr);
DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value);
if (eval_result == DW_ExprEvalResult_Ok) {
if (DW_ExprValueType_IsInt(value.type)) {
*cfa_out = value.u64;
unwind_status = MachineOpResult_Ok;
}
} else if (eval_result == DW_ExprEvalResult_Maybe) {
unwind_status = MachineOpResult_Maybe;
}
scratch_end(scratch);
}break;
}
return unwind_status;
}
internal MachineOpResult
dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud)
{
Temp scratch = scratch_begin(0,0);
MachineOpResult unwind_status = MachineOpResult_Ok;
ARCH_Info *arch_info = arch_info_from_arch(arch);
U64 max_reg_size = dw_reg_max_size_from_arch(arch);
void *reg_buffer = push_array(scratch.arena, U8, max_reg_size);
U64 reg_count = dw_reg_count_from_arch(arch);
for EachIndex(reg_idx, reg_count)
{
DW_CFI_Register *reg = &row->regs[reg_idx];
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
switch(reg->rule)
{
default:{}break;
case DW_CFI_RegisterRule_Undefined: {} break;
case DW_CFI_RegisterRule_SameValue: {} break;
case DW_CFI_RegisterRule_Offset:
{
// read register value from memory
U64 addr = cfa + reg->n;
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud);
if (unwind_status != MachineOpResult_Ok) { goto exit; }
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_ValOffset:
{
// compute register value
U64 reg_value = cfa + reg->n;
// write register value to the thread context
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, &reg_value))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_Register:
{
// read register value from another register
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
if (unwind_status != MachineOpResult_Ok) { goto exit; }
}break;
case DW_CFI_RegisterRule_Expression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_ValExpression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_Architectural:
{
NotImplemented;
}break;
}
}
// update stack pointer
arch_reg_block_write_sp(arch_info, reg_block, cfa);
exit:;
scratch_end(scratch);
return unwind_status;
}
+81
View File
@@ -0,0 +1,81 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_UNWIND_H
#define DWARF_UNWIND_H
typedef enum DW_CFI_RegisterRule
{
DW_CFI_RegisterRule_Undefined,
DW_CFI_RegisterRule_SameValue,
DW_CFI_RegisterRule_Offset,
DW_CFI_RegisterRule_ValOffset,
DW_CFI_RegisterRule_Register,
DW_CFI_RegisterRule_Expression,
DW_CFI_RegisterRule_ValExpression,
DW_CFI_RegisterRule_Architectural
} DW_CFI_RegisterRule;
typedef enum DW_CFA_Rule
{
DW_CFA_Rule_Null,
DW_CFA_Rule_RegOff,
DW_CFA_Rule_Expression
} DW_CFA_Rule;
typedef struct DW_CFA
{
DW_CFA_Rule rule;
union {
struct {
DW_Reg reg;
S64 off;
};
String8 expr;
};
} DW_CFA;
typedef struct DW_CFI_Register
{
DW_CFI_RegisterRule rule;
union {
S64 n;
String8 expr;
};
} DW_CFI_Register;
typedef struct DW_CFI_Row
{
DW_CFA cfa;
DW_CFI_Register *regs;
struct DW_CFI_Row *next;
} DW_CFI_Row;
typedef struct DW_CFI_Unwind
{
DW_CFA_InstList insts;
DW_CIE *cie;
DW_FDE *fde;
DW_CFI_Row *initial_row;
DW_CFI_Row *row;
DW_CFA_InstNode *curr_inst;
DW_CFI_Row *free_rows;
U64 pc;
Arch arch;
U64 reg_count;
} DW_CFI_Unwind;
////////////////////////////////
internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count);
internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count);
internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw);
internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc);
internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out);
internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud);
#endif // DWARF_UNWIND_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,275 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RDI_FROM_DWARF_H
#define RDI_FROM_DWARF_H
////////////////////////////////
//~ Conversion
typedef struct D2R_ConvertParams
{
String8 dbg_name;
String8 dbg_data;
String8 exe_name;
String8 exe_data;
ExecutableImageKind exe_kind;
RDIM_SubsetFlags subset_flags;
B32 deterministic;
B32 is_parse_relaxed;
} D2R_ConvertParams;
#define D2R_UNIT_CHUNK_CAP 512
#define D2R_UDT_CHUNK_CAP 1024
#define D2R_TYPE_CHUNK_CAP 1024
#define D2R_SRC_FILE_CAP 1024
#define D2R_LINE_TABLE_CAP 1024
#define D2R_GVAR_CHUNK_CAP 1024
#define D2R_TVAR_CHUNK_CAP 1024
#define D2R_LOCATIONS_CAP 4096
#define D2R_PROC_CHUNK_CAP 4096
#define D2R_SCOPE_CHUNK_CAP 4096
#define D2R_INLINE_SITE_CHUNK_CAP 4096
typedef struct D2R_Shared
{
RDIM_TopLevelInfo top_level_info;
RDIM_BinarySectionList binary_sections;
RDIM_UnitChunkList units;
RDIM_UDTChunkList udts;
RDIM_TypeChunkList types;
RDIM_SrcFileChunkList src_files;
RDIM_LineTableChunkList line_tables;
} D2R_Shared;
////////////////////////////////
//~ Value Types
typedef enum
{
D2R_ArithmeticType_Null,
D2R_ArithmeticType_Signed,
D2R_ArithmeticType_Unsigned,
D2R_ArithmeticType_Float,
} D2R_ArithmeticType;
#define D2R_ValueType_Signed_XList \
X(S8, Signed, 1 ) \
X(S16, Signed, 2 ) \
X(S32, Signed, 4 ) \
X(S64, Signed, 8 ) \
X(S128, Signed, 16) \
X(S256, Signed, 32) \
X(S512, Signed, 64)
#define D2R_ValueType_Unsigned_XList \
X(U8, Unsigned, 1 ) \
X(U16, Unsigned, 2 ) \
X(U32, Unsigned, 4 ) \
X(U64, Unsigned, 8 ) \
X(U128, Unsigned, 16) \
X(U256, Unsigned, 32) \
X(U512, Unsigned, 64)
#define D2R_ValueType_Float_XList \
X(F16, Float, 2 ) \
X(F32, Float, 4 ) \
X(F48, Float, 6 ) \
X(F64, Float, 8 ) \
X(F80, Float, 10) \
X(F96, Float, 12) \
X(F128, Float, 16)
#define D2R_ValueType_XList \
X(Generic, Null, 0 ) \
X(ImplicitValue, Null, 0 ) \
X(Address, Unsigned, 0 ) \
D2R_ValueType_Signed_XList \
D2R_ValueType_Unsigned_XList \
D2R_ValueType_Float_XList
typedef enum
{
#define X(t, ...) D2R_ValueType_##t,
D2R_ValueType_XList
#undef X
D2R_ValueType_Bool = D2R_ValueType_S8,
} D2R_ValueType;
typedef struct D2R_ValueTypeNode
{
D2R_ValueType type;
struct D2R_ValueTypeNode *next;
} D2R_ValueTypeNode;
typedef struct D2R_ValueTypeStack
{
U64 count;
D2R_ValueTypeNode *top;
D2R_ValueTypeNode *free_list;
} D2R_ValueTypeStack;
////////////////////////////////
//~ Type Table
typedef struct D2R_TypeTable
{
HashTable *ht;
RDIM_TypeChunkList *types;
U64 type_chunk_cap;
RDIM_Type **builtin_types;
} D2R_TypeTable;
////////////////////////////////
//~ Tag Iterator
typedef DW_TagSpare D2R_TagFlags;
enum
{
D2R_TagFlags_TypeConverted = (1 << 0),
D2R_TagFlags_UdtConverted = (1 << 1),
};
typedef struct D2R_TagFrame
{
DW_TagNode *node;
RDIM_Scope *scope;
struct D2R_TagFrame *next;
} D2R_TagFrame;
typedef struct D2R_TagIterator
{
D2R_TagFrame *free_list;
D2R_TagFrame *stack;
DW_TagNode *null_tag_node;
DW_TagNode *tag_node;
B32 visit_children;
} D2R_TagIterator;
////////////////////////////////
//~ Line Table Conversion
typedef struct D2R_SrcFileLookup
{
DW_LineFile *file;
DW_LineVM *vm;
RDIM_SrcFile *src_file;
} D2R_SrcFileLookup;
////////////////////////////////
//~ Contrib Map
typedef struct D2R_CompUnitContribMap
{
U64 count;
U64 *info_off_arr;
RDIM_Rng1U64ChunkList *voff_range_arr;
} D2R_CompUnitContribMap;
////////////////////////////////
//~ RDIM Bytecode Extensions
internal B32 rdim_is_eval_bytecode_static (RDIM_EvalBytecode bc);
internal B32 rdim_static_eval_bytecode_to_voff(RDIM_EvalBytecode bc, U64 image_base, U64 *voff_out);
////////////////////////////////
//~ DWARF -> RDI Enums
internal RDI_Language d2r_rdi_language_from_dw_language(DW_Language v);
internal RDI_RegCodeX64 d2r_rdi_reg_code_from_dw_reg_x64 (DW_RegX64 v);
internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg (Arch arch, DW_Reg v);
////////////////////////////////
//~ Value Type
internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type);
internal D2R_ValueType d2r_value_type_stack_pop (D2R_ValueTypeStack *stack);
internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack);
internal D2R_ValueType d2r_signed_value_type_from_bit_size (U64 bit_size);
internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size);
internal D2R_ValueType d2r_float_type_from_bit_size (U64 bit_size);
internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type);
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
internal B32 d2r_is_value_type_signed (D2R_ValueType v);
internal B32 d2r_is_value_type_integral(D2R_ValueType v);
internal B32 d2r_is_value_type_unsigned(D2R_ValueType v);
internal B32 d2r_is_value_type_float (D2R_ValueType v);
internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs);
internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v);
internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc);
internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
////////////////////////////////
//~ Expression Conversion
internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out);
internal RDIM_Location d2r_transpile_expression (Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr);
internal RDIM_Location d2r_location_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
internal RDIM_LocationCaseList d2r_locset_from_attrib (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
internal RDIM_LocationCaseList d2r_var_locset_from_tag (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag);
////////////////////////////////
//~ Type Table
internal RDIM_Type * d2r_create_type (Arena *arena, D2R_TypeTable *type_table);
internal RDIM_Type * d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off);
internal RDIM_Type * d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off);
internal RDIM_Type * d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
////////////////////////////////
//~ Tag Iterator
internal D2R_TagIterator * d2r_tag_iterator_init(Arena *arena, DW_TagNode *root);
internal void d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter);
internal void d2r_tag_iterator_skip_children (D2R_TagIterator *iter);
internal DW_TagNode * d2r_tag_iterator_parent_tag_node(D2R_TagIterator *iter);
internal DW_Tag d2r_tag_iterator_parent_tag (D2R_TagIterator *iter);
////////////////////////////////
//~ Type Conversion
internal void d2r_flag_converted_tag(DW_TagNode *tag_node);
internal B8 d2r_is_tag_converted (DW_TagNode *tag_node);
internal RDIM_Type * d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_Tag tag, DW_AttribKind kind);
internal void d2r_convert_types(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_TagNode *root);
////////////////////////////////
//~ UDT Conversion
internal B8 d2r_is_udt_tag_converted (DW_TagNode *tag_node);
internal void d2r_flag_converted_udt_tag(DW_TagNode *tag_node);
internal void d2r_inline_anonymous_udt_member(Arena *arena, RDIM_UDT *top_udt, U64 base_off, RDIM_UDT *udt);
internal void d2r_convert_udts(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, DW_TagNode *root);
////////////////////////////////
//~ Symbol Conversion
internal RDIM_Scope * d2r_push_scope (Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges);
internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out);
internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag);
internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, U64 image_base, Arch arch, DW_TagNode *root, RDIM_Unit *unit_rdi);
////////////////////////////////
//~ Line Table Conversion
internal U64 d2r_hash_line_file(String8 dir_path, DW_LineFile *file);
internal void d2r_sort_ptrs(void **ptrs, U64 count, int (* is_before)(void *a, void *b));
////////////////////////////////
//~ Contrib Map
internal D2R_CompUnitContribMap d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Raw *input, U64 image_base);
internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off);
////////////////////////////////
//~ Entry Point
internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params);
#endif // RDI_FROM_DWARF_H
+7 -3
View File
@@ -46,14 +46,17 @@ load_paths =
commands =
{
//- rjf: [raddbg]
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "raddbg_stable --ipc kill_all && build radbin no_meta debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [scratch]
.f2 = { .win = "build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f2 = { .win = "pushd build && for /l %i in (1, 1, 3) do (radbin --rdi raddbg.exe --out:raddbg_%i.rdi && radbin --dump raddbg_%i.rdi --out:raddbg_%i.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f2 = { .win = "pushd build && radbin --rdi raddbg.exe --thread_count=1 --out:1.rdi && radbin --rdi raddbg.exe --thread_count=8 --out:8.rdi && radbin --dump 1.rdi --out:1.dump && radbin --dump 8.rdi --out:8.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [textperf]
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
@@ -66,6 +69,7 @@ commands =
//- rjf: running target
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "build torture", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+59
View File
@@ -0,0 +1,59 @@
// raddbg 0.9.28 project file
name: "The RAD Debugger"
target:
{
executable: "build/raddbg.exe"
working_directory: "../raddebugger"
arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user"
debug_subprocesses: 0
}
target:
{
executable: "build/raddbg.exe"
working_directory: "../raddebugger"
arguments: "--user:test123"
debug_subprocesses: 0
}
target:
{
executable: "build/mule_main.exe"
working_directory: build
output_label: output_a
}
target:
{
executable: "build/torture.exe"
working_directory: build
arguments: "raddbg/*"
}
target:
{
executable: "build/metagen.exe"
working_directory: build
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--rdi raddbg"
}
target:
{
executable: "build/release_version/raddbg.exe"
working_directory: "build/release_version"
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--breakpad fat.so --capture"
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--rdi raddbg"
enabled: 1
}
watch_pin: expression: tag_hash_slots
+122 -17
View File
@@ -1,21 +1,126 @@
@echo off
setlocal
cd /D "%~dp0"
setlocal enabledelayedexpansion
echo --- getting test data folder path ---------------------------------------------
if not exist .\local\test_data_path.txt (
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
goto :EOF
)
set /p test_data_folder=<.\local\test_data_path.txt
echo test data path: %test_data_folder%
echo:
set TARGET_VALUES=radlink radbin mule_main mule_module torture
set CC_VALUES=msvc clang
set MODE_VALUES=debug release
set RAW_ARGS=%*
set TORTURE_ARGS=
set RUN_TORTURE=1
echo --- building all testing executables ------------------------------------------
call build rdi_from_pdb rdi_dump raddbg radlink tester
echo:
echo --- running tests -------------------------------------------------------------
pushd build
call tester.exe --test_data:%test_data_folder%
:: Make test data directories
if not exist local mkdir local
pushd local
if not exist test_data mkdir test_data
popd
:: Check if we need new test data version
pushd local
set need_test_data=0
curl -sfL -o test_data_version_latest.txt https://data.raddbg.com/public/raddbg_test_data_version.txt || exit /b 1
if exist "test_data_version_current.txt" (
fc /b "test_data_version_latest.txt" "test_data_version_current.txt" > nul
) else (
echo Test data not present.
set need_test_data=1
)
if errorlevel 1 (
echo Test data out-of-date.
set need_test_data=1
)
popd
:: Download test data if stale
if "%need_test_data%"=="1" (
echo Downloading test data...
pushd local
pushd test_data
curl -sfL -o test_data.zip https://data.raddbg.com/public/raddbg_test_data.zip || exit /b 1
tar -xf test_data.zip || exit /b 1
del test_data.zip
popd
copy /y test_data_version_latest.txt test_data_version_current.txt
popd
)
popd
:parse_args
if "%~1" == "" goto parse_done
if "%~1" == "--" goto parse_torture_args
if /i "%~1" == "msvc" set CC_VALUES=msvc && shift /1 && goto parse_args
if /i "%~1" == "clang" set CC_VALUES=clang && shift /1 && goto parse_args
if /i "%~1" == "debug" set MODE_VALUES=debug && shift /1 && goto parse_args
if /i "%~1" == "release" set MODE_VALUES=release && shift /1 && goto parse_args
if /i "%~1" == "no_torture" set RUN_TORTURE=0 && shift /1 && goto parse_args
echo usage: %~nx0 [msvc^|clang] [debug^|release] [no_torture] [-- torture-args]
exit /b 1
:parse_torture_args
shift /1
if "%~1" == "" set "TORTURE_ARGS=" && goto parse_done
set "TORTURE_ARGS=%RAW_ARGS%"
if "%TORTURE_ARGS:~0,3%" == "-- " set "TORTURE_ARGS=%TORTURE_ARGS:~3%" && goto parse_done
set "TORTURE_ARGS=%TORTURE_ARGS:* -- =%"
:parse_done
if not defined TORTURE_ARGS set "TORTURE_ARGS=*
for %%m in (%MODE_VALUES%) do for %%c in (%CC_VALUES%) do (
setlocal
:: nuke artifacts from last run
if exist build/torture_artifacts rmdir /s /q build\torture_artifacts
if exist build\metagen.exe del /q build\metagen.exe
for %%t in (%TARGET_VALUES%) do (
if exist build\%%t.exe del /q build\%%t.exe
if exist build\%%t.pdb del /q build\%%t.pdb
)
if "%%c" == "clang" (
:: Prefer standalone LLVM clang over Visual Studio clang so ASAN runtime files match the compiler.
set "clang_path="
for /f "tokens=*" %%i in ('where clang') do (
set "candidate_clang_path=%%~dpi"
if "!candidate_clang_path:Microsoft Visual Studio=!"=="!candidate_clang_path!" (
if not defined clang_path set "clang_path=!candidate_clang_path!"
)
)
if not defined clang_path (
echo ERROR: standalone LLVM clang not found in PATH
exit /b 1
)
set PATH=!clang_path!;!PATH!
for /f "tokens=3 delims=. " %%v in ('clang -v 2^>^&1 ^| findstr version') do set clang_version=%%v
if not defined clang_version (
echo ERROR: failed to detect clang version
exit /b 1
)
set PATH=!clang_path!..\lib\clang\!clang_version!\lib\windows;!PATH!
)
:: TODO: unblock asan
call build.bat meta %%c %%m raddbg raddbg_non_graphical || (endlocal exit /b 1)
:: clang does not compile with asan in release mode because it runs out of memory
if "%%c" equ "clang" (
if /i "%%m" equ "release" (
call build.bat no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
) else (
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
)
) else (
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
)
if "%RUN_TORTURE%" equ "1" (
pushd build
torture %TORTURE_ARGS%
popd
if errorlevel 1 (
endlocal
exit /b 1
)
)
endlocal
)
Executable
+77
View File
@@ -0,0 +1,77 @@
#!/bin/bash
set -eu
cd "$(dirname "$0")"
target_values=(raddbg raddbg_non_graphical radlink radbin torture)
cc_values=(clang gcc)
mode_values=(debug release)
run_torture=1
torture_args=()
while [[ $# -gt 0 ]]; do
case "$1" in
--)
shift
torture_args=("$@")
break
;;
clang)
cc_values=("$1")
shift
;;
gcc)
cc_values=("$1")
shift
;;
debug|release)
mode_values=("$1")
shift
;;
no_torture)
run_torture=0
shift
;;
*)
echo "usage: $0 [clang|gcc] [debug|release] [no_torture] [-- torture-args]"
exit 1
;;
esac
done
if [[ "${#torture_args[@]}" == "0" ]]; then
torture_args=("*")
fi
for m in "${mode_values[@]}"; do
for c in "${cc_values[@]}"; do
# nuke artifacts from last run
rm -rf build/torture_artifacts
rm -f build/metagen
for t in "${target_values[@]}"; do
rm -f "build/$t"
done
# build targets
./build.sh meta "$c" "$m" "${target_values[@]}"
# run torture from build folder
if [[ "$run_torture" == "1" ]]; then
torture_compiler_args=()
has_clang_arg=0
has_gcc_arg=0
for arg in "${torture_args[@]}"; do
case "$arg" in
-clang:*|--clang:*) has_clang_arg=1 ;;
-gcc:*|--gcc:*) has_gcc_arg=1 ;;
esac
done
if [[ "$c" == clang && "$has_clang_arg" == "0" ]]; then
torture_compiler_args=("-clang:$(command -v "${CC:-clang}")")
elif [[ "$c" == gcc && "$has_gcc_arg" == "0" ]]; then
torture_compiler_args=("-gcc:$(command -v "${CC:-gcc}")")
fi
(cd build && ./torture "${torture_compiler_args[@]}" "${torture_args[@]}")
fi
done
done
+174
View File
@@ -0,0 +1,174 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Abstracted Architecture Functions
internal ARCH_Info *
arch_info_from_arch(Arch arch)
{
ARCH_Info *result = &arch_info_nil;
switch(arch)
{
default:{}break;
#if defined(X64_H)
case Arch_x64:
{
local_persist U8 trap_inst_bytes[] = {0xcc};
local_persist read_only ARCH_Info info =
{
.reg_block_size = sizeof(X64_RegBlock),
.instruction_pointer_reg_code = X64_RegCode_rip,
.stack_pointer_reg_code = X64_RegCode_rsp,
.reg_code_count = X64_RegCode_COUNT,
.trap_instruction = {trap_inst_bytes, sizeof(trap_inst_bytes)},
.reg_code_rng_table = x64_reg_code_rng_table,
.reg_code_name_table = x64_reg_code_name_table,
.reg_code_base_table = x64_reg_code_base_table,
.reg_code_is_vector_table = x64_reg_code_is_vector_table,
};
result = &info;
}break;
#endif
}
return result;
}
internal ARCH_RegCode
arch_reg_code_from_name(ARCH_Info *arch_info, String8 name)
{
ARCH_RegCode result = 0;
for EachIndex(code, arch_info->reg_code_count)
{
if(str8_match(arch_info->reg_code_name_table[code], name, 0))
{
result = code;
break;
}
}
return result;
}
internal B32
arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst)
{
B32 result = 0;
{
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
Rng1U16 try_range = range;
Rng1U16 read_range = intersect_1u16(legal_range, try_range);
U64 read_size = dim_1u16(read_range);
if(read_size != 0)
{
MemoryCopy(dst, (U8 *)block + read_range.min, read_size);
result = 1;
}
}
return result;
}
internal B32
arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src)
{
B32 result = 0;
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
Rng1U16 try_range = range;
Rng1U16 write_range = intersect_1u16(legal_range, try_range);
U64 write_size = dim_1u16(write_range);
if(write_size != 0)
{
MemoryCopy((U8 *)block + write_range.min, src, write_size);
result = 1;
}
return result;
}
internal U64
arch_ip_from_reg_block(ARCH_Info *arch_info, void *block)
{
U64 result = 0;
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
}
return result;
}
internal U64
arch_sp_from_reg_block(ARCH_Info *arch_info, void *block)
{
U64 result = 0;
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
}
return result;
}
internal B32
arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip)
{
B32 result = 0;
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &ip);
}
return result;
}
internal B32
arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp)
{
B32 result = 0;
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &sp);
}
return result;
}
#if defined(RDI_H)
internal ARCH_RegCode
arch_reg_code_from_rdi(Arch arch, RDI_RegCode code)
{
ARCH_RegCode result = 0;
{
ARCH_Info *arch_info = arch_info_from_arch(arch);
U8 *rdi_from_reg_code_table = arch_rdi_from_reg_code_table_from_arch(arch);
for EachIndex(c, arch_info->reg_code_count)
{
if(rdi_from_reg_code_table[c] == code)
{
result = c;
break;
}
}
}
return result;
}
#endif
#if defined(DWARF_H)
internal ARCH_RegCode
arch_reg_code_from_dw(Arch arch, DW_RegCode code)
{
ARCH_RegCode result = 0;
{
ARCH_Info *arch_info = arch_info_from_arch(arch);
U8 *dw_from_reg_code_table = arch_dw_from_reg_code_table_from_arch(arch);
for EachIndex(c, arch_info->reg_code_count)
{
if(dw_from_reg_code_table[c] == code)
{
result = c;
break;
}
}
}
return result;
}
#endif
+54
View File
@@ -0,0 +1,54 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_H
#define ARCH_H
////////////////////////////////
//~ rjf: Abstraction Backend Info
typedef U8 ARCH_RegCode;
typedef struct ARCH_Info ARCH_Info;
struct ARCH_Info
{
U16 reg_block_size;
ARCH_RegCode instruction_pointer_reg_code;
ARCH_RegCode stack_pointer_reg_code;
U16 reg_code_count;
String8 trap_instruction;
Rng1U16 *reg_code_rng_table;
String8 *reg_code_name_table;
U8 *reg_code_base_table;
B8 *reg_code_is_vector_table;
};
////////////////////////////////
//~ rjf: Globals
global read_only Rng1U16 arch_reg_code_rng_nil = {0};
global read_only String8 arch_reg_code_name_nil = {0};
global read_only U8 arch_reg_code_u8_nil = 0;
global read_only B8 arch_reg_code_b8_nil = 0;
global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil};
////////////////////////////////
//~ rjf: Abstracted Architecture Functions
internal ARCH_Info *arch_info_from_arch(Arch arch);
internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name);
internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst);
internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src);
internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block);
internal U64 arch_sp_from_reg_block(ARCH_Info *arch_info, void *block);
internal B32 arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip);
internal B32 arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp);
#if defined(RDI_H)
internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code);
#endif
#if defined(DWARF_H)
internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_RegCode code);
#endif
#endif // REGS_H
+11
View File
@@ -0,0 +1,11 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "arch/arch.c"
#include "arch/os/arch_os.c"
#if defined(DWARF_H)
# include "arch/dwarf/arch_dwarf.c"
#endif
#if defined(RDI_H)
# include "arch/rdi/arch_rdi.c"
#endif
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_INC_H
#define ARCH_INC_H
#include "arch/arch.h"
#include "arch/os/arch_os.h"
#if defined(DWARF_H)
# include "arch/dwarf/arch_dwarf.h"
#endif
#if defined(RDI_H)
# include "arch/rdi/arch_rdi.h"
#endif
#endif // ARCH_INC_H
+19
View File
@@ -0,0 +1,19 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal U8 *
arch_dw_from_reg_code_table_from_arch(Arch arch)
{
U8 *result = &arch_reg_code_u8_nil;
switch(arch)
{
default:{}break;
#if defined(X64_H)
case Arch_x64:
{
result = dw_reg_code_from_x64_table;
}break;
#endif
}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_DWARF_H
#define ARCH_DWARF_H
internal U8 *arch_dw_from_reg_code_table_from_arch(Arch arch);
#endif // ARCH_DWARF_H
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx)
{
B32 result = 0;
if(0){}
#define Case(arch_, os_, impl) else if((arch) == arch_ && (os) == os_) do {result = impl(reg_block, thread_ctx);}while(0)
#if defined(X64_H) && defined(WIN32_X64_H)
Case(Arch_x64, OperatingSystem_Windows, w32_x64_write_reg_block_from_thread_ctx);
#endif
#undef Case
else{}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_OS_H
#define ARCH_OS_H
internal B32 arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx);
#endif // ARCH_OS_H
+19
View File
@@ -0,0 +1,19 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal U8 *
arch_rdi_from_reg_code_table_from_arch(Arch arch)
{
U8 *result = &arch_reg_code_u8_nil;
switch(arch)
{
default:{}break;
#if defined(X64_H)
case Arch_x64:
{
result = rdi_reg_code_from_x64_table;
}break;
#endif
}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_RDI_H
#define ARCH_RDI_H
internal U8 *arch_rdi_from_reg_code_table_from_arch(Arch arch);
#endif // ARCH_RDI_H
+83 -12
View File
@@ -18,9 +18,8 @@ ac_init(void)
ac_shared->req_batches[idx].mutex = mutex_alloc();
ac_shared->req_batches[idx].arena = arena_alloc();
}
ac_shared->cancel_thread_semaphore = semaphore_alloc(0, 1, str8_zero());
ac_shared->cancel_thread = thread_launch(ac_cancel_thread_entry_point, 0);
ac_shared->cancel_thread_mutex = mutex_alloc();
mutex_take(ac_shared->cancel_thread_mutex);
}
////////////////////////////////
@@ -59,6 +58,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
cache->slots_count = Max(256, params->slots_count);
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
cache->stripes = stripe_array_alloc(cache_stripe->arena);
cache->stripe_free_node_ptrs = push_array(cache_stripe->arena, AC_NodePtr *, cache->stripes.count);
}
}
if(cache != 0)
@@ -74,6 +74,9 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
//- rjf: unpack thread context
B32 is_node_work_active = (ac_tctx != 0);
//- rjf: cache * key -> existing artifact
B32 artifact_is_stale = 1;
B32 got_artifact = 0;
@@ -93,11 +96,16 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
artifact_is_stale = is_stale;
artifact = n->val;
access_touch(access, &n->access_pt, stripe->cv);
ins_atomic_u64_eval_assign(&n->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
}
if(is_stale)
{
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
need_request = got_task;
if(is_node_work_active)
{
ins_atomic_u32_eval_assign(&n->other_nodes_depend_on_me, 1);
}
}
break;
}
@@ -109,7 +117,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
{
RWMutexScope(stripe->rw_mutex, 1) for(;;)
{
B32 out_of_time = (os_now_microseconds() >= endt_us);
B32 out_of_time = (now_time_us() >= endt_us);
// rjf: find node in cache
AC_Node *node = 0;
@@ -141,8 +149,12 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
node->key = str8_copy(stripe->arena, key);
node->working_count = 1;
node->evict_threshold_us = params->evict_threshold_us;
if(is_node_work_active)
{
node->other_nodes_depend_on_me = 1;
}
node->access_pt.last_time_touched_us = os_now_microseconds();
}
node->access_pt.last_time_touched_us = now_time_us();
node->access_pt.last_update_idx_touched = update_tick_idx();
// rjf: request
@@ -179,9 +191,10 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time))
{
got_artifact = 1;
artifact_is_stale = (node->last_completed_gen == params->gen);
artifact_is_stale = (node->last_completed_gen != params->gen);
artifact = node->val;
access_touch(access, &node->access_pt, stripe->cv);
ins_atomic_u64_eval_assign(&node->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
}
// rjf: abort if needed
@@ -218,7 +231,7 @@ ac_async_tick(void)
//
if(lane_idx() == 0)
{
mutex_drop(ac_shared->cancel_thread_mutex);
semaphore_drop(ac_shared->cancel_thread_semaphore);
}
//////////////////////////////
@@ -244,7 +257,9 @@ ac_async_tick(void)
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
{
next = n->next;
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) == 0)
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) &&
ins_atomic_u64_eval(&n->working_count) == 0 &&
(ins_atomic_u32_eval(&n->other_nodes_depend_on_me) == 0 || ac_shared->request_gen > n->last_touched_ac_request_gen))
{
slot_has_work = 1;
if(!write_mode)
@@ -328,6 +343,11 @@ ac_async_tick(void)
lane_sync_u64(&tasks_count, 0);
lane_sync();
//////////////////////////////
//- rjf: set up artifact cache thread context
//
ac_tctx = push_array(scratch.arena, AC_TCTX, 1);
//////////////////////////////
//- rjf: do all requests
//
@@ -376,7 +396,7 @@ ac_async_tick(void)
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
// rjf: retry? -> resubmit request
if(retry && lane_idx() == 0)
if(retry && lane_idx() == 0 && !ins_atomic_u32_eval(r->cancel_signal))
{
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
@@ -423,6 +443,19 @@ ac_async_tick(void)
{
if(str8_match(n->key, r->key, 0))
{
// rjf: eliminate existing values, if any, if they do not match the current
if(cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
{
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
{
cache->destroy(n->val);
MemoryZeroStruct(&n->val);
break;
}
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
}
// rjf: write new value
n->last_completed_gen = gen;
n->val = val;
ins_atomic_u64_dec_eval(&n->working_count);
@@ -485,7 +518,7 @@ ac_async_tick(void)
lane_ctx(lane_ctx_restore);
// rjf: retry? -> resubmit request
if(retry)
if(retry && !ins_atomic_u32_eval(r->cancel_signal))
{
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
@@ -532,6 +565,19 @@ ac_async_tick(void)
{
if(str8_match(n->key, r->key, 0))
{
// rjf: eliminate existing values, if any, if they do not match the current
if(cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
{
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
{
cache->destroy(n->val);
MemoryZeroStruct(&n->val);
break;
}
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
}
// rjf: store
n->last_completed_gen = gen;
n->val = val;
ins_atomic_u64_dec_eval(&n->working_count);
@@ -585,12 +631,36 @@ ac_async_tick(void)
}
lane_sync();
//////////////////////////////
//- rjf: increment the request gen, only if all requests are empty
//
if(lane_idx() == 0)
{
B32 have_live_requests = 0;
for EachElement(idx, ac_shared->req_batches)
{
MutexScope(ac_shared->req_batches[idx].mutex)
{
have_live_requests = (ac_shared->req_batches[idx].wide_count != 0 || ac_shared->req_batches[idx].thin_count != 0);
}
}
if(!have_live_requests)
{
ac_shared->request_gen += 1;
}
}
//////////////////////////////
//- rjf: reset thread context
//
ac_tctx = 0;
//////////////////////////////
//- rjf: disable cancellation scanning
//
if(lane_idx() == 0)
{
mutex_take(ac_shared->cancel_thread_mutex);
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
}
scratch_end(scratch);
}
@@ -603,8 +673,8 @@ ac_cancel_thread_entry_point(void *p)
{
for(;;)
{
os_sleep_milliseconds(50);
MutexScope(ac_shared->cancel_thread_mutex)
sleep_ms(50);
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
{
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
{
@@ -650,5 +720,6 @@ ac_cancel_thread_entry_point(void *p)
}
}
}
semaphore_drop(ac_shared->cancel_thread_semaphore);
}
}
+19 -2
View File
@@ -59,6 +59,13 @@ struct AC_RequestNode
AC_Request v;
};
typedef struct AC_NodePtr AC_NodePtr;
struct AC_NodePtr
{
AC_NodePtr *next;
struct AC_Node *node;
};
typedef struct AC_Node AC_Node;
struct AC_Node
{
@@ -76,8 +83,9 @@ struct AC_Node
U64 working_count;
U64 completion_count;
U64 evict_threshold_us;
U64 last_touched_ac_request_gen;
B32 cancelled;
U64 _unused_;
B32 other_nodes_depend_on_me;
};
typedef struct AC_Slot AC_Slot;
@@ -99,6 +107,7 @@ struct AC_Cache
U64 slots_count;
AC_Slot *slots;
StripeArray stripes;
AC_NodePtr **stripe_free_node_ptrs;
};
typedef struct AC_RequestBatch AC_RequestBatch;
@@ -114,10 +123,17 @@ struct AC_RequestBatch
U64 thin_count;
};
typedef struct AC_TCTX AC_TCTX;
struct AC_TCTX
{
U64 _unused_;
};
typedef struct AC_Shared AC_Shared;
struct AC_Shared
{
Arena *arena;
U64 request_gen;
// rjf: cache cache
U64 cache_slots_count;
@@ -129,13 +145,14 @@ struct AC_Shared
// rjf: cancel thread
Thread cancel_thread;
Mutex cancel_thread_mutex;
Semaphore cancel_thread_semaphore;
};
////////////////////////////////
//~ rjf: Globals
global AC_Shared *ac_shared = 0;
thread_static AC_TCTX *ac_tctx = 0;
////////////////////////////////
//~ rjf: Layer Initialization
+157 -36
View File
@@ -1,6 +1,25 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Global Arena Table
#if ARENA_TABLE_DEBUG
typedef struct ArenaTableNode ArenaTableNode;
struct ArenaTableNode
{
ArenaTableNode *next;
Arena *arena;
};
global U64 arena_table_take_init = 0;
global U64 arena_table_inited = 0;
global U64 arena_table_lock = 0;
global ArenaTableNode *arena_table = 0;
global U64 arena_table_count = 0;
global U64 arena_table_cap = 0;
global ArenaTableNode *free_arena_table_node = 0;
#endif
////////////////////////////////
//~ rjf: Arena Functions
@@ -9,48 +28,56 @@
internal Arena *
arena_alloc_(ArenaParams *params)
{
// rjf: round up reserve/commit sizes
U64 reserve_size = params->reserve_size;
U64 commit_size = params->commit_size;
if(params->flags & ArenaFlag_LargePages)
{
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
}
else
{
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
}
// rjf: reserve/commit initial block
void *base = params->optional_backing_buffer;
if(base == 0)
{
// rjf: round up reserve/commit sizes
if(params->flags & ArenaFlag_LargePages)
{
base = os_reserve_large(reserve_size);
os_commit_large(base, commit_size);
reserve_size = AlignPow2(reserve_size, get_system_info()->large_page_size);
commit_size = AlignPow2(commit_size, get_system_info()->large_page_size);
}
else
{
base = os_reserve(reserve_size);
os_commit(base, commit_size);
reserve_size = AlignPow2(reserve_size, get_system_info()->page_size);
commit_size = AlignPow2(commit_size, get_system_info()->page_size);
}
raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
if(params->flags & ArenaFlag_LargePages)
{
base = reserve_memory_large(reserve_size);
commit_memory_large(base, commit_size);
}
else
{
base = reserve_memory(reserve_size);
commit_memory(base, commit_size);
}
AsanPoisonMemoryRegion(base, commit_size);
// TODO(rjf): we need to reintroduce this later when we have the ability to remove annotations...
// raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
}
else
{
AsanPoisonMemoryRegion(base, params->reserve_size);
}
// rjf: panic on arena creation failure
#if OS_FEATURE_GRAPHICAL
if(Unlikely(base == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
abort_self(1);
}
#endif
// rjf: extract arena header & fill
Arena *arena = (Arena *)base;
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
Arena *arena = base;
arena->current = arena;
arena->flags = params->flags;
arena->cmt_size = params->commit_size;
@@ -61,21 +88,88 @@ arena_alloc_(ArenaParams *params)
arena->res = reserve_size;
arena->allocation_site_file = params->allocation_site_file;
arena->allocation_site_line = params->allocation_site_line;
arena->name = params->name;
#if ARENA_FREE_LIST
arena->free_last = 0;
#endif
AsanPoisonMemoryRegion(base, commit_size);
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
// rjf: store in global arena table
#if ARENA_TABLE_DEBUG
if(ins_atomic_u64_eval_cond_assign(&arena_table_take_init, 1, 0) == 0)
{
arena_table = reserve_memory(GB(256));
arena_table_cap = 4096;
commit_memory(arena_table, arena_table_cap * sizeof(arena_table[0]));
ins_atomic_u64_inc_eval(&arena_table_inited);
}
for(;!ins_atomic_u64_eval(&arena_table_inited);) {}
for(;;)
{
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
if(got_lock)
{
ArenaTableNode *node = free_arena_table_node;
if(node != 0)
{
SLLStackPop(free_arena_table_node);
}
else
{
node = &arena_table[arena_table_count];
if(arena_table_count >= arena_table_cap)
{
U64 arena_table_cap__pre_grow = arena_table_cap;
arena_table_cap *= 2;
U64 arena_table_cap__post_grow = arena_table_cap;
commit_memory(arena_table + arena_table_cap__pre_grow, sizeof(arena_table[0]) * (arena_table_cap__post_grow - arena_table_cap__pre_grow));
}
arena_table_count += 1;
}
node->arena = arena;
arena->table_node = node;
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
break;
}
}
#endif
return arena;
}
internal void
arena_release(Arena *arena)
{
#if PROFILE_TELEMETRY
{
Arena *base_arena = arena;
while (base_arena->prev) base_arena = base_arena->prev;
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, 0, "%s/%p", base_arena->name, base_arena);
}
#endif
#if ARENA_TABLE_DEBUG
for(Arena *n = arena->current; n != 0; n = n->prev)
{
for(;;)
{
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
if(got_lock)
{
ArenaTableNode *table_node = n->table_node;
MemoryZeroStruct(table_node);
SLLStackPush(free_arena_table_node, table_node);
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
break;
}
}
}
#endif
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
{
prev = n->prev;
os_release(n, n->res);
AsanUnpoisonMemoryRegion(n, n->cmt);
release_memory(n, n->res);
}
}
@@ -88,6 +182,16 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
U64 pos_pre = AlignPow2(current->pos, align);
U64 pos_pst = pos_pre + size;
// TODO: Newly allocated arenas already have zeroed commited pages,
// so this unnecessarily zeroes them again.
//
// rjf: compute the size we need to zero
U64 size_to_zero = 0;
if(zero)
{
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
}
// rjf: chain, if needed
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
{
@@ -128,6 +232,12 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
.flags = current->flags,
.allocation_site_file = current->allocation_site_file,
.allocation_site_line = current->allocation_site_line);
size_to_zero = 0;
}
else
{
size_to_zero = size;
}
new_block->base_pos = current->base_pos + current->res;
@@ -138,13 +248,6 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
pos_pst = pos_pre + size;
}
// rjf: compute the size we need to zero
U64 size_to_zero = 0;
if(zero)
{
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
}
// rjf: commit new pages, if needed
if(current->cmt < pos_pst)
{
@@ -155,12 +258,13 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
U8 *cmt_ptr = (U8 *)current + current->cmt;
if(current->flags & ArenaFlag_LargePages)
{
os_commit_large(cmt_ptr, cmt_size);
commit_memory_large(cmt_ptr, cmt_size);
}
else
{
os_commit(cmt_ptr, cmt_size);
commit_memory(cmt_ptr, cmt_size);
}
AsanPoisonMemoryRegion(cmt_ptr, cmt_size);
current->cmt = cmt_pst_clamped;
}
@@ -171,18 +275,24 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
result = (U8 *)current+pos_pre;
current->pos = pos_pst;
AsanUnpoisonMemoryRegion(result, size);
if(size_to_zero != 0)
{
MemoryZero(result, size_to_zero);
}
#if PROFILE_TELEMETRY
if(size > KB(1))
{
Arena *base_arena = arena;
while (base_arena->prev) base_arena = base_arena->prev;
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
}
#endif
// rjf: panic on failure
#if OS_FEATURE_GRAPHICAL
if(Unlikely(result == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
abort_self(1);
}
#endif
@@ -215,7 +325,8 @@ arena_pop_to(Arena *arena, U64 pos)
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{
prev = current->prev;
os_release(current, current->res);
AsanUnpoisonMemoryRegion(current, current->cmt);
release_memory(current, current->res);
}
#endif
arena->current = current;
@@ -223,6 +334,16 @@ arena_pop_to(Arena *arena, U64 pos)
AssertAlways(new_pos <= current->pos);
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
current->pos = new_pos;
#if PROFILE_TELEMETRY
if((pos - (new_pos + current->base_pos)) > KB(1))
{
Arena *base_arena = arena;
while (base_arena->prev) base_arena = base_arena->prev;
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
}
#endif
}
//- rjf: arena push/pop helpers
+5
View File
@@ -25,6 +25,7 @@ struct ArenaParams
void *optional_backing_buffer;
char *allocation_site_file;
int allocation_site_line;
char *name;
};
typedef struct Arena Arena;
@@ -41,9 +42,13 @@ struct Arena
U64 res;
char *allocation_site_file;
int allocation_site_line;
char *name;
#if ARENA_FREE_LIST
Arena *free_last;
#endif
#if ARENA_TABLE_DEBUG
struct ArenaTableNode *table_node;
#endif
};
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
+49 -1
View File
@@ -138,6 +138,10 @@
# define BUILD_DEBUG 1
#endif
#if !defined(BUILD_TESTS)
# define BUILD_TESTS 0
#endif
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
# define BUILD_SUPPLEMENTARY_UNIT 0
#endif
@@ -159,7 +163,7 @@
#endif
#if !defined(BUILD_VERSION_PATCH)
# define BUILD_VERSION_PATCH 24
# define BUILD_VERSION_PATCH 28
#endif
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
@@ -244,4 +248,48 @@
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
#endif
////////////////////////////////
// extra intrinisc includes, so older clang versions are happy
// when optiona intrinsics like avx2 & avx512 are used later
// these must come first before any other intrinsic includes
// otherwise compiler will define macros that prevent declarations
// of intrinsics when included next time
#if ARCH_X64 && COMPILER_CLANG
# if defined(__IMMINTRIN_H)
# error "include this header before immintrin.h / x86intrin.h / intrin.h"
# endif
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wreserved-macro-identifier"
# pragma push_macro("__SHA__")
# pragma push_macro("__AVX__")
# pragma push_macro("__AVX2__")
# pragma push_macro("__BMI2__")
# pragma push_macro("__SSE4_1__")
# pragma push_macro("__AVX512F__")
# pragma push_macro("__AVX512VL__")
# pragma push_macro("__AVX512BW__")
# pragma push_macro("__AVX512VBMI__")
# define __SHA__ 1
# define __AVX__ 1
# define __AVX2__ 1
# define __BMI2__ 1
# define __SSE4_1__ 1
# define __AVX512F__ 1
# define __AVX512VL__ 1
# define __AVX512BW__ 1
# define __AVX512VBMI__ 1
# include <immintrin.h>
# pragma pop_macro("__AVX512VBMI__")
# pragma pop_macro("__AVX512BW__")
# pragma pop_macro("__AVX512VL__")
# pragma pop_macro("__AVX512F__")
# pragma pop_macro("__SSE4_1__")
# pragma pop_macro("__BMI2__")
# pragma pop_macro("__AVX2__")
# pragma pop_macro("__AVX__")
# pragma pop_macro("__SHA__")
# pragma clang diagnostic pop
#endif
#endif // BASE_CONTEXT_CRACKING_H
+126 -13
View File
@@ -79,19 +79,21 @@ u64_up_to_pow2(U64 x){
}
internal S32
extend_sign32(U32 x, U32 size){
U32 high_bit = size * 8;
U32 shift = 32 - high_bit;
S32 result = ((S32)x << shift) >> shift;
return result;
extend_sign32(U32 x, U32 size)
{
U32 n = size * 8;
U32 m = (U32)1 << (n - 1);
S32 r = (S32)((x ^ m) - m);
return r;
}
internal S64
extend_sign64(U64 x, U64 size){
U64 high_bit = size * 8;
U64 shift = 64 - high_bit;
S64 result = ((S64)x << shift) >> shift;
return result;
extend_sign64(U64 x, U64 size)
{
U64 n = size * 8;
U64 m = (U64)1 << (n - 1);
S64 r = (S64)((x ^ m) - m);
return r;
}
internal F32
@@ -286,6 +288,56 @@ memory_is_zero(void *ptr, U64 size)
return result;
}
internal void UBSAN_NO_ALIGN
memory_write16(void *ptr, U16 v)
{
MemoryCopy(ptr, &v, sizeof(v));
}
internal void UBSAN_NO_ALIGN
memory_write32(void *ptr, U32 v)
{
MemoryCopy(ptr, &v, sizeof(v));
}
internal void UBSAN_NO_ALIGN
memory_write64(void *ptr, U64 v)
{
MemoryCopy(ptr, &v, sizeof(v));
}
internal U8 UBSAN_NO_ALIGN
memory_read8(void *ptr)
{
U8 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
internal U16 UBSAN_NO_ALIGN
memory_read16(void *ptr)
{
U16 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
internal U32 UBSAN_NO_ALIGN
memory_read32(void *ptr)
{
U32 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
internal U64 UBSAN_NO_ALIGN
memory_read64(void *ptr)
{
U64 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
@@ -413,6 +465,38 @@ byte_size_from_arch(Arch arch)
return bit_size_from_arch(arch) / 8;
}
internal U64
max_ops_per_instruction_from_arch(Arch arch)
{
U64 max_ops = 0;
switch (arch)
{
case Arch_Null: break;
case Arch_x64: max_ops = 1; break;
case Arch_x86:
case Arch_arm32:
case Arch_arm64: NotImplemented; break;
default: InvalidPath;
}
return max_ops;
}
internal U64
min_instruction_size_from_arch(Arch arch)
{
U64 min_instruction_size = 0;
switch(arch)
{
case Arch_Null: break;
case Arch_x64: min_instruction_size = 1; break;
case Arch_x86:
case Arch_arm32:
case Arch_arm64: NotImplemented; break;
default: InvalidPath;
}
return min_instruction_size;
}
internal U64
max_instruction_size_from_arch(Arch arch)
{
@@ -539,10 +623,10 @@ date_time_from_unix_time(U64 unix_time)
}
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
//~ rjf: Wrapped Ring Buffer Reads/Writes
internal U64
ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
{
Assert(src_data_size <= ring_size);
{
@@ -559,7 +643,7 @@ ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_d
}
internal U64
ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
{
Assert(read_size <= ring_size);
{
@@ -608,6 +692,26 @@ u64_array_bsearch(U64 *arr, U64 count, U64 value)
////////////////////////////////
internal U32
idx_of_zero_byte64(U8 *ptr, U64 size)
{
Assert(size == 8);
#if ARCH_X64
__m128i v = _mm_loadl_epi64((__m128i*)ptr);
__m128i m = _mm_cmpeq_epi8(v, _mm_setzero_si128());
U32 bits = _mm_movemask_epi8(m);
return ctz32(bits);
#else
U64 x;
MemoryCopyStruct(&x, ptr);
U64 splat = ~0ULL / 255;
U64 mask_lsb = 0x01 * splat;
U64 mask_msb = 0x80 * splat;
U64 t = (x - mask_lsb) & (~x & mask_msb);
return ctz64(t) / 8;
#endif
}
internal U64
index_of_zero_u32(U32 *ptr, U64 count)
{
@@ -630,6 +734,15 @@ index_of_zero_u64(U64 *ptr, U64 count)
return max_U64;
}
internal U64
count_digits_u64(U64 v, U64 radix)
{
if (v == 0) { return 1; }
U64 count = 0;
for (U64 x = v; x > 0; x /= radix) { count += 1; }
return count;
}
////////////////////////////////
//~ rjf: Third Party Includes
+172 -63
View File
@@ -7,11 +7,13 @@
////////////////////////////////
//~ rjf: Foreign Includes
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
////////////////////////////////
//~ rjf: Third Party Includes
@@ -180,8 +182,9 @@
//~ rjf: Member Offsets
#define Member(T,m) (((T*)0)->m)
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
#define OffsetOf(T,m) offsetof(T, m)
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
#define MemberFromPtr(T,ptr,m) (void*)((((U8 *)ptr)+OffsetOf(T,m)))
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
////////////////////////////////
@@ -196,6 +199,7 @@
#define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1))
#define EachInRange(it, range) (U64 it = (range).min; it < (range).max; it += 1)
#define EachNode(it, T, first) (T *it = first; it != 0; it = it->next)
#define EachBit(it, flags) (U64 (_i_) = (flags), it = (flags) & -(flags); (_i_) != 0; (_i_) &= ((_i_) - 1), it = (flags) & -(flags))
////////////////////////////////
//~ rjf: Memory Operation Macros
@@ -203,7 +207,6 @@
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
#define MemoryStrlen(ptr) strlen(ptr)
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
@@ -221,9 +224,6 @@
#define MemoryIsZeroStruct(ptr) memory_is_zero((ptr), sizeof(*(ptr)))
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
#define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
////////////////////////////////
//~ rjf: Asserts
@@ -252,38 +252,44 @@
#if COMPILER_MSVC
# include <intrin.h>
# if ARCH_X64
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)InterlockedCompareExchange128((__int64 *)(x), ((__int64 *)&(k))[1], ((__int64 *)&(k))[0], (__int64 *)c)
# define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((__int64 *)(x))
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((__int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((__int64 *)(x),(c))
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((__int64 *)(x), c)
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((__int64 *)(x),(k),(c))
# define ins_atomic_u32_eval(x) *((volatile U32 *)(x))
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((LONG *)(x))
# define ins_atomic_u32_dec_eval(x) InterlockedDecrement((LONG *)(x))
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((LONG *)(x),(c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((LONG *)(x),(k),(c))
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((LONG *)(x), (c))
# define ins_atomic_u8_eval_assign(x,c) InterlockedExchange8((CHAR *)(x), (c))
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)_InterlockedCompareExchange128((__int64 *)(x), ((__int64 *)&(k))[1], ((__int64 *)&(k))[0], (__int64 *)(c))
# define ins_atomic_u64_eval(x) (U64)__iso_volatile_load64((__int64*)(x))
# define ins_atomic_u64_inc_eval(x) _InterlockedIncrement64((__int64 *)(x))
# define ins_atomic_u64_dec_eval(x) _InterlockedDecrement64((__int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) _InterlockedExchange64((__int64 *)(x), (c))
# define ins_atomic_u64_add_eval(x,c) _interlockedadd64((__int64 *)(x), (c))
# define ins_atomic_u64_eval_cond_assign(x,k,c) _InterlockedCompareExchange64((__int64 *)(x), (k), (c))
# define ins_atomic_u32_eval(x) (U32)__iso_volatile_load32((__int32*)(x))
# define ins_atomic_u32_inc_eval(x) _InterlockedIncrement((long *)(x))
# define ins_atomic_u32_dec_eval(x) _InterlockedDecrement((long *)(x))
# define ins_atomic_u32_eval_assign(x,c) _InterlockedExchange((long *)(x), (c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) _InterlockedCompareExchange((long *)(x), (k), (c))
# define ins_atomic_u32_add_eval(x,c) _interlockedadd((long *)(x), (c))
# define ins_atomic_u8_eval_assign(x,c) _InterlockedExchange8((char *)(x), (char)(c))
# define ins_atomic_u8_or(x,c) _InterlockedOr8((char *)(x), (char)(c))
# define ins_atomic_u32_or(x,c) _InterlockedOr((long *)(x), (long)(c))
# else
# error Atomic intrinsics not defined for this compiler / architecture combination.
# endif
#elif COMPILER_CLANG || COMPILER_GCC
# include <immintrin.h>
# include <emmintrin.h>
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)__atomic_compare_exchange_n((__int128 *)(x),(__int128 *)(c),*(__int128 *)(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST)
# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
# define ins_atomic_u64_eval(x) __atomic_load_n((U64 *)(x), __ATOMIC_SEQ_CST)
# define ins_atomic_u64_inc_eval(x) __atomic_add_fetch((U64 *)(x), 1, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_dec_eval(x) __atomic_sub_fetch((U64 *)(x), 1, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((U64 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u64_add_eval(x,c) __atomic_add_fetch((U64 *)(x), c, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u32_dec_eval(x) (__atomic_fetch_sub((U32 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u32_inc_eval(x) __atomic_add_fetch((U32 *)(x), 1, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_dec_eval(x) __atomic_sub_fetch((U32 *)(x), 1, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_add_eval(x,c) __atomic_add_fetch((U32 *)(x), c, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST)
# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST)
# define ins_atomic_u8_or(x,c) __atomic_fetch_or((U8 *)(x), (U8)(c), __ATOMIC_SEQ_CST)
# define ins_atomic_u32_or(x,c) __atomic_fetch_or((U32 *)(x), (U32)(c), __ATOMIC_SEQ_CST)
#else
# error Atomic intrinsics not defined for this compiler / architecture.
#endif
@@ -363,9 +369,7 @@ CheckNil(nil,p) ? \
#if COMPILER_MSVC
# if defined(__SANITIZE_ADDRESS__)
# define ASAN_ENABLED 1
# define NO_ASAN __declspec(no_sanitize_address)
# else
# define NO_ASAN
# define ASAN_NO_ADDR __declspec(no_sanitize_address)
# endif
#elif COMPILER_CLANG
# if defined(__has_feature)
@@ -373,9 +377,15 @@ CheckNil(nil,p) ? \
# define ASAN_ENABLED 1
# endif
# endif
# define NO_ASAN __attribute__((no_sanitize("address")))
#else
# define NO_ASAN
# define ASAN_NO_ADDR __attribute__((no_sanitize("address")))
# define UBSAN_NO_ALIGN __attribute__((no_sanitize("alignment")))
#endif
#ifndef ASAN_NO_ADDR
# define ASAN_NO_ADDR
#endif
#ifndef UBSAN_NO_ALIGN
# define UBSAN_NO_ALIGN
#endif
#if ASAN_ENABLED
@@ -437,6 +447,9 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s
# define this_function_name __func__
#endif
#define TryRead(func__, cursor__, label__) do { U64 size__ = (func__); if (size__ == 0) { goto label__; } cursor__ += size__; } while (0)
#define TryReadBreak(func__, cursor__) { U64 size__ = (func__); if (size__ == 0) { break; } cursor__ += size__; }
////////////////////////////////
//~ rjf: Base Types
@@ -462,6 +475,8 @@ union U128
U16 u16[8];
U32 u32[4];
U64 u64[2];
F32 f32[4];
F64 f64[2];
};
typedef union U256 U256;
union U256
@@ -471,6 +486,8 @@ union U256
U32 u32[8];
U64 u64[4];
U128 u128[2];
F32 f32[8];
F64 f64[4];
};
typedef union U512 U512;
union U512
@@ -481,37 +498,48 @@ union U512
U64 u64[8];
U128 u128[4];
U256 u256[2];
F32 f32[16];
F64 f64[8];
};
#pragma pack(push, 1)
typedef struct U80 U80;
struct U80
{
U64 int1_frac63;
U16 sign1_exp15;
};
#pragma pack(pop)
////////////////////////////////
//~ rjf: Basic Type Structures
typedef struct U16Array U16Array;
struct U16Array
{
U64 count;
U16 *v;
U64 count;
};
typedef struct U32Array U32Array;
struct U32Array
{
U64 count;
U32 *v;
U64 count;
};
typedef struct U64Array U64Array;
struct U64Array
{
U64 count;
U64 *v;
U64 count;
};
typedef struct U128Array U128Array;
struct U128Array
{
U64 count;
U128 *v;
U64 count;
};
////////////////////////////////
@@ -611,19 +639,19 @@ typedef enum Arch
Arch_arm64,
Arch_arm32,
Arch_COUNT,
#if ARCH_X64
Arch_CURRENT = Arch_x64,
#elif ARCH_X86
Arch_CURRENT = Arch_x86,
#elif ARCH_ARM64
Arch_CURRENT = Arch_arm64,
#elif ARCH_ARM32
Arch_CURRENT = Arch_arm32,
#else
Arch_CURRENT = Arch_Null,
#endif
}
Arch;
#if ARCH_X64
# define Arch_CURRENT Arch_x64
#elif ARCH_X86
# define Arch_CURRENT Arch_x86
#elif ARCH_ARM64
# define Arch_CURRENT Arch_arm64
#elif ARCH_ARM32
# define Arch_CURRENT Arch_arm32
#else
# define Arch_CURRENT Arch_Null
#endif
typedef enum Compiler
{
@@ -632,17 +660,42 @@ typedef enum Compiler
Compiler_gcc,
Compiler_clang,
Compiler_COUNT,
#if COMPILER_MSVC
Compiler_CURRENT = Compiler_msvc,
#elif COMPILER_GCC
Compiler_CURRENT = Compiler_gcc,
#elif COMPILER_CLANG
Compiler_CURRENT = Compiler_clang,
#else
Compiler_CURRENT = Compiler_Null,
#endif
}
Compiler;
#if COMPILER_MSVC
# define Compiler_CURRENT Compiler_msvc
#elif COMPILER_GCC
# define Compiler_CURRENT Compiler_gcc
#elif COMPILER_CLANG
# define Compiler_CURRENT Compiler_clang
#else
# define Compiler_CURRENT Compiler_Null
#endif
typedef enum Linker
{
Linker_Null,
Linker_radlink,
Linker_msvc,
Linker_lld,
Linker_COUNT
}
Linker;
////////////////////////////////
//~ rjf: Access Flags
typedef U32 AccessFlags;
enum
{
AccessFlag_Read = (1<<0),
AccessFlag_Write = (1<<1),
AccessFlag_Execute = (1<<2),
AccessFlag_Append = (1<<3),
AccessFlag_ShareRead = (1<<4),
AccessFlag_ShareWrite = (1<<5),
AccessFlag_Inherited = (1<<6),
};
////////////////////////////////
//~ rjf: Text 2D Coordinates & Ranges
@@ -678,6 +731,29 @@ union Guid
};
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
////////////////////////////////
//~ Machine Ops
typedef enum MachineOpResult
{
MachineOpResult_Null,
MachineOpResult_Ok,
MachineOpResult_Fail,
MachineOpResult_Maybe,
} MachineOpResult;
#define MACHINE_OP_REG_READ(name) MachineOpResult name(U64 reg_id, void *buffer, U64 buffer_max, void *ud)
typedef MACHINE_OP_REG_READ(MachineOp_RegRead);
#define MACHINE_OP_REG_WRITE(name) MachineOpResult name(U64 reg_id, void *value, U64 value_size, void *ud)
typedef MACHINE_OP_REG_WRITE(MachineOp_RegWrite);
#define MACHINE_OP_MEM_READ(name) MachineOpResult name(U64 addr, void *buffer, U64 buffer_size, void *ud)
typedef MACHINE_OP_MEM_READ(MachineOp_MemRead);
#define MACHINE_OP_MEM_WRITE(name) MachineOpResult name(U64 addr, void *value, U64 value_size, void *ud)
typedef MACHINE_OP_MEM_WRITE(MachineOp_MemWrite);
////////////////////////////////
//~ rjf: Basic Constants
@@ -973,6 +1049,15 @@ internal F32 sign_from_side_F32(Side side);
internal B32 memory_is_zero(void *ptr, U64 size);
internal void memory_write16(void *ptr, U16 v);
internal void memory_write32(void *ptr, U32 v);
internal void memory_write64(void *ptr, U64 v);
internal U8 memory_read8(void *ptr);
internal U16 memory_read16(void *ptr);
internal U32 memory_read32(void *ptr);
internal U64 memory_read64(void *ptr);
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
@@ -991,6 +1076,8 @@ internal B32 txt_rng_contains(TxtRng r, TxtPt pt);
internal U64 bit_size_from_arch(Arch arch);
internal U64 byte_size_from_arch(Arch arch);
internal U64 max_ops_per_instruction_from_arch(Arch arch);
internal U64 min_instruction_size_from_arch(Arch arch);
internal U64 max_instruction_size_from_arch(Arch arch);
////////////////////////////////
@@ -1002,12 +1089,32 @@ internal DateTime date_time_from_micro_seconds(U64 time);
internal DateTime date_time_from_unix_time(U64 unix_time);
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
//~ rjf: @per_os_impl Debugger Attachment Checking
internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
internal B32 debugger_is_attached(void);
////////////////////////////////
//~ rjf: @per_os_impl Platform Time Functions
internal U64 now_time_us(void);
internal U32 now_time_unix(void);
internal DateTime now_time_universal(void);
internal DateTime universal_from_local_time(DateTime *dt);
internal DateTime local_from_universal_time(DateTime *dt);
internal void sleep_ms(U32 ms);
////////////////////////////////
//~ rjf: @per_os_impl Platform GUID Functions
internal Guid make_guid(void);
////////////////////////////////
//~ rjf: Wrapped Ring Buffer Reads/Writes
internal U64 wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
internal U64 wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
#define wrapped_write_struct(ring_base, ring_size, ring_pos, ptr) wrapped_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
#define wrapped_read_struct(ring_base, ring_size, ring_pos, ptr) wrapped_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
////////////////////////////////
//~ rjf: Sorts
@@ -1020,7 +1127,9 @@ internal U64 u64_array_bsearch(U64 *arr, U64 count, U64 value);
////////////////////////////////
internal U32 idx_of_zero_byte64(U8 *ptr, U64 size); // size must be exactly 8 bytes
internal U64 index_of_zero_u32(U32 *ptr, U64 count);
internal U64 index_of_zero_u64(U64 *ptr, U64 count);
internal U64 count_digits_u64(U64 v, U64 radix);
#endif // BASE_CORE_H
@@ -1,2 +1,2 @@
// Copyright (c) 2024 Epic Games Tools
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+20
View File
@@ -0,0 +1,20 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_DYNAMIC_LIBARIES_H
#define BASE_DYNAMIC_LIBARIES_H
typedef struct Library Library;
struct Library
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: @per_os_impl Dynamically-Loaded Libraries
internal Library library_open(String8 path);
internal void library_close(Library lib);
internal VoidProc *library_load_proc(Library lib, String8 name);
#endif // BASE_DYNAMIC_LIBARIES_H
+27 -13
View File
@@ -11,6 +11,10 @@ global B32 async_loop_again_high_priority = 0;
global B32 global_async_exit = 0;
thread_static B32 is_async_thread = 0;
// NOTE(rjf): defined by target
raddbg_entry_point(entry_point);
internal void entry_point(CmdLine *cmdline);
internal void
main_thread_base_entry_point(int arguments_count, char **arguments)
{
@@ -54,12 +58,15 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
}
//- rjf: initialize all included layers
#if defined(HTTP_H) && !defined(HTTP_INIT_MANUAL)
http_init();
#endif
#if defined(SYMBOL_SERVER_H) && !defined(SMSV_INIT_MANUAL)
smsv_init();
#endif
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
ac_init();
#endif
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
async_init(&cmdline);
#endif
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
c_init();
#endif
@@ -75,11 +82,11 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
dmn_init();
#endif
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
ctrl_init();
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
d_init();
#endif
#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL)
os_gfx_init();
#if defined(WINDOW_MANAGER_H) && !defined(WM_INIT_MANUAL)
wm_init();
#endif
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
fp_init();
@@ -90,22 +97,20 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
fnt_init();
#endif
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
d_init();
#endif
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
rd_init(&cmdline);
#endif
#if !NO_ASYNC
//- rjf: launch async threads
Thread *async_threads = 0;
U64 lane_broadcast_val = 0;
{
U64 num_main_threads = 1;
#if defined(CTRL_CORE_H)
#if defined(DBG_ENGINE_CORE_H)
num_main_threads += 1;
#endif
U64 num_async_threads = os_get_system_info()->logical_processor_count;
U64 num_async_threads = get_system_info()->logical_processor_count;
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
num_async_threads -= num_main_threads_clamped;
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
@@ -127,10 +132,12 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
}
}
#endif
//- rjf: call into entry point
entry_point(&cmdline);
#if !NO_ASYNC
//- rjf: join async threads
ins_atomic_u32_inc_eval(&global_async_exit);
cond_var_broadcast(async_tick_start_cond_var);
@@ -138,6 +145,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
{
thread_join(async_threads[idx], max_U64);
}
#endif
//- rjf: end captures
if(capture)
@@ -194,7 +202,7 @@ async_thread_entry_point(void *params)
{
if(!ins_atomic_u32_eval(&async_loop_again))
{
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+1000000);
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, now_time_us()+1000000);
}
ins_atomic_u32_eval_assign(&async_loop_again, 0);
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
@@ -213,6 +221,12 @@ async_thread_entry_point(void *params)
#if defined(FILE_STREAM_H)
fs_async_tick();
#endif
#if defined(HTTP_H)
http_async_tick();
#endif
#if defined(SYMBOL_SERVER_H)
smsv_async_tick();
#endif
#if defined(DBG_INFO_H)
di_async_tick();
#endif
+169
View File
@@ -0,0 +1,169 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Handle Type Functions
internal File
file_zero(void)
{
File f = {0};
return f;
}
internal B32
file_match(File a, File b)
{
B32 result = MemoryMatchStruct(&a, &b);
return result;
}
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
internal String8
data_from_file_path(Arena *arena, String8 path)
{
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
FileProperties props = properties_from_file(file);
String8 data = string_from_file_range(arena, file, r1u64(0, props.size));
file_close(file);
return data;
}
internal B32
write_data_to_file_path(String8 path, String8 data)
{
B32 good = 0;
File file = file_open(AccessFlag_Write, path);
if(!file_match(file, file_zero()))
{
U64 bytes_written = file_write(file, r1u64(0, data.size), data.str);
good = (bytes_written == data.size);
file_close(file);
}
return good;
}
internal B32
write_data_list_to_file_path(String8 path, String8List list)
{
B32 good = 0;
File file = file_open(AccessFlag_Write, path);
if(!file_match(file, file_zero()))
{
Temp scratch = scratch_begin(0, 0);
U64 write_buffer_size = KB(64);
U8 *write_buffer = push_array_no_zero(scratch.arena, U8, write_buffer_size);
U64 write_buffer_write_pos = 0;
U64 write_buffer_read_pos = 0;
U64 file_off = 0;
{
for(String8Node *n = list.first; n != 0; n = n->next)
{
for(U64 n_off = 0; n_off < n->string.size;)
{
U64 write_buffer_unconsumed_size = (write_buffer_write_pos - write_buffer_read_pos);
U64 write_buffer_available_size = (write_buffer_size - write_buffer_unconsumed_size);
if(write_buffer_available_size == 0)
{
U64 file_write_size = file_write(file, r1u64(file_off, file_off+write_buffer_size), write_buffer);
if(file_write_size != write_buffer_size)
{
goto dbl_break;
}
file_off += write_buffer_size;
write_buffer_read_pos += write_buffer_size;
}
else
{
U64 bytes_to_copy = Min(write_buffer_available_size, n->string.size - n_off);
write_buffer_write_pos += wrapped_write(write_buffer, write_buffer_size, write_buffer_write_pos, n->string.str + n_off, bytes_to_copy);
n_off += bytes_to_copy;
}
}
}
if(write_buffer_write_pos > write_buffer_read_pos)
{
U64 file_write_size = file_write(file, r1u64(file_off, file_off + (write_buffer_write_pos-write_buffer_read_pos)), write_buffer);
file_off += file_write_size;
}
}
dbl_break:;
good = (file_off == list.total_size);
file_close(file);
scratch_end(scratch);
}
return good;
}
internal B32
append_data_to_file_path(String8 path, String8 data)
{
B32 good = 0;
if(data.size != 0)
{
File file = file_open(AccessFlag_Write|AccessFlag_Append, path);
if(!file_match(file, file_zero()))
{
U64 pos = properties_from_file(file).size;
U64 bytes_written = file_write(file, r1u64(pos, pos+data.size), data.str);
good = (bytes_written == data.size);
file_close(file);
}
}
return good;
}
internal FileID
id_from_file_path(String8 path)
{
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
FileID id = id_from_file(file);
file_close(file);
return id;
}
internal S64
file_id_compare(FileID a, FileID b)
{
S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v));
return cmp;
}
internal String8
string_from_file_range(Arena *arena, File file, Rng1U64 range)
{
U64 pre_pos = arena_pos(arena);
String8 result;
result.size = dim_1u64(range);
result.str = push_array_no_zero(arena, U8, result.size);
U64 actual_read_size = file_read(file, range, result.str);
if(actual_read_size < result.size)
{
arena_pop_to(arena, pre_pos + actual_read_size);
result.size = actual_read_size;
}
return result;
}
internal String8
file_read_cstring(Arena *arena, File file, U64 off)
{
Temp scratch = scratch_begin(&arena, 1);
String8List block_list = {0};
for(U64 cursor = off, stride = 256;; cursor += stride)
{
U8 *raw_block = push_array_no_zero(scratch.arena, U8, stride);
U64 read_size = file_read(file, r1u64(cursor, cursor + stride), raw_block);
String8 block = str8_cstring_capped(raw_block, raw_block+read_size);
str8_list_push(scratch.arena, &block_list, block);
if(read_size != stride || (block.size+1 <= read_size && block.str[block.size] == 0))
{
break;
}
}
String8 result = str8_list_join(arena, &block_list, 0);
scratch_end(scratch);
return result;
}
+102
View File
@@ -0,0 +1,102 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_FILES_H
#define BASE_FILES_H
typedef U32 FileIterFlags;
enum
{
FileIterFlag_SkipFolders = (1 << 0),
FileIterFlag_SkipFiles = (1 << 1),
FileIterFlag_SkipHiddenFiles = (1 << 2),
FileIterFlag_Done = (1 << 31),
};
typedef struct FileIter FileIter;
struct FileIter
{
FileIterFlags flags;
U8 memory[800];
};
typedef struct FileInfo FileInfo;
struct FileInfo
{
String8 name;
FileProperties props;
};
// nick: on-disk file identifier
typedef struct FileID FileID;
struct FileID
{
U64 v[3];
};
typedef struct File File;
struct File
{
U64 u64[1];
};
typedef struct FileMap FileMap;
struct FileMap
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: Handle Type Functions
internal File file_zero(void);
internal B32 file_match(File a, File b);
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
internal String8 data_from_file_path(Arena *arena, String8 path);
internal B32 write_data_to_file_path(String8 path, String8 data);
internal B32 write_data_list_to_file_path(String8 path, String8List list);
internal B32 append_data_to_file_path(String8 path, String8 data);
internal FileID id_from_file_path(String8 path);
internal S64 file_id_compare(FileID a, FileID b);
internal String8 string_from_file_range(Arena *arena, File file, Rng1U64 range);
internal String8 file_read_cstring(Arena *arena, File file, U64 off);
////////////////////////////////
//~ rjf: @per_os_impl File System (Implemented Per-OS)
//- rjf: files
internal File file_open(AccessFlags flags, String8 path);
internal void file_close(File file);
internal U64 file_read(File file, Rng1U64 rng, void *out_data);
#define file_read_struct(f, off, ptr) file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr))
internal U64 file_write(File file, Rng1U64 rng, void *data);
internal B32 file_set_times(File file, DateTime time);
internal FileProperties properties_from_file(File file);
internal FileID id_from_file(File file);
internal B32 file_reserve_size(File file, U64 size);
internal B32 delete_file_at_path(String8 path);
internal B32 copy_file_path(String8 dst, String8 src);
internal B32 move_file_path(String8 dst, String8 src);
internal String8 full_path_from_path(Arena *arena, String8 path);
internal B32 file_path_exists(String8 path);
internal B32 folder_path_exists(String8 path);
internal FileProperties properties_from_file_path(String8 path);
//- rjf: file maps
internal FileMap file_map_open(AccessFlags flags, File file);
internal void file_map_close(FileMap map);
internal void * file_map_view_open(FileMap map, AccessFlags flags, Rng1U64 range);
internal void file_map_view_close(FileMap map, void *ptr, Rng1U64 range);
//- rjf: directory iteration
internal FileIter *file_iter_begin(Arena *arena, String8 path, FileIterFlags flags);
internal B32 file_iter_next(Arena *arena, FileIter *iter, FileInfo *info_out);
internal void file_iter_end(FileIter *iter);
//- rjf: directory creation
internal B32 make_directory(String8 path);
#endif // BASE_FILES_H
+17
View File
@@ -9,14 +9,31 @@
#include "base_core.c"
#include "base_profile.c"
#include "base_memory.c"
#include "base_arena.c"
#include "base_math.c"
#include "base_strings.c"
#include "base_memory_map.c"
#include "base_hash.c"
#include "base_system.c"
#include "base_threads.c"
#include "base_ring.c"
#include "base_thread_context.c"
#include "base_files.c"
#include "base_shared_memory.c"
#include "base_processes.c"
#include "base_dynamic_libraries.c"
#include "base_command_line.c"
#include "base_markup.c"
#include "base_meta.c"
#include "base_log.c"
#include "base_test.c"
#include "base_entry_point.c"
#if OS_WINDOWS
# include "win32/base/win32_base.c"
#elif OS_LINUX
# include "linux/base/linux_base.c"
#else
# error Operating system backend not found for base layer.
#endif
+17
View File
@@ -11,16 +11,33 @@
#include "base_core.h"
#include "base_profile.h"
#include "base_memory.h"
#include "base_arena.h"
#include "base_math.h"
#include "base_strings.h"
#include "base_memory_map.h"
#include "base_hash.h"
#include "base_system.h"
#include "base_threads.h"
#include "base_ring.h"
#include "base_thread_context.h"
#include "base_files.h"
#include "base_shared_memory.h"
#include "base_processes.h"
#include "base_dynamic_libraries.h"
#include "base_command_line.h"
#include "base_markup.h"
#include "base_meta.h"
#include "base_log.h"
#include "base_test.h"
#include "base_entry_point.h"
#if OS_WINDOWS
# include "win32/base/win32_base.h"
#elif OS_LINUX
# include "linux/base/linux_base.h"
#else
# error Operating system backend not found for base layer.
#endif
#endif // BASE_INC_H
+2
View File
@@ -9,6 +9,8 @@ C_LINKAGE thread_static Log *log_active;
C_LINKAGE thread_static Log *log_active = 0;
#endif
String8 g_logs_folder;
////////////////////////////////
//~ rjf: Log Creation/Selection
+5
View File
@@ -36,6 +36,11 @@ struct Log
LogScope *top_scope;
};
////////////////////////////////
// Globals
extern String8 g_logs_folder;
////////////////////////////////
//~ rjf: Log Creation/Selection
-19
View File
@@ -1,21 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
set_thread_name(String8 string)
{
ProfThreadName("%.*s", str8_varg(string));
os_set_thread_name(string);
}
internal void
set_thread_namef(char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
set_thread_name(string);
va_end(args);
scratch_end(scratch);
}
-2
View File
@@ -15,8 +15,6 @@
# define LAYER_COLOR 0x404040ff
#endif
internal void set_thread_name(String8 string);
internal void set_thread_namef(char *fmt, ...);
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
#endif // BASE_MARKUP_H
+35 -16
View File
@@ -407,6 +407,26 @@ transpose_4x4f32(Mat4x4F32 mat)
////////////////////////////////
//~ rjf: Range Ops
internal Rng1U8 rng_1u8(U8 min, U8 max) {Rng1U8 r = {min, max}; if(r.min > r.max) { Swap(U8, r.min, r.max); } return r;}
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x) {r.min += x; r.max += x; return r;}
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x) {r.min -= x; r.max += x; return r;}
internal U8 center_1u8(Rng1U8 r) {U8 c = (r.min+r.max)/2; return c;}
internal B32 contains_1u8(Rng1U8 r, U8 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal U8 dim_1u8(Rng1U8 r) {U8 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal U8 clamp_1u8(Rng1U8 r, U8 v) {v = Clamp(r.min, v, r.max); return v;}
internal Rng1U16 rng_1u16(U16 min, U16 max) {Rng1U16 r = {min, max}; if(r.min > r.max) { Swap(U16, r.min, r.max); } return r;}
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x) {r.min += x; r.max += x; return r;}
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x) {r.min -= x; r.max += x; return r;}
internal U16 center_1u16(Rng1U16 r) {U16 c = (r.min+r.max)/2; return c;}
internal B32 contains_1u16(Rng1U16 r, U16 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal U16 dim_1u16(Rng1U16 r) {U16 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal U16 clamp_1u16(Rng1U16 r, U16 v) {v = Clamp(r.min, v, r.max); return v;}
internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;}
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;}
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
@@ -738,6 +758,7 @@ rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat)
list->first = to_concat->first;
list->last = to_concat->last;
}
list->count += to_concat->count;
MemoryZeroStruct(to_concat);
}
}
@@ -758,34 +779,32 @@ rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
}
internal U64
rng_1u64_array_bsearch(Rng1U64Array arr, U64 value)
rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value)
{
if(arr.count > 0 && arr.v[0].min < value && value < arr.v[arr.count-1].max)
U64 result = 0;
if(array->count > 0 && array->v[0].min <= value && value < array->v[array->count-1].max)
{
U64 l = 0;
U64 r = arr.count - 1;
for(; l <= r; )
U64 min_idx = 0;
U64 max_idx = array->count - 1;
for(;min_idx <= max_idx;)
{
U64 m = l + (r - l) / 2;
if(contains_1u64(arr.v[m], value))
U64 mid_idx = min_idx + (max_idx - min_idx) / 2;
if(contains_1u64(array->v[mid_idx], value))
{
return m;
result = mid_idx+1;
break;
}
else if(arr.v[m].min < value)
else if(array->v[mid_idx].min < value)
{
l = m + 1;
min_idx = mid_idx + 1;
}
else
{
r = m - 1;
max_idx = mid_idx - 1;
}
}
}
else if(arr.count == 1 && contains_1u64(arr.v[0], value))
{
return 0;
}
return max_U64;
return result;
}
internal void
+57 -2
View File
@@ -177,6 +177,28 @@ struct Mat4x4F32
//- rjf: 1-range
typedef union Rng1U8 Rng1U8;
union Rng1U8
{
struct
{
U8 min;
U8 max;
};
U8 v[2];
};
typedef union Rng1U16 Rng1U16;
union Rng1U16
{
struct
{
U16 min;
U16 max;
};
U16 v[2];
};
typedef union Rng1U32 Rng1U32;
union Rng1U32
{
@@ -339,9 +361,9 @@ struct Rng1U64Node
typedef struct Rng1U64List Rng1U64List;
struct Rng1U64List
{
U64 count;
Rng1U64Node *first;
Rng1U64Node *last;
U64 count;
};
typedef struct Rng1U64Array Rng1U64Array;
@@ -546,7 +568,32 @@ internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
////////////////////////////////
//~ rjf: Range Ops
#define r1u8(min, max) rng_1u8((min), (max))
#define r1u8s(min, size) rng_1u8((min), (min)+(size))
internal Rng1U8 rng_1u8(U8 min, U8 max);
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x);
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x);
internal U8 center_1u8(Rng1U8 r);
internal B32 contains_1u8(Rng1U8 r, U8 x);
internal U8 dim_1u8(Rng1U8 r);
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b);
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b);
internal U8 clamp_1u8(Rng1U8 r, U8 v);
#define r1u16(min, max) rng_1u16((min), (max))
#define r1u16s(min, size) rng_1u16((min), (min)+(size))
internal Rng1U16 rng_1u16(U16 min, U16 max);
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x);
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x);
internal U16 center_1u16(Rng1U16 r);
internal B32 contains_1u16(Rng1U16 r, U16 x);
internal U16 dim_1u16(Rng1U16 r);
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b);
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b);
internal U16 clamp_1u16(Rng1U16 r, U16 v);
#define r1u32(min, max) rng_1u32((min), (max))
#define r1u32s(min, size) rng_1u32((min), (min)+(size))
internal Rng1U32 rng_1u32(U32 min, U32 max);
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x);
@@ -558,6 +605,7 @@ internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b);
internal U32 clamp_1u32(Rng1U32 r, U32 v);
#define r1s32(min, max) rng_1s32((min), (max))
#define r1s32s(min,size) rng_1s32((min), (min)+(size))
internal Rng1S32 rng_1s32(S32 min, S32 max);
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x);
@@ -569,6 +617,7 @@ internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b);
internal S32 clamp_1s32(Rng1S32 r, S32 v);
#define r1u64(min, max) rng_1u64((min), (max))
#define r1u64s(min, size) rng_1u64((min), (min)+(size))
internal Rng1U64 rng_1u64(U64 min, U64 max);
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x);
@@ -580,6 +629,7 @@ internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b);
internal U64 clamp_1u64(Rng1U64 r, U64 v);
#define r1s64(min, max) rng_1s64((min), (max))
#define r1s64s(min, size) rng_1s64((min), (min)+(size))
internal Rng1S64 rng_1s64(S64 min, S64 max);
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x);
@@ -591,6 +641,7 @@ internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b);
internal S64 clamp_1s64(Rng1S64 r, S64 v);
#define r1f32(min, max) rng_1f32((min), (max))
#define r1f32s(min, size) rng_1f32((min), (min)+(size))
internal Rng1F32 rng_1f32(F32 min, F32 max);
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x);
@@ -602,6 +653,7 @@ internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b);
internal F32 clamp_1f32(Rng1F32 r, F32 v);
#define r2s16(min, max) rng_2s16((min), (max))
#define r2s16s(min, size) r2s16((min), (min)+(size))
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
@@ -614,6 +666,7 @@ internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b);
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
#define r2s32(min, max) rng_2s32((min), (max))
#define r2s32s(min, size) r2s32((min), (min)+(size))
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
@@ -626,6 +679,7 @@ internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b);
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
#define r2s64(min, max) rng_2s64((min), (max))
#define r2s64s(min, size) r2s64((min), (min)+(size))
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
@@ -638,6 +692,7 @@ internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b);
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
#define r2f32(min, max) rng_2f32((min), (max))
#define r2f32s(min, size) r2f32((min), (min)+(size))
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
@@ -682,7 +737,7 @@ internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value);
internal U64 rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value);
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
+2
View File
@@ -0,0 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+20
View File
@@ -0,0 +1,20 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_MEMORY_H
#define BASE_MEMORY_H
////////////////////////////////
//~ rjf: @per_os_impl Platform Memory Allocation
//- rjf: basic
internal void *reserve_memory(U64 size);
internal B32 commit_memory(void *ptr, U64 size);
internal void decommit_memory(void *ptr, U64 size);
internal void release_memory(void *ptr, U64 size);
//- rjf: large pages
internal void *reserve_memory_large(U64 size);
internal B32 commit_memory_large(void *ptr, U64 size);
#endif // BASE_MEMORY_H
+36
View File
@@ -0,0 +1,36 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Memory Map Functions
internal void
memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data)
{
MemoryMapRangeNode *n = push_array(arena, MemoryMapRangeNode, 1);
n->v.vaddr_range = vaddr_range;
n->v.base = data;
SLLQueuePush(map->first_range, map->last_range, n);
}
internal U64
memory_map_read(MemoryMap *map, Rng1U64 range, void *dst)
{
U64 dst_vaddr = range.min;
{
for(MemoryMapRangeNode *n = map->first_range; n != 0; n = n->next)
{
if(contains_1u64(n->v.vaddr_range, dst_vaddr))
{
U64 src_off = dst_vaddr - n->v.vaddr_range.min;
U64 num_bytes_possible = n->v.vaddr_range.max - dst_vaddr;
U64 num_bytes_needed = range.max - dst_vaddr;
U64 num_bytes_to_read = Min(num_bytes_needed, num_bytes_possible);
MemoryCopy((U8 *)dst + (dst_vaddr - range.min), (U8 *)n->v.base + src_off, num_bytes_to_read);
dst_vaddr += num_bytes_to_read;
}
}
}
U64 bytes_read = (dst_vaddr - range.min);
return bytes_read;
}
+38
View File
@@ -0,0 +1,38 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_MEMORY_MAP_H
#define BASE_MEMORY_MAP_H
////////////////////////////////
//~ rjf: Memory Map Types
typedef struct MemoryMapRange MemoryMapRange;
struct MemoryMapRange
{
Rng1U64 vaddr_range;
void *base;
};
typedef struct MemoryMapRangeNode MemoryMapRangeNode;
struct MemoryMapRangeNode
{
MemoryMapRangeNode *next;
MemoryMapRange v;
};
typedef struct MemoryMap MemoryMap;
struct MemoryMap
{
MemoryMapRangeNode *first_range;
MemoryMapRangeNode *last_range;
};
////////////////////////////////
//~ rjf: Memory Map Functions
internal void memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data);
internal U64 memory_map_read(MemoryMap *map, Rng1U64 range, void *dst);
#define memory_map_read_struct(map, vaddr, ptr) memory_map_read((map), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
#endif // BASE_MEMORY_MAP_H
+115
View File
@@ -0,0 +1,115 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Handle Type Functions
internal Process
process_zero(void)
{
Process p = {0};
return p;
}
internal B32
process_match(Process a, Process b)
{
B32 result = MemoryMatchStruct(&a, &b);
return result;
}
internal void
process_list_push(Arena *arena, ProcessList *list, Process p)
{
ProcessNode *n = push_array(arena, ProcessNode, 1);
SLLQueuePush(list->first, list->last, n);
n->v = p;
list->count += 1;
}
////////////////////////////////
//~ rjf: Process Launcher Helpers
internal Process
launch_cmd_line(String8 string)
{
Temp scratch = scratch_begin(0, 0);
U8 split_chars[] = {' '};
String8List parts = str8_split(scratch.arena, string, split_chars, ArrayCount(split_chars), 0);
Process process = {0};
if(parts.node_count != 0)
{
// rjf: unpack exe part
String8 exe = parts.first->string;
String8 exe_folder = str8_chop_last_slash(exe);
if(exe_folder.size == 0)
{
exe_folder = get_current_path(scratch.arena);
}
// rjf: find stdout delimiter
String8Node *stdout_delimiter_n = 0;
for(String8Node *n = parts.first; n != 0; n = n->next)
{
if(str8_match(n->string, str8_lit(">"), 0))
{
stdout_delimiter_n = n;
break;
}
}
// rjf: read stdout path
String8 stdout_path = {0};
if(stdout_delimiter_n && stdout_delimiter_n->next)
{
stdout_path = stdout_delimiter_n->next->string;
}
// rjf: open stdout handle
File stdout_handle = {0};
if(stdout_path.size != 0)
{
File file = file_open(AccessFlag_Write|AccessFlag_Read, stdout_path);
file_close(file);
stdout_handle = file_open(AccessFlag_Write|AccessFlag_Append|AccessFlag_ShareRead|AccessFlag_ShareWrite|AccessFlag_Inherited, stdout_path);
}
// rjf: form command line
String8List cmdline = {0};
for(String8Node *n = parts.first; n != stdout_delimiter_n && n != 0; n = n->next)
{
str8_list_push(scratch.arena, &cmdline, n->string);
}
// rjf: launch
ProcessLaunchParams params = {0};
params.cmd_line = cmdline;
params.path = exe_folder;
params.inherit_env = 1;
params.stdout_file = stdout_handle;
process = process_launch(&params);
// rjf: close stdout handle
{
if(stdout_path.size != 0)
{
file_close(stdout_handle);
}
}
}
scratch_end(scratch);
return process;
}
internal Process
launch_cmd_linef(char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = str8fv(scratch.arena, fmt, args);
Process result = launch_cmd_line(string);
va_end(args);
scratch_end(scratch);
return result;
}
+91
View File
@@ -0,0 +1,91 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_PROCESSES_H
#define BASE_PROCESSES_H
typedef struct ProcessInfo ProcessInfo;
struct ProcessInfo
{
U32 pid;
B32 large_pages_allowed;
String8 binary_file_path;
String8 binary_path;
String8 initial_path;
String8 user_program_config_data_path;
String8 user_program_cache_data_path;
String8 user_program_logs_data_path;
String8List module_load_paths;
String8List environment;
};
typedef struct Process Process;
struct Process
{
U64 u64[1];
};
typedef struct ProcessNode ProcessNode;
struct ProcessNode
{
ProcessNode *next;
Process v;
};
typedef struct ProcessList ProcessList;
struct ProcessList
{
ProcessNode *first;
ProcessNode *last;
U64 count;
};
typedef struct ProcessLaunchParams ProcessLaunchParams;
struct ProcessLaunchParams
{
String8List cmd_line;
String8 path;
String8List env;
B32 inherit_env;
B32 debug_subprocesses;
B32 consoleless;
File stdout_file;
File stderr_file;
File stdin_file;
};
////////////////////////////////
//~ rjf: Handle Type Functions
internal Process process_zero(void);
internal B32 process_match(Process a, Process b);
internal void process_list_push(Arena *arena, ProcessList *list, Process p);
////////////////////////////////
//~ rjf: Process Launcher Helpers
internal Process launch_cmd_line(String8 string);
internal Process launch_cmd_linef(char *fmt, ...);
////////////////////////////////
//~ rjf: @per_os_impl Aborting
internal void abort_self(U64 exit_code);
////////////////////////////////
//~ rjf: @per_os_impl Process Info
internal ProcessInfo *get_process_info(void);
internal String8 get_current_path(Arena *arena);
internal U32 get_process_start_time_unix(void);
////////////////////////////////
//~ rjf: @per_os_impl Child Processes
internal Process process_launch(ProcessLaunchParams *params);
internal U64 pid_from_process(Process process);
internal B32 process_join(Process process, U64 endt_us, U64 *exit_code_out);
internal void process_detach(Process process);
internal B32 process_kill(Process process);
#endif // BASE_PROCESSES_H
+1 -1
View File
@@ -24,7 +24,7 @@ spall_begin(char *fmt, ...)
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, os_now_microseconds(), spall_tid, spall_pid);
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, now_time_us(), spall_tid, spall_pid);
va_end(args);
scratch_end(scratch);
}
+1 -1
View File
@@ -79,7 +79,7 @@ thread_static U32 spall_pid = 0;
internal inline void spall_begin(char *fmt, ...);
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
# define ProfBeginDynamic(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, os_now_microseconds(), spall_tid, spall_pid)), 0 : 0)
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, now_time_us(), spall_tid, spall_pid)), 0 : 0)
# define ProfTick(...)
# define ProfIsCapturing(...) (!!spall_capturing)
# define ProfBeginCapture(...) (spall_capturing = 1)
+135
View File
@@ -0,0 +1,135 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Ring Functions
internal Ring *
make_ring(Arena *arena, U64 size)
{
Ring *ring = push_array(arena, Ring, 1);
ring->size = size;
ring->base = push_array(arena, U8, ring->size);
return ring;
}
internal B32
ring_try_write(Ring *ring, U64 size, void *ptr)
{
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
U64 bytes_available = ring->size - bytes_unconsumed;
B32 result = 0;
if(bytes_available >= size)
{
result = 1;
ring->write_pos += wrapped_write(ring->base, ring->size, ring->write_pos, ptr, size);
}
return result;
}
internal B32
ring_try_read(Ring *ring, U64 size, void *ptr)
{
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
B32 result = 0;
if(bytes_unconsumed >= size)
{
result = 1;
ring->read_pos += wrapped_read(ring->base, ring->size, ring->read_pos, ptr, size);
}
return result;
}
////////////////////////////////
//~ rjf: Guarded Ring Functions
internal GuardedRing *
guarded_ring_alloc(Arena *arena, U64 size)
{
GuardedRing *gr = push_array(arena, GuardedRing, 1);
gr->ring = make_ring(arena, size);
gr->mutex = mutex_alloc();
gr->cv = cond_var_alloc();
return gr;
}
internal void
guarded_ring_release(GuardedRing *ring)
{
mutex_release(ring->mutex);
cond_var_release(ring->cv);
}
internal RingGuard
guarded_ring_open(GuardedRing *ring)
{
RingGuard guard = {ring};
mutex_take(ring->mutex);
return guard;
}
internal void
guarded_ring_close(RingGuard *guard)
{
mutex_drop(guard->r->mutex);
}
internal B32
guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr)
{
B32 result = ring_try_write(guard->r->ring, size, ptr);
if(result)
{
cond_var_broadcast(guard->r->cv);
}
return result;
}
internal B32
guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr)
{
B32 result = ring_try_read(guard->r->ring, size, ptr);
if(result)
{
cond_var_broadcast(guard->r->cv);
}
return result;
}
internal B32
guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
{
B32 write_good = 0;
for(;!write_good;)
{
write_good = guarded_ring_try_write(guard, size, ptr);
if(now_time_us() >= endt_us)
{
break;
}
if(!write_good)
{
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
}
}
return write_good;
}
internal B32
guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
{
B32 read_good = 0;
for(;!read_good;)
{
read_good = guarded_ring_try_read(guard, size, ptr);
if(now_time_us() >= endt_us)
{
break;
}
if(!read_good)
{
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
}
}
return read_good;
}
+56
View File
@@ -0,0 +1,56 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_RING_H
#define BASE_RING_H
typedef struct Ring Ring;
struct Ring
{
U8 *base;
U64 size;
U64 write_pos;
U64 read_pos;
};
typedef struct GuardedRing GuardedRing;
struct GuardedRing
{
Ring *ring;
Mutex mutex;
CondVar cv;
};
typedef struct RingGuard RingGuard;
struct RingGuard
{
GuardedRing *r;
};
////////////////////////////////
//~ rjf: Ring Functions
internal Ring *make_ring(Arena *arena, U64 size);
internal B32 ring_try_write(Ring *ring, U64 size, void *ptr);
internal B32 ring_try_read(Ring *ring, U64 size, void *ptr);
#define ring_try_write_struct(ring, ptr) ring_try_write((ring), sizeof(*(ptr)), (ptr))
#define ring_try_read_struct(ring, ptr) ring_try_read((ring), sizeof(*(ptr)), (ptr))
////////////////////////////////
//~ rjf: Guarded Ring Functions
internal GuardedRing *guarded_ring_alloc(Arena *arena, U64 size);
internal void guarded_ring_release(GuardedRing *ring);
internal RingGuard guarded_ring_open(GuardedRing *ring);
internal void guarded_ring_close(RingGuard *guard);
internal B32 guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr);
internal B32 guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr);
#define guarded_ring_try_write_struct(ring, ptr) guarded_ring_try_write((ring), sizeof(*(ptr)), (ptr))
#define guarded_ring_try_read_struct(ring, ptr) guarded_ring_try_read((ring), sizeof(*(ptr)), (ptr))
internal B32 guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
internal B32 guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
#define guarded_ring_write_struct_or_wait(ring, ptr, endt_us) guarded_ring_write_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
#define guarded_ring_read_struct_or_wait(ring, ptr, endt_us) guarded_ring_read_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
#define guarded_ring_write_string_or_wait(ring, string, endt_us) guarded_ring_write_or_wait((ring), (string).size, (string).str, (endt_us))
#endif // BASE_RING_H
+2
View File
@@ -0,0 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_SHARED_MEMORY_H
#define BASE_SHARED_MEMORY_H
typedef struct SharedMemory SharedMemory;
struct SharedMemory
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: @per_os_impl Shared Memory
internal SharedMemory shared_memory_alloc(U64 size, String8 name);
internal SharedMemory shared_memory_open(String8 name);
internal void shared_memory_close(SharedMemory handle);
internal void * shared_memory_view_open(SharedMemory handle, Rng1U64 range);
internal void shared_memory_view_close(SharedMemory handle, void *ptr, Rng1U64 range);
#endif // BASE_SHARED_MEMORY_H
+498 -146
View File
@@ -1,6 +1,14 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
#ifndef MEM_STATIC
# define MEM_STATIC
# define MEM_API ASAN_NO_ADDR static inline
# include "third_party/martins_memfun/memfun.h"
#endif
////////////////////////////////
//~ rjf: Character Classification & Conversion Functions
@@ -211,12 +219,9 @@ str32_cstring(U32 *c)
internal String8
str8_cstring_capped(void *cstr, void *cap)
{
char *ptr = (char *)cstr;
char *opl = (char *)cap;
for (;ptr < opl && *ptr != 0; ptr += 1);
U64 size = (U64)(ptr - (char *)cstr);
String8 result = str8((U8*)cstr, size);
return result;
U64 cap_size = (U64)((U8 *)cap - (U8 *)cstr);
U64 size = MemFind(cstr, cap_size, 0);
return str8(cstr, size);
}
internal String16
@@ -230,24 +235,6 @@ str16_cstring_capped(void *cstr, void *cap)
return result;
}
internal String8
str8_cstring_capped_reverse(void *raw_start, void *raw_cap)
{
U8 *start = raw_start;
U8 *ptr = raw_cap;
for(; ptr > start; )
{
ptr -= 1;
if (*ptr == '\0')
{
break;
}
}
U64 size = (U64)(ptr - start);
String8 result = str8(start, size);
return result;
}
////////////////////////////////
//~ rjf: String Stylization
@@ -293,7 +280,11 @@ str8_match(String8 a, String8 b, StringMatchFlags flags)
B32 result = 0;
if(a.size == b.size && flags == 0)
{
result = MemoryMatch(a.str, b.str, b.size);
result = MemIsEqual(a.str, b.str, b.size);
}
else if (a.size == b.size && flags == StringMatchFlag_CaseInsensitive)
{
result = MemCompareI(a.str, b.str, a.size) == 0;
}
else if(a.size == b.size || (flags & StringMatchFlag_RightSideSloppy))
{
@@ -325,6 +316,88 @@ str8_match(String8 a, String8 b, StringMatchFlags flags)
return result;
}
internal B32
str8_char_match(U8 a, U8 b, StringMatchFlags flags)
{
U8 at = a;
U8 bt = b;
if (flags & StringMatchFlag_CaseInsensitive) {
at = upper_from_char(at);
bt = upper_from_char(bt);
}
if (flags & StringMatchFlag_SlashInsensitive) {
if (at == '\\') { at = '/'; }
if (bt == '\\') { bt = '/'; }
}
return (at == bt);
}
internal B32
str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags)
{
B32 matched = 0;
U64 pattern_cursor = 0;
U64 string_cursor = 0;
U64 pattern_start = max_U64;
U64 string_start = 0;
for (;;) {
if (pattern_cursor == pattern.size) {
if (string_cursor == string.size || (flags & StringMatchFlag_RightSideSloppy)) {
matched = 1;
break;
}
}
if (string_cursor == string.size) {
while (pattern_cursor < pattern.size && pattern.str[pattern_cursor] == '*') {
pattern_cursor += 1;
}
matched = (pattern_cursor == pattern.size);
break;
}
if (pattern_cursor < pattern.size && pattern.str[pattern_cursor] == '*') {
pattern_start = pattern_cursor;
string_start = string_cursor;
pattern_cursor += 1;
continue;
}
if (pattern_cursor < pattern.size && (pattern.str[pattern_cursor] == '?' || str8_char_match(string.str[string_cursor], pattern.str[pattern_cursor], flags))) {
string_cursor += 1;
pattern_cursor += 1;
continue;
}
if (pattern_start != max_U64) {
pattern_cursor = pattern_start + 1;
string_start += 1;
string_cursor = string_start;
continue;
}
break;
}
return matched;
}
internal B32
str8_starts_with(String8 string, String8 expected_prefix)
{
return str8_match(str8_prefix(string, expected_prefix.size), expected_prefix, 0);
}
internal B32
str8_starts_withi(String8 string, String8 expected_prefix)
{
return str8_match(str8_prefix(string, expected_prefix.size), expected_prefix, StringMatchFlag_CaseInsensitive);
}
internal U64
str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
{
@@ -341,6 +414,10 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
{
needle_first_char_adjusted = upper_from_char(needle_first_char_adjusted);
}
if(adjusted_flags & StringMatchFlag_SlashInsensitive)
{
needle_first_char_adjusted = correct_slash_from_char(needle_first_char_adjusted);
}
for(;p < stop_p; p += 1)
{
U8 haystack_char_adjusted = *p;
@@ -348,6 +425,10 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
{
haystack_char_adjusted = upper_from_char(haystack_char_adjusted);
}
if(adjusted_flags & StringMatchFlag_SlashInsensitive)
{
haystack_char_adjusted = correct_slash_from_char(haystack_char_adjusted);
}
if(haystack_char_adjusted == needle_first_char_adjusted)
{
if(str8_match(str8_range(p + 1, string_opl), needle_tail, adjusted_flags))
@@ -454,6 +535,18 @@ str8_chop(String8 str, U64 amt)
return str;
}
internal String8
str8_chop_line(String8 *str)
{
U64 new_line_pos = str8_find_needle(*str, 0, str8_lit("\n"), 0);
String8 line = str8_prefix(*str, new_line_pos);
if (str8_ends_with(line, str8_lit("\r"), 0)) {
line = str8_chop(line, 1);
}
*str = str8_skip(*str, new_line_pos + 1);
return line;
}
internal String8
str8_skip_chop_whitespace(String8 string)
{
@@ -616,6 +709,22 @@ str8_is_integer(String8 string, U32 radix)
return result;
}
internal B32
str8_is_integer_signed(String8 string, U32 radix)
{
B32 result = 0;
String8 sign = str8_prefix(string, 1);
if(str8_match(sign, str8_lit("-"), 0))
{
result = str8_is_integer(str8_skip(string, 1), radix);
}
else
{
result = str8_is_integer(string, radix);
}
return result;
}
internal U64
u64_from_str8(String8 string, U32 radix)
{
@@ -715,7 +824,7 @@ str8_from_memory_size(Arena *arena, U64 size)
{
if(size < KB(1))
{
result = push_str8f(arena, "%llu Bytes", size);
result = push_str8f(arena, "%llu byte%s", size, size == 1 ? "" : "s");
}
else if(size < MB(1))
{
@@ -1062,26 +1171,19 @@ str8_list_concat_in_place(String8List *list, String8List *to_push)
}
internal String8Node*
str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){
String8Node *node = push_array_no_zero(arena, String8Node, 1);
U64 new_size = list->total_size + min;
U64 increase_size = 0;
if (align > 1){
// NOTE(allen): assert is power of 2
Assert(((align - 1) & align) == 0);
U64 mask = align - 1;
new_size += mask;
new_size &= (~mask);
increase_size = new_size - list->total_size;
str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align)
{
read_only local_persist U8 zeroes[64] = {0};
Assert(IsPow2OrZero(align));
U64 pad = Max(min, AlignPadPow2(list->total_size, align));
if(pad < sizeof(zeroes))
{
return str8_list_push(arena, list, str8(zeroes, pad));
}
else
{
return str8_list_push(arena, list, str8(push_array(arena, U8, pad), pad));
}
local_persist const U8 zeroes_buffer[64] = {0};
Assert(increase_size <= ArrayCount(zeroes_buffer));
SLLQueuePush(list->first, list->last, node);
list->node_count += 1;
list->total_size = new_size;
node->string.str = (U8*)zeroes_buffer;
node->string.size = increase_size;
return(node);
}
internal String8Node*
@@ -1106,6 +1208,21 @@ str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...)
return result;
}
internal String8Node*
str8_list_pop_front(String8List *list)
{
String8Node *node = 0;
if(list->node_count)
{
node = list->first;
Assert(list->total_size >= list->first->string.size);
list->node_count -= 1;
list->total_size -= list->first->string.size;
SLLQueuePop(list->first, list->last);
}
return node;
}
internal String8List
str8_list_copy(Arena *arena, String8List *list)
{
@@ -1119,6 +1236,42 @@ str8_list_copy(Arena *arena, String8List *list)
return result;
}
internal String8List
str8_list_substr(Arena *arena, String8List list, Rng1U64 range)
{
String8List result = {0};
String8Node *n = list.first;
U64 front_min = 0;
{
U64 cursor = 0;
for (; n != 0; cursor += n->string.size, n = n->next) {
if (cursor + n->string.size > range.min) {
front_min = range.min - cursor;
break;
}
}
}
if (front_min > 0) {
U64 front_max = front_min + Min(dim_1u64(range), n->string.size);
str8_list_push(arena, &result, str8_substr(n->string, r1u64(front_min, front_max)));
n = n->next;
}
for (; n != 0; n = n->next) {
if (result.total_size >= dim_1u64(range)) {
break;
}
U64 copy_max = dim_1u64(range) - result.total_size;
U64 copy_size = Min(copy_max, n->string.size);
str8_list_push(arena, &result, str8_substr(n->string, r1u64(0, copy_size)));
}
return result;
}
////////////////////////////////
//~ rjf: String Splitting & Joining
@@ -1313,6 +1466,31 @@ str8_from_version(Arena *arena, U64 version)
////////////////////////////////
//~ rjf: String Path Helpers
internal String8
program_ext_postfix_from_os(OperatingSystem os, B32 require_ext)
{
String8 result = {0};
switch(os)
{
default:{}break;
case OperatingSystem_Windows:
{
result = s(".exe");
}break;
case OperatingSystem_Linux:
if(require_ext)
{
result = s(".elf");
}break;
case OperatingSystem_Mac:
if(require_ext)
{
result = s(".macho");
}break;
}
return result;
}
internal String8
str8_chop_last_slash(String8 string)
{
@@ -2222,24 +2400,35 @@ string_from_elapsed_time(Arena *arena, DateTime dt)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if(dt.year)
{
if (dt.year) {
str8_list_pushf(scratch.arena, &list, "%dy", dt.year);
str8_list_pushf(scratch.arena, &list, "%um", dt.mon);
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
}
else if(dt.mon)
{
} else if (dt.mon) {
str8_list_pushf(scratch.arena, &list, "%um", dt.mon);
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
}
else if (dt.day)
{
} else if (dt.day) {
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
}
str8_list_pushf(scratch.arena, &list, "%u:%u:%u:%u ms", dt.hour, dt.min, dt.sec, dt.msec);
StringJoin join = { str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") };
String8 result = str8_list_join(arena, &list, &join);
if (dt.hour) {
str8_list_pushf(scratch.arena, &list, "%uh %um %u.%us", dt.hour, dt.min, dt.sec, dt.msec);
} else if (dt.min) {
str8_list_pushf(scratch.arena, &list, "%um %u.%us", dt.min, dt.sec, dt.msec);
} else if (dt.sec) {
str8_list_pushf(scratch.arena, &list, "%u.%us", dt.sec, dt.msec);
} else if (dt.msec) {
str8_list_pushf(scratch.arena, &list, "%ums", dt.msec);
} else if (dt.micro_sec) {
str8_list_pushf(scratch.arena, &list, "%uus", dt.micro_sec);
}
if (list.node_count == 0) {
str8_list_pushf(scratch.arena, &list, "0");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") });
scratch_end(scratch);
return result;
}
@@ -2606,7 +2795,8 @@ fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src)
//~ NOTE(allen): Serialization Helpers
internal void
str8_serial_begin(Arena *arena, String8List *srl){
str8_serial_begin(Arena *arena, String8List *srl)
{
String8Node *node = push_array(arena, String8Node, 1);
node->string.str = push_array_no_zero(arena, U8, 0);
srl->first = srl->last = node;
@@ -2615,7 +2805,8 @@ str8_serial_begin(Arena *arena, String8List *srl){
}
internal String8
str8_serial_end(Arena *arena, String8List *srl){
str8_serial_end(Arena *arena, String8List *srl)
{
U64 size = srl->total_size;
U8 *out = push_array_no_zero(arena, U8, size);
str8_serial_write_to_dst(srl, out);
@@ -2624,19 +2815,20 @@ str8_serial_end(Arena *arena, String8List *srl){
}
internal void
str8_serial_write_to_dst(String8List *srl, void *out){
str8_serial_write_to_dst(String8List *srl, void *out)
{
U8 *ptr = (U8*)out;
for (String8Node *node = srl->first;
node != 0;
node = node->next){
U64 size = node->string.size;
MemoryCopy(ptr, node->string.str, size);
for EachNode(n, String8Node, srl->first)
{
U64 size = n->string.size;
MemoryCopy(ptr, n->string.str, size);
ptr += size;
}
}
internal U64
str8_serial_push_align(Arena *arena, String8List *srl, U64 align){
str8_serial_push_align(Arena *arena, String8List *srl, U64 align)
{
Assert(IsPow2(align));
U64 pos = srl->total_size;
@@ -2648,11 +2840,13 @@ str8_serial_push_align(Arena *arena, String8List *srl, U64 align){
U8 *buf = push_array(arena, U8, size);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
if(str->str + str->size == buf)
{
srl->last->string.size += size;
srl->total_size += size;
}
else{
else
{
str8_list_push(arena, srl, str8(buf, size));
}
}
@@ -2665,13 +2859,15 @@ str8_serial_push_size(Arena *arena, String8List *srl, U64 size)
void *result = 0;
if(size != 0)
{
U8 *buf = push_array_no_zero(arena, U8, size);
U8 *buf = push_array(arena, U8, size);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
if(str->str + str->size == buf)
{
srl->last->string.size += size;
srl->total_size += size;
}
else{
else
{
str8_list_push(arena, srl, str8(buf, size));
}
result = buf;
@@ -2680,7 +2876,8 @@ str8_serial_push_size(Arena *arena, String8List *srl, U64 size)
}
internal void *
str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size){
str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size)
{
void *result = str8_serial_push_size(arena, srl, size);
if(result != 0)
{
@@ -2690,61 +2887,50 @@ str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size){
}
internal void
str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first){
for (String8Node *node = first;
node != 0;
node = node->next){
str8_serial_push_data(arena, srl, node->string.str, node->string.size);
str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first)
{
for EachNode(n, String8Node, first)
{
str8_serial_push_data(arena, srl, n->string.str, n->string.size);
}
}
internal void
str8_serial_push_u64(Arena *arena, String8List *srl, U64 x){
U8 *buf = push_array_no_zero(arena, U8, 8);
MemoryCopy(buf, &x, 8);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
srl->last->string.size += 8;
srl->total_size += 8;
}
else{
str8_list_push(arena, srl, str8(buf, 8));
}
internal void *
str8_serial_push_u64(Arena *arena, String8List *srl, U64 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_u32(Arena *arena, String8List *srl, U32 x){
U8 *buf = push_array_no_zero(arena, U8, 4);
MemoryCopy(buf, &x, 4);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
srl->last->string.size += 4;
srl->total_size += 4;
}
else{
str8_list_push(arena, srl, str8(buf, 4));
}
internal void *
str8_serial_push_u32(Arena *arena, String8List *srl, U32 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_u16(Arena *arena, String8List *srl, U16 x){
str8_serial_push_data(arena, srl, &x, sizeof(x));
internal void *
str8_serial_push_u16(Arena *arena, String8List *srl, U16 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_u8(Arena *arena, String8List *srl, U8 x){
str8_serial_push_data(arena, srl, &x, sizeof(x));
internal void *
str8_serial_push_u8(Arena *arena, String8List *srl, U8 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str){
str8_serial_push_data(arena, srl, str.str, str.size);
internal void *
str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str)
{
void *ptr = str8_serial_push_data(arena, srl, str.str, str.size);
str8_serial_push_u8(arena, srl, 0);
return ptr;
}
internal void
str8_serial_push_string(Arena *arena, String8List *srl, String8 str){
str8_serial_push_data(arena, srl, str.str, str.size);
internal void *
str8_serial_push_string(Arena *arena, String8List *srl, String8 str)
{
return str8_serial_push_data(arena, srl, str.str, str.size);
}
////////////////////////////////
@@ -2822,76 +3008,242 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out)
return block_out->size;
}
internal U64
str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte = 0;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
internal U64
str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
{
value |= -(S64)(1ull << shift);
}
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
////////////////////////////////
internal int
force_inline int
str8_compar(String8 a, String8 b, B32 ignore_case)
{
int cmp = 0;
U64 size = Min(a.size, b.size);
if (ignore_case) {
for (U64 i = 0; i < size; ++i) {
U8 la = lower_from_char(a.str[i]);
U8 lb = lower_from_char(b.str[i]);
if (la < lb) {
cmp = -1;
break;
} else if (la > lb) {
cmp = +1;
break;
}
}
} else {
for (U64 i = 0; i < size; ++i) {
if (a.str[i] < b.str[i]) {
cmp = -1;
break;
} else if (a.str[i] > b.str[i]) {
cmp = +1;
break;
}
}
}
int cmp = ignore_case ? MemCompareI(a.str, b.str, size) : MemCompare(a.str, b.str, size);
// normalize compar result
cmp = cmp > 0 ? 1 : cmp < 0 ? -1 : 0;
if (cmp == 0) {
// shorter prefix must precede longer prefixes
if (a.size > b.size) {
cmp = +1;
} else if (b.size > a.size) {
cmp = -1;
}
if (cmp == 0)
{
cmp = a.size < b.size ? -1 :
a.size > b.size ? +1 : 0;
}
return cmp;
}
internal int str8_compar_ignore_case(const void *a, const void *b)
force_inline int
str8_compar_ignore_case(const void *a, const void *b)
{
return str8_compar(*(String8*)a, *(String8*)b, 1);
}
internal int
force_inline int
str8_compar_case_sensitive(const void *a, const void *b)
{
return str8_compar(*(String8*)a, *(String8*)b, 0);
}
internal int
force_inline int
str8_is_before_case_sensitive(const void *a, const void *b)
{
int cmp = str8_compar_case_sensitive(a, b);
return cmp < 0;
}
////////////////////////////////
// string buffer
internal B32
str8_buffer_skip(String8Node *buf, U64 *pos, U64 skip)
{
S64 to_skip;
for (to_skip = skip; to_skip > 0;) {
if (buf == 0) { break; }
U64 left = Min(to_skip, buf->string.size - *pos);
*pos += left;
if (*pos == buf->string.size) {
if (buf->next) { *buf = *buf->next; }
else { *buf = (String8Node){0}; buf = 0; }
*pos = 0;
}
to_skip -= (S64)left;
}
Assert(to_skip == 0);
return (to_skip == 0);
}
internal U64
str8_buffer_read(String8Node *buf, U64 *pos, U64 read_size, void *out)
{
U64 cursor = 0;
for (; cursor < read_size ;) {
if (buf == 0) { break; }
U64 copy_size = Min(read_size - cursor, (buf->string.size - *pos));
void *dst = (U8 *)out + cursor;
void *src = buf->string.str + *pos;
MemoryCopy(dst, src, copy_size);
*pos += copy_size;
cursor += copy_size;
if (*pos >= buf->string.size) {
if (buf->next) { *buf = *buf->next; }
else { *buf = (String8Node){0}; buf = 0; }
*pos = 0;
}
}
return cursor;
}
internal U64
str8_buffer_peek(String8Node *buf, U64 *pos, U64 read_size, void *out)
{
String8Node buf_copy = *buf;
U64 pos_copy = *pos;
return str8_buffer_read(&buf_copy, &pos_copy, read_size, out);
}
internal U64
str8_buffer_write(String8Node *buf, U64 *pos, String8 data)
{
U64 copy_size = 0;
if (buf) {
for (copy_size = 0; copy_size < data.size; ) {
U64 data_size = data.size - copy_size;
U64 available_size = buf->string.size - *pos;
U64 to_copy = Min(available_size, data_size);
if (data.str == 0) {
MemorySet(buf->string.str + *pos, 0, to_copy);
} else {
U8 *data_ptr = data.str + copy_size;
MemoryCopy(buf->string.str + *pos, data_ptr, to_copy);
}
*pos += to_copy;
copy_size += to_copy;
if (*pos >= buf->string.size) {
if (buf->next) {
*buf = *buf->next;
*pos = 0;
} else {
break;
}
}
}
Assert(copy_size == data.size);
} else {
copy_size = data.size;
}
return copy_size;
}
internal U64
str8_buffer_write_u16(String8Node *buf, U64 *pos, U16 v)
{
return str8_buffer_write(buf, pos, str8_struct(&v));
}
internal U64
str8_buffer_write_u32(String8Node *buf, U64 *pos, U32 v)
{
return str8_buffer_write(buf, pos, str8_struct(&v));
}
internal U64
str8_buffer_write_zeroes(String8Node *buf, U64 *pos, U64 size)
{
return str8_buffer_write(buf, pos, str8(0, size));
}
internal U64
str8_buffer_write_string_list(String8Node *buf, U64 *pos, String8List list)
{
U64 copy_size = 0;
for EachNode(n, String8Node, list.first) { copy_size += str8_buffer_write(buf, pos, n->string); }
return copy_size;
}
////////////////////////////////
//~ rjf: Basic String Hashes
#pragma push_macro("__cpuid")
#undef __cpuid
#if !defined(XXH_IMPLEMENTATION)
# define XXH_INLINE_ALL
# define XXH_IMPLEMENTATION
# define XXH_STATIC_LINKING_ONLY
# include "third_party/xxHash/xxhash.h"
#endif
#pragma pop_macro("__cpuid")
internal U64
u64_hash_from_seed_str8(U64 seed, String8 string)
+33 -8
View File
@@ -160,8 +160,11 @@ internal U64 cstring32_length(U32 *c);
////////////////////////////////
//~ rjf: String Constructors
#define s(S) str8_lit(S)
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
#define str8_lit_cstr(S) str8((U8*)(S), sizeof(S))
#define str8_varg(S) (int)((S).size), ((S).str)
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
@@ -182,7 +185,6 @@ internal String16 str16_cstring(U16 *c);
internal String32 str32_cstring(U32 *c);
internal String8 str8_cstring_capped(void *cstr, void *cap);
internal String16 str16_cstring_capped(void *cstr, void *cap);
internal String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
////////////////////////////////
//~ rjf: String Stylization
@@ -197,6 +199,10 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
#define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags))
#define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags))
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
#define str8_matchi(a, b) str8_match(a, b, StringMatchFlag_CaseInsensitive)
internal B32 str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags);
internal B32 str8_starts_with(String8 string, String8 expected_prefix);
internal B32 str8_starts_withi(String8 string, String8 expected_prefix);
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal B32 str8_is_before(String8 a, String8 b);
@@ -210,6 +216,7 @@ internal String8 str8_prefix(String8 str, U64 size);
internal String8 str8_skip(String8 str, U64 amt);
internal String8 str8_postfix(String8 str, U64 size);
internal String8 str8_chop(String8 str, U64 amt);
internal String8 str8_chop_line(String8 *str);
internal String8 str8_skip_chop_whitespace(String8 string);
internal String8 str8_skip_chop_slashes(String8 string);
@@ -233,6 +240,7 @@ internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unn
//- rjf: string -> integer
internal S64 sign_from_str8(String8 string, String8 *string_tail);
internal B32 str8_is_integer(String8 string, U32 radix);
internal B32 str8_is_integer_signed(String8 string, U32 radix);
internal U64 u64_from_str8(String8 string, U32 radix);
internal S64 s64_from_str8(String8 string, U32 radix);
internal U32 u32_from_str8(String8 string, U32 radix);
@@ -266,7 +274,9 @@ internal void str8_list_concat_in_place(String8List *list, String8List *
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
internal String8Node* str8_list_pop_front(String8List *list);
internal String8List str8_list_copy(Arena *arena, String8List *list);
internal String8List str8_list_substr(Arena *arena, String8List list, Rng1U64 range);
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
////////////////////////////////
@@ -312,6 +322,8 @@ g_path_style_map[] =
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
};
internal String8 program_ext_postfix_from_os(OperatingSystem os, B32 require_ext);
internal String8 str8_chop_last_slash(String8 string);
internal String8 str8_skip_last_slash(String8 string);
internal String8 str8_chop_last_dot(String8 string);
@@ -422,13 +434,12 @@ internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 alig
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
internal void * str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
internal void * str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
internal void * str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
internal void * str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
internal void * str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
internal void * str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
@@ -443,6 +454,20 @@ internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 of
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
////////////////////////////////
//~ string buffer
internal B32 str8_buffer_skip(String8Node *buf, U64 *pos, U64 skip);
internal U64 str8_buffer_read(String8Node *buf, U64 *pos, U64 read_size, void *out);
internal U64 str8_buffer_peek(String8Node *buf, U64 *pos, U64 read_size, void *out);
internal U64 str8_buffer_write(String8Node *buf, U64 *pos, String8 data);
internal U64 str8_buffer_write_u16(String8Node *buf, U64 *pos, U16 v);
internal U64 str8_buffer_write_u32(String8Node *buf, U64 *pos, U32 v);
internal U64 str8_buffer_write_zeroes(String8Node *buf, U64 *pos, U64 size);
internal U64 str8_buffer_write_string_list(String8Node *buf, U64 *pos, String8List list);
////////////////////////////////
//~ rjf: Basic String Hashes
+2
View File
@@ -0,0 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_SYSTEM_H
#define BASE_SYSTEM_H
typedef struct SystemInfo SystemInfo;
struct SystemInfo
{
U32 logical_processor_count;
U64 page_size;
U64 large_page_size;
U64 allocation_granularity;
String8 machine_name;
};
////////////////////////////////
//~ rjf: @per_os_impl System Info
internal SystemInfo *get_system_info(void);
#endif // BASE_SYSTEM_H
+51
View File
@@ -0,0 +1,51 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if BUILD_TESTS
internal String8
test_build_exe_path(Arena *arena, String8 name)
{
String8 folder = get_process_info()->binary_path;
String8 path = str8f(arena, "%S/%S%S", folder, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 0));
return path;
}
internal String8
test_input_path(Arena *arena, TestCtx *ctx, String8 name)
{
String8 path = str8f(arena, "%S/%S", ctx->input_data_path, name);
return path;
}
internal String8
test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name)
{
String8 path = str8f(arena, "%S/%S%S", ctx->input_data_path, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 1));
return path;
}
internal String8
test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name)
{
String8 path = str8f(arena, "%S/%S", ctx->exemplars_path, name);
return path;
}
internal void
base_register_test(char *func_name_cstr, TestFunctionType *fn, char *file_path_cstr, int line, int skip)
{
String8 file_path = str8_cstring(file_path_cstr);
U64 src_min = str8_find_needle(file_path, 0, s("src/"), StringMatchFlag_SlashInsensitive);
U64 src_max = src_min + str8_lit("src/").size;
U64 layer_slash_max = str8_find_needle(file_path, src_max, s("/"), StringMatchFlag_SlashInsensitive);
TestInfo *t = &test_infos[test_infos_count++];
t->layer = str8_substr(file_path, r1u64(src_max, layer_slash_max));
t->label = str8_cstring(func_name_cstr);
t->decl_line = line;
t->skip = skip;
t->test_fn = fn;
}
#endif
+101
View File
@@ -0,0 +1,101 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_TEST_H
#define BASE_TEST_H
typedef enum TestStatus
{
TestStatus_Fail,
TestStatus_Crash,
TestStatus_Pass,
TestStatus_Skip,
TestStatus_COUNT
}
TestStatus;
typedef struct TestResult TestResult;
struct TestResult
{
TestStatus status;
char *fail_file;
int fail_line;
char *fail_cond;
};
typedef struct TestCtx TestCtx;
struct TestCtx
{
CmdLine *cmdline;
String8 exemplars_path;
String8 artifacts_path;
String8 input_data_path;
TestResult *result_out;
String8List *test_out;
};
#define TEST_FUNCTION_SIG(name) void name(Arena *arena, TestCtx *ctx)
#define TEST_FUNCTION_DEF(name) TEST_FUNCTION_SIG(test__##name)
typedef TEST_FUNCTION_SIG(TestFunctionType);
typedef struct TestInfo TestInfo;
struct TestInfo
{
String8 layer;
String8 label;
S64 decl_line;
B32 skip;
TestFunctionType *test_fn;
};
#if BUILD_TESTS
// alloc storage for the tests
global U16 test_infos_count = 0;
global TestInfo test_infos[0xffff] = {0};
internal String8 test_build_exe_path(Arena *arena, String8 name);
internal String8 test_input_path(Arena *arena, TestCtx *ctx, String8 name);
internal String8 test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name);
internal String8 test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name);
internal void base_register_test(char *func_name, TestFunctionType *fn, char *file_path, int line, int skip);
#define AddTest(name, file_path, line, skip_, ...) \
TEST_FUNCTION_DEF(name); \
__VA_ARGS__ void add_test__##name(void) { base_register_test(Stringify(name), test__##name, file_path, line, skip_); }
# if COMPILER_MSVC
# pragma section(".CRT$XCU", read)
# define DeclareTest(name, skip) \
/* register test */ AddTest(name, __FILE__, __LINE__, (skip)) \
/* alloc function pointer */ __declspec(allocate(".CRT$XCU")) void (*add_test_ptr__##name)(void) = add_test__##name; \
/* do not GC test caller */ __pragma(comment(linker, "/include:" Stringify(add_test_ptr__##name)))
# elif COMPILER_GCC || COMPILER_CLANG
// clang and gcc allocate memory for the function pointer automatically
# define DeclareTest(name, skip) AddTest(name, __FILE__, __LINE__, (skip), __attribute__((constructor)))
# else
# error DeclareTest not defined for this compiler.
# endif
#else
# define DeclareTest(name, skip)
#endif
#define Test(name) DeclareTest(name, 0) TEST_FUNCTION_DEF(name)
#define SkippedTest(name) DeclareTest(name, 1) TEST_FUNCTION_DEF(name)
#define TestCheck(c) do { if (!(c)) { \
/* record failed check */ ctx->result_out[0] = (TestResult){ .fail_file = __FILE__, .fail_line = __LINE__, .fail_cond = Stringify(c) }; \
/* under debugger? -> trap */ if(debugger_is_attached()) { Trap(); } \
/* exit test */ return; \
} } while(0)
#define TestSkip() do { \
ctx->result_out[0] = (TestResult){ .status = TestStatus_Skip }; \
return; \
} while(0)
// test log
#define test_out(string) str8_list_push(arena, ctx->test_out, (string))
#define test_outf(...) str8_list_pushf(arena, ctx->test_out, __VA_ARGS__)
#endif // BASE_TEST_H
+17 -8
View File
@@ -17,10 +17,19 @@ C_LINKAGE thread_static TCTX *tctx_thread_local = 0;
internal TCTX *
tctx_alloc(void)
{
Arena *arena = arena_alloc();
TCTX *tctx = push_array(arena, TCTX, 1);
tctx->arenas[0] = arena;
tctx->arenas[1] = arena_alloc();
#if PROFILE_TELEMETRY
thread_static static char name[2][1024];
raddbg_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", tid());
raddbg_snprintf(name[1], sizeof(name[1]), "Scratch/1[TID:%u]", tid());
Arena *arena_0 = arena_alloc(.name = name[0]);
Arena *arena_1 = arena_alloc(.name = name[1]);
#else
Arena *arena_0 = arena_alloc();
Arena *arena_1 = arena_alloc();
#endif
TCTX *tctx = push_array(arena_0, TCTX, 1);
tctx->arenas[0] = arena_0;
tctx->arenas[1] = arena_1;
tctx->lane_ctx.lane_count = 1;
return tctx;
}
@@ -99,7 +108,7 @@ tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_sr
}
// rjf: all cases: barrier
os_barrier_wait(tctx->lane_ctx.barrier);
barrier_wait(tctx->lane_ctx.barrier);
// rjf: doing broadcast -> copy from broadcast memory on destination lanes
if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx)
@@ -110,7 +119,7 @@ tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_sr
// rjf: doing broadcast -> barrier on all lanes
if(broadcast_ptr != 0)
{
os_barrier_wait(tctx->lane_ctx.barrier);
barrier_wait(tctx->lane_ctx.barrier);
}
ProfEnd();
@@ -193,7 +202,7 @@ internal void
access_touch(Access *access, AccessPt *pt, CondVar cv)
{
ins_atomic_u64_inc_eval(&pt->access_refcount);
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, os_now_microseconds());
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, now_time_us());
ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx());
Touch *touch = tctx_thread_local->free_touch;
if(touch != 0)
@@ -219,7 +228,7 @@ access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params)
U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us);
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
B32 result = (access_refcount == 0 &&
last_time_touched_us + params->time <= os_now_microseconds() &&
last_time_touched_us + params->time <= now_time_us() &&
last_update_idx_touched + params->update_idxs <= update_tick_idx());
return result;
}
+167 -65
View File
@@ -1,70 +1,6 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Thread Functions
internal Thread
thread_launch(ThreadEntryPointFunctionType *f, void *p)
{
Thread thread = os_thread_launch(f, p);
return thread;
}
internal B32
thread_join(Thread thread, U64 endt_us)
{
B32 result = os_thread_join(thread, endt_us);
return result;
}
internal void
thread_detach(Thread thread)
{
os_thread_detach(thread);
}
////////////////////////////////
//~ rjf: Synchronization Primitive Functions
//- rjf: recursive mutexes
internal Mutex mutex_alloc(void) {return os_mutex_alloc();}
internal void mutex_release(Mutex mutex) {os_mutex_release(mutex);}
internal void mutex_take(Mutex mutex) {os_mutex_take(mutex);}
internal void mutex_drop(Mutex mutex) {os_mutex_drop(mutex);}
//- rjf: reader/writer mutexes
internal RWMutex rw_mutex_alloc(void) {return os_rw_mutex_alloc();}
internal void rw_mutex_release(RWMutex mutex) {os_rw_mutex_release(mutex);}
internal void rw_mutex_take(RWMutex mutex, B32 write_mode) {os_rw_mutex_take(mutex, write_mode);}
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode) {os_rw_mutex_drop(mutex, write_mode);}
//- rjf: condition variables
internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();}
internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);}
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);}
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) {return os_cond_var_wait_rw(cv, mutex_rw, write_mode, endt_us);}
internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);}
internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);}
//- rjf: cross-process semaphores
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name) {return os_semaphore_alloc(initial_count, max_count, name);}
internal void semaphore_release(Semaphore semaphore) {os_semaphore_release(semaphore);}
internal Semaphore semaphore_open(String8 name) {return os_semaphore_open(name);}
internal void semaphore_close(Semaphore semaphore) {os_semaphore_close(semaphore);}
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us) {return os_semaphore_take(semaphore, endt_us);}
internal void semaphore_drop(Semaphore semaphore) {os_semaphore_drop(semaphore);}
//- rjf: barriers
internal Barrier barrier_alloc(U64 count) {return os_barrier_alloc(count);}
internal void barrier_release(Barrier barrier) {os_barrier_release(barrier);}
internal void barrier_wait(Barrier barrier) {os_barrier_wait(barrier);}
////////////////////////////////
//~ rjf: Table Stripe Functions
@@ -72,7 +8,7 @@ internal StripeArray
stripe_array_alloc(Arena *arena)
{
StripeArray array = {0};
array.count = os_get_system_info()->logical_processor_count;
array.count = get_system_info()->logical_processor_count;
array.v = push_array(arena, Stripe, array.count);
for EachIndex(idx, array.count)
{
@@ -100,3 +36,169 @@ stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx)
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
return stripe;
}
////////////////////////////////
//~ rjf: Thread Info Helpers
internal void
set_thread_name(String8 string)
{
ProfThreadName("%.*s", str8_varg(string));
set_platform_thread_name(string);
}
internal void
set_thread_namef(char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
set_thread_name(string);
va_end(args);
scratch_end(scratch);
}
////////////////////////////////
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
//- rjf: slow barriers
typedef struct BarrierNode BarrierNode;
struct BarrierNode
{
BarrierNode *next;
U64 count;
U64 threads_left_to_enter;
U64 threads_left_to_leave;
RWMutex rw_mutex;
CondVar cv;
};
typedef struct BarrierTCTX BarrierTCTX;
struct BarrierTCTX
{
Arena *arena;
BarrierNode *free_barrier_node;
};
thread_static BarrierTCTX *barrier_tctx = 0;
internal Barrier
slow_barrier_alloc(U64 count)
{
if(barrier_tctx == 0)
{
Arena *arena = arena_alloc();
barrier_tctx = push_array(arena, BarrierTCTX, 1);
barrier_tctx->arena = arena;
}
BarrierNode *n = barrier_tctx->free_barrier_node;
if(n != 0)
{
SLLStackPop(barrier_tctx->free_barrier_node);
}
else
{
n = push_array_no_zero(barrier_tctx->arena, BarrierNode, 1);
}
MemoryZeroStruct(n);
n->count = count;
n->threads_left_to_enter = count;
n->rw_mutex = rw_mutex_alloc();
n->cv = cond_var_alloc();
Barrier result = {(U64)n};
return result;
}
internal void
slow_barrier_release(Barrier barrier)
{
if(barrier_tctx == 0)
{
Arena *arena = arena_alloc();
barrier_tctx = push_array(arena, BarrierTCTX, 1);
barrier_tctx->arena = arena;
}
BarrierNode *n = (BarrierNode *)barrier.u64[0];
rw_mutex_release(n->rw_mutex);
cond_var_release(n->cv);
SLLStackPush(barrier_tctx->free_barrier_node, n);
}
internal void
slow_barrier_wait(Barrier barrier)
{
ProfBeginFunction();
BarrierNode *n = (BarrierNode *)barrier.u64[0];
U64 threads_left_to_enter = ins_atomic_u64_dec_eval(&n->threads_left_to_enter);
//- rjf: threads left to enter > 0 => wait
if(threads_left_to_enter > 0)
{
// rjf: first try a spin loop
B32 done_waiting = 0;
ProfScope("spin loop wait") for(U64 spin_count = 0; spin_count < 10000; spin_count += 1)
{
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
{
done_waiting = 1;
break;
}
}
// rjf: not done waiting -> need to do slow wait on condition variable
if(!done_waiting) ProfScope("slow wait")
{
RWMutexScope(n->rw_mutex, 0) for(;;)
{
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
{
break;
}
cond_var_wait_rw(n->cv, n->rw_mutex, 0, max_U64);
}
}
// rjf: decrement leave counter
if(ins_atomic_u64_dec_eval(&n->threads_left_to_leave) > 0)
{
ProfScope("signal") cond_var_signal(n->cv);
}
}
//- rjf: threads left to enter == 0 -> last thread, wakeup
else
{
ins_atomic_u64_eval_assign(&n->threads_left_to_enter, n->count);
ProfScope("wake up") RWMutexScope(n->rw_mutex, 1)
{
ins_atomic_u64_eval_assign(&n->threads_left_to_leave, n->count-1);
}
ProfScope("signal") cond_var_signal(n->cv);
}
//- rjf: wait for threads left to leave == 0
ProfScope("wait for threads to leave")
{
for(U64 spin_count = 0;; spin_count += 1)
{
if(ins_atomic_u64_eval(&n->threads_left_to_leave) == 0)
{
break;
}
}
}
ProfEnd();
}
////////////////////////////////
///~ Semaphore
internal void
semaphore_drop(Semaphore semaphore)
{
semaphore_drop_count(semaphore, 1);
}
+32 -6
View File
@@ -67,14 +67,33 @@ struct StripeArray
};
////////////////////////////////
//~ rjf: Thread Functions
//~ rjf: Table Stripe Functions
internal StripeArray stripe_array_alloc(Arena *arena);
internal void stripe_array_release(StripeArray *stripes);
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
////////////////////////////////
//~ rjf: Thread Info Helpers
internal void set_thread_name(String8 string);
internal void set_thread_namef(char *fmt, ...);
////////////////////////////////
//~ rjf: @per_os_impl Current Thread Info
internal U32 tid(void);
internal void set_platform_thread_name(String8 name);
////////////////////////////////
//~ rjf: @per_os_impl Thread Functions
internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
internal B32 thread_join(Thread thread, U64 endt_us);
internal void thread_detach(Thread thread);
////////////////////////////////
//~ rjf: Synchronization Primitive Functions
//~ rjf: @per_os_impl Synchronization Primitive Functions
//- rjf: recursive mutexes
internal Mutex mutex_alloc(void);
@@ -110,6 +129,7 @@ internal Semaphore semaphore_open(String8 name);
internal void semaphore_close(Semaphore semaphore);
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
internal void semaphore_drop(Semaphore semaphore);
internal void semaphore_drop_count(Semaphore semaphore, U64 drop_count);
//- rjf: barriers
internal Barrier barrier_alloc(U64 count);
@@ -124,10 +144,16 @@ internal void barrier_wait(Barrier barrier);
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
////////////////////////////////
//~ rjf: Table Stripe Functions
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
internal StripeArray stripe_array_alloc(Arena *arena);
internal void stripe_array_release(StripeArray *stripes);
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
//- rjf: slow barriers
internal Barrier slow_barrier_alloc(U64 count);
internal void slow_barrier_release(Barrier barrier);
internal void slow_barrier_wait(Barrier barrier);
////////////////////////////////
//~ rjf: @per_os_impl Safe Calls
internal void safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr);
#endif // BASE_THREADS_H
+340
View File
@@ -0,0 +1,340 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
Test(str8_list_substr)
{
String8List zero_list = {0};
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "b");
str8_list_pushf(arena, &list, "c");
String8List sub = str8_list_substr(arena, list, r1u64(0, 3));
String8 result = str8_list_join(arena, &list, 0);
T_Ok(str8_match(result, str8_lit("abc"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "b");
str8_list_pushf(arena, &list, "c");
String8List sub = str8_list_substr(arena, list, r1u64(0, max_U64));
String8 result = str8_list_join(arena, &list, 0);
T_Ok(str8_match(result, str8_lit("abc"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "bcd");
String8List sub = str8_list_substr(arena, list, r1u64(2, 3));
String8 result = str8_list_join(arena, &sub, 0);
T_Ok(str8_match(result, str8_lit("c"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "bcd");
String8List sub = str8_list_substr(arena, list, r1u64(1, 2));
String8 result = str8_list_join(arena, &sub, 0);
T_Ok(str8_match(result, str8_lit("b"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "ab");
str8_list_pushf(arena, &list, "cd");
str8_list_pushf(arena, &list, "ef");
String8List sub = str8_list_substr(arena, list, r1u64(1, 5));
String8 result = str8_list_join(arena, &sub, 0);
T_Ok(str8_match(result, str8_lit("bcde"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "abc");
String8List zero = str8_list_substr(arena, list, r1u64(0, 0));
T_Ok(MemoryMatchStruct(&zero, &zero_list));
String8List out_of_bounds_range = str8_list_substr(arena, list, r1u64(max_U64/2, max_U64));
T_Ok(MemoryMatchStruct(&out_of_bounds_range, &zero_list));
}
}
TEST(bit_array)
{
for (U64 start=0; start<32*3; start++) {
for (U64 end=start; end<32*3; end++) {
U32 v[3] = { 0 };
for (U64 i=start; i<end; i++) {
v[i/32] |= 1 << (i%32);
}
for (U64 lo=0; lo<32*3; lo++) {
for (U64 hi=0; hi<32*3; hi++) {
U64 expected_idx = Min(hi, end) - 1;
B32 expected_r = hi <= start || lo >= end || lo >= hi || start >= end ? 0 : 1;
U64 idx = bit_array_scan_right_to_left32((U32Array){.v=v, .count=ArrayCount(v)}, lo, hi, 1);
B32 r = idx < hi;
T_Ok(r == expected_r);
if (r) {
T_Ok(idx == expected_idx);
}
}
}
}
}
}
TEST(count_digits)
{
T_Ok(count_digits_u64(0, 10) == 1);
T_Ok(count_digits_u64(99, 10) == 2);
T_Ok(count_digits_u64(999, 10) == 3);
T_Ok(count_digits_u64(9999, 10) == 4);
T_Ok(count_digits_u64(99999, 10) == 5);
T_Ok(count_digits_u64(999999, 10) == 6);
}
TEST(match_wildcard)
{
// empty strings
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit(""), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("**"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit(""), 0) == 0);
// exact
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("a"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), 0) == 0);
// ?
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("a?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?b"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("??"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a?c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("???"), 0) == 0);
// *
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("b*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("**"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a**c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*b*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*a*d*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abcd"), str8_lit("a*d"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abefcdgiescdfimde"), str8_lit("ab*cd?i*de"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("mississippi"), str8_lit("m*iss*ppi"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("aa"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("aa"), str8_lit("a"), 0) == 0);
// case insensitive
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), StringMatchFlag_CaseInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("FooBar"), str8_lit("foobar"), StringMatchFlag_CaseInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("Foobar"), str8_lit("foo*"), StringMatchFlag_CaseInsensitive) == 1);
// right side sloppy
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("ab"), StringMatchFlag_RightSideSloppy) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit(""), StringMatchFlag_RightSideSloppy) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("a"), StringMatchFlag_RightSideSloppy) == 0);
// slash insensitive
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), StringMatchFlag_SlashInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("a/b/c"), str8_lit("a\\*\\c"), StringMatchFlag_SlashInsensitive) == 1);
// combined
T_Ok(str8_match_wildcard(str8_lit("Ab\\Cde"), str8_lit("ab/*e"), StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*?*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*?*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("?*?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?*?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?*?"), 0) == 0);
}
TEST(hash_map)
{
{
HashMap hm = {0};
U64 test_count = 256;
for EachIndex(i, test_count) { hash_map_push_u64_u64(arena, &hm, i, i*2); }
// test tombstone reuse
for (U64 i = 10; i < test_count; ++i) {
HashMapNode *test_node = hash_map_search(&hm, hash_map_hasher(str8_struct(&i)), (HashMapKey){ .key_u64 = i }, hash_map_match_u64);
T_Ok(hash_map_purge_u64(&hm, i) == 1);
T_Ok(hash_map_push_u64_u64(arena, &hm, i, 10) == test_node);
}
// delete some items and after search them
for (U64 i = 0; i < 10; ++i) {
T_Ok(hash_map_purge_u64(&hm, i));
}
T_Ok(hm.tombstone_count == 10);
for (U64 i = 0; i < 10; ++i) {
T_Ok(hash_map_search_u64_raw(&hm, i) == 0);
}
// extract pairs and test sorting
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
sort_hash_map_key_value_u64(pairs, hm.count);
for (U64 i = 1; i < hm.count; ++i) {
T_Ok(pairs[i-1].key.key_u64 < pairs[i].key.key_u64);
}
// did purge put all the nodes on free list?
hash_map_purge(&hm);
U64 free_list_count = 0;
for (HashMapNode *n = hm.free_list; n != 0; n = n->next) { free_list_count += 1; }
T_Ok(free_list_count == test_count);
}
// test search through tombstones
{
HashMap hm = {0};
U64 hash = 12345;
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 1 }, .value = { .value_u64 = 10 } }, hash_map_match_u64);
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 2 }, .value = { .value_u64 = 20 } }, hash_map_match_u64);
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 3 }, .value = { .value_u64 = 30 } }, hash_map_match_u64);
T_Ok(hash_map_purge_u64(&hm, 1));
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 2 }, hash_map_match_u64)->v.value.value_u64 == 20);
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 3 }, hash_map_match_u64)->v.value.value_u64 == 30);
}
// interleaved purges
{
HashMap hm = {0};
for EachIndex(round, 100) {
for EachIndex(i, 256) { hash_map_push_u64_u64(arena, &hm, i, round); }
for (U64 i = 0; i < 256; i += 2) { hash_map_purge_u64(&hm, i); }
for (U64 i = 0; i < 256; i += 2) { hash_map_push_u64_u64(arena, &hm, i, round + 1); }
T_Ok(hm.count == 256);
T_Ok(hm.tombstone_count == 0);
}
for EachIndex(i, 100) {
T_Ok(hash_map_purge_u64(&hm, 123123123 + i) == 0);
}
}
// empty hash map test
{
HashMap hm = {0};
T_Ok(hash_map_search_u64_raw(&hm, 123) == 0);
T_Ok(hash_map_purge_u64(&hm, 123) == 0);
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
T_Ok(pairs == 0 || hm.count == 0);
hash_map_purge(&hm);
T_Ok(hm.count == 0);
T_Ok(hm.tombstone_count == 0);
}
// heavy collision
{
HashMap hm = {0};
U64 hash = 12345;
U64 count = 1024;
for EachIndex(i, count) {
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = i }, .value = { .value_u64 = i*3 } }, hash_map_match_u64);
}
for EachIndex(i, count) {
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = i }, hash_map_match_u64)->v.value.value_u64 == i*3);
}
}
// duplicate key test
{
HashMap hm = {0};
U64 a = 1;
U64 b = 2;
HashMapNode *n0 = hash_map_push_u64_u64(arena, &hm, 1, a);
HashMapNode *n1 = hash_map_push_u64_u64(arena, &hm, 1, b);
T_Ok(hm.count == 1);
T_Ok(n0 == n1);
U64 test = *hash_map_search_u64_u64(&hm, 1);
T_Ok(test != b);
}
// test paths
{
HashMap hm = {0};
U64 foo = 0;
U64 bar = 1;
hash_map_push_path_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
hash_map_push_path_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
hash_map_push_path_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
hash_map_push_path_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
hash_map_push_path_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
T_Ok(hm.count == 2);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:/devel/test")) == &foo);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:\\devel\\TEST")) == &foo);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/mnt/devel")) == &bar);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/MNT/DEVEL")) == &bar);
}
// test strings
{
HashMap hm = {0};
U64 foo = 0;
U64 bar = 1;
hash_map_push_string_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
hash_map_push_string_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
hash_map_push_string_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
hash_map_push_string_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
hash_map_push_string_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
T_Ok(hm.count == 5);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/DEVEL/test")) == &foo);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:\\DEVEL\\test")) == &foo);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/devel\\test")) == &foo);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/mnt/devel")) == &bar);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/MNT/devel")) == &bar);
}
}
-41
View File
@@ -47,7 +47,6 @@ cv_size_from_reg(CV_Arch arch, CV_Reg reg)
{
switch(arch)
{
case CV_Arch_8086: return cv_size_from_reg_x86(reg);
case CV_Arch_X64 : return cv_size_from_reg_x64(reg);
default: NotImplemented;
}
@@ -59,25 +58,12 @@ cv_is_reg_sp(CV_Arch arch, CV_Reg reg)
{
switch(arch)
{
case CV_Arch_8086: return reg == CV_Regx86_ESP;
case CV_Arch_X64: return reg == CV_Regx64_RSP;
default: NotImplemented;
}
return 0;
}
internal U64
cv_size_from_reg_x86(CV_Reg reg)
{
switch(reg)
{
#define X(NAME, CODE, RDI_NAME, BYTE_POS, BYTE_SIZE) case CV_Regx86_##NAME: return BYTE_SIZE;
CV_Reg_X86_XList(X)
#undef X
}
return 0;
}
internal U64
cv_size_from_reg_x64(CV_Reg reg)
{
@@ -111,18 +97,6 @@ cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg)
CV_Reg fp_reg = 0;
switch (arch)
{
case CV_Arch_8086:
{
switch (encoded_reg)
{
case CV_EncodedFramePtrReg_None : break;
case CV_EncodedFramePtrReg_StackPtr: AssertAlways(!"TODO: not tested, this is a guess");
fp_reg = CV_Regx86_ESP; break;
case CV_EncodedFramePtrReg_FramePtr: fp_reg = CV_Regx86_EBP; break;
case CV_EncodedFramePtrReg_BasePtr : fp_reg = CV_Regx86_EBX; break;
default: InvalidPath;
}
} break;
case CV_Arch_X64:
{
switch (encoded_reg)
@@ -144,14 +118,6 @@ cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg)
{
U32 r = 0;
switch (arch) {
case CV_Arch_8086: {
switch (encoded_frame_reg) {
case 0: r = 0; break;
case 1: r = CV_AllReg_VFRAME; break;
case 2: r = CV_Regx86_EBP; break;
case 3: r = CV_Regx86_EBX; break;
}
} break;
case CV_Arch_X64: {
switch (encoded_frame_reg) {
case 0: r = 0; break;
@@ -207,13 +173,6 @@ cv_string_from_reg_id(Arena *arena, CV_Arch arch, U32 id)
{
String8 result = str8_zero();
switch (arch) {
case CV_Arch_8086: {
switch (id) {
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
CV_Reg_X86_XList(X)
#undef X
}
} break;
case CV_Arch_X64: {
switch (id) {
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
+29 -282
View File
@@ -33,7 +33,7 @@ read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF;
////////////////////////////////
//~ Aligns
#define CV_LeafAlign 4
#define CV_LeafAlign 1
#define CV_SymbolAlign 1
#define CV_C13SubSectionAlign 4
#define CV_FileCheckSumsAlign 4
@@ -41,261 +41,6 @@ read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF;
////////////////////////////////
//~ rjf: Registers
// X(NAME, CODE, (RDI_RegCode_X86) NAME, BYTE_POS, BYTE_SIZE)
#define CV_Reg_X86_XList(X) \
X(NONE, 0, nil, 0, 0) \
X(AL, 1, eax, 0, 1) \
X(CL, 2, ecx, 0, 1) \
X(DL, 3, edx, 0, 1) \
X(BL, 4, ebx, 0, 1) \
X(AH, 5, eax, 1, 1) \
X(CH, 6, ecx, 1, 1) \
X(DH, 7, edx, 1, 1) \
X(BH, 8, ebx, 1, 1) \
X(AX, 9, eax, 0, 2) \
X(CX, 10, ecx, 0, 2) \
X(DX, 11, edx, 0, 2) \
X(BX, 12, ebx, 0, 2) \
X(SP, 13, esp, 0, 2) \
X(BP, 14, ebp, 0, 2) \
X(SI, 15, esi, 0, 2) \
X(DI, 16, edi, 0, 2) \
X(EAX, 17, eax, 0, 4) \
X(ECX, 18, ecx, 0, 4) \
X(EDX, 19, edx, 0, 4) \
X(EBX, 20, ebx, 0, 4) \
X(ESP, 21, esp, 0, 4) \
X(EBP, 22, ebp, 0, 4) \
X(ESI, 23, esi, 0, 4) \
X(EDI, 24, edi, 0, 4) \
X(ES, 25, es, 0, 2) \
X(CS, 26, cs, 0, 2) \
X(SS, 27, ss, 0, 2) \
X(DS, 28, ds, 0, 2) \
X(FS, 29, fs, 0, 2) \
X(GS, 30, gs, 0, 2) \
X(IP, 31, eip, 0, 2) \
X(FLAGS, 32, eflags, 0, 2) \
X(EIP, 33, eip, 0, 4) \
X(EFLAGS, 34, eflags, 0, 4) \
X(MM0, 146, fpr0, 0, 8) \
X(MM1, 147, fpr1, 0, 8) \
X(MM2, 148, fpr2, 0, 8) \
X(MM3, 149, fpr3, 0, 8) \
X(MM4, 150, fpr4, 0, 8) \
X(MM5, 151, fpr5, 0, 8) \
X(MM6, 152, fpr6, 0, 8) \
X(MM7, 153, fpr7, 0, 8) \
X(XMM0, 154, ymm0, 0, 16) \
X(XMM1, 155, ymm1, 0, 16) \
X(XMM2, 156, ymm2, 0, 16) \
X(XMM3, 157, ymm3, 0, 16) \
X(XMM4, 158, ymm4, 0, 16) \
X(XMM5, 159, ymm5, 0, 16) \
X(XMM6, 160, ymm6, 0, 16) \
X(XMM7, 161, ymm7, 0, 16) \
X(XMM00, 162, ymm0, 0, 4) \
X(XMM01, 163, ymm0, 4, 4) \
X(XMM02, 164, ymm0, 8, 4) \
X(XMM03, 165, ymm0, 12, 4) \
X(XMM10, 166, ymm1, 0, 4) \
X(XMM11, 167, ymm1, 4, 4) \
X(XMM12, 168, ymm1, 8, 4) \
X(XMM13, 169, ymm1, 12, 4) \
X(XMM20, 170, ymm2, 0, 4) \
X(XMM21, 171, ymm2, 4, 4) \
X(XMM22, 172, ymm2, 8, 4) \
X(XMM23, 173, ymm2, 12, 4) \
X(XMM30, 174, ymm3, 0, 4) \
X(XMM31, 175, ymm3, 4, 4) \
X(XMM32, 176, ymm3, 8, 4) \
X(XMM33, 177, ymm3, 12, 4) \
X(XMM40, 178, ymm4, 0, 4) \
X(XMM41, 179, ymm4, 4, 4) \
X(XMM42, 180, ymm4, 8, 4) \
X(XMM43, 181, ymm4, 12, 4) \
X(XMM50, 182, ymm5, 0, 4) \
X(XMM51, 183, ymm5, 4, 4) \
X(XMM52, 184, ymm5, 8, 4) \
X(XMM53, 185, ymm5, 12, 4) \
X(XMM60, 186, ymm6, 0, 4) \
X(XMM61, 187, ymm6, 4, 4) \
X(XMM62, 188, ymm6, 8, 4) \
X(XMM63, 189, ymm6, 12, 4) \
X(XMM70, 190, ymm7, 0, 4) \
X(XMM71, 191, ymm7, 4, 4) \
X(XMM72, 192, ymm7, 8, 4) \
X(XMM73, 193, ymm7, 12, 4) \
X(XMM0L, 194, ymm0, 0, 8) \
X(XMM1L, 195, ymm1, 0, 8) \
X(XMM2L, 196, ymm2, 0, 8) \
X(XMM3L, 197, ymm3, 0, 8) \
X(XMM4L, 198, ymm4, 0, 8) \
X(XMM5L, 199, ymm5, 0, 8) \
X(XMM6L, 200, ymm6, 0, 8) \
X(XMM7L, 201, ymm7, 0, 8) \
X(XMM0H, 202, ymm0, 8, 8) \
X(XMM1H, 203, ymm1, 8, 8) \
X(XMM2H, 204, ymm2, 8, 8) \
X(XMM3H, 205, ymm3, 8, 8) \
X(XMM4H, 206, ymm4, 8, 8) \
X(XMM5H, 207, ymm5, 8, 8) \
X(XMM6H, 208, ymm6, 8, 8) \
X(XMM7H, 209, ymm7, 8, 8) \
X(YMM0, 252, ymm0, 0, 32) \
X(YMM1, 253, ymm1, 0, 32) \
X(YMM2, 254, ymm2, 0, 32) \
X(YMM3, 255, ymm3, 0, 32) \
X(YMM4, 256, ymm4, 0, 32) \
X(YMM5, 257, ymm5, 0, 32) \
X(YMM6, 258, ymm6, 0, 32) \
X(YMM7, 259, ymm7, 0, 32) \
X(YMM0H, 260, ymm0, 16, 16) \
X(YMM1H, 261, ymm1, 16, 16) \
X(YMM2H, 262, ymm2, 16, 16) \
X(YMM3H, 263, ymm3, 16, 16) \
X(YMM4H, 264, ymm4, 16, 16) \
X(YMM5H, 265, ymm5, 16, 16) \
X(YMM6H, 266, ymm6, 16, 16) \
X(YMM7H, 267, ymm7, 16, 16) \
X(YMM0I0, 268, ymm0, 0, 8) \
X(YMM0I1, 269, ymm0, 8, 8) \
X(YMM0I2, 270, ymm0, 16, 8) \
X(YMM0I3, 271, ymm0, 24, 8) \
X(YMM1I0, 272, ymm1, 0, 8) \
X(YMM1I1, 273, ymm1, 8, 8) \
X(YMM1I2, 274, ymm1, 16, 8) \
X(YMM1I3, 275, ymm1, 24, 8) \
X(YMM2I0, 276, ymm2, 0, 8) \
X(YMM2I1, 277, ymm2, 8, 8) \
X(YMM2I2, 278, ymm2, 16, 8) \
X(YMM2I3, 279, ymm2, 24, 8) \
X(YMM3I0, 280, ymm3, 0, 8) \
X(YMM3I1, 281, ymm3, 8, 8) \
X(YMM3I2, 282, ymm3, 16, 8) \
X(YMM3I3, 283, ymm3, 24, 8) \
X(YMM4I0, 284, ymm4, 0, 8) \
X(YMM4I1, 285, ymm4, 8, 8) \
X(YMM4I2, 286, ymm4, 16, 8) \
X(YMM4I3, 287, ymm4, 24, 8) \
X(YMM5I0, 288, ymm5, 0, 8) \
X(YMM5I1, 289, ymm5, 8, 8) \
X(YMM5I2, 290, ymm5, 16, 8) \
X(YMM5I3, 291, ymm5, 24, 8) \
X(YMM6I0, 292, ymm6, 0, 8) \
X(YMM6I1, 293, ymm6, 8, 8) \
X(YMM6I2, 294, ymm6, 16, 8) \
X(YMM6I3, 295, ymm6, 24, 8) \
X(YMM7I0, 296, ymm7, 0, 8) \
X(YMM7I1, 297, ymm7, 8, 8) \
X(YMM7I2, 298, ymm7, 16, 8) \
X(YMM7I3, 299, ymm7, 24, 8) \
X(YMM0F0, 300, ymm0, 0, 4) \
X(YMM0F1, 301, ymm0, 4, 4) \
X(YMM0F2, 302, ymm0, 8, 4) \
X(YMM0F3, 303, ymm0, 12, 4) \
X(YMM0F4, 304, ymm0, 16, 4) \
X(YMM0F5, 305, ymm0, 20, 4) \
X(YMM0F6, 306, ymm0, 24, 4) \
X(YMM0F7, 307, ymm0, 28, 4) \
X(YMM1F0, 308, ymm1, 0, 4) \
X(YMM1F1, 309, ymm1, 4, 4) \
X(YMM1F2, 310, ymm1, 8, 4) \
X(YMM1F3, 311, ymm1, 12, 4) \
X(YMM1F4, 312, ymm1, 16, 4) \
X(YMM1F5, 313, ymm1, 20, 4) \
X(YMM1F6, 314, ymm1, 24, 4) \
X(YMM1F7, 315, ymm1, 28, 4) \
X(YMM2F0, 316, ymm2, 0, 4) \
X(YMM2F1, 317, ymm2, 4, 4) \
X(YMM2F2, 318, ymm2, 8, 4) \
X(YMM2F3, 319, ymm2, 12, 4) \
X(YMM2F4, 320, ymm2, 16, 4) \
X(YMM2F5, 321, ymm2, 20, 4) \
X(YMM2F6, 322, ymm2, 24, 4) \
X(YMM2F7, 323, ymm2, 28, 4) \
X(YMM3F0, 324, ymm3, 0, 4) \
X(YMM3F1, 325, ymm3, 4, 4) \
X(YMM3F2, 326, ymm3, 8, 4) \
X(YMM3F3, 327, ymm3, 12, 4) \
X(YMM3F4, 328, ymm3, 16, 4) \
X(YMM3F5, 329, ymm3, 20, 4) \
X(YMM3F6, 330, ymm3, 24, 4) \
X(YMM3F7, 331, ymm3, 28, 4) \
X(YMM4F0, 332, ymm4, 0, 4) \
X(YMM4F1, 333, ymm4, 4, 4) \
X(YMM4F2, 334, ymm4, 8, 4) \
X(YMM4F3, 335, ymm4, 12, 4) \
X(YMM4F4, 336, ymm4, 16, 4) \
X(YMM4F5, 337, ymm4, 20, 4) \
X(YMM4F6, 338, ymm4, 24, 4) \
X(YMM4F7, 339, ymm4, 28, 4) \
X(YMM5F0, 340, ymm5, 0, 4) \
X(YMM5F1, 341, ymm5, 4, 4) \
X(YMM5F2, 342, ymm5, 8, 4) \
X(YMM5F3, 343, ymm5, 12, 4) \
X(YMM5F4, 344, ymm5, 16, 4) \
X(YMM5F5, 345, ymm5, 20, 4) \
X(YMM5F6, 346, ymm5, 24, 4) \
X(YMM5F7, 347, ymm5, 28, 4) \
X(YMM6F0, 348, ymm6, 0, 4) \
X(YMM6F1, 349, ymm6, 4, 4) \
X(YMM6F2, 350, ymm6, 8, 4) \
X(YMM6F3, 351, ymm6, 12, 4) \
X(YMM6F4, 352, ymm6, 16, 4) \
X(YMM6F5, 353, ymm6, 20, 4) \
X(YMM6F6, 354, ymm6, 24, 4) \
X(YMM6F7, 355, ymm6, 28, 4) \
X(YMM7F0, 356, ymm7, 0, 4) \
X(YMM7F1, 357, ymm7, 4, 4) \
X(YMM7F2, 358, ymm7, 8, 4) \
X(YMM7F3, 359, ymm7, 12, 4) \
X(YMM7F4, 360, ymm7, 16, 4) \
X(YMM7F5, 361, ymm7, 20, 4) \
X(YMM7F6, 362, ymm7, 24, 4) \
X(YMM7F7, 363, ymm7, 28, 4) \
X(YMM0D0, 364, ymm0, 0, 8) \
X(YMM0D1, 365, ymm0, 8, 8) \
X(YMM0D2, 366, ymm0, 16, 8) \
X(YMM0D3, 367, ymm0, 24, 8) \
X(YMM1D0, 368, ymm1, 0, 8) \
X(YMM1D1, 369, ymm1, 8, 8) \
X(YMM1D2, 370, ymm1, 16, 8) \
X(YMM1D3, 371, ymm1, 24, 8) \
X(YMM2D0, 372, ymm2, 0, 8) \
X(YMM2D1, 373, ymm2, 8, 8) \
X(YMM2D2, 374, ymm2, 16, 8) \
X(YMM2D3, 375, ymm2, 24, 8) \
X(YMM3D0, 376, ymm3, 0, 8) \
X(YMM3D1, 377, ymm3, 8, 8) \
X(YMM3D2, 378, ymm3, 16, 8) \
X(YMM3D3, 379, ymm3, 24, 8) \
X(YMM4D0, 380, ymm4, 0, 8) \
X(YMM4D1, 381, ymm4, 8, 8) \
X(YMM4D2, 382, ymm4, 16, 8) \
X(YMM4D3, 383, ymm4, 24, 8) \
X(YMM5D0, 384, ymm5, 0, 8) \
X(YMM5D1, 385, ymm5, 8, 8) \
X(YMM5D2, 386, ymm5, 16, 8) \
X(YMM5D3, 387, ymm5, 24, 8) \
X(YMM6D0, 388, ymm6, 0, 8) \
X(YMM6D1, 389, ymm6, 8, 8) \
X(YMM6D2, 390, ymm6, 16, 8) \
X(YMM6D3, 391, ymm6, 24, 8) \
X(YMM7D0, 392, ymm7, 0, 8) \
X(YMM7D1, 393, ymm7, 8, 8) \
X(YMM7D2, 394, ymm7, 16, 8) \
X(YMM7D3, 395, ymm7, 24, 8)
typedef U16 CV_Regx86;
typedef enum CV_Regx86Enum
{
#define X(CVN,C,RDN,BP,BZ) CV_Regx86_##CVN = C,
CV_Reg_X86_XList(X)
#undef X
}
CV_Regx86Enum;
// X(NAME, CODE, (RDI_RegisterCode_X64) NAME, BYTE_POS, BYTE_SIZE)
#define CV_Reg_X64_XList(X) \
X(NONE, 0, nil, 0, 0) \
@@ -382,14 +127,14 @@ X(FPDS, 142, nil, 0, 0) \
X(ISEM, 143, nil, 0, 0) \
X(FPEIP, 144, nil, 0, 0) \
X(FPEDO, 145, nil, 0, 0) \
X(MM0, 146, fpr0, 0, 8) \
X(MM1, 147, fpr1, 0, 8) \
X(MM2, 148, fpr2, 0, 8) \
X(MM3, 149, fpr3, 0, 8) \
X(MM4, 150, fpr4, 0, 8) \
X(MM5, 151, fpr5, 0, 8) \
X(MM6, 152, fpr6, 0, 8) \
X(MM7, 153, fpr7, 0, 8) \
X(MM0, 146, st0, 0, 8) \
X(MM1, 147, st1, 0, 8) \
X(MM2, 148, st2, 0, 8) \
X(MM3, 149, st3, 0, 8) \
X(MM4, 150, st4, 0, 8) \
X(MM5, 151, st5, 0, 8) \
X(MM6, 152, st6, 0, 8) \
X(MM7, 153, st7, 0, 8) \
X(XMM0, 154, zmm0, 0, 16) \
X(XMM1, 155, zmm1, 0, 16) \
X(XMM2, 156, zmm2, 0, 16) \
@@ -463,22 +208,22 @@ X(EMM4H, 232, zmm4, 8, 8) \
X(EMM5H, 233, zmm5, 8, 8) \
X(EMM6H, 234, zmm6, 8, 8) \
X(EMM7H, 235, zmm7, 8, 8) \
X(MM00, 236, fpr0, 0, 4) \
X(MM01, 237, fpr0, 4, 4) \
X(MM10, 238, fpr1, 0, 4) \
X(MM11, 239, fpr1, 4, 4) \
X(MM20, 240, fpr2, 0, 4) \
X(MM21, 241, fpr2, 4, 4) \
X(MM30, 242, fpr3, 0, 4) \
X(MM31, 243, fpr3, 4, 4) \
X(MM40, 244, fpr4, 0, 4) \
X(MM41, 245, fpr4, 4, 4) \
X(MM50, 246, fpr5, 0, 4) \
X(MM51, 247, fpr5, 4, 4) \
X(MM60, 248, fpr6, 0, 4) \
X(MM61, 249, fpr6, 4, 4) \
X(MM70, 250, fpr7, 0, 4) \
X(MM71, 251, fpr7, 4, 4) \
X(MM00, 236, st0, 0, 4) \
X(MM01, 237, st0, 4, 4) \
X(MM10, 238, st1, 0, 4) \
X(MM11, 239, st1, 4, 4) \
X(MM20, 240, st2, 0, 4) \
X(MM21, 241, st2, 4, 4) \
X(MM30, 242, st3, 0, 4) \
X(MM31, 243, st3, 4, 4) \
X(MM40, 244, st4, 0, 4) \
X(MM41, 245, st4, 4, 4) \
X(MM50, 246, st5, 0, 4) \
X(MM51, 247, st5, 4, 4) \
X(MM60, 248, st6, 0, 4) \
X(MM61, 249, st6, 4, 4) \
X(MM70, 250, st7, 0, 4) \
X(MM71, 251, st7, 4, 4) \
X(XMM8, 252, zmm8, 0, 16) \
X(XMM9, 253, zmm9, 0, 16) \
X(XMM10, 254, zmm10, 0, 16) \
@@ -1416,6 +1161,8 @@ struct CV_SymPub32
//- (SymKind: LPROC32, GPROC32)
#define CV_IsProc32(x) (x == CV_SymKind_LPROC32_ID || x == CV_SymKind_GPROC32_ID || x == CV_SymKind_LPROC32_DPC)
typedef struct CV_SymProc32 CV_SymProc32;
struct CV_SymProc32
{
@@ -2795,7 +2542,8 @@ X(TypeMDTokenMap, 0xFB) \
X(MergedAssemblyInput, 0xFC) \
X(CoffSymbolRVA, 0xFD) \
X(XfgHashType, 0xFF) \
X(XfgHashVirtual, 0x100)
X(XfgHashVirtual, 0x100) \
X(GlobalRefs, 0xCAFE) \
typedef U32 CV_C13SubSectionKind;
typedef enum CV_C13SubSectionKindEnum
@@ -2963,7 +2711,6 @@ struct CV_TypeIndexArray
////////////////////////////////
internal CV_Arch cv_arch_from_coff_machine(COFF_MachineType machine);
internal U64 cv_size_from_reg_x86(CV_Reg reg);
internal U64 cv_size_from_reg_x64(CV_Reg reg);
internal U64 cv_size_from_reg(CV_Arch arch, CV_Reg reg);
internal B32 cv_is_reg_sp(CV_Arch arch, CV_Reg reg);
+29 -1
View File
@@ -29,7 +29,7 @@ cv_numeric_from_data_range(U8 *first, U8 *opl)
CV_NumericParsed result = {0};
if(first + 2 <= opl)
{
U16 x = *(U16*)first;
U16 x = memory_read16(first);
if(x < 0x8000)
{
result.kind = CV_NumericKind_USHORT;
@@ -1606,3 +1606,31 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
return result;
}
//- rjf: record iterator
internal B32
cv_rec_next(String8 data, CV_RecRangeArray *recs, B32 is_leaf, CV_RecIter *iter)
{
B32 result = 0;
{
U64 next_num = iter->num+1;
for(;1 <= next_num && next_num <= recs->count; next_num += 1)
{
CV_RecRange *rec_range = &recs->ranges[next_num-1];
U64 rec_off_first = rec_range->off + 2; // (skip 2 header bytes)
U64 rec_off_opl = rec_range->off + rec_range->hdr.size;
U16 kind = rec_range->hdr.kind;
U64 header_struct_size = (is_leaf ? cv_header_struct_size_from_leaf_kind(kind) : cv_header_struct_size_from_sym_kind(kind));
if(rec_off_opl <= data.size && rec_off_first + header_struct_size <= data.size)
{
result = 1;
iter->num = next_num;
iter->kind = kind;
iter->struct_base = data.str + rec_off_first;
iter->opl = data.str + rec_off_opl;
break;
}
}
}
return result;
}
+15
View File
@@ -236,6 +236,18 @@ struct CV_TypeIdArray
U64 count;
};
////////////////////////////////
//~ Record Iterator
typedef struct CV_RecIter CV_RecIter;
struct CV_RecIter
{
U64 num;
U16 kind;
void *struct_base;
void *opl;
};
////////////////////////////////
//- Hasher
@@ -301,5 +313,8 @@ internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym
internal CV_LeafParsed * cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first);
internal CV_C13Parsed * cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections);
//- rjf: record iterator
internal B32 cv_rec_next(String8 data, CV_RecRangeArray *recs, B32 is_leaf, CV_RecIter *iter);
#endif // CODEVIEW_PARSE_H
+17 -7
View File
@@ -92,13 +92,8 @@ coff_read_symbol_name(String8 string_table, COFF_SymbolName *name)
if (name->long_name.zeroes == 0) {
str8_deserial_read_cstr(string_table, name->long_name.string_table_offset, &name_str);
} else {
U32 i;
for (i = 0; i < sizeof(name->short_name); ++i) {
if (name->short_name[i] == '\0') {
break;
}
}
name_str = str8(name->short_name, i);
U32 name_size = idx_of_zero_byte64(name->short_name, sizeof(name->short_name));
name_str = str8(name->short_name, name_size);
}
return name_str;
}
@@ -455,6 +450,21 @@ arch_from_coff_machine(COFF_MachineType machine)
return result;
}
internal COFF_MachineType
coff_machine_from_arch(Arch arch)
{
COFF_MachineType machine = COFF_MachineType_Unknown;
switch (arch) {
case Arch_Null: machine = COFF_MachineType_Unknown; break;
case Arch_x86: machine = COFF_MachineType_X86; break;
case Arch_x64: machine = COFF_MachineType_X64; break;
case Arch_arm64: machine = COFF_MachineType_Arm64; break;
case Arch_arm32: machine = COFF_MachineType_Arm; break;
default: InvalidPath; break;
}
return machine;
}
internal U64
coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff)
{
+10 -6
View File
@@ -163,7 +163,8 @@ enum
#define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask)
#define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl)
typedef struct COFF_SectionHeader
typedef struct COFF_SectionHeader COFF_SectionHeader;
struct COFF_SectionHeader
{
U8 name[8];
U32 vsize;
@@ -175,12 +176,12 @@ typedef struct COFF_SectionHeader
U16 reloc_count;
U16 line_count;
COFF_SectionFlags flags;
} COFF_SectionHeader;
};
////////////////////////////////
typedef U8 COFF_SymType;
enum
typedef enum COFF_SymTypeEnum
{
COFF_SymType_Null,
COFF_SymType_Void,
@@ -198,10 +199,11 @@ enum
COFF_SymType_Word,
COFF_SymType_UInt,
COFF_SymType_DWord
};
}
COFF_SymTypeEnum;
typedef U8 COFF_SymStorageClass;
enum
typedef enum COFF_SymStorageClassEnum
{
COFF_SymStorageClass_Null = 0x00,
COFF_SymStorageClass_Automatic = 0x01,
@@ -230,7 +232,8 @@ enum
COFF_SymStorageClass_WeakExternal = 0x69,
COFF_SymStorageClass_CLRToken = 0x6b,
COFF_SymStorageClass_EndOfFunction = 0xff
};
}
COFF_SymStorageClassEnum;
typedef U8 COFF_SymDType;
enum
@@ -629,6 +632,7 @@ internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine);
internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
internal Arch arch_from_coff_machine(COFF_MachineType machine);
internal COFF_MachineType coff_machine_from_arch(Arch arch);
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
////////////////////////////////
+1 -1
View File
@@ -648,7 +648,7 @@ coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data,
}
if (opts & RD_Option_Dwarf) {
DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
DW_Raw dwarf_input = dw_raw_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
dw_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
}
+1 -4
View File
@@ -184,10 +184,7 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta
U64 name_with_slash_size = member->name.size + 1;
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
// have we seen this member name before?
KeyValuePair *is_present = hash_table_search_string(name_ht, member->name);
if (is_present) {
name = is_present->value_string;
} else {
if (!hash_table_search_string_string(name_ht, member->name, &name)) {
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
+111 -1
View File
@@ -1,7 +1,10 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal COFF_ObjWriter*
coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine)
{
Arena *arena = arena_alloc();
Arena *arena = arena_alloc(.name = "COFF OBJ WRITER");
COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1);
obj_writer->arena = arena;
obj_writer->time_stamp = time_stamp;
@@ -440,6 +443,18 @@ coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *
return reloc;
}
internal COFF_ObjReloc *
coff_obj_writer_section_push_reloc_rel32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
{
COFF_RelocType reloc_type = 0;
switch (obj_writer->machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Rel32; break;
default: { NotImplemented; } break;
}
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
}
internal COFF_ObjReloc *
coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
{
@@ -496,5 +511,100 @@ coff_obj_section_is_before(void *raw_a, void *raw_b)
return (*a)->section_number < (*b)->section_number;
}
#ifdef OBJ_H
internal String8
coff_from_obj(Arena *arena, OBJ *obj)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_MachineType machine = coff_machine_from_arch(obj->arch);
COFF_TimeStamp time_stamp = (COFF_TimeStamp)obj->time_stamp;
COFF_ObjWriter *cow = coff_obj_writer_alloc(time_stamp, machine);
// push sections
HashTable *section_remap = hash_table_init(scratch.arena, obj->symbols.count * 2);
for EachNode(section_n, OBJ_SectionNode, obj->sections.first) {
OBJ_Section *section = &section_n->v;
COFF_SectionFlags flags = 0;
if (section->flags & OBJ_SectionFlag_Read) { flags |= COFF_SectionFlag_MemRead; }
if (section->flags & OBJ_SectionFlag_Write) { flags |= COFF_SectionFlag_MemWrite; }
if (section->flags & OBJ_SectionFlag_Exec) { flags |= COFF_SectionFlag_MemExecute|COFF_SectionFlag_CntCode; }
if ( ! (section->flags & OBJ_SectionFlag_Exec)) { flags |= COFF_SectionFlag_CntInitializedData; }
if ( ! (section->flags & OBJ_SectionFlag_Load)) { flags |= COFF_SectionFlag_MemDiscardable; }
COFF_ObjSection *section_coff = coff_obj_writer_push_section(cow, section->name, flags, str8_zero());
section_coff->data = section->data;
// obj -> coff section
hash_table_push_raw_raw(scratch.arena, section_remap, section, section_coff);
}
// push symbols
HashTable *symbol_remap = hash_table_init(scratch.arena, obj->symbols.count * 2);
for EachNode(symbol_n, OBJ_SymbolNode, obj->symbols.first) {
OBJ_Symbol *symbol = &symbol_n->v;
switch (symbol->ref_kind) {
case OBJ_RefKind_Null: break;
case OBJ_RefKind_Section: {
OBJ_Section *section = symbol->ref;
COFF_ObjSection *section_coff = hash_table_search_raw_raw(section_remap, section);
COFF_SymbolLocation location = (COFF_SymbolLocation){ .type = COFF_SymbolLocation_Section, .u.section = section_coff };
COFF_SymStorageClass storage_class = COFF_SymStorageClass_Null;
switch (symbol->scope) {
case OBJ_SymbolScope_Null: break;
case OBJ_SymbolScope_Local: storage_class = COFF_SymStorageClass_Static; break;
case OBJ_SymbolScope_Global: storage_class = COFF_SymStorageClass_External; break;
}
COFF_ObjSymbol *symbol_coff = coff_obj_writer_push_symbol(cow,
symbol->name,
0,
location,
(COFF_SymbolType){0},
storage_class);
hash_table_push_raw_raw(scratch.arena, symbol_remap, symbol, symbol_coff);
} break;
}
}
// push relocations
for EachNode(section_n, OBJ_SectionNode, obj->sections.first) {
OBJ_Section *section = &section_n->v;
COFF_ObjSection *section_coff = hash_table_search_raw_raw(section_remap, section);
for EachNode(reloc_n, OBJ_RelocNode, section->relocs.first) {
OBJ_Reloc *reloc = &reloc_n->v;
// obj -> coff reloc type
COFF_RelocType reloc_type_coff = 0;
switch (cow->machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: {
switch (reloc->kind) {
case OBJ_RelocKind_Null: break;
case OBJ_RelocKind_SecRel: reloc_type_coff = COFF_Reloc_X64_SecRel; break;
default: InvalidPath; break;
}
} break;
default: InvalidPath; break;
}
// push reloc entry
COFF_ObjSymbol *symbol_coff = hash_table_search_raw_raw(symbol_remap, reloc->symbol);
AssertAlways(symbol_coff);
coff_obj_writer_section_push_reloc(cow, section_coff, reloc->offset, symbol_coff, reloc_type_coff);
}
}
String8 raw_obj = coff_obj_writer_serialize(arena, cow);
coff_obj_writer_release(&cow);
scratch_end(scratch);
return raw_obj;
}
#endif
+24 -16
View File
@@ -1,3 +1,6 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_OBJ_WRITER_H
#define COFF_OBJ_WRITER_H
@@ -95,34 +98,39 @@ typedef struct COFF_ObjWriter
////////////////////////////////
internal COFF_ObjWriter * coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
internal COFF_ObjWriter * coff_obj_writer_alloc (COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal void coff_obj_writer_release (COFF_ObjWriter **obj_writer);
internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer);
internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol* coff_obj_writer_push_symbol (COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern (COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static (COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef (COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak (COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs (COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef (COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func (COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect (COFF_ObjWriter *obj_writer, String8 name, U32 value);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect (COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common (COFF_ObjWriter *obj_writer, String8 name, U32 size);
internal void coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_rel32 (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal void coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive);
#ifdef OBJ_H
internal String8 coff_from_obj(Arena *arena, OBJ *obj);
#endif
#endif // COFF_OBJ_WRITER_H
+35 -2
View File
@@ -127,12 +127,45 @@ coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_r
U64 section_count = dim_1u64(section_table_range) / sizeof(COFF_SectionHeader);
COFF_SectionHeader **section_table = push_array_no_zero(arena, COFF_SectionHeader *, section_count+1);
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
for (U64 i = 0; i < section_count; ++i) {
section_table[i+1] = str8_deserial_get_raw_ptr(data, section_table_range.min + i*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
for EachIndex(sect_idx, section_count) {
section_table[sect_idx + 1] = str8_deserial_get_raw_ptr(data, section_table_range.min + sect_idx*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
}
return section_table;
}
internal COFF_SectionHeader *
coff_section_header_from_name(String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name)
{
for EachIndex(sect_idx, section_count) {
if (str8_match(coff_name_from_section_header(string_table, &section_table[sect_idx]), name, 0)) {
return &section_table[sect_idx];
}
}
return 0;
}
internal COFF_SectionHeaderArray
coff_section_header_array_from_name(Arena *arena, String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name)
{
U64 match_count = 0;
for EachIndex(sect_idx, section_count) {
if (str8_match(coff_name_from_section_header(string_table, &section_table[sect_idx]), name, 0)) {
match_count += 1;
}
}
COFF_SectionHeader *matches = push_array(arena, COFF_SectionHeader, match_count);
for (U64 sect_idx = 0, match_idx = 0; sect_idx < section_count; sect_idx += 1) {
if (str8_match(coff_name_from_section_header(string_table, &section_table[sect_idx]), name, 0)) {
matches[match_idx] = section_table[sect_idx];
match_idx += 1;
}
}
return (COFF_SectionHeaderArray){ .count = match_count, .v = matches };
}
internal COFF_ParsedSymbol
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
{
+5 -2
View File
@@ -251,14 +251,17 @@ internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff);
////////////////////////////////
// Section
internal COFF_SectionHeader ** coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range);
internal COFF_SectionHeader ** coff_section_table_from_data (Arena *arena, String8 data, Rng1U64 section_table_range);
internal COFF_SectionHeader * coff_section_header_from_name (String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name);
internal COFF_SectionHeaderArray coff_section_header_array_from_name(Arena *arena, String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name);
internal String8 coff_name_from_section_header (String8 string_table, COFF_SectionHeader *header);
////////////////////////////////
// Symbol
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16);
internal COFF_ParsedSymbol coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
internal COFF_ParsedSymbol coff_parse_symbol (COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
+65
View File
@@ -0,0 +1,65 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#define NO_ASYNC 1
#define BUILD_CONSOLE_INTERFACE 1
#define BUILD_TITLE "The RAD Debugger (Command Line Launcher)"
#include "base/base_inc.h"
#include "base/base_inc.c"
internal void
entry_point(CmdLine *cmd_line)
{
Temp scratch = scratch_begin(0, 0);
B32 wait_for_process = cmd_line_has_flag(cmd_line, s("cli")) || cmd_line_has_flag(cmd_line, s("bin"));
String8List command_parts = {0};
String8 exe_name = str8f(scratch.arena, "%S.exe", str8_chop_last_dot(cmd_line->exe_name));
if(str8_match(exe_name, cmd_line->exe_name, 0))
{
fprintf(stderr,
"ERROR: Attempting to launch %.*s recursively.\n"
"\n"
"This executable needs to be used with a .com extension next to the real target\n"
"executable, with the same name, but with a .exe extension. This guarantees that\n"
"cmd.exe will prefer launching this .com file when the executable name is used,\n"
"allowing the same executable to be used in the Windows command-line subsystem\n"
"style when launched from the command line, but used graphically when launched\n"
"via Explorer.\n\n", str8_varg(exe_name));
fflush(stderr);
}
else
{
// NOTE(rjf): sub-processes must be killed if the parent process
// is killed, if we're waiting for it
if(wait_for_process)
{
#if OS_WINDOWS
HANDLE job_handle = CreateJobObjectA(0, 0);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = { .BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE };
SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info));
AssignProcessToJobObject(job_handle, GetCurrentProcess());
#endif
}
str8_list_push(scratch.arena, &command_parts, exe_name);
str8_list_push(scratch.arena, &command_parts, s("--cli"));
for EachIndex(idx, cmd_line->argc)
{
String8 arg = str8_cstring(cmd_line->argv[idx]);
str8_list_push(scratch.arena, &command_parts, arg);
}
StringJoin join = {.sep = s(" ")};
String8 command = str8_list_join(scratch.arena, &command_parts, &join);
Process process = launch_cmd_line(command);
if(wait_for_process)
{
U64 exit_code = 0;
process_join(process, max_U64, &exit_code);
abort_self(exit_code);
}
else
{
process_detach(process);
}
}
scratch_end(scratch);
}
+7 -7
View File
@@ -24,21 +24,21 @@ cfg_key_map_from_cfg(Arena *arena)
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
{
if(0){}
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= WM_Modifier_Ctrl; }
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= WM_Modifier_Alt; }
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= WM_Modifier_Shift; }
else
{
OS_Key key = OS_Key_Null;
for EachEnumVal(OS_Key, k)
WM_Key key = WM_Key_Null;
for EachEnumVal(WM_Key, k)
{
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
if(str8_match(child->string, wm_key_cfg_name_table[k], StringMatchFlag_CaseInsensitive))
{
key = k;
break;
}
}
if(key != OS_Key_Null)
if(key != WM_Key_Null)
{
binding.key = key;
}
+2 -2
View File
@@ -7,8 +7,8 @@
typedef struct CFG_Binding CFG_Binding;
struct CFG_Binding
{
OS_Key key;
OS_Modifiers modifiers;
WM_Key key;
WM_Modifiers modifiers;
};
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
+2 -2
View File
@@ -649,13 +649,13 @@ cfg_node_release(CFG_State *state, CFG_Node *node)
for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next)
{
CFG_Node *c = n->v;
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
U64 slot_idx = hash%state->ctx.id_slots_count;
cfg_string_release(state, c->string);
SLLStackPush(state->free, c);
c->first = c->last = c->prev = c->parent = 0;
c->id = 0;
c->string = str8_zero();
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
U64 slot_idx = hash%state->ctx.id_slots_count;
for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next)
{
if(n->v == c)
+1 -1
View File
@@ -3,6 +3,6 @@
#include "config_core.c"
#include "config_panels.c"
#if defined(OS_GFX_H)
#if defined(WINDOW_MANAGER_H)
# include "config_bindings.c"
#endif
+1 -1
View File
@@ -6,7 +6,7 @@
#include "config_core.h"
#include "config_panels.h"
#if defined(OS_GFX_H)
#if defined(WINDOW_MANAGER_H)
# include "config_bindings.h"
#endif
+3 -3
View File
@@ -46,7 +46,7 @@ c_init(void)
c_shared = push_array(arena, C_Shared, 1);
c_shared->arena = arena;
c_shared->blob_slots_count = 16384;
c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, os_get_system_info()->logical_processor_count);
c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, get_system_info()->logical_processor_count);
c_shared->blob_slots = push_array(arena, C_BlobSlot, c_shared->blob_slots_count);
c_shared->blob_stripes = push_array(arena, C_Stripe, c_shared->blob_stripes_count);
c_shared->blob_stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->blob_stripes_count);
@@ -58,7 +58,7 @@ c_init(void)
stripe->cv = cond_var_alloc();
}
c_shared->key_slots_count = 4096;
c_shared->key_stripes_count = Min(c_shared->key_slots_count, os_get_system_info()->logical_processor_count);
c_shared->key_stripes_count = Min(c_shared->key_slots_count, get_system_info()->logical_processor_count);
c_shared->key_slots = push_array(arena, C_KeySlot, c_shared->key_slots_count);
c_shared->key_stripes = push_array(arena, C_Stripe, c_shared->key_stripes_count);
c_shared->key_stripes_free_nodes = push_array(arena, C_KeyNode *, c_shared->key_stripes_count);
@@ -70,7 +70,7 @@ c_init(void)
stripe->cv = cond_var_alloc();
}
c_shared->root_slots_count = 4096;
c_shared->root_stripes_count = Min(c_shared->root_slots_count, os_get_system_info()->logical_processor_count);
c_shared->root_stripes_count = Min(c_shared->root_slots_count, get_system_info()->logical_processor_count);
c_shared->root_slots = push_array(arena, C_RootSlot, c_shared->root_slots_count);
c_shared->root_stripes = push_array(arena, C_Stripe, c_shared->root_stripes_count);
c_shared->root_stripes_free_nodes = push_array(arena, C_RootNode *, c_shared->root_stripes_count);
-192
View File
@@ -1,192 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Entity Kinds
@table(name code_name display_string)
CTRL_EntityKindTable:
{
{Root root "Root" }
{Machine machine "Machine" }
{Process process "Process" }
{Thread thread "Thread" }
{Module module "Module" }
{EntryPoint entry_point "Entry Point" }
{DebugInfoPath debug_info_path "Debug Info Path" }
{PendingThreadName pending_thread_name "Pending Thread Name" }
{PendingThreadColor pending_thread_color "Pending Thread Color" }
{Breakpoint breakpoint "Breakpoint" }
{AddressRangeAnnotation address_range_annotation "Address Range Annotation" }
}
@enum CTRL_EntityKind:
{
Null,
@expand(CTRL_EntityKindTable a) `$(a.name)`,
COUNT,
}
@data(String8) ctrl_entity_kind_code_name_table:
{
`{0}`,
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.code_name)")`
}
@data(String8) ctrl_entity_kind_display_string_table:
{
`{0}`,
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.display_name)")`
}
////////////////////////////////
//~ rjf: Exception Codes
@table(name lower_name code default display_string)
CTRL_ExceptionCodeKindTable:
{
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
}
@enum CTRL_ExceptionCodeKind:
{
Null,
@expand(CTRL_ExceptionCodeKindTable a) `$(a.name)`,
COUNT,
}
@data(U32) ctrl_exception_code_kind_code_table:
{
`0`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code)`;
}
@data(String8) ctrl_exception_code_kind_display_string_table:
{
`{0}`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`;
}
@data(String8) ctrl_exception_code_kind_lowercase_code_string_table:
{
`{0}`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`;
}
@data(B8) ctrl_exception_code_kind_default_enable_table:
{
`0`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default)`;
}
////////////////////////////////
//~ rjf: Exception Sub-Codes
@table(name, value)
CTRL_ExceptionSubCodeKindTable:
{
{ W32_FAST_FAIL_LEGACY_GS_VIOLATION 0 }
{ W32_FAST_FAIL_VTGUARD_CHECK_FAILURE 1 }
{ W32_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2 }
{ W32_FAST_FAIL_CORRUPT_LIST_ENTRY 3 }
{ W32_FAST_FAIL_INCORRECT_STACK 4 }
{ W32_FAST_FAIL_INVALID_ARG 5 }
{ W32_FAST_FAIL_GS_COOKIE_INIT 6 }
{ W32_FAST_FAIL_FATAL_APP_EXIT 7 }
{ W32_FAST_FAIL_RANGE_CHECK_FAILURE 8 }
{ W32_FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10 }
{ W32_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11 }
{ W32_FAST_FAIL_INVALID_FIBER_SWITCH 12 }
{ W32_FAST_FAIL_INVALID_SET_OF_CONTEXT 13 }
{ W32_FAST_FAIL_INVALID_REFERENCE_COUNT 14 }
{ W32_FAST_FAIL_INVALID_JUMP_BUFFER 18 }
{ W32_FAST_FAIL_MRDATA_MODIFIED 19 }
{ W32_FAST_FAIL_CERTIFICATION_FAILURE 20 }
{ W32_FAST_FAIL_INVALID_EXCEPTION_CHAIN 21 }
{ W32_FAST_FAIL_CRYPTO_LIBRARY 22 }
{ W32_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23 }
{ W32_FAST_FAIL_INVALID_IMAGE_BASE 24 }
{ W32_FAST_FAIL_DLOAD_PROTECTION_FAILURE 25 }
{ W32_FAST_FAIL_UNSAFE_EXTENSION_CALL 26 }
{ W32_FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27 }
{ W32_FAST_FAIL_INVALID_BUFFER_ACCESS 28 }
{ W32_FAST_FAIL_INVALID_BALANCED_TREE 29 }
{ W32_FAST_FAIL_INVALID_NEXT_THREAD 30 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 }
{ W32_FAST_FAIL_APCS_DISABLED 32 }
{ W32_FAST_FAIL_INVALID_IDLE_STATE 33 }
{ W32_FAST_FAIL_MRDATA_PROTECTION_FAILURE 34 }
{ W32_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35 }
{ W32_FAST_FAIL_INVALID_LOCK_STATE 36 }
{ W32_FAST_FAIL_GUARD_JUMPTABLE 37 }
{ W32_FAST_FAIL_INVALID_LONGJUMP_TARGET 38 }
{ W32_FAST_FAIL_INVALID_DISPATCH_CONTEXT 39 }
{ W32_FAST_FAIL_INVALID_THREAD 40 }
{ W32_FAST_FAIL_INVALID_SYSCALL_NUMBER 41 }
{ W32_FAST_FAIL_INVALID_FILE_OPERATION 42 }
{ W32_FAST_FAIL_LPAC_ACCESS_DENIED 43 }
{ W32_FAST_FAIL_GUARD_SS_FAILURE 44 }
{ W32_FAST_FAIL_LOADER_CONTINUITY_FAILURE 45 }
{ W32_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE 46 }
{ W32_FAST_FAIL_INVALID_CONTROL_STACK 47 }
{ W32_FAST_FAIL_SET_CONTEXT_DENIED 48 }
{ W32_FAST_FAIL_INVALID_IAT 49 }
{ W32_FAST_FAIL_HEAP_METADATA_CORRUPTION 50 }
{ W32_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION 51 }
{ W32_FAST_FAIL_LOW_LABEL_ACCESS_DENIED 52 }
{ W32_FAST_FAIL_ENCLAVE_CALL_FAILURE 53 }
{ W32_FAST_FAIL_UNHANDLED_LSS_EXCEPTON 54 }
{ W32_FAST_FAIL_ADMINLESS_ACCESS_DENIED 55 }
{ W32_FAST_FAIL_UNEXPECTED_CALL 56 }
{ W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS 57 }
{ W32_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR 58 }
{ W32_FAST_FAIL_FLAGS_CORRUPTION 59 }
{ W32_FAST_FAIL_VEH_CORRUPTION 60 }
{ W32_FAST_FAIL_ETW_CORRUPTION 61 }
{ W32_FAST_FAIL_RIO_ABORT 62 }
{ W32_FAST_FAIL_INVALID_PFN 63 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG 64 }
{ W32_FAST_FAIL_CAST_GUARD 65 }
{ W32_FAST_FAIL_HOST_VISIBILITY_CHANGE 66 }
{ W32_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST 67 }
{ W32_FAST_FAIL_PATCH_CALLBACK_FAILED 68 }
{ W32_FAST_FAIL_NTDLL_PATCH_FAILED 69 }
{ W32_FAST_FAIL_INVALID_FLS_DATA 70 }
}
-6739
View File
File diff suppressed because it is too large Load Diff
-1032
View File
File diff suppressed because it is too large Load Diff
-77
View File
@@ -1,77 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CTRL_INC_H
#define CTRL_INC_H
////////////////////////////////
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
//
// This layer's purpose is to provide access to the asynchronously-running, low
// level parts of a debugger, running on the debugger client. This primarily
// consists of process control, using the Demon layer (the lower level
// abstraction layer for process control, across multiple OSes), but including
// higher-level concepts, like stepping, breakpoint resolution, conditional
// breakpoint evaluation, and so on. Right now, this just includes process
// control *local to the debugger client machine*. But in the future, this can
// also include communication to multiple target machines, all running their
// own process controller, using the Demon layer.
//
// This part of a debugger must run asynchronously to prevent blocking the UI -
// ideally our debugger is designed such that, if targets are running, the
// debugger frontend is still usable for a variety of purposes. So, in short,
// the asynchronously-running "control thread", implemented by this layer, is
// tasked with communicating with a separately executing "user thread". This
// communication happens in two directions - `user -> ctrl`, and the reverse,
// `ctrl -> user`.
//
// In the case of `user -> ctrl` communication, this is done with a ring buffer
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
// include commands like: launching targets, attaching to targets, killing
// targets, detaching from targets, stepping/running, or single stepping.
//
// In the case of `ctrl -> user` communication, this is done with a ring buffer
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
// include information about what happened during the execution of targets -
// including: process/module/thread creation, process/module/thread deletion,
// debug strings, thread name events, memory allocation events, and stop events
// (where stops can be caused by: user breakpoints, traps set for stepping,
// exceptions, halts, or errors).
//
// The various stepping algorithms are implemented with two concepts: (a) the
// "trap net", and (b) "spoofs".
//
// A "trap net" is a term which refers to a set of addresses paired with a set
// of behavioral flags. Before targets run, trap instructions are written to
// these addresses. After targets stop, these addresses are reset to their
// original bytes. These trap instructions cause the debugger's targets to
// stop executing, and based on which behavioral flags are associated with
// the instruction causing the stop, the control thread may adjust parameters
// used for running, then continue execution, or it will not resume target
// execution, and will report stopped events. These behavioral flags can
// include: single-stepping the stopped thread to execute the instruction at
// the trap location, saving a stack pointer "check value" (where this check
// value is compared against when making decisions about whether to continue
// running or not), and so on. It's complicated to unpack why exactly these
// behaviors are useful, but the TL;DR of it is that they are used for a
// variety of stepping behaviors. For example, when doing a "step into" step,
// a `call` instruction can have a trap set at it, and will be marked with
// a "single-step-after" trap flag, as well as the "end stepping" trap flag,
// such that the step operation will complete after the `call` has executed.
//
// A "spoof" is a feature the control layer uses to detect when some thread
// returns from a particular sub-callstack. This is useful when implementing
// "step over" in functions that may be recursive. In short, unlike a trap,
// which writes a trap instruction (like `int3`) into an instruction stream,
// a spoof overwrites a *return address* on some thread's *stack*. This return
// address is not a valid address for executing code -- it is simply a value
// that the debugger can recognize, such that it is notified when the thread
// returns from some level in a callstack. When the thread exits some function,
// it will return to the "spoofed" address, and it will immediately hit an
// exception, because the spoofed address will not be a valid address for
// code execution. At that point, the debugger can move the thread back to
// the pre-spoof return address, and resume execution.
#include "ctrl_core.h"
#endif // CTRL_INC_H
-208
View File
@@ -1,208 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
C_LINKAGE_BEGIN
String8 ctrl_entity_kind_code_name_table[12] =
{
{0},
str8_lit_comp("root"),
str8_lit_comp("machine"),
str8_lit_comp("process"),
str8_lit_comp("thread"),
str8_lit_comp("module"),
str8_lit_comp("entry_point"),
str8_lit_comp("debug_info_path"),
str8_lit_comp("pending_thread_name"),
str8_lit_comp("pending_thread_color"),
str8_lit_comp("breakpoint"),
str8_lit_comp("address_range_annotation"),
};
String8 ctrl_entity_kind_display_string_table[12] =
{
{0},
str8_lit_comp("Root"),
str8_lit_comp("Machine"),
str8_lit_comp("Process"),
str8_lit_comp("Thread"),
str8_lit_comp("Module"),
str8_lit_comp("EntryPoint"),
str8_lit_comp("DebugInfoPath"),
str8_lit_comp("PendingThreadName"),
str8_lit_comp("PendingThreadColor"),
str8_lit_comp("Breakpoint"),
str8_lit_comp("AddressRangeAnnotation"),
};
U32 ctrl_exception_code_kind_code_table[38] =
{
0,
0x40010005,
0x40010008,
0x40080201,
0x40080202,
0x0000071a,
0x80000002,
0xc0000005,
0xc0000006,
0xc0000008,
0xc0000017,
0xc000001d,
0xc0000025,
0xc0000026,
0xc000008c,
0xc000008d,
0xc000008e,
0xc000008f,
0xc0000090,
0xc0000091,
0xc0000092,
0xc0000093,
0xc0000094,
0xc0000095,
0xc0000096,
0xc00000fd,
0xc0000135,
0xc0000138,
0xc0000139,
0xc0000142,
0xc00002b4,
0xc00002b5,
0xc0000420,
0xc06d007e,
0xc06d007f,
0xe073616e,
0xe0736171,
0x0000087a,
};
String8 ctrl_exception_code_kind_display_string_table[38] =
{
{0},
str8_lit_comp("(Win32) Control-C"),
str8_lit_comp("(Win32) Control-Break"),
str8_lit_comp("(Win32) WinRT Originate Error"),
str8_lit_comp("(Win32) WinRT Transform Error"),
str8_lit_comp("(Win32) RPC Call Cancelled"),
str8_lit_comp("(Win32) Data Type Misalignment"),
str8_lit_comp("(Win32) Access Violation"),
str8_lit_comp("(Win32) In Page Error"),
str8_lit_comp("(Win32) Invalid Handle Specified"),
str8_lit_comp("(Win32) Not Enough Quota"),
str8_lit_comp("(Win32) Illegal Instruction"),
str8_lit_comp("(Win32) Cannot Continue From Exception"),
str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"),
str8_lit_comp("(Win32) Array Bounds Exceeded"),
str8_lit_comp("(Win32) Floating-Point Denormal Operand"),
str8_lit_comp("(Win32) Floating-Point Division By Zero"),
str8_lit_comp("(Win32) Floating-Point Inexact Result"),
str8_lit_comp("(Win32) Floating-Point Invalid Operation"),
str8_lit_comp("(Win32) Floating-Point Overflow"),
str8_lit_comp("(Win32) Floating-Point Stack Check"),
str8_lit_comp("(Win32) Floating-Point Underflow"),
str8_lit_comp("(Win32) Integer Division By Zero"),
str8_lit_comp("(Win32) Integer Overflow"),
str8_lit_comp("(Win32) Privileged Instruction"),
str8_lit_comp("(Win32) Stack Overflow"),
str8_lit_comp("(Win32) Unable To Locate DLL"),
str8_lit_comp("(Win32) Ordinal Not Found"),
str8_lit_comp("(Win32) Entry Point Not Found"),
str8_lit_comp("(Win32) DLL Initialization Failed"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"),
str8_lit_comp("(Win32) Assertion Failed"),
str8_lit_comp("(Win32) Module Not Found"),
str8_lit_comp("(Win32) Procedure Not Found"),
str8_lit_comp("(Win32) Sanitizer Error Detected"),
str8_lit_comp("(Win32) Sanitizer Raw Access Violation"),
str8_lit_comp("(Win32) DirectX Debug Layer"),
};
String8 ctrl_exception_code_kind_lowercase_code_string_table[38] =
{
{0},
str8_lit_comp("win32_ctrl_c"),
str8_lit_comp("win32_ctrl_break"),
str8_lit_comp("win32_win_rt_originate_error"),
str8_lit_comp("win32_win_rt_transform_error"),
str8_lit_comp("win32_rpc_call_cancelled"),
str8_lit_comp("win32_datatype_misalignment"),
str8_lit_comp("win32_access_violation"),
str8_lit_comp("win32_in_page_error"),
str8_lit_comp("win32_invalid_handle"),
str8_lit_comp("win32_not_enough_quota"),
str8_lit_comp("win32_illegal_instruction"),
str8_lit_comp("win32_cannot_continue_exception"),
str8_lit_comp("win32_invalid_exception_disposition"),
str8_lit_comp("win32_array_bounds_exceeded"),
str8_lit_comp("win32_floating_point_denormal_operand"),
str8_lit_comp("win32_floating_point_division_by_zero"),
str8_lit_comp("win32_floating_point_inexact_result"),
str8_lit_comp("win32_floating_point_invalid_operation"),
str8_lit_comp("win32_floating_point_overflow"),
str8_lit_comp("win32_floating_point_stack_check"),
str8_lit_comp("win32_floating_point_underflow"),
str8_lit_comp("win32_integer_division_by_zero"),
str8_lit_comp("win32_integer_overflow"),
str8_lit_comp("win32_privileged_instruction"),
str8_lit_comp("win32_stack_overflow"),
str8_lit_comp("win32_unable_to_locate_dll"),
str8_lit_comp("win32_ordinal_not_found"),
str8_lit_comp("win32_entry_point_not_found"),
str8_lit_comp("win32_dll_initialization_failed"),
str8_lit_comp("win32_floating_point_sse_multiple_faults"),
str8_lit_comp("win32_floating_point_sse_multiple_traps"),
str8_lit_comp("win32_assertion_failed"),
str8_lit_comp("win32_module_not_found"),
str8_lit_comp("win32_procedure_not_found"),
str8_lit_comp("win32_sanitizer_error_detected"),
str8_lit_comp("win32_sanitizer_raw_access_violation"),
str8_lit_comp("win32_directx_debug_layer"),
};
B8 ctrl_exception_code_kind_default_enable_table[38] =
{
0,
1,
1,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
1,
};
C_LINKAGE_END
-79
View File
@@ -1,79 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
#ifndef CTRL_META_H
#define CTRL_META_H
typedef enum CTRL_EntityKind
{
CTRL_EntityKind_Null,
CTRL_EntityKind_Root,
CTRL_EntityKind_Machine,
CTRL_EntityKind_Process,
CTRL_EntityKind_Thread,
CTRL_EntityKind_Module,
CTRL_EntityKind_EntryPoint,
CTRL_EntityKind_DebugInfoPath,
CTRL_EntityKind_PendingThreadName,
CTRL_EntityKind_PendingThreadColor,
CTRL_EntityKind_Breakpoint,
CTRL_EntityKind_AddressRangeAnnotation,
CTRL_EntityKind_COUNT,
} CTRL_EntityKind;
typedef enum CTRL_ExceptionCodeKind
{
CTRL_ExceptionCodeKind_Null,
CTRL_ExceptionCodeKind_Win32CtrlC,
CTRL_ExceptionCodeKind_Win32CtrlBreak,
CTRL_ExceptionCodeKind_Win32WinRTOriginateError,
CTRL_ExceptionCodeKind_Win32WinRTTransformError,
CTRL_ExceptionCodeKind_Win32RPCCallCancelled,
CTRL_ExceptionCodeKind_Win32DatatypeMisalignment,
CTRL_ExceptionCodeKind_Win32AccessViolation,
CTRL_ExceptionCodeKind_Win32InPageError,
CTRL_ExceptionCodeKind_Win32InvalidHandle,
CTRL_ExceptionCodeKind_Win32NotEnoughQuota,
CTRL_ExceptionCodeKind_Win32IllegalInstruction,
CTRL_ExceptionCodeKind_Win32CannotContinueException,
CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition,
CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded,
CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand,
CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero,
CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult,
CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation,
CTRL_ExceptionCodeKind_Win32FloatingPointOverflow,
CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck,
CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow,
CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero,
CTRL_ExceptionCodeKind_Win32IntegerOverflow,
CTRL_ExceptionCodeKind_Win32PrivilegedInstruction,
CTRL_ExceptionCodeKind_Win32StackOverflow,
CTRL_ExceptionCodeKind_Win32UnableToLocateDLL,
CTRL_ExceptionCodeKind_Win32OrdinalNotFound,
CTRL_ExceptionCodeKind_Win32EntryPointNotFound,
CTRL_ExceptionCodeKind_Win32DLLInitializationFailed,
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults,
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps,
CTRL_ExceptionCodeKind_Win32AssertionFailed,
CTRL_ExceptionCodeKind_Win32ModuleNotFound,
CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
CTRL_ExceptionCodeKind_COUNT,
} CTRL_ExceptionCodeKind;
C_LINKAGE_BEGIN
extern String8 ctrl_entity_kind_code_name_table[12];
extern String8 ctrl_entity_kind_display_string_table[12];
extern U32 ctrl_exception_code_kind_code_table[38];
extern String8 ctrl_exception_code_kind_display_string_table[38];
extern String8 ctrl_exception_code_kind_lowercase_code_string_table[38];
extern B8 ctrl_exception_code_kind_default_enable_table[38];
C_LINKAGE_END
#endif // CTRL_META_H
+235 -36
View File
@@ -4,52 +4,60 @@
////////////////////////////////
//~ rjf: Built-In Command Tables
@table(name ui_vis ipc_docs_vis text_pt_vis text_rng_vis q_expr q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags ctx_filter)
// / | | | | | | \___ _________________________________/ | | | | | |
// / | | | | | | \ / | | | | | |
D_CmdTable: // | | | | | | | | | | | | | |
@table(name ui_vis ipc_docs_vis q_expr q_slot q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags filter_tags)
// / | | | | \__ ______________________________________________________________/ / / | | | |
// / | | | | \ / _________________/ _________________/ | | | |
D_CmdTable: // | | | | | | / / | | | |
{
//- rjf: low-level target control operations
{LaunchAndRun 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" }
{LaunchAndStepInto 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" }
{Kill 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" }
{KillAll 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" }
{Detach 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" }
{Continue 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" }
{StepIntoInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" }
{StepOverInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" }
{StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
{StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
{StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" "" }
{Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
{SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
{SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
{LaunchAndRun 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" }
{LaunchAndStepInto 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" }
{Kill 1 1 "query:processes" Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" }
{KillAll 1 1 "" Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" }
{Detach 1 1 "query:processes" Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" }
{Continue 1 1 "" Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" }
{StepIntoInst 1 1 "" Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" }
{StepOverInst 1 1 "" Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" }
{StepIntoLine 1 1 "" Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
{StepOverLine 1 1 "" Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
{StepOut 1 1 "" Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the first instruction after the current scope is exited." "" "" }
{StepToExit 1 1 "" Null 0 0 0 0 0 0 0 StepOut "step_to_exit" "Step To Exit" "Runs to the first encountered instruction which will exit the current scope." "" "" }
{Halt 1 1 "" Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
{SoftHaltRefresh 0 0 "" Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
{SetThreadIP 0 1 "" Vaddr 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
//- rjf: high-level composite target control operations
{RunToLine 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "$text_pt," }
{Run 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" }
{Restart 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" }
{StepInto 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" }
{StepOver 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" }
{RunToLine 1 1 "" Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "{text_pt_commands}{disasm_pt_commands}" }
{RunToName 1 1 "query:procedures" String 0 0 0 0 0 1 1 Play "run_to_name" "Run To Name" "Runs until a particular symbol name is hit." "" "" }
{Run 1 1 "" Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" }
{Restart 1 1 "" Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" }
{StepInto 1 1 "" Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" }
{StepOver 1 1 "" Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" }
//- rjf: debug control context management operations
{FreezeThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" }
{ThawThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" }
{FreezeProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" }
{ThawProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" }
{FreezeMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" }
{ThawMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" }
{FreezeLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" }
{ThawLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" }
{FreezeEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" }
{ThawEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" }
{FreezeThread 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" }
{ThawThread 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" }
{FreezeProcess 1 1 "query:processes" Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" }
{ThawProcess 1 1 "query:processes" Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" }
{FreezeMachine 0 1 "query:machines" Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" }
{ThawMachine 0 1 "query:machines" Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" }
{FreezeLocalMachine 1 1 "" Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" }
{ThawLocalMachine 1 1 "" Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" }
{FreezeEntity 0 0 "" Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" }
{ThawEntity 0 0 "" Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" }
//- rjf: entity decoration
{SetEntityColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
{SetEntityName 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
{SetEntityColor 0 0 "" Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
{SetEntityName 0 0 "" Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
//- rjf: modules
{DownloadModuleDebugInfo 1 1 "query:modules" CtrlEntity 0 0 0 0 0 1 1 Module "download_module_debug_info" "Download Module Debug Info" "Tries to download a module's debug info from symbol server(s)." "" "{module_commands}" }
//- rjf: attaching
{Attach 1 1 0 0 "query:unattached_processes" PID null Nil Null 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" }
{Attach 1 1 "query:unattached_processes" PID 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" }
//- rjf: crash dump opening
{OpenCrashDump 0 0 `folder:\\"$input\\"` FilePath 0 0 0 0 0 1 1 FileOutline "open_crash_dump" "Open Crash Dump" "Opens a crash dump file and recreates debuggee state at the time of the crash." "" "" }
}
@enum D_CmdKind:
@@ -88,3 +96,194 @@ D_DevToggleTable:
@expand(D_DevToggleTable a) `{&DEV_$(a.name), str8_lit_comp("$(a.name)")},`
`};`;
}
////////////////////////////////
//~ rjf: Entity Kinds
@table(name code_name display_string)
D_EntityKindTable:
{
{Root root "Root" }
{Machine machine "Machine" }
{Process process "Process" }
{Thread thread "Thread" }
{Module module "Module" }
{EntryPoint entry_point "Entry Point" }
{LaunchMsgID launch_msg_id "Launch Message ID" }
{DebugInfoPath debug_info_path "Debug Info Path" }
{PendingThreadName pending_thread_name "Pending Thread Name" }
{PendingThreadColor pending_thread_color "Pending Thread Color" }
{Breakpoint breakpoint "Breakpoint" }
{AddressRangeAnnotation address_range_annotation "Address Range Annotation" }
}
@enum D_EntityKind:
{
Null,
@expand(D_EntityKindTable a) `$(a.name)`,
COUNT,
}
@data(String8) d_entity_kind_code_name_table:
{
`{0}`,
@expand(D_EntityKindTable a) `str8_lit_comp("$(a.code_name)")`
}
@data(String8) d_entity_kind_display_string_table:
{
`{0}`,
@expand(D_EntityKindTable a) `str8_lit_comp("$(a.display_name)")`
}
////////////////////////////////
//~ rjf: Exception Codes
@table(name lower_name code default display_string)
D_ExceptionCodeKindTable:
{
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
}
@enum D_ExceptionCodeKind:
{
Null,
@expand(D_ExceptionCodeKindTable a) `$(a.name)`,
COUNT,
}
@data(U32) d_exception_code_kind_code_table:
{
`0`;
@expand(D_ExceptionCodeKindTable a) `$(a.code)`;
}
@data(String8) d_exception_code_kind_display_string_table:
{
`{0}`;
@expand(D_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`;
}
@data(String8) d_exception_code_kind_lowercase_code_string_table:
{
`{0}`;
@expand(D_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`;
}
@data(B8) d_exception_code_kind_default_enable_table:
{
`0`;
@expand(D_ExceptionCodeKindTable a) `$(a.default)`;
}
////////////////////////////////
//~ rjf: Exception Sub-Codes
@table(name, value)
DL_ExceptionSubCodeKindTable:
{
{ W32_FAST_FAIL_LEGACY_GS_VIOLATION 0 }
{ W32_FAST_FAIL_VTGUARD_CHECK_FAILURE 1 }
{ W32_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2 }
{ W32_FAST_FAIL_CORRUPT_LIST_ENTRY 3 }
{ W32_FAST_FAIL_INCORRECT_STACK 4 }
{ W32_FAST_FAIL_INVALID_ARG 5 }
{ W32_FAST_FAIL_GS_COOKIE_INIT 6 }
{ W32_FAST_FAIL_FATAL_APP_EXIT 7 }
{ W32_FAST_FAIL_RANGE_CHECK_FAILURE 8 }
{ W32_FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10 }
{ W32_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11 }
{ W32_FAST_FAIL_INVALID_FIBER_SWITCH 12 }
{ W32_FAST_FAIL_INVALID_SET_OF_CONTEXT 13 }
{ W32_FAST_FAIL_INVALID_REFERENCE_COUNT 14 }
{ W32_FAST_FAIL_INVALID_JUMP_BUFFER 18 }
{ W32_FAST_FAIL_MRDATA_MODIFIED 19 }
{ W32_FAST_FAIL_CERTIFICATION_FAILURE 20 }
{ W32_FAST_FAIL_INVALID_EXCEPTION_CHAIN 21 }
{ W32_FAST_FAIL_CRYPTO_LIBRARY 22 }
{ W32_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23 }
{ W32_FAST_FAIL_INVALID_IMAGE_BASE 24 }
{ W32_FAST_FAIL_DLOAD_PROTECTION_FAILURE 25 }
{ W32_FAST_FAIL_UNSAFE_EXTENSION_CALL 26 }
{ W32_FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27 }
{ W32_FAST_FAIL_INVALID_BUFFER_ACCESS 28 }
{ W32_FAST_FAIL_INVALID_BALANCED_TREE 29 }
{ W32_FAST_FAIL_INVALID_NEXT_THREAD 30 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 }
{ W32_FAST_FAIL_APCS_DISABLED 32 }
{ W32_FAST_FAIL_INVALID_IDLE_STATE 33 }
{ W32_FAST_FAIL_MRDATA_PROTECTION_FAILURE 34 }
{ W32_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35 }
{ W32_FAST_FAIL_INVALID_LOCK_STATE 36 }
{ W32_FAST_FAIL_GUARD_JUMPTABLE 37 }
{ W32_FAST_FAIL_INVALID_LONGJUMP_TARGET 38 }
{ W32_FAST_FAIL_INVALID_DISPATCH_CONTEXT 39 }
{ W32_FAST_FAIL_INVALID_THREAD 40 }
{ W32_FAST_FAIL_INVALID_SYSCALL_NUMBER 41 }
{ W32_FAST_FAIL_INVALID_FILE_OPERATION 42 }
{ W32_FAST_FAIL_LPAC_ACCESS_DENIED 43 }
{ W32_FAST_FAIL_GUARD_SS_FAILURE 44 }
{ W32_FAST_FAIL_LOADER_CONTINUITY_FAILURE 45 }
{ W32_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE 46 }
{ W32_FAST_FAIL_INVALID_CONTROL_STACK 47 }
{ W32_FAST_FAIL_SET_CONTEXT_DENIED 48 }
{ W32_FAST_FAIL_INVALID_IAT 49 }
{ W32_FAST_FAIL_HEAP_METADATA_CORRUPTION 50 }
{ W32_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION 51 }
{ W32_FAST_FAIL_LOW_LABEL_ACCESS_DENIED 52 }
{ W32_FAST_FAIL_ENCLAVE_CALL_FAILURE 53 }
{ W32_FAST_FAIL_UNHANDLED_LSS_EXCEPTON 54 }
{ W32_FAST_FAIL_ADMINLESS_ACCESS_DENIED 55 }
{ W32_FAST_FAIL_UNEXPECTED_CALL 56 }
{ W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS 57 }
{ W32_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR 58 }
{ W32_FAST_FAIL_FLAGS_CORRUPTION 59 }
{ W32_FAST_FAIL_VEH_CORRUPTION 60 }
{ W32_FAST_FAIL_ETW_CORRUPTION 61 }
{ W32_FAST_FAIL_RIO_ABORT 62 }
{ W32_FAST_FAIL_INVALID_PFN 63 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG 64 }
{ W32_FAST_FAIL_CAST_GUARD 65 }
{ W32_FAST_FAIL_HOST_VISIBILITY_CHANGE 66 }
{ W32_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST 67 }
{ W32_FAST_FAIL_PATCH_CALLBACK_FAILED 68 }
{ W32_FAST_FAIL_NTDLL_PATCH_FAILED 69 }
{ W32_FAST_FAIL_INVALID_FLS_DATA 70 }
}
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More