mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-08 14:58:08 +00:00
Merge remote-tracking branch 'EpicGamesExt/master'
# Conflicts: # .gitignore
This commit is contained in:
@@ -1 +1,8 @@
|
|||||||
*.sh text=auto eol=lf
|
*.sh text=auto eol=lf
|
||||||
|
src/lib_rdi/rdi.h text=auto eol=lf
|
||||||
|
src/lib_rdi/rdi.c text=auto eol=lf
|
||||||
|
*.meta.* text=auto eol=lf
|
||||||
|
*.exe filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pdb filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.elf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.rdi filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
+117
-18
@@ -8,7 +8,45 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
|
|
||||||
|
env:
|
||||||
|
TORTURE_FLAGS: "--gen_crash_dump"
|
||||||
|
|
||||||
jobs:
|
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:
|
build-windows-2022:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
strategy:
|
strategy:
|
||||||
@@ -18,6 +56,7 @@ jobs:
|
|||||||
- raddbg
|
- raddbg
|
||||||
- radlink
|
- radlink
|
||||||
- radbin
|
- radbin
|
||||||
|
- mule_main
|
||||||
compiler:
|
compiler:
|
||||||
- msvc
|
- msvc
|
||||||
- clang
|
- clang
|
||||||
@@ -25,28 +64,88 @@ jobs:
|
|||||||
- debug
|
- debug
|
||||||
- release
|
- release
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
- name: build (vs 2022)
|
- name: build (vs 2022)
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
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 build "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
|
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||||
|
call build meta "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
|
||||||
|
|
||||||
run-torture:
|
run-ubuntu-24-04:
|
||||||
runs-on: windows-2022
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
compiler:
|
||||||
|
- clang-22
|
||||||
|
# TODO: - gcc
|
||||||
|
mode:
|
||||||
|
- debug
|
||||||
|
# TODO: - release
|
||||||
steps:
|
steps:
|
||||||
# - name: Install ASAN
|
- name: Checkout
|
||||||
# shell: cmd
|
uses: actions/checkout@v6
|
||||||
# run: |
|
with:
|
||||||
# "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
|
lfs: true
|
||||||
- name: checkout
|
- name: Install Dependencies
|
||||||
uses: actions/checkout@v2
|
shell: bash
|
||||||
- name: run-torture
|
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
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
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 build radlink asan debug no_meta || exit /b 1
|
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||||
call build torture debug no_meta || exit /b 1
|
call run_tests.bat ${{ matrix.compiler }} ${{ matrix.mode }} -- * %TORTURE_FLAGS% || exit /b 1
|
||||||
cd build
|
- name: Upload Artifacts
|
||||||
torture -l:radlink || exit /b 1
|
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/
|
/build/
|
||||||
/local/
|
/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
|
# v0.9.24-alpha
|
||||||
|
|
||||||
## Debugger Changes
|
## Debugger Changes
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ cd /D "%~dp0"
|
|||||||
:: Below is a list of all possible non-target command line options:
|
:: Below is a list of all possible non-target command line options:
|
||||||
::
|
::
|
||||||
:: - `asan`: enable address sanitizer
|
:: - `asan`: enable address sanitizer
|
||||||
|
:: - `ubsan`: enable undefined-behavior sanitizer
|
||||||
:: - `telemetry`: enable RAD telemetry profiling support
|
:: - `telemetry`: enable RAD telemetry profiling support
|
||||||
:: - `spall`: enable spall 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 "%release%"=="1" set debug=0 && echo [release mode]
|
||||||
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
||||||
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
||||||
if "%~1"=="" 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
|
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 ------------------------------------
|
:: --- Unpack Command Line Build Arguments ------------------------------------
|
||||||
set auto_compile_flags=
|
set auto_compile_flags=
|
||||||
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
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 "%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 "%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 "%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%"=="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
|
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
|
||||||
@@ -66,21 +68,22 @@ if "%pgo%"=="1" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /Zc:preprocessor
|
||||||
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
set cl_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_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_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_out= /out:
|
||||||
|
set cl_obj_out= /Fo:
|
||||||
set cl_linker=
|
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_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 %clang_common% %auto_compile_flags%
|
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 %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:icf
|
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_out= -o
|
||||||
|
set clang_obj_out= -o
|
||||||
set clang_linker= -Xlinker
|
set clang_linker= -Xlinker
|
||||||
|
|
||||||
:: --- Per-Build Settings -----------------------------------------------------
|
:: --- Per-Build Settings -----------------------------------------------------
|
||||||
set link_dll=-DLL
|
|
||||||
set link_icon=logo.res
|
set link_icon=logo.res
|
||||||
if "%msvc%"=="1" set linker=%cl_linker%
|
if "%msvc%"=="1" set linker=%cl_linker%
|
||||||
if "%clang%"=="1" set linker=%clang_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 "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
|
||||||
if "%msvc%"=="1" set rc=call rc
|
if "%msvc%"=="1" set rc=call rc
|
||||||
if "%clang%"=="1" set rc=call llvm-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 ----------------------------------------------
|
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||||
if "%msvc%"=="1" set compile_release=%cl_release%
|
if "%msvc%"=="1" set compile_release=%cl_release%
|
||||||
if "%msvc%"=="1" set compile_link=%cl_link%
|
if "%msvc%"=="1" set compile_link=%cl_link%
|
||||||
if "%msvc%"=="1" set out=%cl_out%
|
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_debug=%clang_debug%
|
||||||
if "%clang%"=="1" set compile_release=%clang_release%
|
if "%clang%"=="1" set compile_release=%clang_release%
|
||||||
if "%clang%"=="1" set compile_link=%clang_link%
|
if "%clang%"=="1" set compile_link=%clang_link%
|
||||||
if "%clang%"=="1" set out=%clang_out%
|
if "%clang%"=="1" set out=%clang_out%
|
||||||
|
if "%clang%"=="1" set obj_out=%clang_obj_out%
|
||||||
if "%debug%"=="1" set compile=%compile_debug%
|
if "%debug%"=="1" set compile=%compile_debug%
|
||||||
if "%release%"=="1" set compile=%compile_release%
|
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\"
|
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
|
||||||
|
|
||||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||||
|
pushd build
|
||||||
if "%meta%"=="1" (
|
if "%meta%"=="1" (
|
||||||
echo [doing metagen]
|
echo [building metagen]
|
||||||
pushd build
|
|
||||||
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
%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) --------------------------------------
|
:: --- Build Everything (@build_targets) --------------------------------------
|
||||||
pushd build
|
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%"=="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 "%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 "%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 "%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 "%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 "%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 "%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 "%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 "%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 "%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_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 %compile_link% %link_dll% %out%mule_module.dll || 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 "%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" (
|
if "%mule_peb_trample%"=="1" (
|
||||||
set didbuild=1
|
set didbuild=1
|
||||||
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
|
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
|
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 ------------------------------------------------------
|
:: --- Warn On No Builds ------------------------------------------------------
|
||||||
if "%didbuild%"=="" (
|
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`.
|
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 "%pgo_run%"=="1" (
|
||||||
if "%radlink%"=="1" (
|
if "%radlink%"=="1" (
|
||||||
pushd local\lyra_pgo
|
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
|
popd
|
||||||
)
|
)
|
||||||
goto restart
|
goto restart
|
||||||
|
|||||||
@@ -4,78 +4,74 @@ cd "$(dirname "$0")"
|
|||||||
|
|
||||||
# --- Unpack Arguments --------------------------------------------------------
|
# --- Unpack Arguments --------------------------------------------------------
|
||||||
for arg in "$@"; do declare $arg='1'; done
|
for arg in "$@"; do declare $arg='1'; done
|
||||||
if [ ! -v gcc ]; then clang=1; fi
|
if [[ "$#" == "0" ]]; then raddbg='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
|
|
||||||
|
|
||||||
# --- Unpack Command Line Build Arguments -------------------------------------
|
cc_sanitize=""
|
||||||
auto_compile_flags=''
|
if [[ "${asan:-0}" == "1" ]]; then
|
||||||
|
echo "[asan enabled]"
|
||||||
|
cc_sanitize="-fsanitize=address"
|
||||||
|
fi
|
||||||
|
|
||||||
# --- Get Current Git Commit Id -----------------------------------------------
|
# --- Get Current Git Commit Id -----------------------------------------------
|
||||||
git_hash=$(git describe --always --dirty)
|
git_hash=$(git describe --always --dirty)
|
||||||
git_hash_full=$(git rev-parse HEAD)
|
git_hash_full=$(git rev-parse HEAD)
|
||||||
|
|
||||||
# --- Compile/Link Line Definitions -------------------------------------------
|
# --- 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"
|
cc_cflags_gcc=""
|
||||||
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
|
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"
|
||||||
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
|
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"
|
||||||
clang_link="-lpthread -lm -lrt -ldl"
|
cc_debug="-g -O0 -DBUILD_DEBUG=1 ${cc_common}"
|
||||||
clang_out="-o"
|
cc_release="-g -O2 -DBUILD_DEBUG=0 ${cc_common}"
|
||||||
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"
|
cc_link="-lpthread -lm -lrt -ldl"
|
||||||
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"
|
|
||||||
|
|
||||||
# --- Per-Build Settings ------------------------------------------------------
|
# --- Per-Build Settings ------------------------------------------------------
|
||||||
link_dll="-fPIC"
|
cc_link_dll="-fPIC"
|
||||||
link_os_gfx="-lX11 -lXext"
|
|
||||||
link_render="-lGL -lEGL"
|
# --- External Libraries ------------------------------------------------------
|
||||||
link_font_provider="-lfreetype"
|
# 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 -----------------------------------------------
|
# --- Choose Compile/Link Lines -----------------------------------------------
|
||||||
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
|
if [[ "${gcc:-0}" == "1" ]]; then compiler="${CC:-gcc} $cc_cflags_gcc"; echo "[gcc compile]";
|
||||||
if [ -v gcc ]; then compile_release="$gcc_release"; fi
|
elif [[ "${clang:-1}" == "1" ]]; then compiler="${CC:-clang} $cc_cflags_clang"; echo "[clang compile]";
|
||||||
if [ -v gcc ]; then compile_link="$gcc_link"; fi
|
fi
|
||||||
if [ -v gcc ]; then out="$gcc_out"; fi
|
if [[ "${release:-0}" == "1" ]]; then echo "[release mode]"; compile="$compiler $cc_release";
|
||||||
if [ -v clang ]; then compile_debug="$clang_debug"; fi
|
elif [[ "${debug:-1}" == "1" ]]; then echo "[debug mode]"; compile="$compiler $cc_debug";
|
||||||
if [ -v clang ]; then compile_release="$clang_release"; fi
|
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
|
|
||||||
|
|
||||||
# --- Prep Directories --------------------------------------------------------
|
# --- Prep Directories --------------------------------------------------------
|
||||||
mkdir -p build
|
mkdir -p build local
|
||||||
mkdir -p local
|
|
||||||
|
|
||||||
# --- Build & Run Metaprogram -------------------------------------------------
|
# --- Build & Run Metaprogram -------------------------------------------------
|
||||||
if [ -v no_meta ]; then echo "[skipping metagen]"; fi
|
if [[ "${no_meta:-0}" == "0" ]]
|
||||||
if [ ! -v no_meta ]
|
|
||||||
then
|
then
|
||||||
|
echo "[building metagen]"
|
||||||
cd build
|
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
|
./metagen
|
||||||
cd ..
|
cd ..
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Build Everything (@build_targets) ---------------------------------------
|
# --- Build Everything (@build_targets) ---------------------------------------
|
||||||
cd build
|
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 [[ "${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 [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; 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 [ -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 [[ "${radbin:-0}" == "1" ]]; then didbuild=1 && $compile ../src/radbin/radbin_main.c $cc_link -o radbin; 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 [[ "${radlink:-0}" == "1" ]]; then didbuild=1 && $compile ../src/linker/lnk.c $cc_link -o radlink; fi
|
||||||
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; 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
|
||||||
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
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
# --- Warn On No Builds -------------------------------------------------------
|
# --- Warn On No Builds -------------------------------------------------------
|
||||||
if [ ! -v didbuild ]
|
if [[ "${didbuild:-0}" == "0" ]]
|
||||||
then
|
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
|
exit 1
|
||||||
fi
|
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 =
|
commands =
|
||||||
{
|
{
|
||||||
//- rjf: [raddbg]
|
//- 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 raddbg", .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 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]
|
//- rjf: [raddbg wsl]
|
||||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||||
|
|
||||||
//- rjf: [scratch]
|
//- 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]
|
//- 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, },
|
// .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
|
//- 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 = "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 = "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 = "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, },
|
// .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
|
||||||
+122
-17
@@ -1,21 +1,126 @@
|
|||||||
@echo off
|
@echo off
|
||||||
setlocal
|
setlocal enabledelayedexpansion
|
||||||
cd /D "%~dp0"
|
|
||||||
|
|
||||||
echo --- getting test data folder path ---------------------------------------------
|
set TARGET_VALUES=radlink radbin mule_main mule_module torture
|
||||||
if not exist .\local\test_data_path.txt (
|
set CC_VALUES=msvc clang
|
||||||
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
|
set MODE_VALUES=debug release
|
||||||
goto :EOF
|
set RAW_ARGS=%*
|
||||||
)
|
set TORTURE_ARGS=
|
||||||
set /p test_data_folder=<.\local\test_data_path.txt
|
set RUN_TORTURE=1
|
||||||
echo test data path: %test_data_folder%
|
|
||||||
echo:
|
|
||||||
|
|
||||||
echo --- building all testing executables ------------------------------------------
|
:: Make test data directories
|
||||||
call build rdi_from_pdb rdi_dump raddbg radlink tester
|
if not exist local mkdir local
|
||||||
echo:
|
pushd local
|
||||||
|
if not exist test_data mkdir test_data
|
||||||
echo --- running tests -------------------------------------------------------------
|
|
||||||
pushd build
|
|
||||||
call tester.exe --test_data:%test_data_folder%
|
|
||||||
popd
|
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].mutex = mutex_alloc();
|
||||||
ac_shared->req_batches[idx].arena = arena_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 = 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_count = Max(256, params->slots_count);
|
||||||
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
||||||
cache->stripes = stripe_array_alloc(cache_stripe->arena);
|
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)
|
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];
|
AC_Slot *slot = &cache->slots[slot_idx];
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, 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
|
//- rjf: cache * key -> existing artifact
|
||||||
B32 artifact_is_stale = 1;
|
B32 artifact_is_stale = 1;
|
||||||
B32 got_artifact = 0;
|
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_is_stale = is_stale;
|
||||||
artifact = n->val;
|
artifact = n->val;
|
||||||
access_touch(access, &n->access_pt, stripe->cv);
|
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)
|
if(is_stale)
|
||||||
{
|
{
|
||||||
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
||||||
need_request = got_task;
|
need_request = got_task;
|
||||||
|
if(is_node_work_active)
|
||||||
|
{
|
||||||
|
ins_atomic_u32_eval_assign(&n->other_nodes_depend_on_me, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -109,7 +117,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
|||||||
{
|
{
|
||||||
RWMutexScope(stripe->rw_mutex, 1) for(;;)
|
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
|
// rjf: find node in cache
|
||||||
AC_Node *node = 0;
|
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->key = str8_copy(stripe->arena, key);
|
||||||
node->working_count = 1;
|
node->working_count = 1;
|
||||||
node->evict_threshold_us = params->evict_threshold_us;
|
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();
|
node->access_pt.last_update_idx_touched = update_tick_idx();
|
||||||
|
|
||||||
// rjf: request
|
// 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))
|
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;
|
got_artifact = 1;
|
||||||
artifact_is_stale = (node->last_completed_gen == params->gen);
|
artifact_is_stale = (node->last_completed_gen != params->gen);
|
||||||
artifact = node->val;
|
artifact = node->val;
|
||||||
access_touch(access, &node->access_pt, stripe->cv);
|
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
|
// rjf: abort if needed
|
||||||
@@ -218,7 +231,7 @@ ac_async_tick(void)
|
|||||||
//
|
//
|
||||||
if(lane_idx() == 0)
|
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)
|
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
||||||
{
|
{
|
||||||
next = 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;
|
slot_has_work = 1;
|
||||||
if(!write_mode)
|
if(!write_mode)
|
||||||
@@ -328,6 +343,11 @@ ac_async_tick(void)
|
|||||||
lane_sync_u64(&tasks_count, 0);
|
lane_sync_u64(&tasks_count, 0);
|
||||||
lane_sync();
|
lane_sync();
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: set up artifact cache thread context
|
||||||
|
//
|
||||||
|
ac_tctx = push_array(scratch.arena, AC_TCTX, 1);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- rjf: do all requests
|
//- rjf: do all requests
|
||||||
//
|
//
|
||||||
@@ -376,7 +396,7 @@ ac_async_tick(void)
|
|||||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
// 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];
|
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
||||||
MutexScope(batch->mutex)
|
MutexScope(batch->mutex)
|
||||||
@@ -423,6 +443,19 @@ ac_async_tick(void)
|
|||||||
{
|
{
|
||||||
if(str8_match(n->key, r->key, 0))
|
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->last_completed_gen = gen;
|
||||||
n->val = val;
|
n->val = val;
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
ins_atomic_u64_dec_eval(&n->working_count);
|
||||||
@@ -485,7 +518,7 @@ ac_async_tick(void)
|
|||||||
lane_ctx(lane_ctx_restore);
|
lane_ctx(lane_ctx_restore);
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
// rjf: retry? -> resubmit request
|
||||||
if(retry)
|
if(retry && !ins_atomic_u32_eval(r->cancel_signal))
|
||||||
{
|
{
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
||||||
MutexScope(batch->mutex)
|
MutexScope(batch->mutex)
|
||||||
@@ -532,6 +565,19 @@ ac_async_tick(void)
|
|||||||
{
|
{
|
||||||
if(str8_match(n->key, r->key, 0))
|
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->last_completed_gen = gen;
|
||||||
n->val = val;
|
n->val = val;
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
ins_atomic_u64_dec_eval(&n->working_count);
|
||||||
@@ -585,12 +631,36 @@ ac_async_tick(void)
|
|||||||
}
|
}
|
||||||
lane_sync();
|
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
|
//- rjf: disable cancellation scanning
|
||||||
//
|
//
|
||||||
if(lane_idx() == 0)
|
if(lane_idx() == 0)
|
||||||
{
|
{
|
||||||
mutex_take(ac_shared->cancel_thread_mutex);
|
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
|
||||||
}
|
}
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
@@ -603,8 +673,8 @@ ac_cancel_thread_entry_point(void *p)
|
|||||||
{
|
{
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
os_sleep_milliseconds(50);
|
sleep_ms(50);
|
||||||
MutexScope(ac_shared->cancel_thread_mutex)
|
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
|
||||||
{
|
{
|
||||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
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;
|
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;
|
typedef struct AC_Node AC_Node;
|
||||||
struct AC_Node
|
struct AC_Node
|
||||||
{
|
{
|
||||||
@@ -76,8 +83,9 @@ struct AC_Node
|
|||||||
U64 working_count;
|
U64 working_count;
|
||||||
U64 completion_count;
|
U64 completion_count;
|
||||||
U64 evict_threshold_us;
|
U64 evict_threshold_us;
|
||||||
|
U64 last_touched_ac_request_gen;
|
||||||
B32 cancelled;
|
B32 cancelled;
|
||||||
U64 _unused_;
|
B32 other_nodes_depend_on_me;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct AC_Slot AC_Slot;
|
typedef struct AC_Slot AC_Slot;
|
||||||
@@ -99,6 +107,7 @@ struct AC_Cache
|
|||||||
U64 slots_count;
|
U64 slots_count;
|
||||||
AC_Slot *slots;
|
AC_Slot *slots;
|
||||||
StripeArray stripes;
|
StripeArray stripes;
|
||||||
|
AC_NodePtr **stripe_free_node_ptrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct AC_RequestBatch AC_RequestBatch;
|
typedef struct AC_RequestBatch AC_RequestBatch;
|
||||||
@@ -114,10 +123,17 @@ struct AC_RequestBatch
|
|||||||
U64 thin_count;
|
U64 thin_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct AC_TCTX AC_TCTX;
|
||||||
|
struct AC_TCTX
|
||||||
|
{
|
||||||
|
U64 _unused_;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct AC_Shared AC_Shared;
|
typedef struct AC_Shared AC_Shared;
|
||||||
struct AC_Shared
|
struct AC_Shared
|
||||||
{
|
{
|
||||||
Arena *arena;
|
Arena *arena;
|
||||||
|
U64 request_gen;
|
||||||
|
|
||||||
// rjf: cache cache
|
// rjf: cache cache
|
||||||
U64 cache_slots_count;
|
U64 cache_slots_count;
|
||||||
@@ -129,13 +145,14 @@ struct AC_Shared
|
|||||||
|
|
||||||
// rjf: cancel thread
|
// rjf: cancel thread
|
||||||
Thread cancel_thread;
|
Thread cancel_thread;
|
||||||
Mutex cancel_thread_mutex;
|
Semaphore cancel_thread_semaphore;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Globals
|
//~ rjf: Globals
|
||||||
|
|
||||||
global AC_Shared *ac_shared = 0;
|
global AC_Shared *ac_shared = 0;
|
||||||
|
thread_static AC_TCTX *ac_tctx = 0;
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Layer Initialization
|
//~ rjf: Layer Initialization
|
||||||
|
|||||||
+157
-36
@@ -1,6 +1,25 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// 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
|
//~ rjf: Arena Functions
|
||||||
|
|
||||||
@@ -9,48 +28,56 @@
|
|||||||
internal Arena *
|
internal Arena *
|
||||||
arena_alloc_(ArenaParams *params)
|
arena_alloc_(ArenaParams *params)
|
||||||
{
|
{
|
||||||
// rjf: round up reserve/commit sizes
|
|
||||||
U64 reserve_size = params->reserve_size;
|
U64 reserve_size = params->reserve_size;
|
||||||
U64 commit_size = params->commit_size;
|
U64 commit_size = params->commit_size;
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: reserve/commit initial block
|
// rjf: reserve/commit initial block
|
||||||
void *base = params->optional_backing_buffer;
|
void *base = params->optional_backing_buffer;
|
||||||
if(base == 0)
|
if(base == 0)
|
||||||
{
|
{
|
||||||
|
// rjf: round up reserve/commit sizes
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
if(params->flags & ArenaFlag_LargePages)
|
||||||
{
|
{
|
||||||
base = os_reserve_large(reserve_size);
|
reserve_size = AlignPow2(reserve_size, get_system_info()->large_page_size);
|
||||||
os_commit_large(base, commit_size);
|
commit_size = AlignPow2(commit_size, get_system_info()->large_page_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
base = os_reserve(reserve_size);
|
reserve_size = AlignPow2(reserve_size, get_system_info()->page_size);
|
||||||
os_commit(base, commit_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
|
// rjf: panic on arena creation failure
|
||||||
#if OS_FEATURE_GRAPHICAL
|
#if OS_FEATURE_GRAPHICAL
|
||||||
if(Unlikely(base == 0))
|
if(Unlikely(base == 0))
|
||||||
{
|
{
|
||||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||||
os_abort(1);
|
abort_self(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// rjf: extract arena header & fill
|
// rjf: extract arena header & fill
|
||||||
Arena *arena = (Arena *)base;
|
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
||||||
|
Arena *arena = base;
|
||||||
arena->current = arena;
|
arena->current = arena;
|
||||||
arena->flags = params->flags;
|
arena->flags = params->flags;
|
||||||
arena->cmt_size = params->commit_size;
|
arena->cmt_size = params->commit_size;
|
||||||
@@ -61,21 +88,88 @@ arena_alloc_(ArenaParams *params)
|
|||||||
arena->res = reserve_size;
|
arena->res = reserve_size;
|
||||||
arena->allocation_site_file = params->allocation_site_file;
|
arena->allocation_site_file = params->allocation_site_file;
|
||||||
arena->allocation_site_line = params->allocation_site_line;
|
arena->allocation_site_line = params->allocation_site_line;
|
||||||
|
arena->name = params->name;
|
||||||
#if ARENA_FREE_LIST
|
#if ARENA_FREE_LIST
|
||||||
arena->free_last = 0;
|
arena->free_last = 0;
|
||||||
#endif
|
#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;
|
return arena;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_release(Arena *arena)
|
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)
|
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
||||||
{
|
{
|
||||||
prev = 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_pre = AlignPow2(current->pos, align);
|
||||||
U64 pos_pst = pos_pre + size;
|
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
|
// rjf: chain, if needed
|
||||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
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,
|
.flags = current->flags,
|
||||||
.allocation_site_file = current->allocation_site_file,
|
.allocation_site_file = current->allocation_site_file,
|
||||||
.allocation_site_line = current->allocation_site_line);
|
.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;
|
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;
|
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
|
// rjf: commit new pages, if needed
|
||||||
if(current->cmt < pos_pst)
|
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;
|
U8 *cmt_ptr = (U8 *)current + current->cmt;
|
||||||
if(current->flags & ArenaFlag_LargePages)
|
if(current->flags & ArenaFlag_LargePages)
|
||||||
{
|
{
|
||||||
os_commit_large(cmt_ptr, cmt_size);
|
commit_memory_large(cmt_ptr, cmt_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
os_commit(cmt_ptr, cmt_size);
|
commit_memory(cmt_ptr, cmt_size);
|
||||||
}
|
}
|
||||||
|
AsanPoisonMemoryRegion(cmt_ptr, cmt_size);
|
||||||
current->cmt = cmt_pst_clamped;
|
current->cmt = cmt_pst_clamped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,18 +275,24 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
|
|||||||
result = (U8 *)current+pos_pre;
|
result = (U8 *)current+pos_pre;
|
||||||
current->pos = pos_pst;
|
current->pos = pos_pst;
|
||||||
AsanUnpoisonMemoryRegion(result, size);
|
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
|
// rjf: panic on failure
|
||||||
#if OS_FEATURE_GRAPHICAL
|
#if OS_FEATURE_GRAPHICAL
|
||||||
if(Unlikely(result == 0))
|
if(Unlikely(result == 0))
|
||||||
{
|
{
|
||||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||||
os_abort(1);
|
abort_self(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -215,7 +325,8 @@ arena_pop_to(Arena *arena, U64 pos)
|
|||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
||||||
{
|
{
|
||||||
prev = current->prev;
|
prev = current->prev;
|
||||||
os_release(current, current->res);
|
AsanUnpoisonMemoryRegion(current, current->cmt);
|
||||||
|
release_memory(current, current->res);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
arena->current = current;
|
arena->current = current;
|
||||||
@@ -223,6 +334,16 @@ arena_pop_to(Arena *arena, U64 pos)
|
|||||||
AssertAlways(new_pos <= current->pos);
|
AssertAlways(new_pos <= current->pos);
|
||||||
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - 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
|
//- rjf: arena push/pop helpers
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ struct ArenaParams
|
|||||||
void *optional_backing_buffer;
|
void *optional_backing_buffer;
|
||||||
char *allocation_site_file;
|
char *allocation_site_file;
|
||||||
int allocation_site_line;
|
int allocation_site_line;
|
||||||
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Arena Arena;
|
typedef struct Arena Arena;
|
||||||
@@ -41,9 +42,13 @@ struct Arena
|
|||||||
U64 res;
|
U64 res;
|
||||||
char *allocation_site_file;
|
char *allocation_site_file;
|
||||||
int allocation_site_line;
|
int allocation_site_line;
|
||||||
|
char *name;
|
||||||
#if ARENA_FREE_LIST
|
#if ARENA_FREE_LIST
|
||||||
Arena *free_last;
|
Arena *free_last;
|
||||||
#endif
|
#endif
|
||||||
|
#if ARENA_TABLE_DEBUG
|
||||||
|
struct ArenaTableNode *table_node;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,10 @@
|
|||||||
# define BUILD_DEBUG 1
|
# define BUILD_DEBUG 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BUILD_TESTS)
|
||||||
|
# define BUILD_TESTS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
||||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
# define BUILD_SUPPLEMENTARY_UNIT 0
|
||||||
#endif
|
#endif
|
||||||
@@ -159,7 +163,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_PATCH)
|
#if !defined(BUILD_VERSION_PATCH)
|
||||||
# define BUILD_VERSION_PATCH 24
|
# define BUILD_VERSION_PATCH 28
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
#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.
|
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
|
||||||
#endif
|
#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
|
#endif // BASE_CONTEXT_CRACKING_H
|
||||||
|
|||||||
+126
-13
@@ -79,19 +79,21 @@ u64_up_to_pow2(U64 x){
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal S32
|
internal S32
|
||||||
extend_sign32(U32 x, U32 size){
|
extend_sign32(U32 x, U32 size)
|
||||||
U32 high_bit = size * 8;
|
{
|
||||||
U32 shift = 32 - high_bit;
|
U32 n = size * 8;
|
||||||
S32 result = ((S32)x << shift) >> shift;
|
U32 m = (U32)1 << (n - 1);
|
||||||
return result;
|
S32 r = (S32)((x ^ m) - m);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal S64
|
internal S64
|
||||||
extend_sign64(U64 x, U64 size){
|
extend_sign64(U64 x, U64 size)
|
||||||
U64 high_bit = size * 8;
|
{
|
||||||
U64 shift = 64 - high_bit;
|
U64 n = size * 8;
|
||||||
S64 result = ((S64)x << shift) >> shift;
|
U64 m = (U64)1 << (n - 1);
|
||||||
return result;
|
S64 r = (S64)((x ^ m) - m);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal F32
|
internal F32
|
||||||
@@ -286,6 +288,56 @@ memory_is_zero(void *ptr, U64 size)
|
|||||||
return result;
|
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
|
//~ rjf: Text 2D Coordinate/Range Functions
|
||||||
|
|
||||||
@@ -413,6 +465,38 @@ byte_size_from_arch(Arch arch)
|
|||||||
return bit_size_from_arch(arch) / 8;
|
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
|
internal U64
|
||||||
max_instruction_size_from_arch(Arch arch)
|
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
|
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);
|
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
|
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);
|
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
|
internal U64
|
||||||
index_of_zero_u32(U32 *ptr, U64 count)
|
index_of_zero_u32(U32 *ptr, U64 count)
|
||||||
{
|
{
|
||||||
@@ -630,6 +734,15 @@ index_of_zero_u64(U64 *ptr, U64 count)
|
|||||||
return max_U64;
|
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
|
//~ rjf: Third Party Includes
|
||||||
|
|
||||||
|
|||||||
+172
-63
@@ -7,11 +7,13 @@
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Foreign Includes
|
//~ rjf: Foreign Includes
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Third Party Includes
|
//~ rjf: Third Party Includes
|
||||||
@@ -180,8 +182,9 @@
|
|||||||
//~ rjf: Member Offsets
|
//~ rjf: Member Offsets
|
||||||
|
|
||||||
#define Member(T,m) (((T*)0)->m)
|
#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 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))
|
#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 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 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 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
|
//~ rjf: Memory Operation Macros
|
||||||
@@ -203,7 +207,6 @@
|
|||||||
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
|
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
|
||||||
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
|
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
|
||||||
#define MemoryCompare(a, b, size) memcmp((a), (b), (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 MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
|
||||||
#define MemoryCopyArray(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 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
|
//~ rjf: Asserts
|
||||||
|
|
||||||
@@ -252,38 +252,44 @@
|
|||||||
#if COMPILER_MSVC
|
#if COMPILER_MSVC
|
||||||
# include <intrin.h>
|
# include <intrin.h>
|
||||||
# if ARCH_X64
|
# 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_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_eval(x) (U64)__iso_volatile_load64((__int64*)(x))
|
||||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((__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_dec_eval(x) _InterlockedDecrement64((__int64 *)(x))
|
||||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((__int64 *)(x),(c))
|
# 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_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_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_eval(x) (U32)__iso_volatile_load32((__int32*)(x))
|
||||||
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((LONG *)(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_dec_eval(x) _InterlockedDecrement((long *)(x))
|
||||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((LONG *)(x),(c))
|
# 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_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_u32_add_eval(x,c) _interlockedadd((long *)(x), (c))
|
||||||
# define ins_atomic_u8_eval_assign(x,c) InterlockedExchange8((CHAR *)(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
|
# else
|
||||||
# error Atomic intrinsics not defined for this compiler / architecture combination.
|
# error Atomic intrinsics not defined for this compiler / architecture combination.
|
||||||
# endif
|
# endif
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
#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_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_eval(x) __atomic_load_n((U64 *)(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_inc_eval(x) __atomic_add_fetch((U64 *)(x), 1, __ATOMIC_SEQ_CST)
|
||||||
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
|
# 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_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_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_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_inc_eval(x) __atomic_add_fetch((U32 *)(x), 1, __ATOMIC_SEQ_CST)
|
||||||
# define ins_atomic_u32_dec_eval(x) (__atomic_fetch_sub((U32 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
|
# 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_fetch_add((U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
|
# 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_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_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_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
|
#else
|
||||||
# error Atomic intrinsics not defined for this compiler / architecture.
|
# error Atomic intrinsics not defined for this compiler / architecture.
|
||||||
#endif
|
#endif
|
||||||
@@ -363,9 +369,7 @@ CheckNil(nil,p) ? \
|
|||||||
#if COMPILER_MSVC
|
#if COMPILER_MSVC
|
||||||
# if defined(__SANITIZE_ADDRESS__)
|
# if defined(__SANITIZE_ADDRESS__)
|
||||||
# define ASAN_ENABLED 1
|
# define ASAN_ENABLED 1
|
||||||
# define NO_ASAN __declspec(no_sanitize_address)
|
# define ASAN_NO_ADDR __declspec(no_sanitize_address)
|
||||||
# else
|
|
||||||
# define NO_ASAN
|
|
||||||
# endif
|
# endif
|
||||||
#elif COMPILER_CLANG
|
#elif COMPILER_CLANG
|
||||||
# if defined(__has_feature)
|
# if defined(__has_feature)
|
||||||
@@ -373,9 +377,15 @@ CheckNil(nil,p) ? \
|
|||||||
# define ASAN_ENABLED 1
|
# define ASAN_ENABLED 1
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# define NO_ASAN __attribute__((no_sanitize("address")))
|
# define ASAN_NO_ADDR __attribute__((no_sanitize("address")))
|
||||||
#else
|
# define UBSAN_NO_ALIGN __attribute__((no_sanitize("alignment")))
|
||||||
# define NO_ASAN
|
#endif
|
||||||
|
|
||||||
|
#ifndef ASAN_NO_ADDR
|
||||||
|
# define ASAN_NO_ADDR
|
||||||
|
#endif
|
||||||
|
#ifndef UBSAN_NO_ALIGN
|
||||||
|
# define UBSAN_NO_ALIGN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ASAN_ENABLED
|
#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__
|
# define this_function_name __func__
|
||||||
#endif
|
#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
|
//~ rjf: Base Types
|
||||||
|
|
||||||
@@ -462,6 +475,8 @@ union U128
|
|||||||
U16 u16[8];
|
U16 u16[8];
|
||||||
U32 u32[4];
|
U32 u32[4];
|
||||||
U64 u64[2];
|
U64 u64[2];
|
||||||
|
F32 f32[4];
|
||||||
|
F64 f64[2];
|
||||||
};
|
};
|
||||||
typedef union U256 U256;
|
typedef union U256 U256;
|
||||||
union U256
|
union U256
|
||||||
@@ -471,6 +486,8 @@ union U256
|
|||||||
U32 u32[8];
|
U32 u32[8];
|
||||||
U64 u64[4];
|
U64 u64[4];
|
||||||
U128 u128[2];
|
U128 u128[2];
|
||||||
|
F32 f32[8];
|
||||||
|
F64 f64[4];
|
||||||
};
|
};
|
||||||
typedef union U512 U512;
|
typedef union U512 U512;
|
||||||
union U512
|
union U512
|
||||||
@@ -481,37 +498,48 @@ union U512
|
|||||||
U64 u64[8];
|
U64 u64[8];
|
||||||
U128 u128[4];
|
U128 u128[4];
|
||||||
U256 u256[2];
|
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
|
//~ rjf: Basic Type Structures
|
||||||
|
|
||||||
typedef struct U16Array U16Array;
|
typedef struct U16Array U16Array;
|
||||||
struct U16Array
|
struct U16Array
|
||||||
{
|
{
|
||||||
U64 count;
|
|
||||||
U16 *v;
|
U16 *v;
|
||||||
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct U32Array U32Array;
|
typedef struct U32Array U32Array;
|
||||||
struct U32Array
|
struct U32Array
|
||||||
{
|
{
|
||||||
U64 count;
|
|
||||||
U32 *v;
|
U32 *v;
|
||||||
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct U64Array U64Array;
|
typedef struct U64Array U64Array;
|
||||||
struct U64Array
|
struct U64Array
|
||||||
{
|
{
|
||||||
U64 count;
|
|
||||||
U64 *v;
|
U64 *v;
|
||||||
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct U128Array U128Array;
|
typedef struct U128Array U128Array;
|
||||||
struct U128Array
|
struct U128Array
|
||||||
{
|
{
|
||||||
U64 count;
|
|
||||||
U128 *v;
|
U128 *v;
|
||||||
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -611,19 +639,19 @@ typedef enum Arch
|
|||||||
Arch_arm64,
|
Arch_arm64,
|
||||||
Arch_arm32,
|
Arch_arm32,
|
||||||
Arch_COUNT,
|
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;
|
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
|
typedef enum Compiler
|
||||||
{
|
{
|
||||||
@@ -632,17 +660,42 @@ typedef enum Compiler
|
|||||||
Compiler_gcc,
|
Compiler_gcc,
|
||||||
Compiler_clang,
|
Compiler_clang,
|
||||||
Compiler_COUNT,
|
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;
|
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
|
//~ rjf: Text 2D Coordinates & Ranges
|
||||||
@@ -678,6 +731,29 @@ union Guid
|
|||||||
};
|
};
|
||||||
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
|
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
|
//~ 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 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
|
//~ 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 bit_size_from_arch(Arch arch);
|
||||||
internal U64 byte_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);
|
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);
|
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 B32 debugger_is_attached(void);
|
||||||
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)))
|
//~ 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
|
//~ 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_u32(U32 *ptr, U64 count);
|
||||||
internal U64 index_of_zero_u64(U64 *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
|
#endif // BASE_CORE_H
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// 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;
|
global B32 global_async_exit = 0;
|
||||||
thread_static B32 is_async_thread = 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
|
internal void
|
||||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
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
|
//- 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)
|
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
|
||||||
ac_init();
|
ac_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
|
|
||||||
async_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
|
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
|
||||||
c_init();
|
c_init();
|
||||||
#endif
|
#endif
|
||||||
@@ -75,11 +82,11 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
|
|||||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||||
dmn_init();
|
dmn_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
|
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
|
||||||
ctrl_init();
|
d_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL)
|
#if defined(WINDOW_MANAGER_H) && !defined(WM_INIT_MANUAL)
|
||||||
os_gfx_init();
|
wm_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
||||||
fp_init();
|
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)
|
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
|
||||||
fnt_init();
|
fnt_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
|
|
||||||
d_init();
|
|
||||||
#endif
|
|
||||||
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
|
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
|
||||||
rd_init(&cmdline);
|
rd_init(&cmdline);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !NO_ASYNC
|
||||||
//- rjf: launch async threads
|
//- rjf: launch async threads
|
||||||
Thread *async_threads = 0;
|
Thread *async_threads = 0;
|
||||||
U64 lane_broadcast_val = 0;
|
U64 lane_broadcast_val = 0;
|
||||||
{
|
{
|
||||||
U64 num_main_threads = 1;
|
U64 num_main_threads = 1;
|
||||||
#if defined(CTRL_CORE_H)
|
#if defined(DBG_ENGINE_CORE_H)
|
||||||
num_main_threads += 1;
|
num_main_threads += 1;
|
||||||
#endif
|
#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);
|
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
|
||||||
num_async_threads -= num_main_threads_clamped;
|
num_async_threads -= num_main_threads_clamped;
|
||||||
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
|
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]);
|
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//- rjf: call into entry point
|
//- rjf: call into entry point
|
||||||
entry_point(&cmdline);
|
entry_point(&cmdline);
|
||||||
|
|
||||||
|
#if !NO_ASYNC
|
||||||
//- rjf: join async threads
|
//- rjf: join async threads
|
||||||
ins_atomic_u32_inc_eval(&global_async_exit);
|
ins_atomic_u32_inc_eval(&global_async_exit);
|
||||||
cond_var_broadcast(async_tick_start_cond_var);
|
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);
|
thread_join(async_threads[idx], max_U64);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//- rjf: end captures
|
//- rjf: end captures
|
||||||
if(capture)
|
if(capture)
|
||||||
@@ -194,7 +202,7 @@ async_thread_entry_point(void *params)
|
|||||||
{
|
{
|
||||||
if(!ins_atomic_u32_eval(&async_loop_again))
|
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, 0);
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 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)
|
#if defined(FILE_STREAM_H)
|
||||||
fs_async_tick();
|
fs_async_tick();
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HTTP_H)
|
||||||
|
http_async_tick();
|
||||||
|
#endif
|
||||||
|
#if defined(SYMBOL_SERVER_H)
|
||||||
|
smsv_async_tick();
|
||||||
|
#endif
|
||||||
#if defined(DBG_INFO_H)
|
#if defined(DBG_INFO_H)
|
||||||
di_async_tick();
|
di_async_tick();
|
||||||
#endif
|
#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_core.c"
|
||||||
#include "base_profile.c"
|
#include "base_profile.c"
|
||||||
|
#include "base_memory.c"
|
||||||
#include "base_arena.c"
|
#include "base_arena.c"
|
||||||
#include "base_math.c"
|
#include "base_math.c"
|
||||||
#include "base_strings.c"
|
#include "base_strings.c"
|
||||||
|
#include "base_memory_map.c"
|
||||||
#include "base_hash.c"
|
#include "base_hash.c"
|
||||||
|
#include "base_system.c"
|
||||||
#include "base_threads.c"
|
#include "base_threads.c"
|
||||||
|
#include "base_ring.c"
|
||||||
#include "base_thread_context.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_command_line.c"
|
||||||
#include "base_markup.c"
|
#include "base_markup.c"
|
||||||
#include "base_meta.c"
|
#include "base_meta.c"
|
||||||
#include "base_log.c"
|
#include "base_log.c"
|
||||||
|
#include "base_test.c"
|
||||||
#include "base_entry_point.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_core.h"
|
||||||
#include "base_profile.h"
|
#include "base_profile.h"
|
||||||
|
#include "base_memory.h"
|
||||||
#include "base_arena.h"
|
#include "base_arena.h"
|
||||||
#include "base_math.h"
|
#include "base_math.h"
|
||||||
#include "base_strings.h"
|
#include "base_strings.h"
|
||||||
|
#include "base_memory_map.h"
|
||||||
#include "base_hash.h"
|
#include "base_hash.h"
|
||||||
|
#include "base_system.h"
|
||||||
#include "base_threads.h"
|
#include "base_threads.h"
|
||||||
|
#include "base_ring.h"
|
||||||
#include "base_thread_context.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_command_line.h"
|
||||||
#include "base_markup.h"
|
#include "base_markup.h"
|
||||||
#include "base_meta.h"
|
#include "base_meta.h"
|
||||||
#include "base_log.h"
|
#include "base_log.h"
|
||||||
|
#include "base_test.h"
|
||||||
#include "base_entry_point.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
|
#endif // BASE_INC_H
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ C_LINKAGE thread_static Log *log_active;
|
|||||||
C_LINKAGE thread_static Log *log_active = 0;
|
C_LINKAGE thread_static Log *log_active = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
String8 g_logs_folder;
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Log Creation/Selection
|
//~ rjf: Log Creation/Selection
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ struct Log
|
|||||||
LogScope *top_scope;
|
LogScope *top_scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Globals
|
||||||
|
|
||||||
|
extern String8 g_logs_folder;
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Log Creation/Selection
|
//~ rjf: Log Creation/Selection
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,2 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// 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
|
# define LAYER_COLOR 0x404040ff
|
||||||
#endif
|
#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))
|
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
|
||||||
|
|
||||||
#endif // BASE_MARKUP_H
|
#endif // BASE_MARKUP_H
|
||||||
|
|||||||
+35
-16
@@ -407,6 +407,26 @@ transpose_4x4f32(Mat4x4F32 mat)
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range Ops
|
//~ 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 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 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;}
|
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->first = to_concat->first;
|
||||||
list->last = to_concat->last;
|
list->last = to_concat->last;
|
||||||
}
|
}
|
||||||
|
list->count += to_concat->count;
|
||||||
MemoryZeroStruct(to_concat);
|
MemoryZeroStruct(to_concat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -758,34 +779,32 @@ rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
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 min_idx = 0;
|
||||||
U64 r = arr.count - 1;
|
U64 max_idx = array->count - 1;
|
||||||
for(; l <= r; )
|
for(;min_idx <= max_idx;)
|
||||||
{
|
{
|
||||||
U64 m = l + (r - l) / 2;
|
U64 mid_idx = min_idx + (max_idx - min_idx) / 2;
|
||||||
if(contains_1u64(arr.v[m], value))
|
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
|
else
|
||||||
{
|
{
|
||||||
r = m - 1;
|
max_idx = mid_idx - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(arr.count == 1 && contains_1u64(arr.v[0], value))
|
return result;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return max_U64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
|||||||
+57
-2
@@ -177,6 +177,28 @@ struct Mat4x4F32
|
|||||||
|
|
||||||
//- rjf: 1-range
|
//- 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;
|
typedef union Rng1U32 Rng1U32;
|
||||||
union Rng1U32
|
union Rng1U32
|
||||||
{
|
{
|
||||||
@@ -339,9 +361,9 @@ struct Rng1U64Node
|
|||||||
typedef struct Rng1U64List Rng1U64List;
|
typedef struct Rng1U64List Rng1U64List;
|
||||||
struct Rng1U64List
|
struct Rng1U64List
|
||||||
{
|
{
|
||||||
U64 count;
|
|
||||||
Rng1U64Node *first;
|
Rng1U64Node *first;
|
||||||
Rng1U64Node *last;
|
Rng1U64Node *last;
|
||||||
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Rng1U64Array Rng1U64Array;
|
typedef struct Rng1U64Array Rng1U64Array;
|
||||||
@@ -546,7 +568,32 @@ internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range Ops
|
//~ 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 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 rng_1u32(U32 min, U32 max);
|
||||||
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
|
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
|
||||||
internal Rng1U32 pad_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);
|
internal U32 clamp_1u32(Rng1U32 r, U32 v);
|
||||||
|
|
||||||
#define r1s32(min, max) rng_1s32((min), (max))
|
#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 rng_1s32(S32 min, S32 max);
|
||||||
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
|
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
|
||||||
internal Rng1S32 pad_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);
|
internal S32 clamp_1s32(Rng1S32 r, S32 v);
|
||||||
|
|
||||||
#define r1u64(min, max) rng_1u64((min), (max))
|
#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 rng_1u64(U64 min, U64 max);
|
||||||
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
|
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
|
||||||
internal Rng1U64 pad_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);
|
internal U64 clamp_1u64(Rng1U64 r, U64 v);
|
||||||
|
|
||||||
#define r1s64(min, max) rng_1s64((min), (max))
|
#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 rng_1s64(S64 min, S64 max);
|
||||||
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
|
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
|
||||||
internal Rng1S64 pad_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);
|
internal S64 clamp_1s64(Rng1S64 r, S64 v);
|
||||||
|
|
||||||
#define r1f32(min, max) rng_1f32((min), (max))
|
#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 rng_1f32(F32 min, F32 max);
|
||||||
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
|
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
|
||||||
internal Rng1F32 pad_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);
|
internal F32 clamp_1f32(Rng1F32 r, F32 v);
|
||||||
|
|
||||||
#define r2s16(min, max) rng_2s16((min), (max))
|
#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)))
|
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
|
||||||
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
|
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
|
||||||
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
|
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);
|
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
|
||||||
|
|
||||||
#define r2s32(min, max) rng_2s32((min), (max))
|
#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)))
|
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
|
||||||
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
|
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
|
||||||
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
|
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);
|
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
|
||||||
|
|
||||||
#define r2s64(min, max) rng_2s64((min), (max))
|
#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)))
|
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
|
||||||
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
|
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
|
||||||
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
|
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);
|
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
|
||||||
|
|
||||||
#define r2f32(min, max) rng_2f32((min), (max))
|
#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)))
|
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
|
||||||
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
|
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
|
||||||
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
|
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 Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
|
||||||
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
|
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
|
||||||
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
|
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 void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
|
||||||
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
|
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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
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);
|
va_end(args);
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ thread_static U32 spall_pid = 0;
|
|||||||
internal inline void spall_begin(char *fmt, ...);
|
internal inline void spall_begin(char *fmt, ...);
|
||||||
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
||||||
# define ProfBeginDynamic(...) (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 ProfTick(...)
|
||||||
# define ProfIsCapturing(...) (!!spall_capturing)
|
# define ProfIsCapturing(...) (!!spall_capturing)
|
||||||
# define ProfBeginCapture(...) (spall_capturing = 1)
|
# 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
|
||||||
+498
-146
@@ -1,6 +1,14 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// 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
|
//~ rjf: Character Classification & Conversion Functions
|
||||||
|
|
||||||
@@ -211,12 +219,9 @@ str32_cstring(U32 *c)
|
|||||||
internal String8
|
internal String8
|
||||||
str8_cstring_capped(void *cstr, void *cap)
|
str8_cstring_capped(void *cstr, void *cap)
|
||||||
{
|
{
|
||||||
char *ptr = (char *)cstr;
|
U64 cap_size = (U64)((U8 *)cap - (U8 *)cstr);
|
||||||
char *opl = (char *)cap;
|
U64 size = MemFind(cstr, cap_size, 0);
|
||||||
for (;ptr < opl && *ptr != 0; ptr += 1);
|
return str8(cstr, size);
|
||||||
U64 size = (U64)(ptr - (char *)cstr);
|
|
||||||
String8 result = str8((U8*)cstr, size);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String16
|
internal String16
|
||||||
@@ -230,24 +235,6 @@ str16_cstring_capped(void *cstr, void *cap)
|
|||||||
return result;
|
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
|
//~ rjf: String Stylization
|
||||||
|
|
||||||
@@ -293,7 +280,11 @@ str8_match(String8 a, String8 b, StringMatchFlags flags)
|
|||||||
B32 result = 0;
|
B32 result = 0;
|
||||||
if(a.size == b.size && flags == 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))
|
else if(a.size == b.size || (flags & StringMatchFlag_RightSideSloppy))
|
||||||
{
|
{
|
||||||
@@ -325,6 +316,88 @@ str8_match(String8 a, String8 b, StringMatchFlags flags)
|
|||||||
return result;
|
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
|
internal U64
|
||||||
str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
|
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);
|
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)
|
for(;p < stop_p; p += 1)
|
||||||
{
|
{
|
||||||
U8 haystack_char_adjusted = *p;
|
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);
|
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(haystack_char_adjusted == needle_first_char_adjusted)
|
||||||
{
|
{
|
||||||
if(str8_match(str8_range(p + 1, string_opl), needle_tail, adjusted_flags))
|
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;
|
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
|
internal String8
|
||||||
str8_skip_chop_whitespace(String8 string)
|
str8_skip_chop_whitespace(String8 string)
|
||||||
{
|
{
|
||||||
@@ -616,6 +709,22 @@ str8_is_integer(String8 string, U32 radix)
|
|||||||
return result;
|
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
|
internal U64
|
||||||
u64_from_str8(String8 string, U32 radix)
|
u64_from_str8(String8 string, U32 radix)
|
||||||
{
|
{
|
||||||
@@ -715,7 +824,7 @@ str8_from_memory_size(Arena *arena, U64 size)
|
|||||||
{
|
{
|
||||||
if(size < KB(1))
|
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))
|
else if(size < MB(1))
|
||||||
{
|
{
|
||||||
@@ -1062,26 +1171,19 @@ str8_list_concat_in_place(String8List *list, String8List *to_push)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal String8Node*
|
internal String8Node*
|
||||||
str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){
|
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;
|
read_only local_persist U8 zeroes[64] = {0};
|
||||||
U64 increase_size = 0;
|
Assert(IsPow2OrZero(align));
|
||||||
if (align > 1){
|
U64 pad = Max(min, AlignPadPow2(list->total_size, align));
|
||||||
// NOTE(allen): assert is power of 2
|
if(pad < sizeof(zeroes))
|
||||||
Assert(((align - 1) & align) == 0);
|
{
|
||||||
U64 mask = align - 1;
|
return str8_list_push(arena, list, str8(zeroes, pad));
|
||||||
new_size += mask;
|
}
|
||||||
new_size &= (~mask);
|
else
|
||||||
increase_size = new_size - list->total_size;
|
{
|
||||||
|
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*
|
internal String8Node*
|
||||||
@@ -1106,6 +1208,21 @@ str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...)
|
|||||||
return result;
|
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
|
internal String8List
|
||||||
str8_list_copy(Arena *arena, String8List *list)
|
str8_list_copy(Arena *arena, String8List *list)
|
||||||
{
|
{
|
||||||
@@ -1119,6 +1236,42 @@ str8_list_copy(Arena *arena, String8List *list)
|
|||||||
return result;
|
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
|
//~ rjf: String Splitting & Joining
|
||||||
|
|
||||||
@@ -1313,6 +1466,31 @@ str8_from_version(Arena *arena, U64 version)
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Path Helpers
|
//~ 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
|
internal String8
|
||||||
str8_chop_last_slash(String8 string)
|
str8_chop_last_slash(String8 string)
|
||||||
{
|
{
|
||||||
@@ -2222,24 +2400,35 @@ string_from_elapsed_time(Arena *arena, DateTime dt)
|
|||||||
{
|
{
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
String8List list = {0};
|
String8List list = {0};
|
||||||
if(dt.year)
|
if (dt.year) {
|
||||||
{
|
|
||||||
str8_list_pushf(scratch.arena, &list, "%dy", 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, "%um", dt.mon);
|
||||||
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
|
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, "%um", dt.mon);
|
||||||
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
|
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, "%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("") };
|
if (dt.hour) {
|
||||||
String8 result = str8_list_join(arena, &list, &join);
|
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);
|
scratch_end(scratch);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -2606,7 +2795,8 @@ fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src)
|
|||||||
//~ NOTE(allen): Serialization Helpers
|
//~ NOTE(allen): Serialization Helpers
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
str8_serial_begin(Arena *arena, String8List *srl){
|
str8_serial_begin(Arena *arena, String8List *srl)
|
||||||
|
{
|
||||||
String8Node *node = push_array(arena, String8Node, 1);
|
String8Node *node = push_array(arena, String8Node, 1);
|
||||||
node->string.str = push_array_no_zero(arena, U8, 0);
|
node->string.str = push_array_no_zero(arena, U8, 0);
|
||||||
srl->first = srl->last = node;
|
srl->first = srl->last = node;
|
||||||
@@ -2615,7 +2805,8 @@ str8_serial_begin(Arena *arena, String8List *srl){
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
str8_serial_end(Arena *arena, String8List *srl){
|
str8_serial_end(Arena *arena, String8List *srl)
|
||||||
|
{
|
||||||
U64 size = srl->total_size;
|
U64 size = srl->total_size;
|
||||||
U8 *out = push_array_no_zero(arena, U8, size);
|
U8 *out = push_array_no_zero(arena, U8, size);
|
||||||
str8_serial_write_to_dst(srl, out);
|
str8_serial_write_to_dst(srl, out);
|
||||||
@@ -2624,19 +2815,20 @@ str8_serial_end(Arena *arena, String8List *srl){
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
str8_serial_write_to_dst(String8List *srl, void *out){
|
str8_serial_write_to_dst(String8List *srl, void *out)
|
||||||
|
{
|
||||||
U8 *ptr = (U8*)out;
|
U8 *ptr = (U8*)out;
|
||||||
for (String8Node *node = srl->first;
|
for EachNode(n, String8Node, srl->first)
|
||||||
node != 0;
|
{
|
||||||
node = node->next){
|
U64 size = n->string.size;
|
||||||
U64 size = node->string.size;
|
MemoryCopy(ptr, n->string.str, size);
|
||||||
MemoryCopy(ptr, node->string.str, size);
|
|
||||||
ptr += size;
|
ptr += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
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));
|
Assert(IsPow2(align));
|
||||||
|
|
||||||
U64 pos = srl->total_size;
|
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);
|
U8 *buf = push_array(arena, U8, size);
|
||||||
|
|
||||||
String8 *str = &srl->last->string;
|
String8 *str = &srl->last->string;
|
||||||
if (str->str + str->size == buf){
|
if(str->str + str->size == buf)
|
||||||
|
{
|
||||||
srl->last->string.size += size;
|
srl->last->string.size += size;
|
||||||
srl->total_size += size;
|
srl->total_size += size;
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
str8_list_push(arena, srl, str8(buf, size));
|
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;
|
void *result = 0;
|
||||||
if(size != 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;
|
String8 *str = &srl->last->string;
|
||||||
if (str->str + str->size == buf){
|
if(str->str + str->size == buf)
|
||||||
|
{
|
||||||
srl->last->string.size += size;
|
srl->last->string.size += size;
|
||||||
srl->total_size += size;
|
srl->total_size += size;
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
str8_list_push(arena, srl, str8(buf, size));
|
str8_list_push(arena, srl, str8(buf, size));
|
||||||
}
|
}
|
||||||
result = buf;
|
result = buf;
|
||||||
@@ -2680,7 +2876,8 @@ str8_serial_push_size(Arena *arena, String8List *srl, U64 size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void *
|
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);
|
void *result = str8_serial_push_size(arena, srl, size);
|
||||||
if(result != 0)
|
if(result != 0)
|
||||||
{
|
{
|
||||||
@@ -2690,61 +2887,50 @@ str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size){
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first){
|
str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first)
|
||||||
for (String8Node *node = first;
|
{
|
||||||
node != 0;
|
for EachNode(n, String8Node, first)
|
||||||
node = node->next){
|
{
|
||||||
str8_serial_push_data(arena, srl, node->string.str, node->string.size);
|
str8_serial_push_data(arena, srl, n->string.str, n->string.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void *
|
||||||
str8_serial_push_u64(Arena *arena, String8List *srl, U64 x){
|
str8_serial_push_u64(Arena *arena, String8List *srl, U64 x)
|
||||||
U8 *buf = push_array_no_zero(arena, U8, 8);
|
{
|
||||||
MemoryCopy(buf, &x, 8);
|
return str8_serial_push_data(arena, srl, &x, sizeof(x));
|
||||||
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
|
internal void *
|
||||||
str8_serial_push_u32(Arena *arena, String8List *srl, U32 x){
|
str8_serial_push_u32(Arena *arena, String8List *srl, U32 x)
|
||||||
U8 *buf = push_array_no_zero(arena, U8, 4);
|
{
|
||||||
MemoryCopy(buf, &x, 4);
|
return str8_serial_push_data(arena, srl, &x, sizeof(x));
|
||||||
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
|
internal void *
|
||||||
str8_serial_push_u16(Arena *arena, String8List *srl, U16 x){
|
str8_serial_push_u16(Arena *arena, String8List *srl, U16 x)
|
||||||
str8_serial_push_data(arena, srl, &x, sizeof(x));
|
{
|
||||||
|
return str8_serial_push_data(arena, srl, &x, sizeof(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void *
|
||||||
str8_serial_push_u8(Arena *arena, String8List *srl, U8 x){
|
str8_serial_push_u8(Arena *arena, String8List *srl, U8 x)
|
||||||
str8_serial_push_data(arena, srl, &x, sizeof(x));
|
{
|
||||||
|
return str8_serial_push_data(arena, srl, &x, sizeof(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void *
|
||||||
str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str){
|
str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str)
|
||||||
str8_serial_push_data(arena, srl, str.str, str.size);
|
{
|
||||||
|
void *ptr = str8_serial_push_data(arena, srl, str.str, str.size);
|
||||||
str8_serial_push_u8(arena, srl, 0);
|
str8_serial_push_u8(arena, srl, 0);
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void *
|
||||||
str8_serial_push_string(Arena *arena, String8List *srl, String8 str){
|
str8_serial_push_string(Arena *arena, String8List *srl, String8 str)
|
||||||
str8_serial_push_data(arena, srl, str.str, str.size);
|
{
|
||||||
|
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;
|
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)
|
str8_compar(String8 a, String8 b, B32 ignore_case)
|
||||||
{
|
{
|
||||||
int cmp = 0;
|
|
||||||
U64 size = Min(a.size, b.size);
|
U64 size = Min(a.size, b.size);
|
||||||
if (ignore_case) {
|
int cmp = ignore_case ? MemCompareI(a.str, b.str, size) : MemCompare(a.str, b.str, size);
|
||||||
for (U64 i = 0; i < size; ++i) {
|
|
||||||
U8 la = lower_from_char(a.str[i]);
|
// normalize compar result
|
||||||
U8 lb = lower_from_char(b.str[i]);
|
cmp = cmp > 0 ? 1 : cmp < 0 ? -1 : 0;
|
||||||
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
|
// shorter prefix must precede longer prefixes
|
||||||
if (a.size > b.size) {
|
if (cmp == 0)
|
||||||
cmp = +1;
|
{
|
||||||
} else if (b.size > a.size) {
|
cmp = a.size < b.size ? -1 :
|
||||||
cmp = -1;
|
a.size > b.size ? +1 : 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmp;
|
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);
|
return str8_compar(*(String8*)a, *(String8*)b, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int
|
force_inline int
|
||||||
str8_compar_case_sensitive(const void *a, const void *b)
|
str8_compar_case_sensitive(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
return str8_compar(*(String8*)a, *(String8*)b, 0);
|
return str8_compar(*(String8*)a, *(String8*)b, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int
|
force_inline int
|
||||||
str8_is_before_case_sensitive(const void *a, const void *b)
|
str8_is_before_case_sensitive(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
int cmp = str8_compar_case_sensitive(a, b);
|
int cmp = str8_compar_case_sensitive(a, b);
|
||||||
return cmp < 0;
|
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
|
//~ rjf: Basic String Hashes
|
||||||
|
|
||||||
|
#pragma push_macro("__cpuid")
|
||||||
|
#undef __cpuid
|
||||||
#if !defined(XXH_IMPLEMENTATION)
|
#if !defined(XXH_IMPLEMENTATION)
|
||||||
# define XXH_INLINE_ALL
|
# define XXH_INLINE_ALL
|
||||||
# define XXH_IMPLEMENTATION
|
# define XXH_IMPLEMENTATION
|
||||||
# define XXH_STATIC_LINKING_ONLY
|
# define XXH_STATIC_LINKING_ONLY
|
||||||
# include "third_party/xxHash/xxhash.h"
|
# include "third_party/xxHash/xxhash.h"
|
||||||
#endif
|
#endif
|
||||||
|
#pragma pop_macro("__cpuid")
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
u64_hash_from_seed_str8(U64 seed, String8 string)
|
u64_hash_from_seed_str8(U64 seed, String8 string)
|
||||||
|
|||||||
+33
-8
@@ -160,8 +160,11 @@ internal U64 cstring32_length(U32 *c);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Constructors
|
//~ rjf: String Constructors
|
||||||
|
|
||||||
|
#define s(S) str8_lit(S)
|
||||||
|
|
||||||
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
||||||
#define str8_lit_comp(S) {(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_varg(S) (int)((S).size), ((S).str)
|
||||||
|
|
||||||
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
#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 String32 str32_cstring(U32 *c);
|
||||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||||
internal String16 str16_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
|
//~ 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_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))
|
#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);
|
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(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 U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||||
internal B32 str8_is_before(String8 a, String8 b);
|
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_skip(String8 str, U64 amt);
|
||||||
internal String8 str8_postfix(String8 str, U64 size);
|
internal String8 str8_postfix(String8 str, U64 size);
|
||||||
internal String8 str8_chop(String8 str, U64 amt);
|
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_whitespace(String8 string);
|
||||||
internal String8 str8_skip_chop_slashes(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
|
//- rjf: string -> integer
|
||||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
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 U64 u64_from_str8(String8 string, U32 radix);
|
||||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||||
internal U32 u32_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_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_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||||
internal String8Node* str8_list_push_frontf(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_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())
|
#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 },
|
{ 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_chop_last_slash(String8 string);
|
||||||
internal String8 str8_skip_last_slash(String8 string);
|
internal String8 str8_skip_last_slash(String8 string);
|
||||||
internal String8 str8_chop_last_dot(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_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(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_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_u64(Arena *arena, String8List *srl, U64 x);
|
||||||
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 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_u16(Arena *arena, String8List *srl, U16 x);
|
||||||
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 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_cstr(Arena *arena, String8List *srl, String8 str);
|
||||||
internal void str8_serial_push_string(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);
|
|
||||||
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
#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)
|
#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);
|
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_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)
|
#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
|
//~ 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 *
|
internal TCTX *
|
||||||
tctx_alloc(void)
|
tctx_alloc(void)
|
||||||
{
|
{
|
||||||
Arena *arena = arena_alloc();
|
#if PROFILE_TELEMETRY
|
||||||
TCTX *tctx = push_array(arena, TCTX, 1);
|
thread_static static char name[2][1024];
|
||||||
tctx->arenas[0] = arena;
|
raddbg_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", tid());
|
||||||
tctx->arenas[1] = arena_alloc();
|
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;
|
tctx->lane_ctx.lane_count = 1;
|
||||||
return tctx;
|
return tctx;
|
||||||
}
|
}
|
||||||
@@ -99,7 +108,7 @@ tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_sr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rjf: all cases: barrier
|
// 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
|
// rjf: doing broadcast -> copy from broadcast memory on destination lanes
|
||||||
if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx)
|
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
|
// rjf: doing broadcast -> barrier on all lanes
|
||||||
if(broadcast_ptr != 0)
|
if(broadcast_ptr != 0)
|
||||||
{
|
{
|
||||||
os_barrier_wait(tctx->lane_ctx.barrier);
|
barrier_wait(tctx->lane_ctx.barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
@@ -193,7 +202,7 @@ internal void
|
|||||||
access_touch(Access *access, AccessPt *pt, CondVar cv)
|
access_touch(Access *access, AccessPt *pt, CondVar cv)
|
||||||
{
|
{
|
||||||
ins_atomic_u64_inc_eval(&pt->access_refcount);
|
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());
|
ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx());
|
||||||
Touch *touch = tctx_thread_local->free_touch;
|
Touch *touch = tctx_thread_local->free_touch;
|
||||||
if(touch != 0)
|
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_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);
|
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
|
||||||
B32 result = (access_refcount == 0 &&
|
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());
|
last_update_idx_touched + params->update_idxs <= update_tick_idx());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+167
-65
@@ -1,70 +1,6 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// 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
|
//~ rjf: Table Stripe Functions
|
||||||
|
|
||||||
@@ -72,7 +8,7 @@ internal StripeArray
|
|||||||
stripe_array_alloc(Arena *arena)
|
stripe_array_alloc(Arena *arena)
|
||||||
{
|
{
|
||||||
StripeArray array = {0};
|
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);
|
array.v = push_array(arena, Stripe, array.count);
|
||||||
for EachIndex(idx, 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];
|
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
|
||||||
return stripe;
|
return stripe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Thread Info Helpers
|
||||||
|
|
||||||
|
internal void
|
||||||
|
set_thread_name(String8 string)
|
||||||
|
{
|
||||||
|
ProfThreadName("%.*s", str8_varg(string));
|
||||||
|
set_platform_thread_name(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
set_thread_namef(char *fmt, ...)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(0, 0);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||||
|
set_thread_name(string);
|
||||||
|
va_end(args);
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
|
||||||
|
|
||||||
|
//- rjf: slow barriers
|
||||||
|
|
||||||
|
typedef struct BarrierNode BarrierNode;
|
||||||
|
struct BarrierNode
|
||||||
|
{
|
||||||
|
BarrierNode *next;
|
||||||
|
U64 count;
|
||||||
|
U64 threads_left_to_enter;
|
||||||
|
U64 threads_left_to_leave;
|
||||||
|
RWMutex rw_mutex;
|
||||||
|
CondVar cv;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct BarrierTCTX BarrierTCTX;
|
||||||
|
struct BarrierTCTX
|
||||||
|
{
|
||||||
|
Arena *arena;
|
||||||
|
BarrierNode *free_barrier_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
thread_static BarrierTCTX *barrier_tctx = 0;
|
||||||
|
|
||||||
|
internal Barrier
|
||||||
|
slow_barrier_alloc(U64 count)
|
||||||
|
{
|
||||||
|
if(barrier_tctx == 0)
|
||||||
|
{
|
||||||
|
Arena *arena = arena_alloc();
|
||||||
|
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
||||||
|
barrier_tctx->arena = arena;
|
||||||
|
}
|
||||||
|
BarrierNode *n = barrier_tctx->free_barrier_node;
|
||||||
|
if(n != 0)
|
||||||
|
{
|
||||||
|
SLLStackPop(barrier_tctx->free_barrier_node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = push_array_no_zero(barrier_tctx->arena, BarrierNode, 1);
|
||||||
|
}
|
||||||
|
MemoryZeroStruct(n);
|
||||||
|
n->count = count;
|
||||||
|
n->threads_left_to_enter = count;
|
||||||
|
n->rw_mutex = rw_mutex_alloc();
|
||||||
|
n->cv = cond_var_alloc();
|
||||||
|
Barrier result = {(U64)n};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
slow_barrier_release(Barrier barrier)
|
||||||
|
{
|
||||||
|
if(barrier_tctx == 0)
|
||||||
|
{
|
||||||
|
Arena *arena = arena_alloc();
|
||||||
|
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
||||||
|
barrier_tctx->arena = arena;
|
||||||
|
}
|
||||||
|
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
||||||
|
rw_mutex_release(n->rw_mutex);
|
||||||
|
cond_var_release(n->cv);
|
||||||
|
SLLStackPush(barrier_tctx->free_barrier_node, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
slow_barrier_wait(Barrier barrier)
|
||||||
|
{
|
||||||
|
ProfBeginFunction();
|
||||||
|
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
||||||
|
U64 threads_left_to_enter = ins_atomic_u64_dec_eval(&n->threads_left_to_enter);
|
||||||
|
|
||||||
|
//- rjf: threads left to enter > 0 => wait
|
||||||
|
if(threads_left_to_enter > 0)
|
||||||
|
{
|
||||||
|
// rjf: first try a spin loop
|
||||||
|
B32 done_waiting = 0;
|
||||||
|
ProfScope("spin loop wait") for(U64 spin_count = 0; spin_count < 10000; spin_count += 1)
|
||||||
|
{
|
||||||
|
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
||||||
|
{
|
||||||
|
done_waiting = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: not done waiting -> need to do slow wait on condition variable
|
||||||
|
if(!done_waiting) ProfScope("slow wait")
|
||||||
|
{
|
||||||
|
RWMutexScope(n->rw_mutex, 0) for(;;)
|
||||||
|
{
|
||||||
|
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cond_var_wait_rw(n->cv, n->rw_mutex, 0, max_U64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: decrement leave counter
|
||||||
|
if(ins_atomic_u64_dec_eval(&n->threads_left_to_leave) > 0)
|
||||||
|
{
|
||||||
|
ProfScope("signal") cond_var_signal(n->cv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: threads left to enter == 0 -> last thread, wakeup
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ins_atomic_u64_eval_assign(&n->threads_left_to_enter, n->count);
|
||||||
|
ProfScope("wake up") RWMutexScope(n->rw_mutex, 1)
|
||||||
|
{
|
||||||
|
ins_atomic_u64_eval_assign(&n->threads_left_to_leave, n->count-1);
|
||||||
|
}
|
||||||
|
ProfScope("signal") cond_var_signal(n->cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: wait for threads left to leave == 0
|
||||||
|
ProfScope("wait for threads to leave")
|
||||||
|
{
|
||||||
|
for(U64 spin_count = 0;; spin_count += 1)
|
||||||
|
{
|
||||||
|
if(ins_atomic_u64_eval(&n->threads_left_to_leave) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
///~ Semaphore
|
||||||
|
|
||||||
|
internal void
|
||||||
|
semaphore_drop(Semaphore semaphore)
|
||||||
|
{
|
||||||
|
semaphore_drop_count(semaphore, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+32
-6
@@ -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 Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
|
||||||
internal B32 thread_join(Thread thread, U64 endt_us);
|
internal B32 thread_join(Thread thread, U64 endt_us);
|
||||||
internal void thread_detach(Thread thread);
|
internal void thread_detach(Thread thread);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Synchronization Primitive Functions
|
//~ rjf: @per_os_impl Synchronization Primitive Functions
|
||||||
|
|
||||||
//- rjf: recursive mutexes
|
//- rjf: recursive mutexes
|
||||||
internal Mutex mutex_alloc(void);
|
internal Mutex mutex_alloc(void);
|
||||||
@@ -110,6 +129,7 @@ internal Semaphore semaphore_open(String8 name);
|
|||||||
internal void semaphore_close(Semaphore semaphore);
|
internal void semaphore_close(Semaphore semaphore);
|
||||||
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
|
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
|
||||||
internal void semaphore_drop(Semaphore semaphore);
|
internal void semaphore_drop(Semaphore semaphore);
|
||||||
|
internal void semaphore_drop_count(Semaphore semaphore, U64 drop_count);
|
||||||
|
|
||||||
//- rjf: barriers
|
//- rjf: barriers
|
||||||
internal Barrier barrier_alloc(U64 count);
|
internal Barrier barrier_alloc(U64 count);
|
||||||
@@ -124,10 +144,16 @@ internal void barrier_wait(Barrier barrier);
|
|||||||
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
|
#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);
|
//- rjf: slow barriers
|
||||||
internal void stripe_array_release(StripeArray *stripes);
|
internal Barrier slow_barrier_alloc(U64 count);
|
||||||
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
|
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
|
#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)
|
switch(arch)
|
||||||
{
|
{
|
||||||
case CV_Arch_8086: return cv_size_from_reg_x86(reg);
|
|
||||||
case CV_Arch_X64 : return cv_size_from_reg_x64(reg);
|
case CV_Arch_X64 : return cv_size_from_reg_x64(reg);
|
||||||
default: NotImplemented;
|
default: NotImplemented;
|
||||||
}
|
}
|
||||||
@@ -59,25 +58,12 @@ cv_is_reg_sp(CV_Arch arch, CV_Reg reg)
|
|||||||
{
|
{
|
||||||
switch(arch)
|
switch(arch)
|
||||||
{
|
{
|
||||||
case CV_Arch_8086: return reg == CV_Regx86_ESP;
|
|
||||||
case CV_Arch_X64: return reg == CV_Regx64_RSP;
|
case CV_Arch_X64: return reg == CV_Regx64_RSP;
|
||||||
default: NotImplemented;
|
default: NotImplemented;
|
||||||
}
|
}
|
||||||
return 0;
|
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
|
internal U64
|
||||||
cv_size_from_reg_x64(CV_Reg reg)
|
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;
|
CV_Reg fp_reg = 0;
|
||||||
switch (arch)
|
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:
|
case CV_Arch_X64:
|
||||||
{
|
{
|
||||||
switch (encoded_reg)
|
switch (encoded_reg)
|
||||||
@@ -144,14 +118,6 @@ cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg)
|
|||||||
{
|
{
|
||||||
U32 r = 0;
|
U32 r = 0;
|
||||||
switch (arch) {
|
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: {
|
case CV_Arch_X64: {
|
||||||
switch (encoded_frame_reg) {
|
switch (encoded_frame_reg) {
|
||||||
case 0: r = 0; break;
|
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();
|
String8 result = str8_zero();
|
||||||
switch (arch) {
|
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: {
|
case CV_Arch_X64: {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
|
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
|
||||||
|
|||||||
+29
-282
@@ -33,7 +33,7 @@ read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF;
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Aligns
|
//~ Aligns
|
||||||
|
|
||||||
#define CV_LeafAlign 4
|
#define CV_LeafAlign 1
|
||||||
#define CV_SymbolAlign 1
|
#define CV_SymbolAlign 1
|
||||||
#define CV_C13SubSectionAlign 4
|
#define CV_C13SubSectionAlign 4
|
||||||
#define CV_FileCheckSumsAlign 4
|
#define CV_FileCheckSumsAlign 4
|
||||||
@@ -41,261 +41,6 @@ read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF;
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Registers
|
//~ 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)
|
// X(NAME, CODE, (RDI_RegisterCode_X64) NAME, BYTE_POS, BYTE_SIZE)
|
||||||
#define CV_Reg_X64_XList(X) \
|
#define CV_Reg_X64_XList(X) \
|
||||||
X(NONE, 0, nil, 0, 0) \
|
X(NONE, 0, nil, 0, 0) \
|
||||||
@@ -382,14 +127,14 @@ X(FPDS, 142, nil, 0, 0) \
|
|||||||
X(ISEM, 143, nil, 0, 0) \
|
X(ISEM, 143, nil, 0, 0) \
|
||||||
X(FPEIP, 144, nil, 0, 0) \
|
X(FPEIP, 144, nil, 0, 0) \
|
||||||
X(FPEDO, 145, nil, 0, 0) \
|
X(FPEDO, 145, nil, 0, 0) \
|
||||||
X(MM0, 146, fpr0, 0, 8) \
|
X(MM0, 146, st0, 0, 8) \
|
||||||
X(MM1, 147, fpr1, 0, 8) \
|
X(MM1, 147, st1, 0, 8) \
|
||||||
X(MM2, 148, fpr2, 0, 8) \
|
X(MM2, 148, st2, 0, 8) \
|
||||||
X(MM3, 149, fpr3, 0, 8) \
|
X(MM3, 149, st3, 0, 8) \
|
||||||
X(MM4, 150, fpr4, 0, 8) \
|
X(MM4, 150, st4, 0, 8) \
|
||||||
X(MM5, 151, fpr5, 0, 8) \
|
X(MM5, 151, st5, 0, 8) \
|
||||||
X(MM6, 152, fpr6, 0, 8) \
|
X(MM6, 152, st6, 0, 8) \
|
||||||
X(MM7, 153, fpr7, 0, 8) \
|
X(MM7, 153, st7, 0, 8) \
|
||||||
X(XMM0, 154, zmm0, 0, 16) \
|
X(XMM0, 154, zmm0, 0, 16) \
|
||||||
X(XMM1, 155, zmm1, 0, 16) \
|
X(XMM1, 155, zmm1, 0, 16) \
|
||||||
X(XMM2, 156, zmm2, 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(EMM5H, 233, zmm5, 8, 8) \
|
||||||
X(EMM6H, 234, zmm6, 8, 8) \
|
X(EMM6H, 234, zmm6, 8, 8) \
|
||||||
X(EMM7H, 235, zmm7, 8, 8) \
|
X(EMM7H, 235, zmm7, 8, 8) \
|
||||||
X(MM00, 236, fpr0, 0, 4) \
|
X(MM00, 236, st0, 0, 4) \
|
||||||
X(MM01, 237, fpr0, 4, 4) \
|
X(MM01, 237, st0, 4, 4) \
|
||||||
X(MM10, 238, fpr1, 0, 4) \
|
X(MM10, 238, st1, 0, 4) \
|
||||||
X(MM11, 239, fpr1, 4, 4) \
|
X(MM11, 239, st1, 4, 4) \
|
||||||
X(MM20, 240, fpr2, 0, 4) \
|
X(MM20, 240, st2, 0, 4) \
|
||||||
X(MM21, 241, fpr2, 4, 4) \
|
X(MM21, 241, st2, 4, 4) \
|
||||||
X(MM30, 242, fpr3, 0, 4) \
|
X(MM30, 242, st3, 0, 4) \
|
||||||
X(MM31, 243, fpr3, 4, 4) \
|
X(MM31, 243, st3, 4, 4) \
|
||||||
X(MM40, 244, fpr4, 0, 4) \
|
X(MM40, 244, st4, 0, 4) \
|
||||||
X(MM41, 245, fpr4, 4, 4) \
|
X(MM41, 245, st4, 4, 4) \
|
||||||
X(MM50, 246, fpr5, 0, 4) \
|
X(MM50, 246, st5, 0, 4) \
|
||||||
X(MM51, 247, fpr5, 4, 4) \
|
X(MM51, 247, st5, 4, 4) \
|
||||||
X(MM60, 248, fpr6, 0, 4) \
|
X(MM60, 248, st6, 0, 4) \
|
||||||
X(MM61, 249, fpr6, 4, 4) \
|
X(MM61, 249, st6, 4, 4) \
|
||||||
X(MM70, 250, fpr7, 0, 4) \
|
X(MM70, 250, st7, 0, 4) \
|
||||||
X(MM71, 251, fpr7, 4, 4) \
|
X(MM71, 251, st7, 4, 4) \
|
||||||
X(XMM8, 252, zmm8, 0, 16) \
|
X(XMM8, 252, zmm8, 0, 16) \
|
||||||
X(XMM9, 253, zmm9, 0, 16) \
|
X(XMM9, 253, zmm9, 0, 16) \
|
||||||
X(XMM10, 254, zmm10, 0, 16) \
|
X(XMM10, 254, zmm10, 0, 16) \
|
||||||
@@ -1416,6 +1161,8 @@ struct CV_SymPub32
|
|||||||
|
|
||||||
//- (SymKind: LPROC32, GPROC32)
|
//- (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;
|
typedef struct CV_SymProc32 CV_SymProc32;
|
||||||
struct CV_SymProc32
|
struct CV_SymProc32
|
||||||
{
|
{
|
||||||
@@ -2795,7 +2542,8 @@ X(TypeMDTokenMap, 0xFB) \
|
|||||||
X(MergedAssemblyInput, 0xFC) \
|
X(MergedAssemblyInput, 0xFC) \
|
||||||
X(CoffSymbolRVA, 0xFD) \
|
X(CoffSymbolRVA, 0xFD) \
|
||||||
X(XfgHashType, 0xFF) \
|
X(XfgHashType, 0xFF) \
|
||||||
X(XfgHashVirtual, 0x100)
|
X(XfgHashVirtual, 0x100) \
|
||||||
|
X(GlobalRefs, 0xCAFE) \
|
||||||
|
|
||||||
typedef U32 CV_C13SubSectionKind;
|
typedef U32 CV_C13SubSectionKind;
|
||||||
typedef enum CV_C13SubSectionKindEnum
|
typedef enum CV_C13SubSectionKindEnum
|
||||||
@@ -2963,7 +2711,6 @@ struct CV_TypeIndexArray
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal CV_Arch cv_arch_from_coff_machine(COFF_MachineType machine);
|
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_x64(CV_Reg reg);
|
||||||
internal U64 cv_size_from_reg(CV_Arch arch, 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);
|
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};
|
CV_NumericParsed result = {0};
|
||||||
if(first + 2 <= opl)
|
if(first + 2 <= opl)
|
||||||
{
|
{
|
||||||
U16 x = *(U16*)first;
|
U16 x = memory_read16(first);
|
||||||
if(x < 0x8000)
|
if(x < 0x8000)
|
||||||
{
|
{
|
||||||
result.kind = CV_NumericKind_USHORT;
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -236,6 +236,18 @@ struct CV_TypeIdArray
|
|||||||
U64 count;
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ Record Iterator
|
||||||
|
|
||||||
|
typedef struct CV_RecIter CV_RecIter;
|
||||||
|
struct CV_RecIter
|
||||||
|
{
|
||||||
|
U64 num;
|
||||||
|
U16 kind;
|
||||||
|
void *struct_base;
|
||||||
|
void *opl;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
//- Hasher
|
//- 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_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);
|
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
|
#endif // CODEVIEW_PARSE_H
|
||||||
|
|
||||||
|
|||||||
+17
-7
@@ -92,13 +92,8 @@ coff_read_symbol_name(String8 string_table, COFF_SymbolName *name)
|
|||||||
if (name->long_name.zeroes == 0) {
|
if (name->long_name.zeroes == 0) {
|
||||||
str8_deserial_read_cstr(string_table, name->long_name.string_table_offset, &name_str);
|
str8_deserial_read_cstr(string_table, name->long_name.string_table_offset, &name_str);
|
||||||
} else {
|
} else {
|
||||||
U32 i;
|
U32 name_size = idx_of_zero_byte64(name->short_name, sizeof(name->short_name));
|
||||||
for (i = 0; i < sizeof(name->short_name); ++i) {
|
name_str = str8(name->short_name, name_size);
|
||||||
if (name->short_name[i] == '\0') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
name_str = str8(name->short_name, i);
|
|
||||||
}
|
}
|
||||||
return name_str;
|
return name_str;
|
||||||
}
|
}
|
||||||
@@ -455,6 +450,21 @@ arch_from_coff_machine(COFF_MachineType machine)
|
|||||||
return result;
|
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
|
internal U64
|
||||||
coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff)
|
coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff)
|
||||||
{
|
{
|
||||||
|
|||||||
+10
-6
@@ -163,7 +163,8 @@ enum
|
|||||||
#define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask)
|
#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)
|
#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];
|
U8 name[8];
|
||||||
U32 vsize;
|
U32 vsize;
|
||||||
@@ -175,12 +176,12 @@ typedef struct COFF_SectionHeader
|
|||||||
U16 reloc_count;
|
U16 reloc_count;
|
||||||
U16 line_count;
|
U16 line_count;
|
||||||
COFF_SectionFlags flags;
|
COFF_SectionFlags flags;
|
||||||
} COFF_SectionHeader;
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
typedef U8 COFF_SymType;
|
typedef U8 COFF_SymType;
|
||||||
enum
|
typedef enum COFF_SymTypeEnum
|
||||||
{
|
{
|
||||||
COFF_SymType_Null,
|
COFF_SymType_Null,
|
||||||
COFF_SymType_Void,
|
COFF_SymType_Void,
|
||||||
@@ -198,10 +199,11 @@ enum
|
|||||||
COFF_SymType_Word,
|
COFF_SymType_Word,
|
||||||
COFF_SymType_UInt,
|
COFF_SymType_UInt,
|
||||||
COFF_SymType_DWord
|
COFF_SymType_DWord
|
||||||
};
|
}
|
||||||
|
COFF_SymTypeEnum;
|
||||||
|
|
||||||
typedef U8 COFF_SymStorageClass;
|
typedef U8 COFF_SymStorageClass;
|
||||||
enum
|
typedef enum COFF_SymStorageClassEnum
|
||||||
{
|
{
|
||||||
COFF_SymStorageClass_Null = 0x00,
|
COFF_SymStorageClass_Null = 0x00,
|
||||||
COFF_SymStorageClass_Automatic = 0x01,
|
COFF_SymStorageClass_Automatic = 0x01,
|
||||||
@@ -230,7 +232,8 @@ enum
|
|||||||
COFF_SymStorageClass_WeakExternal = 0x69,
|
COFF_SymStorageClass_WeakExternal = 0x69,
|
||||||
COFF_SymStorageClass_CLRToken = 0x6b,
|
COFF_SymStorageClass_CLRToken = 0x6b,
|
||||||
COFF_SymStorageClass_EndOfFunction = 0xff
|
COFF_SymStorageClass_EndOfFunction = 0xff
|
||||||
};
|
}
|
||||||
|
COFF_SymStorageClassEnum;
|
||||||
|
|
||||||
typedef U8 COFF_SymDType;
|
typedef U8 COFF_SymDType;
|
||||||
enum
|
enum
|
||||||
@@ -629,6 +632,7 @@ internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine);
|
|||||||
internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
|
internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
|
||||||
|
|
||||||
internal Arch arch_from_coff_machine(COFF_MachineType machine);
|
internal Arch arch_from_coff_machine(COFF_MachineType machine);
|
||||||
|
internal COFF_MachineType coff_machine_from_arch(Arch arch);
|
||||||
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
|
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|||||||
@@ -648,7 +648,7 @@ coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opts & RD_Option_Dwarf) {
|
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);
|
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;
|
U64 name_with_slash_size = member->name.size + 1;
|
||||||
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
|
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
|
||||||
// have we seen this member name before?
|
// have we seen this member name before?
|
||||||
KeyValuePair *is_present = hash_table_search_string(name_ht, member->name);
|
if (!hash_table_search_string_string(name_ht, member->name, &name)) {
|
||||||
if (is_present) {
|
|
||||||
name = is_present->value_string;
|
|
||||||
} else {
|
|
||||||
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
|
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
|
||||||
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
|
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
|
||||||
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
|
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
|
||||||
|
|||||||
+111
-1
@@ -1,7 +1,10 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
internal COFF_ObjWriter*
|
internal COFF_ObjWriter*
|
||||||
coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine)
|
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);
|
COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1);
|
||||||
obj_writer->arena = arena;
|
obj_writer->arena = arena;
|
||||||
obj_writer->time_stamp = time_stamp;
|
obj_writer->time_stamp = time_stamp;
|
||||||
@@ -440,6 +443,18 @@ coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *
|
|||||||
return reloc;
|
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 *
|
internal COFF_ObjReloc *
|
||||||
coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
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;
|
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
|
#ifndef COFF_OBJ_WRITER_H
|
||||||
#define 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 COFF_ObjWriter * coff_obj_writer_alloc (COFF_TimeStamp time_stamp, COFF_MachineType machine);
|
||||||
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
|
internal void coff_obj_writer_release (COFF_ObjWriter **obj_writer);
|
||||||
internal String8 coff_obj_writer_serialize(Arena *arena, 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_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_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_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_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_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_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_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_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 (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_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_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_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_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 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_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_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_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);
|
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
|
#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);
|
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);
|
COFF_SectionHeader **section_table = push_array_no_zero(arena, COFF_SectionHeader *, section_count+1);
|
||||||
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
|
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
|
||||||
for (U64 i = 0; i < section_count; ++i) {
|
for EachIndex(sect_idx, section_count) {
|
||||||
section_table[i+1] = str8_deserial_get_raw_ptr(data, section_table_range.min + i*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
|
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;
|
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
|
internal COFF_ParsedSymbol
|
||||||
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
|
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
|
// 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
|
// Symbol
|
||||||
|
|
||||||
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
|
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_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_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);
|
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)
|
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
|
||||||
{
|
{
|
||||||
if(0){}
|
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("ctrl"), 0)) { binding.modifiers |= WM_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("alt"), 0)) { binding.modifiers |= WM_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("shift"), 0)) { binding.modifiers |= WM_Modifier_Shift; }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OS_Key key = OS_Key_Null;
|
WM_Key key = WM_Key_Null;
|
||||||
for EachEnumVal(OS_Key, k)
|
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;
|
key = k;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(key != OS_Key_Null)
|
if(key != WM_Key_Null)
|
||||||
{
|
{
|
||||||
binding.key = key;
|
binding.key = key;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
typedef struct CFG_Binding CFG_Binding;
|
typedef struct CFG_Binding CFG_Binding;
|
||||||
struct CFG_Binding
|
struct CFG_Binding
|
||||||
{
|
{
|
||||||
OS_Key key;
|
WM_Key key;
|
||||||
OS_Modifiers modifiers;
|
WM_Modifiers modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
|
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)
|
for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
CFG_Node *c = n->v;
|
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);
|
cfg_string_release(state, c->string);
|
||||||
SLLStackPush(state->free, c);
|
SLLStackPush(state->free, c);
|
||||||
c->first = c->last = c->prev = c->parent = 0;
|
c->first = c->last = c->prev = c->parent = 0;
|
||||||
c->id = 0;
|
c->id = 0;
|
||||||
c->string = str8_zero();
|
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)
|
for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
if(n->v == c)
|
if(n->v == c)
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
|
|
||||||
#include "config_core.c"
|
#include "config_core.c"
|
||||||
#include "config_panels.c"
|
#include "config_panels.c"
|
||||||
#if defined(OS_GFX_H)
|
#if defined(WINDOW_MANAGER_H)
|
||||||
# include "config_bindings.c"
|
# include "config_bindings.c"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "config_core.h"
|
#include "config_core.h"
|
||||||
#include "config_panels.h"
|
#include "config_panels.h"
|
||||||
#if defined(OS_GFX_H)
|
#if defined(WINDOW_MANAGER_H)
|
||||||
# include "config_bindings.h"
|
# include "config_bindings.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ c_init(void)
|
|||||||
c_shared = push_array(arena, C_Shared, 1);
|
c_shared = push_array(arena, C_Shared, 1);
|
||||||
c_shared->arena = arena;
|
c_shared->arena = arena;
|
||||||
c_shared->blob_slots_count = 16384;
|
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_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 = 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);
|
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();
|
stripe->cv = cond_var_alloc();
|
||||||
}
|
}
|
||||||
c_shared->key_slots_count = 4096;
|
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_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 = 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);
|
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();
|
stripe->cv = cond_var_alloc();
|
||||||
}
|
}
|
||||||
c_shared->root_slots_count = 4096;
|
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_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 = 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);
|
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
|
|
||||||
+235
-36
@@ -4,52 +4,60 @@
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Built-In Command Tables
|
//~ rjf: Built-In Command Tables
|
||||||
|
|
||||||
@table(name ui_vis ipc_docs_vis text_pt_vis text_rng_vis q_expr q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags ctx_filter)
|
@table(name ui_vis ipc_docs_vis q_expr q_slot q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags filter_tags)
|
||||||
// / | | | | | | \___ _________________________________/ | | | | | |
|
// / | | | | \__ ______________________________________________________________/ / / | | | |
|
||||||
// / | | | | | | \ / | | | | | |
|
// / | | | | \ / _________________/ _________________/ | | | |
|
||||||
D_CmdTable: // | | | | | | | | | | | | | |
|
D_CmdTable: // | | | | | | / / | | | |
|
||||||
{
|
{
|
||||||
//- rjf: low-level target control operations
|
//- rjf: low-level target control operations
|
||||||
{LaunchAndRun 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" }
|
{LaunchAndRun 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" }
|
||||||
{LaunchAndStepInto 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" }
|
{LaunchAndStepInto 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" }
|
||||||
{Kill 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" }
|
{Kill 1 1 "query:processes" Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" }
|
||||||
{KillAll 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" }
|
{KillAll 1 1 "" Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" }
|
||||||
{Detach 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" }
|
{Detach 1 1 "query:processes" Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" }
|
||||||
{Continue 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" }
|
{Continue 1 1 "" Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" }
|
||||||
{StepIntoInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" }
|
{StepIntoInst 1 1 "" Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" }
|
||||||
{StepOverInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" }
|
{StepOverInst 1 1 "" Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" }
|
||||||
{StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
|
{StepIntoLine 1 1 "" Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
|
||||||
{StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
|
{StepOverLine 1 1 "" Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
|
||||||
{StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" "" }
|
{StepOut 1 1 "" Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the first instruction after the current scope is exited." "" "" }
|
||||||
{Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
|
{StepToExit 1 1 "" Null 0 0 0 0 0 0 0 StepOut "step_to_exit" "Step To Exit" "Runs to the first encountered instruction which will exit the current scope." "" "" }
|
||||||
{SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
|
{Halt 1 1 "" Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
|
||||||
{SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
|
{SoftHaltRefresh 0 0 "" Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
|
||||||
|
{SetThreadIP 0 1 "" Vaddr 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
|
||||||
|
|
||||||
//- rjf: high-level composite target control operations
|
//- rjf: high-level composite target control operations
|
||||||
{RunToLine 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "$text_pt," }
|
{RunToLine 1 1 "" Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "{text_pt_commands}{disasm_pt_commands}" }
|
||||||
{Run 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" }
|
{RunToName 1 1 "query:procedures" String 0 0 0 0 0 1 1 Play "run_to_name" "Run To Name" "Runs until a particular symbol name is hit." "" "" }
|
||||||
{Restart 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" }
|
{Run 1 1 "" Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" }
|
||||||
{StepInto 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" }
|
{Restart 1 1 "" Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" }
|
||||||
{StepOver 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" }
|
{StepInto 1 1 "" Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" }
|
||||||
|
{StepOver 1 1 "" Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" }
|
||||||
|
|
||||||
//- rjf: debug control context management operations
|
//- rjf: debug control context management operations
|
||||||
{FreezeThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" }
|
{FreezeThread 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" }
|
||||||
{ThawThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" }
|
{ThawThread 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" }
|
||||||
{FreezeProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" }
|
{FreezeProcess 1 1 "query:processes" Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" }
|
||||||
{ThawProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" }
|
{ThawProcess 1 1 "query:processes" Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" }
|
||||||
{FreezeMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" }
|
{FreezeMachine 0 1 "query:machines" Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" }
|
||||||
{ThawMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" }
|
{ThawMachine 0 1 "query:machines" Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" }
|
||||||
{FreezeLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" }
|
{FreezeLocalMachine 1 1 "" Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" }
|
||||||
{ThawLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" }
|
{ThawLocalMachine 1 1 "" Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" }
|
||||||
{FreezeEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" }
|
{FreezeEntity 0 0 "" Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" }
|
||||||
{ThawEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" }
|
{ThawEntity 0 0 "" Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" }
|
||||||
|
|
||||||
//- rjf: entity decoration
|
//- rjf: entity decoration
|
||||||
{SetEntityColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
|
{SetEntityColor 0 0 "" Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
|
||||||
{SetEntityName 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
|
{SetEntityName 0 0 "" Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
|
||||||
|
|
||||||
|
//- rjf: modules
|
||||||
|
{DownloadModuleDebugInfo 1 1 "query:modules" CtrlEntity 0 0 0 0 0 1 1 Module "download_module_debug_info" "Download Module Debug Info" "Tries to download a module's debug info from symbol server(s)." "" "{module_commands}" }
|
||||||
|
|
||||||
//- rjf: attaching
|
//- rjf: attaching
|
||||||
{Attach 1 1 0 0 "query:unattached_processes" PID null Nil Null 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" }
|
{Attach 1 1 "query:unattached_processes" PID 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" }
|
||||||
|
|
||||||
|
//- rjf: crash dump opening
|
||||||
|
{OpenCrashDump 0 0 `folder:\\"$input\\"` FilePath 0 0 0 0 0 1 1 FileOutline "open_crash_dump" "Open Crash Dump" "Opens a crash dump file and recreates debuggee state at the time of the crash." "" "" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@enum D_CmdKind:
|
@enum D_CmdKind:
|
||||||
@@ -88,3 +96,194 @@ D_DevToggleTable:
|
|||||||
@expand(D_DevToggleTable a) `{&DEV_$(a.name), str8_lit_comp("$(a.name)")},`
|
@expand(D_DevToggleTable a) `{&DEV_$(a.name), str8_lit_comp("$(a.name)")},`
|
||||||
`};`;
|
`};`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Entity Kinds
|
||||||
|
|
||||||
|
@table(name code_name display_string)
|
||||||
|
D_EntityKindTable:
|
||||||
|
{
|
||||||
|
{Root root "Root" }
|
||||||
|
{Machine machine "Machine" }
|
||||||
|
{Process process "Process" }
|
||||||
|
{Thread thread "Thread" }
|
||||||
|
{Module module "Module" }
|
||||||
|
{EntryPoint entry_point "Entry Point" }
|
||||||
|
{LaunchMsgID launch_msg_id "Launch Message ID" }
|
||||||
|
{DebugInfoPath debug_info_path "Debug Info Path" }
|
||||||
|
{PendingThreadName pending_thread_name "Pending Thread Name" }
|
||||||
|
{PendingThreadColor pending_thread_color "Pending Thread Color" }
|
||||||
|
{Breakpoint breakpoint "Breakpoint" }
|
||||||
|
{AddressRangeAnnotation address_range_annotation "Address Range Annotation" }
|
||||||
|
}
|
||||||
|
|
||||||
|
@enum D_EntityKind:
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
@expand(D_EntityKindTable a) `$(a.name)`,
|
||||||
|
COUNT,
|
||||||
|
}
|
||||||
|
|
||||||
|
@data(String8) d_entity_kind_code_name_table:
|
||||||
|
{
|
||||||
|
`{0}`,
|
||||||
|
@expand(D_EntityKindTable a) `str8_lit_comp("$(a.code_name)")`
|
||||||
|
}
|
||||||
|
|
||||||
|
@data(String8) d_entity_kind_display_string_table:
|
||||||
|
{
|
||||||
|
`{0}`,
|
||||||
|
@expand(D_EntityKindTable a) `str8_lit_comp("$(a.display_name)")`
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Exception Codes
|
||||||
|
|
||||||
|
@table(name lower_name code default display_string)
|
||||||
|
D_ExceptionCodeKindTable:
|
||||||
|
{
|
||||||
|
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
|
||||||
|
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
|
||||||
|
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
|
||||||
|
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
|
||||||
|
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
|
||||||
|
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
|
||||||
|
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
|
||||||
|
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
|
||||||
|
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
|
||||||
|
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
|
||||||
|
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
|
||||||
|
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
|
||||||
|
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
|
||||||
|
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
|
||||||
|
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
|
||||||
|
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
|
||||||
|
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
|
||||||
|
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
|
||||||
|
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
|
||||||
|
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
|
||||||
|
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
|
||||||
|
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
|
||||||
|
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
|
||||||
|
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
|
||||||
|
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
|
||||||
|
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
|
||||||
|
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
|
||||||
|
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
|
||||||
|
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
|
||||||
|
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
|
||||||
|
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
|
||||||
|
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
|
||||||
|
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
|
||||||
|
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
|
||||||
|
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
|
||||||
|
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
|
||||||
|
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
||||||
|
}
|
||||||
|
|
||||||
|
@enum D_ExceptionCodeKind:
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
@expand(D_ExceptionCodeKindTable a) `$(a.name)`,
|
||||||
|
COUNT,
|
||||||
|
}
|
||||||
|
|
||||||
|
@data(U32) d_exception_code_kind_code_table:
|
||||||
|
{
|
||||||
|
`0`;
|
||||||
|
@expand(D_ExceptionCodeKindTable a) `$(a.code)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@data(String8) d_exception_code_kind_display_string_table:
|
||||||
|
{
|
||||||
|
`{0}`;
|
||||||
|
@expand(D_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@data(String8) d_exception_code_kind_lowercase_code_string_table:
|
||||||
|
{
|
||||||
|
`{0}`;
|
||||||
|
@expand(D_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@data(B8) d_exception_code_kind_default_enable_table:
|
||||||
|
{
|
||||||
|
`0`;
|
||||||
|
@expand(D_ExceptionCodeKindTable a) `$(a.default)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Exception Sub-Codes
|
||||||
|
|
||||||
|
@table(name, value)
|
||||||
|
DL_ExceptionSubCodeKindTable:
|
||||||
|
{
|
||||||
|
{ W32_FAST_FAIL_LEGACY_GS_VIOLATION 0 }
|
||||||
|
{ W32_FAST_FAIL_VTGUARD_CHECK_FAILURE 1 }
|
||||||
|
{ W32_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2 }
|
||||||
|
{ W32_FAST_FAIL_CORRUPT_LIST_ENTRY 3 }
|
||||||
|
{ W32_FAST_FAIL_INCORRECT_STACK 4 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_ARG 5 }
|
||||||
|
{ W32_FAST_FAIL_GS_COOKIE_INIT 6 }
|
||||||
|
{ W32_FAST_FAIL_FATAL_APP_EXIT 7 }
|
||||||
|
{ W32_FAST_FAIL_RANGE_CHECK_FAILURE 8 }
|
||||||
|
{ W32_FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9 }
|
||||||
|
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10 }
|
||||||
|
{ W32_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_FIBER_SWITCH 12 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_SET_OF_CONTEXT 13 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_REFERENCE_COUNT 14 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_JUMP_BUFFER 18 }
|
||||||
|
{ W32_FAST_FAIL_MRDATA_MODIFIED 19 }
|
||||||
|
{ W32_FAST_FAIL_CERTIFICATION_FAILURE 20 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_EXCEPTION_CHAIN 21 }
|
||||||
|
{ W32_FAST_FAIL_CRYPTO_LIBRARY 22 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_IMAGE_BASE 24 }
|
||||||
|
{ W32_FAST_FAIL_DLOAD_PROTECTION_FAILURE 25 }
|
||||||
|
{ W32_FAST_FAIL_UNSAFE_EXTENSION_CALL 26 }
|
||||||
|
{ W32_FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_BUFFER_ACCESS 28 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_BALANCED_TREE 29 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_NEXT_THREAD 30 }
|
||||||
|
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 }
|
||||||
|
{ W32_FAST_FAIL_APCS_DISABLED 32 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_IDLE_STATE 33 }
|
||||||
|
{ W32_FAST_FAIL_MRDATA_PROTECTION_FAILURE 34 }
|
||||||
|
{ W32_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_LOCK_STATE 36 }
|
||||||
|
{ W32_FAST_FAIL_GUARD_JUMPTABLE 37 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_LONGJUMP_TARGET 38 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_DISPATCH_CONTEXT 39 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_THREAD 40 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_SYSCALL_NUMBER 41 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_FILE_OPERATION 42 }
|
||||||
|
{ W32_FAST_FAIL_LPAC_ACCESS_DENIED 43 }
|
||||||
|
{ W32_FAST_FAIL_GUARD_SS_FAILURE 44 }
|
||||||
|
{ W32_FAST_FAIL_LOADER_CONTINUITY_FAILURE 45 }
|
||||||
|
{ W32_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE 46 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_CONTROL_STACK 47 }
|
||||||
|
{ W32_FAST_FAIL_SET_CONTEXT_DENIED 48 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_IAT 49 }
|
||||||
|
{ W32_FAST_FAIL_HEAP_METADATA_CORRUPTION 50 }
|
||||||
|
{ W32_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION 51 }
|
||||||
|
{ W32_FAST_FAIL_LOW_LABEL_ACCESS_DENIED 52 }
|
||||||
|
{ W32_FAST_FAIL_ENCLAVE_CALL_FAILURE 53 }
|
||||||
|
{ W32_FAST_FAIL_UNHANDLED_LSS_EXCEPTON 54 }
|
||||||
|
{ W32_FAST_FAIL_ADMINLESS_ACCESS_DENIED 55 }
|
||||||
|
{ W32_FAST_FAIL_UNEXPECTED_CALL 56 }
|
||||||
|
{ W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS 57 }
|
||||||
|
{ W32_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR 58 }
|
||||||
|
{ W32_FAST_FAIL_FLAGS_CORRUPTION 59 }
|
||||||
|
{ W32_FAST_FAIL_VEH_CORRUPTION 60 }
|
||||||
|
{ W32_FAST_FAIL_ETW_CORRUPTION 61 }
|
||||||
|
{ W32_FAST_FAIL_RIO_ABORT 62 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_PFN 63 }
|
||||||
|
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG 64 }
|
||||||
|
{ W32_FAST_FAIL_CAST_GUARD 65 }
|
||||||
|
{ W32_FAST_FAIL_HOST_VISIBILITY_CHANGE 66 }
|
||||||
|
{ W32_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST 67 }
|
||||||
|
{ W32_FAST_FAIL_PATCH_CALLBACK_FAILED 68 }
|
||||||
|
{ W32_FAST_FAIL_NTDLL_PATCH_FAILED 69 }
|
||||||
|
{ W32_FAST_FAIL_INVALID_FLS_DATA 70 }
|
||||||
|
}
|
||||||
|
|||||||
+82
-2143
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user