mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-07 22:38:41 +00:00
Merge remote-tracking branch 'EpicGamesExt/master'
# Conflicts: # .gitignore
This commit is contained in:
@@ -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
|
||||
|
||||
+151
-52
@@ -1,52 +1,151 @@
|
||||
name: builds
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build-windows-2022:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- raddbg
|
||||
- radlink
|
||||
- radbin
|
||||
compiler:
|
||||
- msvc
|
||||
- clang
|
||||
mode:
|
||||
- debug
|
||||
- release
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- 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
|
||||
|
||||
run-torture:
|
||||
runs-on: windows-2022
|
||||
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
|
||||
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
|
||||
name: builds
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
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:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- raddbg
|
||||
- radlink
|
||||
- radbin
|
||||
- mule_main
|
||||
compiler:
|
||||
- msvc
|
||||
- clang
|
||||
mode:
|
||||
- debug
|
||||
- release
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
lfs: true
|
||||
- name: build (vs 2022)
|
||||
shell: cmd
|
||||
run: |
|
||||
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-ubuntu-24-04:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler:
|
||||
- clang-22
|
||||
# TODO: - gcc
|
||||
mode:
|
||||
- debug
|
||||
# TODO: - 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
|
||||
# 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: |
|
||||
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
@@ -1,4 +1,5 @@
|
||||
/build/
|
||||
/local/
|
||||
*~
|
||||
.vscode/settings.json
|
||||
.vs
|
||||
tags
|
||||
+245
@@ -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
|
||||
|
||||
@@ -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_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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, ®_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;
|
||||
}
|
||||
@@ -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
@@ -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, },
|
||||
|
||||
@@ -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
|
||||
+126
-21
@@ -1,21 +1,126 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /D "%~dp0"
|
||||
|
||||
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:
|
||||
|
||||
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%
|
||||
popd
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
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
|
||||
|
||||
:: 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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+168
-47
@@ -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,73 +28,148 @@
|
||||
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);
|
||||
}
|
||||
U64 commit_size = params->commit_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;
|
||||
arena->current = arena;
|
||||
arena->flags = params->flags;
|
||||
arena->cmt_size = params->commit_size;
|
||||
arena->res_size = params->reserve_size;
|
||||
arena->base_pos = 0;
|
||||
arena->pos = ARENA_HEADER_SIZE;
|
||||
arena->cmt = commit_size;
|
||||
arena->res = reserve_size;
|
||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
||||
Arena *arena = base;
|
||||
arena->current = arena;
|
||||
arena->flags = params->flags;
|
||||
arena->cmt_size = params->commit_size;
|
||||
arena->res_size = params->reserve_size;
|
||||
arena->base_pos = 0;
|
||||
arena->pos = ARENA_HEADER_SIZE;
|
||||
arena->cmt = commit_size;
|
||||
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);
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ struct Log
|
||||
LogScope *top_scope;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// Globals
|
||||
|
||||
extern String8 g_logs_folder;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Creation/Selection
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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(¶ms);
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
@@ -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
|
||||
+501
-149
@@ -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,16 +2795,18 @@ 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;
|
||||
srl->first = srl->last = node;
|
||||
srl->node_count = 1;
|
||||
srl->total_size = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cmp == 0) {
|
||||
// shorter prefix must precede longer prefixes
|
||||
if (a.size > b.size) {
|
||||
cmp = +1;
|
||||
} else if (b.size > a.size) {
|
||||
cmp = -1;
|
||||
}
|
||||
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;
|
||||
|
||||
// shorter prefix must precede longer prefixes
|
||||
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
@@ -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
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+35
-9
@@ -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,11 +129,12 @@ 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);
|
||||
internal void barrier_release(Barrier barrier);
|
||||
internal void barrier_wait(Barrier barrier);
|
||||
internal Barrier barrier_alloc(U64 count);
|
||||
internal void barrier_release(Barrier barrier);
|
||||
internal void barrier_wait(Barrier barrier);
|
||||
|
||||
//- rjf: scope macros
|
||||
#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex))
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
+35
-288
@@ -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) \
|
||||
@@ -1299,12 +1044,12 @@ CV_ThunkOrdinalEnum;
|
||||
typedef struct CV_SymThunk32 CV_SymThunk32;
|
||||
struct CV_SymThunk32
|
||||
{
|
||||
U32 parent;
|
||||
U32 end;
|
||||
U32 next;
|
||||
U32 off;
|
||||
U16 sec;
|
||||
U16 len;
|
||||
U32 parent;
|
||||
U32 end;
|
||||
U32 next;
|
||||
U32 off;
|
||||
U16 sec;
|
||||
U16 len;
|
||||
CV_ThunkOrdinal ord;
|
||||
// U8[] name (null terminated)
|
||||
// U8[] variant (null terminated)
|
||||
@@ -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,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;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ struct CV_NumericParsed
|
||||
typedef struct CV_RecRange CV_RecRange;
|
||||
struct CV_RecRange
|
||||
{
|
||||
U32 off;
|
||||
U32 off;
|
||||
CV_RecHeader hdr;
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ typedef struct CV_RecRangeChunk CV_RecRangeChunk;
|
||||
struct CV_RecRangeChunk
|
||||
{
|
||||
struct CV_RecRangeChunk *next;
|
||||
CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE];
|
||||
CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE];
|
||||
};
|
||||
|
||||
typedef struct CV_RecRangeStream CV_RecRangeStream;
|
||||
@@ -42,14 +42,14 @@ struct CV_RecRangeStream
|
||||
{
|
||||
CV_RecRangeChunk *first_chunk;
|
||||
CV_RecRangeChunk *last_chunk;
|
||||
U64 total_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct CV_RecRangeArray CV_RecRangeArray;
|
||||
struct CV_RecRangeArray
|
||||
{
|
||||
CV_RecRange *ranges;
|
||||
U64 count;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -58,9 +58,9 @@ struct CV_RecRangeArray
|
||||
typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo;
|
||||
struct CV_SymTopLevelInfo
|
||||
{
|
||||
CV_Arch arch;
|
||||
CV_Arch arch;
|
||||
CV_Language language;
|
||||
String8 compiler_name;
|
||||
String8 compiler_name;
|
||||
};
|
||||
|
||||
typedef struct CV_SymParsed CV_SymParsed;
|
||||
@@ -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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+17
-7
@@ -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)
|
||||
{
|
||||
|
||||
+21
-17
@@ -163,24 +163,25 @@ 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;
|
||||
U32 voff;
|
||||
U32 fsize;
|
||||
U32 foff;
|
||||
U32 relocs_foff;
|
||||
U32 lines_foff;
|
||||
U16 reloc_count;
|
||||
U16 line_count;
|
||||
U8 name[8];
|
||||
U32 vsize;
|
||||
U32 voff;
|
||||
U32 fsize;
|
||||
U32 foff;
|
||||
U32 relocs_foff;
|
||||
U32 lines_foff;
|
||||
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
|
||||
@@ -628,8 +631,9 @@ internal U64 coff_word_size_from_machine (COFF_MachineType machine);
|
||||
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 U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
|
||||
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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum <=> String
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+112
-2
@@ -1,11 +1,14 @@
|
||||
// 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;
|
||||
obj_writer->machine = machine;
|
||||
obj_writer->machine = machine;
|
||||
return obj_writer;
|
||||
}
|
||||
|
||||
@@ -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 = §ion_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 = §ion_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
@@ -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
@@ -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, §ion_table[sect_idx]), name, 0)) {
|
||||
return §ion_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, §ion_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, §ion_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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user