mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-09-22 17:20:05 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76ce8a79c2 | ||
|
|
932db741fa | ||
|
|
0add3ef72c | ||
|
|
e417a96ce4 | ||
|
|
b2262532a7 | ||
|
|
b24326f502 | ||
|
|
66c1fa337c |
@@ -1 +0,0 @@
|
|||||||
*.sh text=auto eol=lf
|
|
||||||
@@ -1,52 +1,28 @@
|
|||||||
name: builds
|
name: builds
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-windows-2022:
|
build-windows-2022:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
steps:
|
||||||
target:
|
- name: checkout
|
||||||
- raddbg
|
uses: actions/checkout@v2
|
||||||
- radlink
|
- name: build (vs 2022)
|
||||||
- radbin
|
shell: cmd
|
||||||
compiler:
|
run: |
|
||||||
- msvc
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||||
- clang
|
call build raddbg msvc debug || exit /b 1
|
||||||
mode:
|
call build raddbg_from_pdb msvc debug || exit /b 1
|
||||||
- debug
|
call build raddbg_from_dwarf msvc debug || exit /b 1
|
||||||
- release
|
call build raddbg clang debug || exit /b 1
|
||||||
steps:
|
call build raddbg_from_pdb clang debug || exit /b 1
|
||||||
- name: checkout
|
call build raddbg_from_dwarf clang debug || exit /b 1
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: build (vs 2022)
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
|
||||||
call build "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
|
|
||||||
|
|
||||||
run-torture:
|
|
||||||
runs-on: windows-2022
|
|
||||||
steps:
|
|
||||||
# - name: Install ASAN
|
|
||||||
# shell: cmd
|
|
||||||
# run: |
|
|
||||||
# "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" modify --installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" --quiet --force --norestart --add Microsoft.VisualStudio.Component.VC.ASAN
|
|
||||||
- name: checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: run-torture
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
|
||||||
call build radlink asan debug no_meta || exit /b 1
|
|
||||||
call build torture debug no_meta || exit /b 1
|
|
||||||
cd build
|
|
||||||
torture -l:radlink || exit /b 1
|
|
||||||
|
|||||||
+3
-4
@@ -1,4 +1,3 @@
|
|||||||
/build/
|
/build/
|
||||||
/local/
|
/local/
|
||||||
*~
|
*~
|
||||||
.vscode/settings.json
|
|
||||||
|
|||||||
-137
@@ -1,137 +0,0 @@
|
|||||||
# v0.9.24-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Added the ability for the debugger to load, use, and evaluate using debug
|
|
||||||
info, even when not actively debugging. The debugger will now keep a process'
|
|
||||||
debug info loaded, even after the process ends. It stores the set of loaded
|
|
||||||
debug info files in the project configuration file, meaning it will also
|
|
||||||
automatically load the same debug info across many runs. Debug info can also
|
|
||||||
be loaded manually (without ever launching a process) with the
|
|
||||||
`Load Debug Info` command. There is also a new tab, `Debug Info`, which allows
|
|
||||||
viewing and managing the set of loaded debug info files.
|
|
||||||
- Improved the debugger's behavior when used as a drag & drop target, to allow
|
|
||||||
for debug info loading as an option (when relevant), and to better handle the
|
|
||||||
case where many files (potentially of different types) are dropped together.
|
|
||||||
- Improved debug info searching performance and reponsiveness in large projects.
|
|
||||||
- Fixed some crashes and incorrect results with the new `list` view.
|
|
||||||
- Fixed some cases where RDIs did not contain some basic types from their
|
|
||||||
originating PDBs.
|
|
||||||
- Allowed `.` and `->` operators to be used with array types.
|
|
||||||
- Fixed the debugger's treatment of quoted command line arguments when building
|
|
||||||
targets. In previous versions, calling `raddbg main.exe "foo bar baz"` would
|
|
||||||
create a target `main.exe` with arguments `foo bar baz` (dropping the quotes).
|
|
||||||
This is now fixed, such that the target's arguments string will also contain
|
|
||||||
the quotes, and pass them to the target when launched.
|
|
||||||
- Fixed the debugger not correctly responding (through font and UI scale) to DPI
|
|
||||||
changes.
|
|
||||||
- Fixed the debugger incorrectly generating conflicting source line info records
|
|
||||||
in PDB -> RDI conversion, which in some scenarios was preventing source line
|
|
||||||
maps from working (leading to breakpoint resolution failing).
|
|
||||||
- Other small fixes, improvements, and tweaks.
|
|
||||||
|
|
||||||
# v0.9.23-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Further improved PDB -> RDI conversion performance & memory usage.
|
|
||||||
- Adjusted limits for the amount of PDB -> RDI conversion work that the
|
|
||||||
debugger will kick off, to prevent PDB -> RDI conversion interfering with
|
|
||||||
debuggee performance.
|
|
||||||
- Reintroduced the `list` lens, which gathers all nodes in a linked list, and
|
|
||||||
visualizes them as a flat list of pointers (the same as how an array of
|
|
||||||
pointers is visualized).
|
|
||||||
- Fixed a crash when closing empty Geometry 3D views. (#652, #657)
|
|
||||||
- Fixed the debugger not visualizing `enum` types when evaluated through a
|
|
||||||
bitfield type. (#655)
|
|
||||||
- Fixed the PDB -> RDI conversion not correctly generating location information
|
|
||||||
for function parameters, when the EXE/PDB were built to include support for
|
|
||||||
Edit and Continue (`-ZI` switch). (#656)
|
|
||||||
|
|
||||||
## Binary Utility Changes
|
|
||||||
|
|
||||||
- Fixed a crash when using the `--compress` option, when generating RDI files.
|
|
||||||
|
|
||||||
# v0.9.22-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Further improved PDB -> RDI conversion performance.
|
|
||||||
- Capped the number of additional threads / processes spawned for PDB -> RDI
|
|
||||||
conversion.
|
|
||||||
- Prioritize PDB -> RDI conversion based on what is actually found to be
|
|
||||||
necessary by the debugger, rather than converting all PDBs in the order in
|
|
||||||
which they're discovered.
|
|
||||||
- Added preliminary support for DWARF -> RDI conversion on Windows.
|
|
||||||
- The debugger now relies on source file checksums to determine whether or not
|
|
||||||
a source file is out-of-date with respect to what was compiled when debug info
|
|
||||||
was produced, rather than just the modification timestamp.
|
|
||||||
- The debugger now will rely on debug info to detect the language of source code
|
|
||||||
files, if it cannot infer from the source file's extension, or view settings.
|
|
||||||
This will enable features like syntax highlighting and hover evaluation in
|
|
||||||
cases like `.inl` files being included in C++ projects.
|
|
||||||
- The debugger now will restore the last focused window when continuing
|
|
||||||
automatically. (#245, #596)
|
|
||||||
- Watch tables have been simplified in that they no longer have a separate
|
|
||||||
column for evaluation types, since this was usually taking a lot more space
|
|
||||||
than it deserved. The type of evaluations is still displayed in watch table
|
|
||||||
cells, and it can always be evaluated directly via `typeof`.
|
|
||||||
- Type evaluations have been simplified in watch tables as well; they no longer
|
|
||||||
have untitled columns for sizes and offsets, this is instead displayed as
|
|
||||||
an extra note by default. Similar behavior to the original behavior can still
|
|
||||||
be obtained using the `columns` view, if needed.
|
|
||||||
- The debugger no longer uses complex `union` types for most registers, and
|
|
||||||
instead just displays the register value plainly.
|
|
||||||
- The hover evaluation UI has been made larger when needed.
|
|
||||||
- The debugger now prefers matching global, function, and type identifiers to
|
|
||||||
the most relevant debug info and module in context; this fixes evaluation in
|
|
||||||
some multi-process debugging contexts. (#581)
|
|
||||||
- Fixed the debugger unnecessarily stripping `enum` type information when
|
|
||||||
accessed through array operators. (#634)
|
|
||||||
- The debugger now understands a standalone `unsigned` keyword as an
|
|
||||||
`unsigned int` type, to match C rules.
|
|
||||||
- The debugger now uses the current working directory to form the working
|
|
||||||
directory for targets specified on the command line, to match behavior when
|
|
||||||
running a command from the command line without the debugger.
|
|
||||||
- Improved call stack computation performance.
|
|
||||||
- Improved debugger memory usage over long periods of time.
|
|
||||||
- Fixed string-pointer comparison not working with not-equal (`!=`) operations.
|
|
||||||
- Fixed a bug which was causing bad debuggee performance on some threads after
|
|
||||||
some interactions with the debugger controller.
|
|
||||||
- Fixed incorrect results when adding two register values. (#642)
|
|
||||||
- Fixed the interpretation of register expressions in visualizers. (#649)
|
|
||||||
- Fixed "forever loading" states in disassembly views in some cases. (#643)
|
|
||||||
- Fixed jittering on window resizing. (#636)
|
|
||||||
- Fixed the bitmap visualizer crashing in some circumstances relating to
|
|
||||||
unsupported bitmap sizes. (#444, #563)
|
|
||||||
- Fixed a crash when an empty `cast()` expression would be evaluated. (#625)
|
|
||||||
- Fixed a crash when an invalid expression would be visualized using the `text`
|
|
||||||
view. (#647)
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
|
|
||||||
- Changed symbol resolution in libaries to match MSVC behavior.
|
|
||||||
- Optimized image building step to reduce memory usage.
|
|
||||||
- Linker memory maps all input files by default to lower memory usage.
|
|
||||||
(`/RAD_MEMORY_MAP_FILES`)
|
|
||||||
- If debug info is available, linker uses it to show file and line number for
|
|
||||||
unresolved relocations.
|
|
||||||
- Improved base relocation build performance for large images, cutting build
|
|
||||||
time by 70%.
|
|
||||||
- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability
|
|
||||||
with existing response files
|
|
||||||
- Implemented section garbage collection (`/OPT:REF`)
|
|
||||||
- Fixed bug where thread local variables pointed to incorrect types.
|
|
||||||
- Changed rules for weak and undefined symbols, now weak symbol is not allowed
|
|
||||||
to replace an undefined symbol.
|
|
||||||
- Linker no longer creates thunks for imports that don't require them.
|
|
||||||
|
|
||||||
## Binary Utility Changes
|
|
||||||
|
|
||||||
- The binary utility, like the debugger, now can convert DWARF debug info to
|
|
||||||
RDI files. When both DWARF and PDB info is present, it can now convert both,
|
|
||||||
and produce a single final RDI file with all information.
|
|
||||||
- Textual dumping of RDI files is now done in parallel, massively improving
|
|
||||||
dumping performance.
|
|
||||||
- PDB -> Breakpad conversion performance has now been parallelized to a greater
|
|
||||||
degree, improving performance.
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
Copyright (c) Epic Games Tools
|
Copyright (c) 2024 Epic Games Tools
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the “Software”), to deal in
|
this software and associated documentation files (the “Software”), to deal in
|
||||||
the Software without restriction, including without limitation the rights to
|
the Software without restriction, including without limitation the rights to
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
so, subject to the following conditions:
|
so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
||||||
copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|||||||
@@ -1,428 +1,325 @@
|
|||||||
# The RAD Debugger Project
|
# The RAD Debugger Project
|
||||||
|
|
||||||
_**NOTE:** This README does not document usage instructions and tips for the
|
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||||
debugger itself, and is intended as a technical overview of the project. The
|
currently only supports local-machine Windows x64 debugging with PDBs, with
|
||||||
debugger's README, which includes usage instructions and tips, can be found
|
plans to expand and port in the future. In the future we'll expand to also
|
||||||
packaged along with debugger releases, or within the `build` folder after a
|
support native Linux debugging and DWARF debug info.
|
||||||
local copy has been built. You can find pre-built release binaries
|
|
||||||
[here](https://github.com/EpicGamesExt/raddebugger/releases)._
|
The RAD Debugger is currently in *ALPHA*. In order to get the debugger bullet-
|
||||||
|
proof, it'd greatly help out if you submitted the issues you find here, along
|
||||||
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
with any information you can gather, like dump files (along with the build you
|
||||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
used), instructions to reproduce, test executables, and so on.
|
||||||
plans to expand and port in the future. In the future we'll expand to also
|
|
||||||
support native Linux debugging and DWARF debug info.
|
You can download pre-built binaries for the debugger
|
||||||
|
[here](https://github.com/EpicGames/raddebugger/releases).
|
||||||
The debugger is currently in *ALPHA*. In order to get the debugger
|
|
||||||
bullet-proof, it'd greatly help out if you submitted the issues you find
|
The RAD Debugger project aims to simplify the debugger by simplifying and
|
||||||
[here](https://github.com/EpicGamesExt/raddebugger/issues), along with any
|
unifying the underlying debug info format. In that pursuit we've built
|
||||||
information you can gather, like dump files (along with the build you used),
|
the RADDBG debug info format, which is what the debugger parses and uses. To
|
||||||
instructions to reproduce, test executables, and so on.
|
work with existing toolchains, we convert PDB (and eventually PE/ELF files
|
||||||
|
with embedded DWARF) into the RADDBG format on-demand. This conversion process
|
||||||
In addition to the debugger, we aim to further improve the toolchain with two
|
is currently an unoptimized reference version. Nevertheless it's still quite
|
||||||
additional related technologies: **(1)** the RAD Debug Info (RDI) format, and
|
fast for smaller PDB files (in many cases faster than many other programs
|
||||||
**(2)** the RAD Linker.
|
simply deserialize the PDBs). It is much slower for much larger projects at the
|
||||||
|
moment, but we expect this will vastly improve overtime.
|
||||||
## The RAD Debug Info (RDI) Format
|
|
||||||
|
The RADDBG format is currently specified in code, in the files within the
|
||||||
The RAD Debug Info (RDI) format is our custom debug information format, which
|
`src/raddbg_format` folder. The other relevant folders for working with the
|
||||||
the debugger parses and uses, rather than the debug information natively
|
format are:
|
||||||
produced by toolchains, like PDB or DWARF. To work with these existing
|
|
||||||
toolchains, we convert PDB (and eventually PE/ELF files with embedded DWARF)
|
- `raddbg_cons`: The RADDBG construction layer, for constructing RADDBG files.
|
||||||
into the RDI format on-demand.
|
- `raddbg_convert`: Our implementation of PDB-to-RADDBG (and an in-progress
|
||||||
|
implementation of a DWARF-to-RADDBG) conversion.
|
||||||
The RDI format is currently specified in code, in the files within the
|
- `raddbg_dump`: Code for textually dumping information from RADDBG files.
|
||||||
`src/lib_rdi` folder. In [`rdi.h`](src/lib_rdi/rdi.h) and
|
|
||||||
[`rdi.c`](src/lib_rdi/rdi.c), the types and functions which define the format
|
## Development Setup Instructions
|
||||||
itself are specified. In [`rdi_parse.h`](src/lib_rdi/rdi_parse.h) and
|
|
||||||
[`rdi_parse.c`](src/lib_rdi/rdi_parse.c), helpers for parsing the format are
|
**Note: Currently, only x64 Windows development is supported.**
|
||||||
included.
|
|
||||||
|
### 1. Installing the Required Tools (MSVC & Windows SDK)
|
||||||
We also have an in-progress library for constructing and serializing RDI data,
|
|
||||||
located within the `src/lib_rdi_make` folder.
|
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
||||||
|
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
||||||
Our `radbin` utility (accessible through the debugger too, via the `--bin`
|
the Windows SDK and the MSVC compiler and linker.
|
||||||
command line argument) is capable of converting native debug information formats
|
|
||||||
to RDI, and of producing textual dumps of contents stored within RDI files.
|
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
||||||
|
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
||||||
## The RAD Linker
|
|
||||||
|
### 2. Build Environment Setup
|
||||||
The RAD Linker is a new performance linker for generating x64 PE/COFF binaries.
|
|
||||||
It is designed to be very fast when creating gigantic executables. It generates
|
Building the codebase can be done in a terminal which is equipped with the
|
||||||
standard PDB files for debugging, but it can also (optionally) natively create
|
ability to call either MSVC or Clang from command line.
|
||||||
RAD Debug Info too, which is useful both to eliminate on-demand conversion time
|
|
||||||
when debugging, but also for huge executables that otherwise create broken
|
This is generally done by calling `vcvarsall.bat x64`, which is included in the
|
||||||
PDBs that overflow internal 32-bit tables.
|
Microsoft C/C++ Build Tools. This script is automatically called by the `x64
|
||||||
|
Native Tools Command Prompt for VS <year>` variant of the vanilla `cmd.exe`. If
|
||||||
The RAD Linker is primarily optimized to handle huge linking projects. In our
|
you've installed the build tools, this command prompt may be easily located by
|
||||||
test cases (where debug info is multiple gigabytes), we see 50% faster link
|
searching for `Native` from the Windows Start Menu search.
|
||||||
times.
|
|
||||||
|
You can ensure that the MSVC compiler is accessible from your command line by
|
||||||
The command line syntax is fully compatible with MSVC; you can get a full list
|
running:
|
||||||
of implemented switches from `/help`.
|
|
||||||
|
```
|
||||||
Our current designed-for use case for the linker is to help with the
|
cl
|
||||||
compile-debug cycle of huge projects. We don't yet have support for
|
```
|
||||||
link-time-optimizations, but this feature is on the road map.
|
|
||||||
|
If everything is set up correctly, you should have output very similar to the
|
||||||
By default, the linker spawns as many threads as there are cores, so if you plan
|
following:
|
||||||
to run multiple linkers in parallel, you can limit the number of thread workers
|
|
||||||
via `/rad_workers`.
|
```
|
||||||
|
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
|
||||||
We also have support for large memory pages, which, when enabled, reduce link
|
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||||
time by another 25%. To link with large pages, you need to explicitly request
|
|
||||||
them via `/rad_large_pages`. Large pages are off by default, since Windows
|
usage: cl [ option... ] filename... [ /link linkoption... ]
|
||||||
support for large pages is a bit buggy; we recommend they only be used in Docker
|
```
|
||||||
or VM images where the environment is reset after each link. In a standard
|
|
||||||
Windows environment, using large pages otherwise will fragment memory quickly,
|
### 3. Building
|
||||||
forcing a reboot. We are working on a Linux port of the linker that will be able
|
|
||||||
to build with large pages robustly.
|
Within this terminal, `cd` to the root directory of the codebase, and just run
|
||||||
|
the `build.bat` script:
|
||||||
A benchmark of the linker's performance is below:
|
|
||||||
|
```
|
||||||

|
build
|
||||||
|
```
|
||||||
---
|
|
||||||
|
You should see the following output:
|
||||||
# Project Development Setup Instructions
|
|
||||||
|
```
|
||||||
**NOTE: Currently, only x64 Windows development is supported for the project.**
|
[debug mode]
|
||||||
|
[msvc compile]
|
||||||
## 1. Installing the Required Tools (MSVC & Windows SDK)
|
[default mode, assuming `raddbg` build]
|
||||||
|
metagen_main.c
|
||||||
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
searching C:\devel\raddebugger/src... 299 files found
|
||||||
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
parsing metadesk... 12 metadesk files parsed
|
||||||
the Windows SDK and the MSVC compiler and linker.
|
gathering tables... 37 tables found
|
||||||
|
generating layer code...
|
||||||
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
raddbg.cpp
|
||||||
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
```
|
||||||
|
|
||||||
## 2. Build Environment Setup
|
If everything worked correctly, there will be a `build` folder in the root
|
||||||
|
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
||||||
Building the codebase can be done in a terminal which is equipped with the
|
|
||||||
ability to call either MSVC or Clang from command line.
|
## Short-To-Medium-Term Roadmap
|
||||||
|
|
||||||
This is generally done by calling `vcvarsall.bat x64`, which is included in the
|
### The Initial Alpha Battle-Testing Phase
|
||||||
Microsoft C/C++ Build Tools. This script is automatically called by the `x64
|
|
||||||
Native Tools Command Prompt for VS <year>` variant of the vanilla `cmd.exe`. If
|
The first priority for the project is to ensure that the most crucial debugger
|
||||||
you've installed the build tools, this command prompt may be easily located by
|
components are functioning extremely reliably for local, x64, Windows
|
||||||
searching for `Native` from the Windows Start Menu search.
|
debugging. This would include parts like debug info conversion, debug info
|
||||||
|
loading, process control, stepping, evaluation (correct usage of both location
|
||||||
You can ensure that the MSVC compiler is accessible from your command line by
|
info and type info), and a robust frontend which ensures the lower level parts
|
||||||
running:
|
are usable.
|
||||||
|
|
||||||
```
|
We feel that the debugger has already come a long way in all of these respects,
|
||||||
cl
|
but given the massive set of possible combinations of languages, build
|
||||||
```
|
settings, toolchains, used language features, and patterns of generated code,
|
||||||
|
there are still cases where the debugger has not been tested, and so there are
|
||||||
If everything is set up correctly, you should have output very similar to the
|
still issues. So, we feel that the top priority is eliminating these issues,
|
||||||
following:
|
such that the debugging experience is rock solid.
|
||||||
|
|
||||||
```
|
Additionally, the debug info conversion process is not fast (nor wide) enough
|
||||||
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
|
to support extremely large projects. This is for two reasons: (a) the
|
||||||
Copyright (C) Microsoft Corporation. All rights reserved.
|
PDB-to-RADDBG converter is an unoptimized reference implementation, and (b) the
|
||||||
|
debugger learns of new modules (and thus which PDBs to load) in a
|
||||||
usage: cl [ option... ] filename... [ /link linkoption... ]
|
serially-dependent way (this is necessarily the case for correct debugging
|
||||||
```
|
results). We expect that the conversion process' performance can be massively
|
||||||
|
improved, and also that some heuristics can be used to begin converting PDBs
|
||||||
### 3. Building
|
to RADDBGs before the debugger knows those PDBs are needed, thus ensuring the
|
||||||
|
associated RADDBG files are ready instantaneously when the associated modules
|
||||||
Within this terminal, `cd` to the root directory of the codebase, and just run
|
are finally loaded by the debugger. Improving this situation is a major part of
|
||||||
the `build.bat` script:
|
this phase, as it will make the debugger much more usable for large projects.
|
||||||
|
|
||||||
```
|
### Local x64 Linux Debugging Phase
|
||||||
build
|
|
||||||
```
|
The next priority for the project is to take the rock solid x64 Windows
|
||||||
|
debugging experience, and port all of the relevant pieces to support local x64
|
||||||
You should see the following output:
|
Linux debugging also.
|
||||||
|
|
||||||
```
|
The debugger has been written to abstract over the parts that need to differ on
|
||||||
[debug mode]
|
either Linux or Windows, and this is mainly going to be a task in building out
|
||||||
[msvc compile]
|
different backends for those abstraction layers.
|
||||||
[default mode, assuming `raddbg` build]
|
|
||||||
metagen_main.c
|
The major parts of this phase are:
|
||||||
searching C:\devel\raddebugger/src... 458 files found
|
|
||||||
parsing metadesk... 16 metadesk files parsed
|
- Porting the `src/demon` layer to implement the Demon local process control
|
||||||
gathering tables... 97 tables found
|
abstraction API.
|
||||||
generating layer code...
|
- Porting the `src/unwind` layer to support x64 ELF unwinding (currently, there
|
||||||
raddbg_main.c
|
is only an x64 PE unwinding implementation).
|
||||||
```
|
- Creating a DWARF-to-RADDBG converter (in the same way that we've built a PDB-
|
||||||
|
to-RADDBG converter). A partial implementation of this is in
|
||||||
If everything worked correctly, there will be a `build` folder in the root
|
`src/raddbg_convert/dwarf`.
|
||||||
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
- Porting the `src/render` layer to implement all of the rendering features the
|
||||||
|
frontend needs on a Linux-compatible API (the backend used on Windows is D3D11).
|
||||||
This `raddbg.exe` will have been built in **debug mode**, which is not built
|
- Porting the `src/font_provider` layer to a Linux-compatible font
|
||||||
with optimizations, and may perform worse. To produce a
|
rasterization backend, like FreeType (the backend used on Windows is
|
||||||
**release mode executable**, run `build.bat` with a `release` argument:
|
DirectWrite).
|
||||||
|
- Porting the `src/os` layers to Linux. This includes core operating system
|
||||||
```
|
abstraction (virtual memory allocation, threading and synchronization
|
||||||
build release
|
primitives, and so on), and graphical operating system abstraction (windows,
|
||||||
```
|
input events, and so on).
|
||||||
|
|
||||||
This build will take significantly longer.
|
Once the above list is complete, and once every part is rock solid, the Windows
|
||||||
|
debugging experience we'll have worked diligently to create will also be
|
||||||
By default, `build.bat` only builds the debugger if no arguments (or just
|
available natively on Linux machines.
|
||||||
`release`) are passed, but additional arguments can be passed to build the RAD
|
|
||||||
Linker, or the `radbin` CLI binary file utility:
|
### And Beyond!
|
||||||
|
|
||||||
```
|
There are several directions we might take after these two major phases,
|
||||||
build radlink release
|
like remote debugging, porting to different architectures, further improving
|
||||||
build radbin release
|
the debugger's features (like improving the visualization engine), and so on.
|
||||||
```
|
But for now, we're mostly focused on those first two phases.
|
||||||
|
|
||||||
---
|
## Top-Level Directory Descriptions
|
||||||
|
|
||||||
# Project Roadmap
|
- `data`: Small binary files which are used when building, either to embed
|
||||||
|
within build artifacts, or to package with them.
|
||||||
### The Initial Alpha Battle-Testing Phase
|
- `src`: All source code.
|
||||||
|
|
||||||
The first priority for the project is to ensure that the most crucial components
|
After setting up the codebase and building, the following directories will
|
||||||
are functioning extremely reliably for local, x64, Windows development.
|
also exist:
|
||||||
For the debugger, this would include parts like debug info conversion, debug
|
|
||||||
info loading, process control, stepping, evaluation (correct usage of both
|
- `build`: All build artifacts. Not checked in to version control.
|
||||||
location info and type info), and a robust frontend which ensures the lower
|
- `local`: Local files, used for local build configuration input files.
|
||||||
level parts are usable. For the linker, this is a matter of reliability and
|
|
||||||
convergence with existing linker behavior.
|
## Codebase Introduction
|
||||||
|
|
||||||
We feel that we've already come a long way in all of these respects, but given
|
The codebase is organized into *layers*. Layers are separated either to isolate
|
||||||
the massive set of possible combinations of languages, build settings,
|
certain problems, and to allow inclusion into various builds without needing to
|
||||||
toolchains, used language features, and patterns of generated code, we still
|
pull everything in the codebase into a build. Layers correspond with folders
|
||||||
expect some issues, and are prioritizing these issues being resolved first.
|
inside of the `src` directory. Sometimes, one folder inside of the `src`
|
||||||
|
directory will include multiple sub-layers, but the structure is intended to be
|
||||||
We also hope to continue to improve performance in this phase. For the debugger,
|
fairly flat.
|
||||||
this primarily includes frontend performance, introducing caches when economical
|
|
||||||
to do so, and tightening existing systems up. For the linker, it has been mostly
|
Layers correspond roughly 1-to-1 with *namespaces*. The term "namespaces" in
|
||||||
tuned thus far for giant projects, and so we'd like to improve linking speed for
|
this context does not refer to specific namespace language features, but rather
|
||||||
small-to-mid sized projects as well.
|
a naming convention for C-style namespaces, which are written in the codebase as
|
||||||
|
a short prefix, usually 1-3 characters, followed by an underscore. These
|
||||||
For the linker, there are also a number of features to come, like
|
namespaces are used such that the layer to which certain code belongs may be
|
||||||
dead-code-elimination (`/opt:ref`), and link-time-optimizations with the help
|
quickly understood by glancing at code. The namespaces are generally quite short
|
||||||
of `clang` (we won't support LTCG from MSVC, since it is undocumented).
|
to ensure that they aren't much of a hassle to write. Sometimes, multiple sub-
|
||||||
|
layers will share a namespace. A few layers do not have a namespace, but most
|
||||||
### Local x64 Linux Debugging Phase
|
do. Namespaces are either all-caps or lowercase depending on the context in
|
||||||
|
which they're used. For types, enum values, and some macros, they are
|
||||||
The next priority for the project is to take the rock solid x64 Windows
|
capitalized. For functions and global variables, they are lowercase.
|
||||||
debugging experience, and port all of the relevant pieces to support local x64
|
|
||||||
Linux debugging also.
|
Layers depend on other layers, but circular dependencies would break the
|
||||||
|
separability and isolation utility of layers (in effect, forming one big layer),
|
||||||
The debugger has been written to abstract over the parts that need to differ on
|
so in other words, layers are arranged into a directed acyclic graph.
|
||||||
either Linux or Windows, and this is mainly going to be a task in building out
|
|
||||||
different backends for those abstraction layers.
|
A list of the layers in the codebase and their associated namespaces is below:
|
||||||
|
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||||
The major parts of this phase are:
|
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||||
|
on no other codebase layers.
|
||||||
- Porting the `src/demon` layer to implement the Demon local process control
|
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||||
abstraction API.
|
Format) file format.
|
||||||
- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer.
|
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||||
- Creating a DWARF-to-RDI converter (in the same way that we've built a
|
asynchronous process control, stepping, and breakpoints for all attached
|
||||||
PDB-to-RDI converter). A partial implementation of this is in
|
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||||
`src/rdi_from_dwarf`.
|
processes are halted. When attached processes are running, it is halted.
|
||||||
- Porting the `src/render` layer to implement all of the rendering features the
|
Driven by a debugger frontend on another thread.
|
||||||
frontend needs on a Linux-compatible API (the backend used on Windows is D3D11).
|
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
|
||||||
- Porting the `src/font_provider` layer to a Linux-compatible font
|
disassembly for a particular virtual address range in a process, and threads
|
||||||
rasterization backend, like FreeType (the backend used on Windows is
|
implemented in this layer decode and cache the disassembly for that range.
|
||||||
DirectWrite).
|
- `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug
|
||||||
- Porting the `src/os` layers to Linux. This includes core operating system
|
info stored in the RADDBG format. Users ask for debug info for a particular
|
||||||
abstraction (virtual memory allocation, threading and synchronization
|
executable, and on separate threads, this layer loads the associated debug
|
||||||
primitives, and so on), and graphical operating system abstraction (windows,
|
info file. If necessary, it will launch a separate conversion process to
|
||||||
input events, and so on).
|
convert original debug info into the RADDBG format.
|
||||||
|
- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process
|
||||||
Once the above list is complete, and once every part is rock solid, the Windows
|
control. The abstraction is used to provide a common interface for process
|
||||||
debugging experience we'll have worked diligently to create will also be
|
control on target platforms. Used to implement part of `ctrl`.
|
||||||
available natively on Linux machines.
|
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
|
||||||
|
debugger "entity cache" (where "entities" include processes, threads, modules,
|
||||||
### And Beyond!
|
breakpoints, source files, targets, and so on). Implements a command loop
|
||||||
|
for driving process control, which is used to implement stepping commands and
|
||||||
There are several directions we might take after these two major phases,
|
user breakpoints. Implements extractors and caches for various entity-related
|
||||||
like remote debugging, porting to different architectures, further improving
|
data, like full thread unwinds and local variable maps. Also implements core
|
||||||
the debugger's features (like improving the visualization engine), and so on.
|
building blocks for evaluation and evaluation visualization.
|
||||||
But for now, we're mostly focused on those first two phases.
|
- `df/gfx` (`DF_`): The debugger's graphical frontend. Builds on top of
|
||||||
|
`df/core` to provide all graphical features, including windows, panels, all
|
||||||
---
|
of the various debugger interfaces, and evaluation visualization.
|
||||||
|
- `draw` (`D_`): Implements a high-level graphics drawing API for the debugger's
|
||||||
# Codebase Introduction
|
purposes, using the underlying `render` abstraction layer. Provides high-level
|
||||||
|
APIs for various draw commands, but takes care of batching them, and so on.
|
||||||
## Top-Level Directory Descriptions
|
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
|
||||||
|
evaluation of variables, registers, and so on from debugger-attached processes
|
||||||
- `data`: Small binary files which are used when building, either to embed
|
and/or debug info. Broken into several phases mostly corresponding to
|
||||||
within build artifacts, or to package with them.
|
traditional compiler phases - lexer, parser, type-checker, IR generation, and
|
||||||
- `src`: All source code.
|
IR evaluation.
|
||||||
|
- `font_cache` (`F_`): Implements a cache of rasterized font data, both in CPU-
|
||||||
After setting up the codebase and building, the following directories will
|
side data for text shaping, and in GPU texture atlases for rasterized glyphs.
|
||||||
also exist:
|
All cache information is sourced from the `font_provider` abstraction layer.
|
||||||
|
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
||||||
- `build`: All build artifacts. Not checked in to version control.
|
and font rasterization backends.
|
||||||
- `local`: Local files, used for local build configuration input files. Not
|
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||||
checked in to version control.
|
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
## Layer Descriptions
|
- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a
|
||||||
|
128-bit hash of the data. Used as a general data store by other layers.
|
||||||
The codebase is organized into *layers*. Layers are separated either to isolate
|
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
||||||
certain problems, and to allow inclusion into various builds without needing to
|
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
||||||
pull everything in the codebase into a build. Layers correspond with folders
|
generates C code which is then included by hand-written C code. Currently, it
|
||||||
inside of the `src` directory. Sometimes, one folder inside of the `src`
|
does not analyze the codebase's hand-written C code, but in principle this is
|
||||||
directory will include multiple sub-layers, but the structure is intended to be
|
possible. This allows easier & less-error-prone management of large data
|
||||||
fairly flat.
|
tables, which are then used to produce e.g. C `enum`s and a number of
|
||||||
|
associated data tables. There are also a number of other generation features,
|
||||||
Layers correspond roughly 1-to-1 with *namespaces*. The term "namespaces" in
|
like embedding binary files or complex multi-line strings into source code.
|
||||||
this context does not refer to specific namespace language features, but rather
|
This layer cannot depend on any other layer in the codebase directly,
|
||||||
a naming convention for C-style namespaces, which are written in the codebase as
|
including `base`, because it may be used to generate code for those layers. To
|
||||||
a short prefix, usually 1-3 characters, followed by an underscore. These
|
still use `base` and `os` layer features in the `metagen` program, a separate,
|
||||||
namespaces are used such that the layer to which certain code belongs may be
|
duplicate version of `base` and `os` are included in this layer. They are
|
||||||
quickly understood by glancing at code. The namespaces are generally quite short
|
updated manually, as needed. This is to ensure the stability of the
|
||||||
to ensure that they aren't much of a hassle to write. Sometimes, multiple sub-
|
metaprogram.
|
||||||
layers will share a namespace. A few layers do not have a namespace, but most
|
- `mule` (no namespace): Test executables for battle testing debugger
|
||||||
do. Namespaces are either all-caps or lowercase depending on the context in
|
functionality.
|
||||||
which they're used. For types, enum values, and some macros, they are
|
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
||||||
capitalized. For functions and global variables, they are lowercase.
|
types in other debuggers.
|
||||||
|
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
||||||
Layers depend on other layers, but circular dependencies would break the
|
functionality from the operating system under an abstract API, which is
|
||||||
separability and isolation utility of layers (in effect, forming one big layer),
|
implemented per-target-operating-system.
|
||||||
so in other words, layers are arranged into a directed acyclic graph.
|
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
|
graphical operating system features under an abstract API, which is
|
||||||
A few layers are built to be used completely independently from the rest of the
|
implemented per-target-operating-system.
|
||||||
codebase, as libraries in other codebases and projects. As such, these layers do
|
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
not depend on any other layers in the codebase. The folders which contain these
|
networking operating system features under an abstract API, which is
|
||||||
layers are prefixed with `lib_`, like `lib_rdi`.
|
implemented per-target-operating-system.
|
||||||
|
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
|
||||||
A list of the layers in the codebase and their associated namespaces is below:
|
file format.
|
||||||
- `artifact_cache` (`AC_`): Implements an asynchronously-filled cache of
|
- `raddbg` (no namespace): The layer which ties everything together for the main
|
||||||
computation artifacts, which are automatically evicted when not accessed. Used
|
graphical debugger. Not much "meat", just drives `df`, implements command line
|
||||||
for asynchronously streaming and caching process memory and file system
|
options, and so on.
|
||||||
contents, as well as asynchronously preparing visualizer data.
|
- `raddbg_cons` (`CONS_`): Implements an API for constructing files of the
|
||||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
RADDBG debug info file format.
|
||||||
memory allocators, helper macros, command-line parsing, and so on. Requires
|
- `raddbg_dump` (`DUMP_`): A dumper utility program for dumping textualizations
|
||||||
no other codebase layers.
|
of RADDBG debug info files.
|
||||||
- `codeview` (`CV_`): Code for parsing and writing the CodeView format.
|
- `raddbg_format` (`RADDBG_`): Standalone types and helper functions for the
|
||||||
- `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File
|
RADDBG debug info file format. Does not depend on `base`.
|
||||||
Format) file format.
|
- `raddbg_markup` (`RADDBG_`): Standalone header file for marking up user
|
||||||
- `content` (`C_`): Implements a cache for general data blobs, keyed by a
|
programs to work with various features in the `raddbg` debugger. Does not
|
||||||
128-bit hash of the data. Also implements a keying system on top, where keys
|
depend on `base`.
|
||||||
refer to a unique identity which corresponds to a history of 128-bit hashes.
|
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
||||||
Used as a general data store by other layers.
|
supported architectures. Used in reading/writing registers in `demon`, or in
|
||||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
looking up register metadata.
|
||||||
asynchronous process control, stepping, and breakpoints for all attached
|
- `render` (`R_`): An abstraction layer providing an abstract API for rendering
|
||||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
using various GPU APIs under a common interface. Does not implement a high
|
||||||
processes are halted. When attached processes are running, it is halted.
|
level drawing API - this layer is strictly for minimally abstracting on an
|
||||||
Driven by a debugger frontend on another thread.
|
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||||
- `dbg_engine` (`D_`): Implements the core debugger system, without any
|
layer.
|
||||||
graphical components. This contains top-level logic for things like stepping,
|
- `scratch` (no namespace): Scratch space for small and transient test or sample
|
||||||
launching, freezing threads, mid-run breakpoint addition, some caches, and so
|
programs.
|
||||||
on.
|
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||||
- `dbg_info` (`DI_`): Implements asynchronous debug info conversion and loading.
|
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
Maintains a cache for loaded debug info. Loads RAD Debug Info (RDI) files.
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
Launches separate processes for on-demand conversion to the RDI format if
|
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
|
||||||
necessary. Also provides various asynchronous operations for using debug info,
|
reloaded, asynchronously parsed, and asynchronously mutated source code files.
|
||||||
like fuzzy searching across all records in loaded debug info.
|
Used by the debugger to visualize source code files. Users ask for text lines,
|
||||||
- `demon` (`DMN_`): An abstraction layer for local-machine, low-level process
|
tokens, and metadata, and it is prepared on background threads.
|
||||||
control. The abstraction is used to provide a common interface for process
|
- `type_graph` (`TG_`): Code for analyzing and navigating type structures from
|
||||||
control on target platforms. Used to implement part of `ctrl`.
|
RADDBG debug info files, with the additional capability of constructing
|
||||||
- `disasm` (`DASM_`): Implements disassembly generation, including exposing the
|
synthetic types *not* found in debug info. Used in `eval` and for various
|
||||||
ability to compute and cache disassembly asynchronously.
|
visualization features.
|
||||||
- `draw` (`DR_`): Implements a high-level graphics drawing API for the
|
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
||||||
debugger's purposes, using the underlying `render` abstraction layer. Provides
|
core immediate mode hierarchical user interface data structure building
|
||||||
high-level APIs for various draw commands, but takes care of batching them,
|
API, and has helper layers for building some higher-level widgets.
|
||||||
and so on.
|
- `unwind` (`UNW_`): Code for generating unwind information from threads, for
|
||||||
- `dwarf` (`DW_`): Code for parsing the DWARF format.
|
supported operating systems and architectures.
|
||||||
- `eh` (`EH_`): Code for parsing the EH frame format.
|
|
||||||
- `elf` (`ELF_`): Code for parsing the ELF format.
|
|
||||||
- `eval` (`E_`): A compiler for an expression language, built for evaluation of
|
|
||||||
variables, registers, types, and more, from debugger-attached processes,
|
|
||||||
debug info, debugger state, and files. Broken into several phases mostly
|
|
||||||
corresponding to traditional compiler phases: lexer, parser, type-checker, IR
|
|
||||||
generation, and IR evaluation.
|
|
||||||
- `eval_visualization` (`EV_`): Implements the core non-graphical evaluation
|
|
||||||
visualization engine, which can be used to visualize evaluations (provided by
|
|
||||||
the `eval` layer) in a number of ways. Implements core data structures and
|
|
||||||
transforms for watch tables.
|
|
||||||
- `file_stream` (`FS_`): Implements asynchronous file streaming, storing the
|
|
||||||
artifacts inside of the cache implemented by the `content` and
|
|
||||||
`artifact_cache` layers, hot-reloading the contents of files when they change.
|
|
||||||
Allows callers to map file paths to data hashes, which can then be used to
|
|
||||||
obtain the file's data.
|
|
||||||
- `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in
|
|
||||||
CPU-side data for text shaping, and in GPU texture atlases for rasterized
|
|
||||||
glyphs. All cache information is sourced from the `font_provider` abstraction
|
|
||||||
layer.
|
|
||||||
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
|
||||||
and font rasterization backends.
|
|
||||||
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
|
|
||||||
programs to work with various features in the debugger. Does not depend on
|
|
||||||
`base`, and can be independently relocated to other codebases.
|
|
||||||
- `lib_rdi` (`RDI_`): Standalone library which defines the core RDI types
|
|
||||||
and helper functions for reading and writing the RDI debug info file format.
|
|
||||||
Does not depend on `base`, and can be independently relocated to other
|
|
||||||
codebases.
|
|
||||||
- `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info
|
|
||||||
data. Does not depend on `base`, and can be independently relocated
|
|
||||||
to other codebases.
|
|
||||||
- `linker` (`LNK_`): The layer which implements the RAD Linker executable
|
|
||||||
itself.
|
|
||||||
- `mdesk` (`MD_`): Code for parsing Metadesk files (stored as `.mdesk`), which
|
|
||||||
is the JSON-like (technically a JSON superset) text format used for the
|
|
||||||
debugger's user and project configuration files and metacode, which is parsed
|
|
||||||
and used to generate code with the `metagen` layer.
|
|
||||||
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
|
||||||
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
|
||||||
generates C code which is then included by hand-written C code. Currently, it
|
|
||||||
does not analyze the codebase's hand-written C code, but in principle this is
|
|
||||||
possible. This allows easier & less-error-prone management of large data
|
|
||||||
tables, which are then used to produce e.g. C `enum`s and a number of
|
|
||||||
associated data tables. There are also a number of other generation features,
|
|
||||||
like embedding binary files or complex multi-line strings into source code.
|
|
||||||
- `msf` (`MSF_`): Code for parsing and writing the MSF file format.
|
|
||||||
- `msvc_crt` (`MSCRT_`): Code for parsing that's specific to the MSVC CRT.
|
|
||||||
- `mule` (no namespace): Test executables for battle testing debugger
|
|
||||||
functionality.
|
|
||||||
- `mutable_text` (`MTX_`): Implements an asynchronously-filled-and-mutated
|
|
||||||
cache for text buffers which are mutated across time. In the debugger, this is
|
|
||||||
used to implement the `Output` log.
|
|
||||||
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
|
||||||
types in other debuggers.
|
|
||||||
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
|
||||||
functionality from the operating system under an abstract API, which is
|
|
||||||
implemented per-target-operating-system.
|
|
||||||
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
|
||||||
graphical operating system features under an abstract API, which is
|
|
||||||
implemented per-target-operating-system.
|
|
||||||
- `pdb` (`PDB_`): Code for parsing and writing the PDB file format.
|
|
||||||
- `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file
|
|
||||||
format.
|
|
||||||
- `radbin` (`RB_`): The layer implementing the `radbin` binary utility
|
|
||||||
executable.
|
|
||||||
- `raddbg` (`RD_`): The layer which ties everything together for the main
|
|
||||||
graphical debugger executable. Implements the debugger's graphical frontend,
|
|
||||||
all of the debugger-specific UI, the debugger executable's command line
|
|
||||||
interface, and all of the built-in visualizers.
|
|
||||||
- `rdi` (`RDI_`): A layer which includes the `lib_rdi` layer and bundles it with
|
|
||||||
codebase-specific helpers, to easily include the library in codebase programs,
|
|
||||||
and have it be integrated with codebase constructs.
|
|
||||||
- `rdi_from_coff` (`C2R_`): Code for converting information in COFF files to the
|
|
||||||
equivalent RDI data.
|
|
||||||
- `rdi_from_dwarf` (`D2R_`): In-progress code for converting DWARF to the
|
|
||||||
equivalent RDI data.
|
|
||||||
- `rdi_from_elf` (`E2R_`)): Code for converting ELF data to the equivalent RDI
|
|
||||||
data.
|
|
||||||
- `rdi_from_pdb` (`P2R_`): Code for converting PDB data to the equivalent RDI
|
|
||||||
data.
|
|
||||||
- `rdi_make` (`RDIM_`): A layer which includes the `lib_rdi_make` layer and
|
|
||||||
bundles it with codebase-specific helpers, to easily include the library in
|
|
||||||
codebase programs, and have it be integrated with codebase constructs.
|
|
||||||
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
|
||||||
supported architectures. Used in reading/writing registers in `demon`, or in
|
|
||||||
looking up register metadata.
|
|
||||||
- `render` (`R_`): An abstraction layer providing an abstract API for rendering
|
|
||||||
using various GPU APIs under a common interface. Does not implement a high
|
|
||||||
level drawing API - this layer is strictly for minimally abstracting on an
|
|
||||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
|
||||||
layer.
|
|
||||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
|
||||||
- `tester` (no namespace): A program used for automated testing.
|
|
||||||
- `text` (`TXT_`): Implements text processing functions, like parsing line
|
|
||||||
breaks, and lexing and parsing source code. Also offers an API to do this
|
|
||||||
asynchronously.
|
|
||||||
- `third_party` (no namespace): External code from other projects, which some
|
|
||||||
layers in the codebase depend on. All external code is included and built
|
|
||||||
directly within the codebase.
|
|
||||||
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
|
||||||
core immediate mode hierarchical user interface data structure building
|
|
||||||
API, and has helper layers for building some higher-level widgets.
|
|
||||||
|
|||||||
@@ -1,172 +1,120 @@
|
|||||||
@echo off
|
@echo off
|
||||||
setlocal enabledelayedexpansion
|
setlocal
|
||||||
cd /D "%~dp0"
|
cd /D "%~dp0"
|
||||||
:restart
|
|
||||||
|
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
::
|
||||||
::
|
:: This is a central build script for the RAD Debugger project. It takes a list
|
||||||
:: This is a central build script for the RAD Debugger project, for use in
|
:: of simple alphanumeric-only arguments which control (a) what is built, (b)
|
||||||
:: Windows development environments. It takes a list of simple alphanumeric-
|
:: which compiler & linker are used, and (c) extra high-level build options. By
|
||||||
:: only arguments which control (a) what is built, (b) which compiler & linker
|
:: default, if no options are passed, then the main "raddbg" graphical debugger
|
||||||
:: are used, and (c) extra high-level build options. By default, if no options
|
:: is built.
|
||||||
:: are passed, then the main "raddbg" graphical debugger is built.
|
::
|
||||||
::
|
:: Below is a non-exhaustive list of possible ways to use the script:
|
||||||
:: Below is a non-exhaustive list of possible ways to use the script:
|
:: `build raddbg`
|
||||||
:: `build raddbg`
|
:: `build raddbg clang`
|
||||||
:: `build raddbg clang`
|
:: `build raddbg release`
|
||||||
:: `build raddbg release`
|
:: `build raddbg asan telemetry`
|
||||||
:: `build raddbg asan telemetry`
|
:: `build raddbg_from_pdb`
|
||||||
:: `build rdi_from_pdb`
|
::
|
||||||
::
|
:: For a full list of possible build targets and their build command lines,
|
||||||
:: For a full list of possible build targets and their build command lines,
|
:: search for @build_targets in this file.
|
||||||
:: search for @build_targets in this file.
|
::
|
||||||
::
|
:: 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
|
:: - `telemetry`: enable RAD telemetry profiling support
|
||||||
:: - `telemetry`: enable RAD telemetry profiling support
|
|
||||||
:: - `spall`: enable spall profiling support
|
:: --- Unpack Arguments -------------------------------------------------------
|
||||||
|
for %%a in (%*) do set "%%a=1"
|
||||||
:: --- Unpack Arguments -------------------------------------------------------
|
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
|
||||||
for %%a in (%*) do set "%%~a=1"
|
if not "%release%"=="1" set debug=1
|
||||||
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
|
if "%debug%"=="1" set release=0 && echo [debug mode]
|
||||||
if not "%release%"=="1" set debug=1
|
if "%release%"=="1" set debug=0 && echo [release mode]
|
||||||
if "%debug%"=="1" set release=0 && echo [debug mode]
|
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
||||||
if "%release%"=="1" set debug=0 && echo [release mode]
|
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
||||||
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
|
||||||
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
|
||||||
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
|
:: --- Unpack Command Line Build Arguments ------------------------------------
|
||||||
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
|
set auto_compile_flags=
|
||||||
|
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
||||||
:: --- Unpack Command Line Build Arguments ------------------------------------
|
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||||
set auto_compile_flags=
|
|
||||||
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||||
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
|
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
||||||
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -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 -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf
|
||||||
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
|
set cl_debug= call cl /Od %cl_common% %auto_compile_flags%
|
||||||
if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info]
|
set cl_release= call cl /O2 /DNDEBUG %cl_common% %auto_compile_flags%
|
||||||
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
|
set clang_debug= call clang -g -O0 %clang_common% %auto_compile_flags%
|
||||||
if "%pgo%"=="1" (
|
set clang_release= call clang -g -O2 -DNDEBUG %clang_common% %auto_compile_flags%
|
||||||
where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1
|
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" logo.res
|
||||||
if "%clang%"=="1" (
|
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res
|
||||||
if "%pgo_run%" == "1" (
|
set cl_out= /out:
|
||||||
call llvm-profdata merge %LLVM_PROFILE_FILE% -output=%~dp0build\build.profdata || exit /b 1
|
set clang_out= -o
|
||||||
set auto_compile_flags=%auto_compile_flags% -fprofile-use=%~dp0build\build.profdata
|
|
||||||
set pgo_run=0
|
:: --- Per-Build Settings -----------------------------------------------------
|
||||||
) else (
|
set gfx=-DOS_FEATURE_GRAPHICAL=1
|
||||||
echo [pgo enabled]
|
set net=-DOS_FEATURE_SOCKET=1
|
||||||
set auto_compile_flags=%auto_compile_flags% -fprofile-generate -mllvm -vp-counters-per-site=5
|
set link_dll=-DLL
|
||||||
set LLVM_PROFILE_FILE=%~dp0build\build.profraw
|
if "%msvc%"=="1" set only_compile=/c
|
||||||
set pgo_run=1
|
if "%clang%"=="1" set only_compile=-c
|
||||||
)
|
if "%msvc%"=="1" set EHsc=/EHsc
|
||||||
) else (
|
if "%clang%"=="1" set EHsc=
|
||||||
echo ERROR: PGO build is not supported with current compiler
|
if "%msvc%"=="1" set rc=rc.exe
|
||||||
exit /b 1
|
if "%clang%"=="1" set rc=llvm-rc.exe
|
||||||
)
|
|
||||||
)
|
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||||
|
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
if "%msvc%"=="1" set compile_release=%cl_release%
|
||||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
if "%msvc%"=="1" set compile_link=%cl_link%
|
||||||
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
if "%msvc%"=="1" set out=%cl_out%
|
||||||
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
if "%clang%"=="1" set compile_debug=%clang_debug%
|
||||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf
|
if "%clang%"=="1" set compile_release=%clang_release%
|
||||||
set cl_out= /out:
|
if "%clang%"=="1" set compile_link=%clang_link%
|
||||||
set cl_linker=
|
if "%clang%"=="1" set out=%clang_out%
|
||||||
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
|
if "%debug%"=="1" set compile=%compile_debug%
|
||||||
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
|
if "%release%"=="1" set compile=%compile_release%
|
||||||
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
|
|
||||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf
|
:: --- Prep Directories -------------------------------------------------------
|
||||||
set clang_out= -o
|
if not exist build mkdir build
|
||||||
set clang_linker= -Xlinker
|
if not exist local mkdir local
|
||||||
|
|
||||||
:: --- Per-Build Settings -----------------------------------------------------
|
:: --- Produce Logo Icon File -------------------------------------------------
|
||||||
set link_dll=-DLL
|
pushd build
|
||||||
set link_icon=logo.res
|
%rc% /nologo /fo logo.res ..\data\logo.rc || exit /b 1
|
||||||
if "%msvc%"=="1" set linker=%cl_linker%
|
popd
|
||||||
if "%clang%"=="1" set linker=%clang_linker%
|
|
||||||
if "%msvc%"=="1" set only_compile=/c
|
:: --- Get Current Git Commit Id ----------------------------------------------
|
||||||
if "%clang%"=="1" set only_compile=-c
|
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DRADDBG_GIT=\"%%i\"
|
||||||
if "%msvc%"=="1" set EHsc=/EHsc
|
|
||||||
if "%clang%"=="1" set EHsc=
|
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||||
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
|
if "%no_meta%"=="1" echo [skipping metagen]
|
||||||
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
|
if not "%no_meta%"=="1" (
|
||||||
if "%msvc%"=="1" set rc=call rc
|
pushd build
|
||||||
if "%clang%"=="1" set rc=call llvm-rc
|
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
||||||
|
metagen.exe || exit /b 1
|
||||||
:: --- Choose Compile/Link Lines ----------------------------------------------
|
popd
|
||||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
)
|
||||||
if "%msvc%"=="1" set compile_release=%cl_release%
|
|
||||||
if "%msvc%"=="1" set compile_link=%cl_link%
|
:: --- Build Everything (@build_targets) --------------------------------------
|
||||||
if "%msvc%"=="1" set out=%cl_out%
|
pushd build
|
||||||
if "%clang%"=="1" set compile_debug=%clang_debug%
|
if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1
|
||||||
if "%clang%"=="1" set compile_release=%clang_release%
|
if "%raddbg_from_pdb%"=="1" %compile% ..\src\raddbg_convert\pdb\raddbg_from_pdb_main.c %compile_link% %out%raddbg_from_pdb.exe || exit /b 1
|
||||||
if "%clang%"=="1" set compile_link=%clang_link%
|
if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe || exit /b 1
|
||||||
if "%clang%"=="1" set out=%clang_out%
|
if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe || exit /b 1
|
||||||
if "%debug%"=="1" set compile=%compile_debug%
|
if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
|
||||||
if "%release%"=="1" set compile=%compile_release%
|
if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1
|
||||||
|
if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1
|
||||||
:: --- Prep Directories -------------------------------------------------------
|
if "%mule_main%"=="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% %out%mule_main.exe || exit /b 1
|
||||||
if not exist build mkdir build
|
if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
|
||||||
if not exist local mkdir local
|
if "%mule_hotload%"=="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
|
||||||
|
popd
|
||||||
:: --- Produce Logo Icon File -------------------------------------------------
|
|
||||||
pushd build
|
:: --- Unset ------------------------------------------------------------------
|
||||||
%rc% /nologo /fo logo.res ..\data\logo.rc || exit /b 1
|
for %%a in (%*) do set "%%a=0"
|
||||||
popd
|
set raddbg=
|
||||||
|
set compile=
|
||||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
set compile_link=
|
||||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
set out=
|
||||||
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
|
set msvc=
|
||||||
|
set debug=
|
||||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
|
||||||
if "%meta%"=="1" (
|
|
||||||
echo [doing metagen]
|
|
||||||
pushd build
|
|
||||||
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
|
||||||
metagen.exe || exit /b 1
|
|
||||||
popd
|
|
||||||
)
|
|
||||||
|
|
||||||
:: --- Build Everything (@build_targets) --------------------------------------
|
|
||||||
pushd build
|
|
||||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
|
|
||||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
|
|
||||||
if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1
|
|
||||||
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
|
|
||||||
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
|
|
||||||
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
|
|
||||||
if "%eval_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\eval_scratch.c %compile_link% %out%eval_scratch.exe || exit /b 1
|
|
||||||
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
|
|
||||||
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
|
|
||||||
if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
|
|
||||||
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
|
|
||||||
if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1
|
|
||||||
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
|
|
||||||
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
|
|
||||||
if "%mule_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 "%mule_peb_trample%"=="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_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb
|
|
||||||
if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi
|
|
||||||
%compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1
|
|
||||||
move mule_peb_trample_new.exe mule_peb_trample.exe
|
|
||||||
)
|
|
||||||
popd
|
|
||||||
|
|
||||||
:: --- Warn On No Builds ------------------------------------------------------
|
|
||||||
if "%didbuild%"=="" (
|
|
||||||
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
:: --- PGO Run ----------------------------------------------------------------
|
|
||||||
if "%pgo_run%"=="1" (
|
|
||||||
if "%radlink%"=="1" (
|
|
||||||
pushd local\lyra_pgo
|
|
||||||
call %~dp0build\radlink @lyra.rsp /rad_alt_pch_dir:%~dp0local\lyra_pgo || exit /b 1
|
|
||||||
popd
|
|
||||||
)
|
|
||||||
goto restart
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
# --- Unpack Arguments --------------------------------------------------------
|
|
||||||
for arg in "$@"; do declare $arg='1'; done
|
|
||||||
if [ ! -v gcc ]; then clang=1; fi
|
|
||||||
if [ ! -v release ]; then debug=1; fi
|
|
||||||
if [ -v debug ]; then echo "[debug mode]"; fi
|
|
||||||
if [ -v release ]; then echo "[release mode]"; fi
|
|
||||||
if [ -v clang ]; then compiler="${CC:-clang}"; echo "[clang compile]"; fi
|
|
||||||
if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
|
|
||||||
|
|
||||||
# --- Unpack Command Line Build Arguments -------------------------------------
|
|
||||||
auto_compile_flags=''
|
|
||||||
|
|
||||||
# --- Get Current Git Commit Id -----------------------------------------------
|
|
||||||
git_hash=$(git describe --always --dirty)
|
|
||||||
git_hash_full=$(git rev-parse HEAD)
|
|
||||||
|
|
||||||
# --- Compile/Link Line Definitions -------------------------------------------
|
|
||||||
clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
|
||||||
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
|
|
||||||
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
|
|
||||||
clang_link="-lpthread -lm -lrt -ldl"
|
|
||||||
clang_out="-o"
|
|
||||||
gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
|
||||||
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
|
|
||||||
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
|
|
||||||
gcc_link="-lpthread -lm -lrt -ldl"
|
|
||||||
gcc_out="-o"
|
|
||||||
|
|
||||||
# --- Per-Build Settings ------------------------------------------------------
|
|
||||||
link_dll="-fPIC"
|
|
||||||
link_os_gfx="-lX11 -lXext"
|
|
||||||
link_render="-lGL -lEGL"
|
|
||||||
link_font_provider="-lfreetype"
|
|
||||||
|
|
||||||
# --- Choose Compile/Link Lines -----------------------------------------------
|
|
||||||
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
|
|
||||||
if [ -v gcc ]; then compile_release="$gcc_release"; fi
|
|
||||||
if [ -v gcc ]; then compile_link="$gcc_link"; fi
|
|
||||||
if [ -v gcc ]; then out="$gcc_out"; fi
|
|
||||||
if [ -v clang ]; then compile_debug="$clang_debug"; fi
|
|
||||||
if [ -v clang ]; then compile_release="$clang_release"; fi
|
|
||||||
if [ -v clang ]; then compile_link="$clang_link"; fi
|
|
||||||
if [ -v clang ]; then out="$clang_out"; fi
|
|
||||||
if [ -v debug ]; then compile="$compile_debug"; fi
|
|
||||||
if [ -v release ]; then compile="$compile_release"; fi
|
|
||||||
|
|
||||||
# --- Prep Directories --------------------------------------------------------
|
|
||||||
mkdir -p build
|
|
||||||
mkdir -p local
|
|
||||||
|
|
||||||
# --- Build & Run Metaprogram -------------------------------------------------
|
|
||||||
if [ -v no_meta ]; then echo "[skipping metagen]"; fi
|
|
||||||
if [ ! -v no_meta ]
|
|
||||||
then
|
|
||||||
cd build
|
|
||||||
$compile_debug ../src/metagen/metagen_main.c $compile_link $out metagen
|
|
||||||
./metagen
|
|
||||||
cd ..
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Build Everything (@build_targets) ---------------------------------------
|
|
||||||
cd build
|
|
||||||
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $link_font_provider $out raddbg; fi
|
|
||||||
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
|
|
||||||
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
|
|
||||||
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
|
|
||||||
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
|
|
||||||
if [ -v rdi_breakpad_from_pdb ]; then didbuild=1 && $compile ../src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c $compile_link $out rdi_breakpad_from_pdb; fi
|
|
||||||
if [ -v ryan_scratch ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $link_render $link_font_provider $out ryan_scratch; fi
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# --- Warn On No Builds -------------------------------------------------------
|
|
||||||
if [ ! -v didbuild ]
|
|
||||||
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\`."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+145
-117
@@ -1,117 +1,145 @@
|
|||||||
version(2);
|
version(2);
|
||||||
project_name = "The RAD Debugger";
|
project_name = "The RAD Debugger";
|
||||||
|
|
||||||
indent_width = "2";
|
indent_width = "2";
|
||||||
default_tab_width = "2";
|
default_tab_width = "2";
|
||||||
|
|
||||||
patterns =
|
patterns =
|
||||||
{
|
{
|
||||||
"*.c",
|
"*.c",
|
||||||
"*.cpp",
|
"*.cpp",
|
||||||
"*.h",
|
"*.h",
|
||||||
"*.inc",
|
"*.inc",
|
||||||
"*.hpp",
|
"*.hpp",
|
||||||
"*.bat",
|
"*.bat",
|
||||||
"*.sh",
|
"*.sh",
|
||||||
"*.4coder",
|
"*.4coder",
|
||||||
"*.glsl",
|
"*.glsl",
|
||||||
"*.bfs",
|
"*.bfs",
|
||||||
"*.html",
|
"*.html",
|
||||||
"*.txt",
|
"*.txt",
|
||||||
"*.md",
|
"*.md",
|
||||||
"*.mdesk",
|
"*.mdesk",
|
||||||
"*.asm",
|
"*.asm",
|
||||||
};
|
};
|
||||||
|
|
||||||
blacklist_patterns =
|
blacklist_patterns =
|
||||||
{
|
{
|
||||||
".*",
|
".*",
|
||||||
"metagen_base_*",
|
"metagen_base_*",
|
||||||
"metagen_os_*",
|
"metagen_os_*",
|
||||||
};
|
};
|
||||||
|
|
||||||
paths =
|
paths =
|
||||||
{
|
{
|
||||||
{ .path = ".", .recursive = false, .relative = true, },
|
{ .path = ".", .recursive = false, .relative = true, },
|
||||||
{ .path = "src", .recursive = true , .relative = true, },
|
{ .path = "src", .recursive = true , .relative = true, },
|
||||||
{ .path = "local", .recursive = true , .relative = true, },
|
{ .path = "local", .recursive = true , .relative = true, },
|
||||||
};
|
};
|
||||||
|
|
||||||
load_paths =
|
load_paths =
|
||||||
{
|
{
|
||||||
.win = paths,
|
.win = paths,
|
||||||
.linux = paths,
|
.linux = paths,
|
||||||
};
|
};
|
||||||
|
|
||||||
commands =
|
commands =
|
||||||
{
|
{
|
||||||
//- rjf: [raddbg]
|
.rjf_f1 =
|
||||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg telemetry",
|
||||||
|
.linux = "",
|
||||||
//- rjf: [raddbg wsl]
|
.out = "*compilation*",
|
||||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
//- rjf: [scratch]
|
.cursor_at_end = false,
|
||||||
.f2 = { .win = "build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
|
.rjf_f2 =
|
||||||
//- 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, },
|
.win = "build raddbg_from_pdb",
|
||||||
|
.linux = "",
|
||||||
//- rjf: [tester]
|
.out = "*compilation*",
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta tester", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
//- rjf: [radbin]
|
.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, },
|
},
|
||||||
|
.rjf_f3 =
|
||||||
//- rjf: running target
|
{
|
||||||
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --profile:local_dev.raddbg_profile && popd",
|
||||||
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
// .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
// .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, },
|
.footer_panel = true,
|
||||||
// .f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
//- rjf: local target builds
|
},
|
||||||
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.build_raddbg =
|
||||||
.build_rdi_from_pdb = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.build_rdi_from_dwarf = { .win = "build rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg",
|
||||||
.build_rdi_dump = { .win = "build rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.build_rdi_breakpad_from_pdb = { .win = "build rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
.build_ryan_scratch = { .win = "build ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_mule_main = { .win = "build mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_mule_module = { .win = "build mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
.build_mule_hotload = { .win = "build mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
.build_mule_peb_trample = { .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.build_raddbg_release_telemetry =
|
||||||
|
{
|
||||||
//- rjf: wsl target builds
|
.win = "build raddbg release telemetry",
|
||||||
.build_raddbg_wsl = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.build_rdi_from_pdb_wsl = { .win = "wsl ./build.sh rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
.build_rdi_from_dwarf_wsl = { .win = "wsl ./build.sh rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_rdi_dump_wsl = { .win = "wsl ./build.sh rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_rdi_breakpad_from_pdb_wsl = { .win = "wsl ./build.sh rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
.build_ryan_scratch_wsl = { .win = "wsl ./build.sh ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
.build_mule_main_wsl = { .win = "wsl ./build.sh mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.build_raddbg_from_pdb =
|
||||||
.build_mule_module_wsl = { .win = "wsl ./build.sh mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.build_mule_hotload_wsl = { .win = "wsl ./build.sh mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg_from_pdb",
|
||||||
.build_mule_peb_trample_wsl = { .win = "wsl ./build.sh mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
//- rjf: local target runs
|
.footer_panel = true,
|
||||||
.run_raddbg = { .win = "pushd build && raddbg.exe && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
};
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
fkey_command =
|
.build_raddbg_dump =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.win = "build raddbg_dump",
|
||||||
.F2 = "f2",
|
.linux = "",
|
||||||
.F3 = "f3",
|
.out = "*compilation*",
|
||||||
};
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
fkey_command_override =
|
.cursor_at_end = false,
|
||||||
{
|
},
|
||||||
.rjf =
|
.build_mule_main =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.win = "build mule_main",
|
||||||
.F2 = "f2",
|
.linux = "",
|
||||||
.F3 = "f3",
|
.out = "*compilation*",
|
||||||
},
|
.footer_panel = true,
|
||||||
};
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.run_raddbg =
|
||||||
|
{
|
||||||
|
.win = "pushd build && raddbg.exe && popd",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
fkey_command =
|
||||||
|
{
|
||||||
|
.F1 = "build_raddbg",
|
||||||
|
.F3 = "run_raddbg",
|
||||||
|
};
|
||||||
|
|
||||||
|
fkey_command_override =
|
||||||
|
{
|
||||||
|
.rjf =
|
||||||
|
{
|
||||||
|
.F1 = "rjf_f1",
|
||||||
|
.F2 = "rjf_f2",
|
||||||
|
.F3 = "rjf_f3",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
@echo off
|
|
||||||
setlocal
|
|
||||||
cd /D "%~dp0"
|
|
||||||
|
|
||||||
echo --- getting test data folder path ---------------------------------------------
|
|
||||||
if not exist .\local\test_data_path.txt (
|
|
||||||
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
|
|
||||||
goto :EOF
|
|
||||||
)
|
|
||||||
set /p test_data_folder=<.\local\test_data_path.txt
|
|
||||||
echo test data path: %test_data_folder%
|
|
||||||
echo:
|
|
||||||
|
|
||||||
echo --- building all testing executables ------------------------------------------
|
|
||||||
call build rdi_from_pdb rdi_dump raddbg radlink tester
|
|
||||||
echo:
|
|
||||||
|
|
||||||
echo --- running tests -------------------------------------------------------------
|
|
||||||
pushd build
|
|
||||||
call tester.exe --test_data:%test_data_folder%
|
|
||||||
popd
|
|
||||||
@@ -4,6 +4,7 @@ $path_root = git rev-parse --show-toplevel
|
|||||||
|
|
||||||
if ($IsWindows) {
|
if ($IsWindows) {
|
||||||
$devshell = Join-Path $path_root 'scripts/helpers/devshell.ps1'
|
$devshell = Join-Path $path_root 'scripts/helpers/devshell.ps1'
|
||||||
|
# This HandmadeHero implementation is only designed for 64-bit systems
|
||||||
& $devshell -arch amd64
|
& $devshell -arch amd64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,654 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Layer Initialization
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_init(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
ac_shared = push_array(arena, AC_Shared, 1);
|
|
||||||
ac_shared->arena = arena;
|
|
||||||
ac_shared->cache_slots_count = 256;
|
|
||||||
ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count);
|
|
||||||
ac_shared->cache_stripes = stripe_array_alloc(arena);
|
|
||||||
for EachElement(idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
ac_shared->req_batches[idx].mutex = mutex_alloc();
|
|
||||||
ac_shared->req_batches[idx].arena = arena_alloc();
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookups
|
|
||||||
|
|
||||||
internal AC_Artifact
|
|
||||||
ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
AC_RequestBatch *req_batch = &ac_shared->req_batches[params->flags & AC_Flag_HighPriority ? 0 : 1];
|
|
||||||
|
|
||||||
//- rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(¶ms->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == params->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(write_mode && cache == 0)
|
|
||||||
{
|
|
||||||
cache = push_array(cache_stripe->arena, AC_Cache, 1);
|
|
||||||
SLLStackPush(ac_shared->cache_slots[cache_slot_idx], cache);
|
|
||||||
cache->create = params->create;
|
|
||||||
cache->destroy = params->destroy;
|
|
||||||
cache->slots_count = Max(256, params->slots_count);
|
|
||||||
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
|
||||||
cache->stripes = stripe_array_alloc(cache_stripe->arena);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(cache != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: unpack key
|
|
||||||
U64 hash = u64_hash_from_str8(key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
|
|
||||||
//- rjf: cache * key -> existing artifact
|
|
||||||
B32 artifact_is_stale = 1;
|
|
||||||
B32 got_artifact = 0;
|
|
||||||
B32 need_request = 0;
|
|
||||||
AC_Artifact artifact = {0};
|
|
||||||
RWMutexScope(stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, key, 0))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(&n->last_requested_gen, params->gen);
|
|
||||||
B32 is_stale = (n->last_completed_gen != params->gen);
|
|
||||||
if(ins_atomic_u64_eval(&n->completion_count) != 0 && (!is_stale || !(params->flags & AC_Flag_WaitForFresh)))
|
|
||||||
{
|
|
||||||
got_artifact = 1;
|
|
||||||
artifact_is_stale = is_stale;
|
|
||||||
artifact = n->val;
|
|
||||||
access_touch(access, &n->access_pt, stripe->cv);
|
|
||||||
}
|
|
||||||
if(is_stale)
|
|
||||||
{
|
|
||||||
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
|
||||||
need_request = got_task;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: didn't get artifact we want? -> fall back to slow path
|
|
||||||
if(!got_artifact || need_request)
|
|
||||||
{
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1) for(;;)
|
|
||||||
{
|
|
||||||
B32 out_of_time = (os_now_microseconds() >= endt_us);
|
|
||||||
|
|
||||||
// rjf: find node in cache
|
|
||||||
AC_Node *node = 0;
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, key, 0))
|
|
||||||
{
|
|
||||||
node = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: no node? -> create
|
|
||||||
if(node == 0)
|
|
||||||
{
|
|
||||||
need_request = 1;
|
|
||||||
node = stripe->free;
|
|
||||||
if(node)
|
|
||||||
{
|
|
||||||
stripe->free = node->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = push_array_no_zero(stripe->arena, AC_Node, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(node);
|
|
||||||
DLLPushBack(slot->first, slot->last, node);
|
|
||||||
// TODO(rjf): string allocator for keys
|
|
||||||
node->key = str8_copy(stripe->arena, key);
|
|
||||||
node->working_count = 1;
|
|
||||||
node->evict_threshold_us = params->evict_threshold_us;
|
|
||||||
}
|
|
||||||
node->access_pt.last_time_touched_us = os_now_microseconds();
|
|
||||||
node->access_pt.last_update_idx_touched = update_tick_idx();
|
|
||||||
|
|
||||||
// rjf: request
|
|
||||||
if(need_request)
|
|
||||||
{
|
|
||||||
need_request = 0;
|
|
||||||
MutexScope(req_batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(req_batch->arena, AC_RequestNode, 1);
|
|
||||||
if(params->flags & AC_Flag_Wide)
|
|
||||||
{
|
|
||||||
SLLQueuePush(req_batch->first_wide, req_batch->last_wide, n);
|
|
||||||
req_batch->wide_count += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SLLQueuePush(req_batch->first_thin, req_batch->last_thin, n);
|
|
||||||
req_batch->thin_count += 1;
|
|
||||||
}
|
|
||||||
n->v.key = str8_copy(req_batch->arena, key);
|
|
||||||
n->v.gen = params->gen;
|
|
||||||
n->v.cancel_signal = &node->cancelled;
|
|
||||||
n->v.create = params->create;
|
|
||||||
}
|
|
||||||
cond_var_broadcast(async_tick_start_cond_var);
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
if(params->flags & AC_Flag_HighPriority)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: get value from node, if possible
|
|
||||||
if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time))
|
|
||||||
{
|
|
||||||
got_artifact = 1;
|
|
||||||
artifact_is_stale = (node->last_completed_gen == params->gen);
|
|
||||||
artifact = node->val;
|
|
||||||
access_touch(access, &node->access_pt, stripe->cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: abort if needed
|
|
||||||
if(out_of_time || got_artifact || is_async_thread)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: wait for results
|
|
||||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, endt_us);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: report staleness
|
|
||||||
if(params->stale_out)
|
|
||||||
{
|
|
||||||
params->stale_out[0] = artifact_is_stale;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
return artifact;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_async_tick(void)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: enable cancellation scanning
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
mutex_drop(ac_shared->cancel_thread_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: do eviction pass across all caches
|
|
||||||
//
|
|
||||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
|
||||||
{
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
|
||||||
{
|
|
||||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
|
||||||
for EachInRange(slot_idx, slot_range)
|
|
||||||
{
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
B32 slot_has_work = 0;
|
|
||||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
|
||||||
{
|
|
||||||
next = n->next;
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) == 0)
|
|
||||||
{
|
|
||||||
slot_has_work = 1;
|
|
||||||
if(!write_mode)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DLLRemove(slot->first, slot->last, n);
|
|
||||||
n->next = (AC_Node *)stripe->free;
|
|
||||||
stripe->free = n;
|
|
||||||
if(cache->destroy)
|
|
||||||
{
|
|
||||||
cache->destroy(n->val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!slot_has_work)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: gather requests
|
|
||||||
//
|
|
||||||
typedef struct RequestBatchTask RequestBatchTask;
|
|
||||||
struct RequestBatchTask
|
|
||||||
{
|
|
||||||
AC_Request *wide;
|
|
||||||
U64 wide_count;
|
|
||||||
AC_Request *thin;
|
|
||||||
U64 thin_count;
|
|
||||||
};
|
|
||||||
RequestBatchTask *tasks = 0;
|
|
||||||
U64 tasks_count = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
tasks_count = 2;
|
|
||||||
tasks = push_array(scratch.arena, RequestBatchTask, tasks_count);
|
|
||||||
for EachElement(task_idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
tasks[task_idx].wide_count = batch->wide_count;
|
|
||||||
tasks[task_idx].thin_count = batch->thin_count;
|
|
||||||
tasks[task_idx].wide = push_array(scratch.arena, AC_Request, tasks[task_idx].wide_count);
|
|
||||||
tasks[task_idx].thin = push_array(scratch.arena, AC_Request, tasks[task_idx].thin_count);
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, AC_RequestNode, batch->first_wide)
|
|
||||||
{
|
|
||||||
MemoryCopyStruct(&tasks[task_idx].wide[idx], &n->v);
|
|
||||||
tasks[task_idx].wide[idx].key = str8_copy(scratch.arena, tasks[task_idx].wide[idx].key);
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, AC_RequestNode, batch->first_thin)
|
|
||||||
{
|
|
||||||
MemoryCopyStruct(&tasks[task_idx].thin[idx], &n->v);
|
|
||||||
tasks[task_idx].thin[idx].key = str8_copy(scratch.arena, tasks[task_idx].thin[idx].key);
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arena_clear(batch->arena);
|
|
||||||
batch->first_wide = batch->last_wide = batch->first_thin = batch->last_thin = 0;
|
|
||||||
batch->wide_count = batch->thin_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync_u64(&tasks, 0);
|
|
||||||
lane_sync_u64(&tasks_count, 0);
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: do all requests
|
|
||||||
//
|
|
||||||
for EachIndex(task_idx, tasks_count)
|
|
||||||
{
|
|
||||||
lane_sync();
|
|
||||||
RequestBatchTask *task = &tasks[task_idx];
|
|
||||||
|
|
||||||
//- rjf: set up cancellation signal
|
|
||||||
U64 cancelled = 0;
|
|
||||||
U64 *cancelled_ptr = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
cancelled_ptr = &cancelled;
|
|
||||||
}
|
|
||||||
lane_sync_u64(&cancelled_ptr, 0);
|
|
||||||
|
|
||||||
//- rjf: do all wide requests for this priority
|
|
||||||
U64 done_wide_count = 0;
|
|
||||||
ProfScope("wide requests (p%I64u)", task_idx)
|
|
||||||
{
|
|
||||||
for EachIndex(idx, task->wide_count)
|
|
||||||
{
|
|
||||||
lane_sync();
|
|
||||||
AC_Request *r = &task->wide[idx];
|
|
||||||
|
|
||||||
// rjf: any new higher priority tasks? -> cancel
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
if(task_idx == 1 && idx != 0 && ins_atomic_u32_eval(&async_loop_again_high_priority))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
// rjf: cancelled? -> exit
|
|
||||||
if(ins_atomic_u32_eval(cancelled_ptr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: compute val
|
|
||||||
B32 retry = 0;
|
|
||||||
U64 gen = r->gen;
|
|
||||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
|
||||||
if(retry && lane_idx() == 0)
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
|
||||||
batch->wide_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
if(!retry && lane_idx() == 0)
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == r->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write value into cache
|
|
||||||
if(!retry && lane_idx() == 0)
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(r->key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, r->key, 0))
|
|
||||||
{
|
|
||||||
n->last_completed_gen = gen;
|
|
||||||
n->val = val;
|
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
|
||||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cond_var_broadcast(stripe->cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: increment count
|
|
||||||
lane_sync();
|
|
||||||
done_wide_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//- rjf: do all thin requests for this priority
|
|
||||||
U64 done_thin_count = 0;
|
|
||||||
ProfScope("thin requests (p%I64u)", task_idx)
|
|
||||||
{
|
|
||||||
U64 req_take_counter = 0;
|
|
||||||
U64 *req_take_counter_ptr = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
req_take_counter_ptr = &req_take_counter;
|
|
||||||
}
|
|
||||||
lane_sync_u64(&req_take_counter_ptr, 0);
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// rjf: any new higher priority tasks? -> cancel
|
|
||||||
if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2 &&
|
|
||||||
ins_atomic_u32_eval(&async_loop_again_high_priority))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: cancelled? -> exit
|
|
||||||
if(ins_atomic_u64_eval(cancelled_ptr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: take next task
|
|
||||||
U64 req_idx = ins_atomic_u64_inc_eval(req_take_counter_ptr) - 1;
|
|
||||||
if(req_idx >= task->thin_count) { break; }
|
|
||||||
AC_Request *r = &task->thin[req_idx];
|
|
||||||
|
|
||||||
// rjf: push thin lane ctx
|
|
||||||
U64 thin_lane_ctx_broadcast_memory = 0;
|
|
||||||
LaneCtx thin_lane_ctx = {0, 1, {0}, &thin_lane_ctx_broadcast_memory};
|
|
||||||
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
|
|
||||||
|
|
||||||
// rjf: compute val
|
|
||||||
B32 retry = 0;
|
|
||||||
U64 gen = r->gen;
|
|
||||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
|
||||||
|
|
||||||
// rjf: restore wide lane ctx
|
|
||||||
lane_ctx(lane_ctx_restore);
|
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
|
||||||
if(retry)
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
|
||||||
batch->thin_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
if(!retry)
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == r->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write value into cache
|
|
||||||
if(!retry)
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(r->key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, r->key, 0))
|
|
||||||
{
|
|
||||||
n->last_completed_gen = gen;
|
|
||||||
n->val = val;
|
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
|
||||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cond_var_broadcast(stripe->cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
done_thin_count = ins_atomic_u64_eval(req_take_counter_ptr);
|
|
||||||
lane_sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: cancelled early, unfinished tasks? -> defer to next tick
|
|
||||||
if(lane_idx() == 0 && task_idx > 0)
|
|
||||||
{
|
|
||||||
B32 need_another_try = (done_wide_count < task->wide_count || done_thin_count < task->thin_count);
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
// rjf: push leftover wide tasks
|
|
||||||
for(U64 idx = done_wide_count; idx < task->wide_count; idx += 1)
|
|
||||||
{
|
|
||||||
AC_Request *r = &task->wide[idx];
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
|
||||||
batch->wide_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push leftover thin tasks
|
|
||||||
for(U64 idx = done_thin_count; idx < task->thin_count; idx += 1)
|
|
||||||
{
|
|
||||||
AC_Request *r = &task->thin[idx];
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
|
||||||
batch->thin_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(need_another_try)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: disable cancellation scanning
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
mutex_take(ac_shared->cancel_thread_mutex);
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cancel Thread
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_cancel_thread_entry_point(void *p)
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
os_sleep_milliseconds(50);
|
|
||||||
MutexScope(ac_shared->cancel_thread_mutex)
|
|
||||||
{
|
|
||||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
|
||||||
{
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
|
||||||
{
|
|
||||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
|
||||||
for EachInRange(slot_idx, slot_range)
|
|
||||||
{
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
B32 slot_has_work = 0;
|
|
||||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
|
||||||
{
|
|
||||||
next = n->next;
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) > 0)
|
|
||||||
{
|
|
||||||
slot_has_work = 1;
|
|
||||||
if(!write_mode)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n->cancelled = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!slot_has_work)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARTIFACT_CACHE_H
|
|
||||||
#define ARTIFACT_CACHE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Handle Type
|
|
||||||
|
|
||||||
typedef struct AC_Artifact AC_Artifact;
|
|
||||||
struct AC_Artifact
|
|
||||||
{
|
|
||||||
U64 u64[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Computation Function Types
|
|
||||||
|
|
||||||
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
|
||||||
typedef void AC_DestroyFunctionType(AC_Artifact artifact);
|
|
||||||
|
|
||||||
typedef U32 AC_Flags;
|
|
||||||
typedef enum AC_FlagsEnum
|
|
||||||
{
|
|
||||||
AC_Flag_WaitForFresh = (1<<0),
|
|
||||||
AC_Flag_HighPriority = (1<<1),
|
|
||||||
AC_Flag_Wide = (1<<2),
|
|
||||||
}
|
|
||||||
AC_FlagsEnum;
|
|
||||||
|
|
||||||
typedef struct AC_ArtifactParams AC_ArtifactParams;
|
|
||||||
struct AC_ArtifactParams
|
|
||||||
{
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
AC_DestroyFunctionType *destroy;
|
|
||||||
U64 slots_count;
|
|
||||||
U64 gen;
|
|
||||||
U64 evict_threshold_us;
|
|
||||||
B32 *stale_out;
|
|
||||||
AC_Flags flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Types
|
|
||||||
|
|
||||||
typedef struct AC_Request AC_Request;
|
|
||||||
struct AC_Request
|
|
||||||
{
|
|
||||||
String8 key;
|
|
||||||
U64 gen;
|
|
||||||
B32 *cancel_signal;
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_RequestNode AC_RequestNode;
|
|
||||||
struct AC_RequestNode
|
|
||||||
{
|
|
||||||
AC_RequestNode *next;
|
|
||||||
AC_Request v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Node AC_Node;
|
|
||||||
struct AC_Node
|
|
||||||
{
|
|
||||||
AC_Node *next;
|
|
||||||
AC_Node *prev;
|
|
||||||
|
|
||||||
// rjf: key/gen/value
|
|
||||||
String8 key;
|
|
||||||
U64 last_requested_gen;
|
|
||||||
U64 last_completed_gen;
|
|
||||||
AC_Artifact val;
|
|
||||||
|
|
||||||
// rjf: metadata
|
|
||||||
AccessPt access_pt;
|
|
||||||
U64 working_count;
|
|
||||||
U64 completion_count;
|
|
||||||
U64 evict_threshold_us;
|
|
||||||
B32 cancelled;
|
|
||||||
U64 _unused_;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Slot AC_Slot;
|
|
||||||
struct AC_Slot
|
|
||||||
{
|
|
||||||
AC_Node *first;
|
|
||||||
AC_Node *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Cache AC_Cache;
|
|
||||||
struct AC_Cache
|
|
||||||
{
|
|
||||||
// rjf: link / key for cache-cache
|
|
||||||
AC_Cache *next;
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
AC_DestroyFunctionType *destroy;
|
|
||||||
|
|
||||||
// rjf: artifact cache
|
|
||||||
U64 slots_count;
|
|
||||||
AC_Slot *slots;
|
|
||||||
StripeArray stripes;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_RequestBatch AC_RequestBatch;
|
|
||||||
struct AC_RequestBatch
|
|
||||||
{
|
|
||||||
Mutex mutex;
|
|
||||||
Arena *arena;
|
|
||||||
AC_RequestNode *first_wide;
|
|
||||||
AC_RequestNode *last_wide;
|
|
||||||
AC_RequestNode *first_thin;
|
|
||||||
AC_RequestNode *last_thin;
|
|
||||||
U64 wide_count;
|
|
||||||
U64 thin_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Shared AC_Shared;
|
|
||||||
struct AC_Shared
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
|
|
||||||
// rjf: cache cache
|
|
||||||
U64 cache_slots_count;
|
|
||||||
AC_Cache **cache_slots;
|
|
||||||
StripeArray cache_stripes;
|
|
||||||
|
|
||||||
// rjf: requests
|
|
||||||
AC_RequestBatch req_batches[2]; // 0: high priority, 1: low priority
|
|
||||||
|
|
||||||
// rjf: cancel thread
|
|
||||||
Thread cancel_thread;
|
|
||||||
Mutex cancel_thread_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
global AC_Shared *ac_shared = 0;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Layer Initialization
|
|
||||||
|
|
||||||
internal void ac_init(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookups
|
|
||||||
|
|
||||||
internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us);
|
|
||||||
#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), .evict_threshold_us = (2000000), __VA_ARGS__}, (endt_us))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
internal void ac_async_tick(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cancel Thread
|
|
||||||
|
|
||||||
internal void ac_cancel_thread_entry_point(void *p);
|
|
||||||
|
|
||||||
#endif // ARTIFACT_CACHE_H
|
|
||||||
+315
-262
@@ -1,262 +1,315 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Functions
|
// Implementation
|
||||||
|
|
||||||
//- rjf: arena creation/destruction
|
internal Arena *
|
||||||
|
arena_alloc__sized(U64 init_res, U64 init_cmt)
|
||||||
internal Arena *
|
{
|
||||||
arena_alloc_(ArenaParams *params)
|
ProfBeginFunction();
|
||||||
{
|
Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res);
|
||||||
// rjf: round up reserve/commit sizes
|
|
||||||
U64 reserve_size = params->reserve_size;
|
void *memory = 0;
|
||||||
U64 commit_size = params->commit_size;
|
U64 res = 0;
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
U64 cmt = 0;
|
||||||
{
|
B32 large_pages = os_large_pages_enabled();
|
||||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
|
if(large_pages)
|
||||||
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
|
{
|
||||||
}
|
U64 page_size = os_large_page_size();
|
||||||
else
|
res = AlignPow2(init_res, page_size);
|
||||||
{
|
#if OS_WINDOWS
|
||||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
|
cmt = res;
|
||||||
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
|
#else
|
||||||
}
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
|
#endif
|
||||||
// rjf: reserve/commit initial block
|
memory = os_reserve_large(res);
|
||||||
void *base = params->optional_backing_buffer;
|
if(!os_commit_large(memory, cmt))
|
||||||
if(base == 0)
|
{
|
||||||
{
|
memory = 0;
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
os_release(memory, res);
|
||||||
{
|
}
|
||||||
base = os_reserve_large(reserve_size);
|
}
|
||||||
os_commit_large(base, commit_size);
|
else
|
||||||
}
|
{
|
||||||
else
|
U64 page_size = os_page_size();
|
||||||
{
|
res = AlignPow2(init_res, page_size);
|
||||||
base = os_reserve(reserve_size);
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
os_commit(base, commit_size);
|
memory = os_reserve(res);
|
||||||
}
|
if(!os_commit(memory, cmt))
|
||||||
raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
|
{
|
||||||
}
|
memory = 0;
|
||||||
|
os_release(memory, res);
|
||||||
// rjf: panic on arena creation failure
|
}
|
||||||
#if OS_FEATURE_GRAPHICAL
|
}
|
||||||
if(Unlikely(base == 0))
|
|
||||||
{
|
Arena *arena = (Arena*)memory;
|
||||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
if(arena)
|
||||||
os_abort(1);
|
{
|
||||||
}
|
AsanPoisonMemoryRegion(memory, cmt);
|
||||||
#endif
|
AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE);
|
||||||
|
arena->prev = 0;
|
||||||
// rjf: extract arena header & fill
|
arena->current = arena;
|
||||||
Arena *arena = (Arena *)base;
|
arena->base_pos = 0;
|
||||||
arena->current = arena;
|
arena->pos = ARENA_HEADER_SIZE;
|
||||||
arena->flags = params->flags;
|
arena->cmt = cmt;
|
||||||
arena->cmt_size = params->commit_size;
|
arena->res = res;
|
||||||
arena->res_size = params->reserve_size;
|
arena->align = 8;
|
||||||
arena->base_pos = 0;
|
#if ENABLE_DEV
|
||||||
arena->pos = ARENA_HEADER_SIZE;
|
arena->dev = 0;
|
||||||
arena->cmt = commit_size;
|
#endif
|
||||||
arena->res = reserve_size;
|
arena->grow = 1;
|
||||||
arena->allocation_site_file = params->allocation_site_file;
|
arena->large_pages = large_pages;
|
||||||
arena->allocation_site_line = params->allocation_site_line;
|
}
|
||||||
#if ARENA_FREE_LIST
|
|
||||||
arena->free_last = 0;
|
ProfEnd();
|
||||||
#endif
|
return arena;
|
||||||
AsanPoisonMemoryRegion(base, commit_size);
|
}
|
||||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
|
||||||
return arena;
|
internal Arena *
|
||||||
}
|
arena_alloc(void)
|
||||||
|
{
|
||||||
internal void
|
ProfBeginFunction();
|
||||||
arena_release(Arena *arena)
|
|
||||||
{
|
U64 init_res, init_cmt;
|
||||||
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
if (os_large_pages_enabled()) {
|
||||||
{
|
init_res = ARENA_RESERVE_SIZE_LARGE_PAGES;
|
||||||
prev = n->prev;
|
init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES;
|
||||||
os_release(n, n->res);
|
} else {
|
||||||
}
|
init_res = ARENA_RESERVE_SIZE;
|
||||||
}
|
init_cmt = ARENA_COMMIT_SIZE;
|
||||||
|
}
|
||||||
//- rjf: arena push/pop core functions
|
|
||||||
|
Arena *arena = arena_alloc__sized(init_res, init_cmt);
|
||||||
internal void *
|
|
||||||
arena_push(Arena *arena, U64 size, U64 align, B32 zero)
|
ProfEnd();
|
||||||
{
|
return arena;
|
||||||
Arena *current = arena->current;
|
}
|
||||||
U64 pos_pre = AlignPow2(current->pos, align);
|
|
||||||
U64 pos_pst = pos_pre + size;
|
internal void
|
||||||
|
arena_release(Arena *arena)
|
||||||
// rjf: chain, if needed
|
{
|
||||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) {
|
||||||
{
|
prev = node->prev;
|
||||||
Arena *new_block = 0;
|
os_release(node, node->res);
|
||||||
|
}
|
||||||
#if ARENA_FREE_LIST
|
}
|
||||||
{
|
|
||||||
Arena *prev_block;
|
internal U64
|
||||||
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
|
arena_huge_push_threshold(void)
|
||||||
{
|
{
|
||||||
if(new_block->res >= AlignPow2(new_block->pos, align) + size)
|
U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE;
|
||||||
{
|
U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1;
|
||||||
if(prev_block)
|
return threshold;
|
||||||
{
|
}
|
||||||
prev_block->prev = new_block->prev;
|
|
||||||
}
|
internal void *
|
||||||
else
|
arena_push__impl(Arena *arena, U64 size)
|
||||||
{
|
{
|
||||||
arena->free_last = new_block->prev;
|
Arena *current = arena->current;
|
||||||
}
|
U64 pos_mem = AlignPow2(current->pos, arena->align);
|
||||||
break;
|
U64 pos_new = pos_mem + size;
|
||||||
}
|
|
||||||
}
|
if (current->res < pos_new && arena->grow) {
|
||||||
}
|
Arena *new_block;
|
||||||
#endif
|
|
||||||
|
// normal growth path
|
||||||
if(new_block == 0)
|
if (size < arena_huge_push_threshold()) {
|
||||||
{
|
new_block = arena_alloc();
|
||||||
U64 res_size = current->res_size;
|
}
|
||||||
U64 cmt_size = current->cmt_size;
|
// huge growth path
|
||||||
if(size + ARENA_HEADER_SIZE > res_size)
|
else {
|
||||||
{
|
U64 new_block_size = size + ARENA_HEADER_SIZE;
|
||||||
res_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
new_block = arena_alloc__sized(new_block_size, new_block_size);
|
||||||
cmt_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
}
|
||||||
}
|
|
||||||
new_block = arena_alloc(.reserve_size = res_size,
|
if (new_block) {
|
||||||
.commit_size = cmt_size,
|
new_block->base_pos = current->base_pos + current->res;
|
||||||
.flags = current->flags,
|
SLLStackPush_N(arena->current, new_block, prev);
|
||||||
.allocation_site_file = current->allocation_site_file,
|
|
||||||
.allocation_site_line = current->allocation_site_line);
|
current = new_block;
|
||||||
}
|
pos_mem = AlignPow2(current->pos, current->align);
|
||||||
|
pos_new = pos_mem + size;
|
||||||
new_block->base_pos = current->base_pos + current->res;
|
}
|
||||||
SLLStackPush_N(arena->current, new_block, prev);
|
}
|
||||||
|
|
||||||
current = new_block;
|
if (current->cmt < pos_new) {
|
||||||
pos_pre = AlignPow2(current->pos, align);
|
U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size;
|
||||||
pos_pst = pos_pre + size;
|
B32 is_cmt_ok;
|
||||||
}
|
|
||||||
|
if (current->large_pages) {
|
||||||
// rjf: compute the size we need to zero
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES);
|
||||||
U64 size_to_zero = 0;
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
if(zero)
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
{
|
is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size);
|
||||||
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
|
} else {
|
||||||
}
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE);
|
||||||
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
// rjf: commit new pages, if needed
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
if(current->cmt < pos_pst)
|
is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size);
|
||||||
{
|
}
|
||||||
U64 cmt_pst_aligned = pos_pst + current->cmt_size-1;
|
|
||||||
cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size;
|
if (is_cmt_ok) {
|
||||||
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
|
current->cmt = cmt_new_clamped;
|
||||||
U64 cmt_size = cmt_pst_clamped - current->cmt;
|
}
|
||||||
U8 *cmt_ptr = (U8 *)current + current->cmt;
|
}
|
||||||
if(current->flags & ArenaFlag_LargePages)
|
|
||||||
{
|
void *memory = 0;
|
||||||
os_commit_large(cmt_ptr, cmt_size);
|
|
||||||
}
|
if (current->cmt >= pos_new) {
|
||||||
else
|
memory = (U8*)current + pos_mem;
|
||||||
{
|
current->pos = pos_new;
|
||||||
os_commit(cmt_ptr, cmt_size);
|
AsanUnpoisonMemoryRegion(memory, size);
|
||||||
}
|
}
|
||||||
current->cmt = cmt_pst_clamped;
|
|
||||||
}
|
#if OS_FEATURE_GRAPHICAL
|
||||||
|
if(Unlikely(memory == 0))
|
||||||
// rjf: push onto current block
|
{
|
||||||
void *result = 0;
|
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||||
if(current->cmt >= pos_pst)
|
os_exit_process(1);
|
||||||
{
|
}
|
||||||
result = (U8 *)current+pos_pre;
|
#endif
|
||||||
current->pos = pos_pst;
|
|
||||||
AsanUnpoisonMemoryRegion(result, size);
|
return memory;
|
||||||
if(size_to_zero != 0)
|
}
|
||||||
{
|
|
||||||
MemoryZero(result, size_to_zero);
|
internal U64
|
||||||
}
|
arena_pos(Arena *arena)
|
||||||
}
|
{
|
||||||
|
Arena *current = arena->current;
|
||||||
// rjf: panic on failure
|
U64 pos = current->base_pos + current->pos;
|
||||||
#if OS_FEATURE_GRAPHICAL
|
return pos;
|
||||||
if(Unlikely(result == 0))
|
}
|
||||||
{
|
|
||||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
internal void
|
||||||
os_abort(1);
|
arena_pop_to(Arena *arena, U64 big_pos_unclamped)
|
||||||
}
|
{
|
||||||
#endif
|
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped);
|
||||||
|
|
||||||
return result;
|
// unroll the chain
|
||||||
}
|
Arena *current = arena->current;
|
||||||
|
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) {
|
||||||
internal U64
|
prev = current->prev;
|
||||||
arena_pos(Arena *arena)
|
os_release(current, current->res);
|
||||||
{
|
}
|
||||||
Arena *current = arena->current;
|
AssertAlways(current);
|
||||||
U64 pos = current->base_pos + current->pos;
|
arena->current = current;
|
||||||
return pos;
|
|
||||||
}
|
// compute arena-relative position
|
||||||
|
U64 new_pos = big_pos - current->base_pos;
|
||||||
internal void
|
AssertAlways(new_pos <= current->pos);
|
||||||
arena_pop_to(Arena *arena, U64 pos)
|
|
||||||
{
|
// poison popped memory block
|
||||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
||||||
Arena *current = arena->current;
|
|
||||||
|
// update position
|
||||||
#if ARENA_FREE_LIST
|
current->pos = new_pos;
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
}
|
||||||
{
|
|
||||||
prev = current->prev;
|
internal void
|
||||||
current->pos = ARENA_HEADER_SIZE;
|
arena_absorb(Arena *arena, Arena *sub)
|
||||||
SLLStackPush_N(arena->free_last, current, prev);
|
{
|
||||||
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res - ARENA_HEADER_SIZE);
|
#if ENABLE_DEV
|
||||||
}
|
arena_annotate_absorb__dev(arena, sub);
|
||||||
#else
|
#endif
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
|
||||||
{
|
// base adjustment
|
||||||
prev = current->prev;
|
Arena *current = arena->current;
|
||||||
os_release(current, current->res);
|
U64 base_adjust = current->base_pos + current->res;
|
||||||
}
|
for (Arena *node = sub->current; node != 0; node = node->prev) {
|
||||||
#endif
|
node->base_pos += base_adjust;
|
||||||
arena->current = current;
|
}
|
||||||
U64 new_pos = big_pos - current->base_pos;
|
|
||||||
AssertAlways(new_pos <= current->pos);
|
// attach sub to arena
|
||||||
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
sub->prev = arena->current;
|
||||||
current->pos = new_pos;
|
arena->current = sub->current;
|
||||||
}
|
sub->current = sub;
|
||||||
|
}
|
||||||
//- rjf: arena push/pop helpers
|
|
||||||
|
////////////////////////////////
|
||||||
internal void
|
// Wrappers
|
||||||
arena_clear(Arena *arena)
|
|
||||||
{
|
internal void *
|
||||||
arena_pop_to(arena, 0);
|
arena_push(Arena *arena, U64 size)
|
||||||
}
|
{
|
||||||
|
void *memory = arena_push__impl(arena, size);
|
||||||
internal void
|
#if ENABLE_DEV
|
||||||
arena_pop(Arena *arena, U64 amt)
|
arena_annotate_push__dev(arena, size, memory);
|
||||||
{
|
#endif
|
||||||
U64 pos_old = arena_pos(arena);
|
return memory;
|
||||||
U64 pos_new = pos_old;
|
}
|
||||||
if(amt < pos_old)
|
|
||||||
{
|
internal void *
|
||||||
pos_new = pos_old - amt;
|
arena_push_contiguous(Arena *arena, U64 size)
|
||||||
}
|
{
|
||||||
arena_pop_to(arena, pos_new);
|
B32 restore = arena->grow;
|
||||||
}
|
arena->grow = 0;
|
||||||
|
void *memory = arena_push(arena, size);
|
||||||
//- rjf: temporary arena scopes
|
arena->grow = restore;
|
||||||
|
#if ENABLE_DEV
|
||||||
internal Temp
|
arena_annotate_push__dev(arena, size, memory);
|
||||||
temp_begin(Arena *arena)
|
#endif
|
||||||
{
|
return memory;
|
||||||
U64 pos = arena_pos(arena);
|
}
|
||||||
Temp temp = {arena, pos};
|
|
||||||
return temp;
|
internal void
|
||||||
}
|
arena_push_align(Arena *arena, U64 align)
|
||||||
|
{
|
||||||
internal void
|
Assert(IsPow2(align));
|
||||||
temp_end(Temp temp)
|
U64 amt = AlignPadPow2(arena->pos, align);
|
||||||
{
|
void *ptr = arena_push(arena, amt);
|
||||||
arena_pop_to(temp.arena, temp.pos);
|
MemoryZero(ptr, amt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_put_back(Arena *arena, U64 amt)
|
||||||
|
{
|
||||||
|
U64 pos_old = arena_pos(arena);
|
||||||
|
U64 pos_new = pos_old;
|
||||||
|
if (amt < pos_old) {
|
||||||
|
pos_new = pos_old - amt;
|
||||||
|
}
|
||||||
|
arena_pop_to(arena, pos_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_clear(Arena *arena)
|
||||||
|
{
|
||||||
|
arena_pop_to(arena, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Temp
|
||||||
|
temp_begin(Arena *arena)
|
||||||
|
{
|
||||||
|
U64 pos = arena_pos(arena);
|
||||||
|
Temp temp = {arena, pos};
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
temp_end(Temp temp)
|
||||||
|
{
|
||||||
|
arena_pop_to(temp.arena, temp.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): "Mini-Arena" Helper
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){
|
||||||
|
B32 result = 0;
|
||||||
|
U8 *cmt = (U8*)*cmtptr;
|
||||||
|
if (cmt < (U8*)pos){
|
||||||
|
U64 cmt_size_raw = (U8*)pos - cmt;
|
||||||
|
U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size);
|
||||||
|
if (os_commit(cmt, cmt_size)){
|
||||||
|
*cmtptr = cmt + cmt_size;
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+94
-88
@@ -1,88 +1,94 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_ARENA_H
|
#ifndef BASE_ARENA_H
|
||||||
#define BASE_ARENA_H
|
#define BASE_ARENA_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Types
|
//~ rjf: Constants
|
||||||
|
|
||||||
#define ARENA_HEADER_SIZE 128
|
#define ARENA_HEADER_SIZE 128
|
||||||
|
|
||||||
typedef U64 ArenaFlags;
|
#ifndef ARENA_RESERVE_SIZE
|
||||||
enum
|
# define ARENA_RESERVE_SIZE MB(64)
|
||||||
{
|
#endif
|
||||||
ArenaFlag_NoChain = (1<<0),
|
#ifndef ARENA_COMMIT_SIZE
|
||||||
ArenaFlag_LargePages = (1<<1),
|
# define ARENA_COMMIT_SIZE KB(64)
|
||||||
};
|
#endif
|
||||||
|
|
||||||
typedef struct ArenaParams ArenaParams;
|
#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES
|
||||||
struct ArenaParams
|
# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8)
|
||||||
{
|
#endif
|
||||||
ArenaFlags flags;
|
#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES
|
||||||
U64 reserve_size;
|
# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2)
|
||||||
U64 commit_size;
|
#endif
|
||||||
void *optional_backing_buffer;
|
|
||||||
char *allocation_site_file;
|
////////////////////////////////
|
||||||
int allocation_site_line;
|
//~ rjf: Arena Types
|
||||||
};
|
|
||||||
|
typedef struct Arena Arena;
|
||||||
typedef struct Arena Arena;
|
struct Arena
|
||||||
struct Arena
|
{
|
||||||
{
|
struct Arena *prev;
|
||||||
Arena *prev; // previous arena in chain
|
struct Arena *current;
|
||||||
Arena *current; // current arena in chain
|
U64 base_pos;
|
||||||
ArenaFlags flags;
|
U64 pos;
|
||||||
U64 cmt_size;
|
U64 cmt;
|
||||||
U64 res_size;
|
U64 res;
|
||||||
U64 base_pos;
|
U64 align;
|
||||||
U64 pos;
|
struct ArenaDev *dev;
|
||||||
U64 cmt;
|
B8 grow;
|
||||||
U64 res;
|
B8 large_pages;
|
||||||
char *allocation_site_file;
|
};
|
||||||
int allocation_site_line;
|
|
||||||
#if ARENA_FREE_LIST
|
typedef struct Temp Temp;
|
||||||
Arena *free_last;
|
struct Temp
|
||||||
#endif
|
{
|
||||||
};
|
Arena *arena;
|
||||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
U64 pos;
|
||||||
|
};
|
||||||
typedef struct Temp Temp;
|
|
||||||
struct Temp
|
////////////////////////////////
|
||||||
{
|
// Implementation
|
||||||
Arena *arena;
|
|
||||||
U64 pos;
|
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt);
|
||||||
};
|
|
||||||
|
internal Arena* arena_alloc(void);
|
||||||
////////////////////////////////
|
internal void arena_release(Arena *arena);
|
||||||
//~ rjf: Arena Functions
|
|
||||||
|
internal void* arena_push__impl(Arena *arena, U64 size);
|
||||||
global U64 arena_default_reserve_size = MB(64);
|
internal U64 arena_pos(Arena *arena);
|
||||||
global U64 arena_default_commit_size = KB(64);
|
internal void arena_pop_to(Arena *arena, U64 pos);
|
||||||
global ArenaFlags arena_default_flags = 0;
|
|
||||||
|
internal void arena_absorb(Arena *arena, Arena *sub);
|
||||||
//- rjf: arena creation/destruction
|
|
||||||
internal Arena *arena_alloc_(ArenaParams *params);
|
////////////////////////////////
|
||||||
#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = arena_default_reserve_size, .commit_size = arena_default_commit_size, .flags = arena_default_flags, .allocation_site_file = __FILE__, .allocation_site_line = __LINE__, __VA_ARGS__})
|
// Wrappers
|
||||||
internal void arena_release(Arena *arena);
|
|
||||||
|
internal void* arena_push(Arena *arena, U64 size);
|
||||||
//- rjf: arena push/pop/pos core functions
|
internal void* arena_push_contiguous(Arena *arena, U64 size);
|
||||||
internal void *arena_push(Arena *arena, U64 size, U64 align, B32 zero);
|
internal void arena_clear(Arena *arena);
|
||||||
internal U64 arena_pos(Arena *arena);
|
internal void arena_push_align(Arena *arena, U64 align);
|
||||||
internal void arena_pop_to(Arena *arena, U64 pos);
|
internal void arena_put_back(Arena *arena, U64 amt);
|
||||||
|
|
||||||
//- rjf: arena push/pop helpers
|
internal Temp temp_begin(Arena *arena);
|
||||||
internal void arena_clear(Arena *arena);
|
internal void temp_end(Temp temp);
|
||||||
internal void arena_pop(Arena *arena, U64 amt);
|
|
||||||
|
////////////////////////////////
|
||||||
//- rjf: temporary arena scopes
|
//~ NOTE(allen): "Mini-Arena" Helper
|
||||||
internal Temp temp_begin(Arena *arena);
|
|
||||||
internal void temp_end(Temp temp);
|
internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size);
|
||||||
|
|
||||||
//- rjf: push helper macros
|
////////////////////////////////
|
||||||
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (0))
|
//~ NOTE(allen): Main API Macros
|
||||||
#define push_array_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (1))
|
|
||||||
#define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T)))
|
#if !ENABLE_DEV
|
||||||
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
|
# define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
|
||||||
|
#else
|
||||||
#endif // BASE_ARENA_H
|
# define push_array_no_zero(a,T,c) (tctx_write_this_srcloc(), (T*)arena_push((a), sizeof(T)*(c)))
|
||||||
|
#endif
|
||||||
|
#define push_array_no_zero__no_annotation(a,T,c) (T*)arena_push__impl((a), sizeof(T)*(c))
|
||||||
|
|
||||||
|
#define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c))
|
||||||
|
|
||||||
|
#endif // BASE_ARENA_H
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Dev Arena
|
||||||
|
|
||||||
|
#if ENABLE_DEV
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){
|
||||||
|
ArenaDev *dev = arena->dev;
|
||||||
|
if (dev != 0 && ptr != 0){
|
||||||
|
//- read location
|
||||||
|
char *file_name = 0;
|
||||||
|
U64 line_number = 0;
|
||||||
|
tctx_read_srcloc(&file_name, &line_number);
|
||||||
|
tctx_write_srcloc(0, 0);
|
||||||
|
|
||||||
|
//- profile
|
||||||
|
ArenaProf *prof = dev->prof;
|
||||||
|
if (prof != 0){
|
||||||
|
// c string -> string
|
||||||
|
String8 file_name_str = str8_lit("(null)");
|
||||||
|
if (file_name != 0){
|
||||||
|
file_name_str = str8_cstring(file_name);
|
||||||
|
}
|
||||||
|
// record
|
||||||
|
arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_annotate_absorb__dev(Arena *arena, Arena *sub){
|
||||||
|
ArenaDev *dev = arena->dev;
|
||||||
|
ArenaDev *sub_dev = sub->dev;
|
||||||
|
if (dev != 0 && sub_dev != 0){
|
||||||
|
//- merge profiles
|
||||||
|
ArenaProf *prof = dev->prof;
|
||||||
|
ArenaProf *sub_prof = sub_dev->prof;
|
||||||
|
if (prof != 0 && sub_prof != 0){
|
||||||
|
for (ArenaProfNode *sub_node = sub_prof->first;
|
||||||
|
sub_node != 0;
|
||||||
|
sub_node = sub_node->next){
|
||||||
|
arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line,
|
||||||
|
sub_node->size, sub_node->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//- release the sub dev memory
|
||||||
|
if (sub_dev != 0){
|
||||||
|
arena_release(sub_dev->arena);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ArenaDev*
|
||||||
|
arena_equip__dev(Arena *arena){
|
||||||
|
ArenaDev *result = arena->dev;
|
||||||
|
if (result == 0){
|
||||||
|
Arena *dev_arena = arena_alloc();
|
||||||
|
ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev));
|
||||||
|
MemoryZeroStruct(dev);
|
||||||
|
dev->arena = dev_arena;
|
||||||
|
arena->dev = dev;
|
||||||
|
result = dev;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_equip_profile__dev(Arena *arena){
|
||||||
|
ArenaDev *dev = arena_equip__dev(arena);
|
||||||
|
if (dev->prof == 0){
|
||||||
|
dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf));
|
||||||
|
MemoryZeroStruct(dev->prof);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){
|
||||||
|
Assert(arena != out_arena);
|
||||||
|
|
||||||
|
//- get dev & disable
|
||||||
|
ArenaDev *dev = arena->dev;
|
||||||
|
arena->dev = 0;
|
||||||
|
|
||||||
|
//- get prof
|
||||||
|
ArenaProf *prof = (dev != 0)?dev->prof:0;
|
||||||
|
|
||||||
|
//- not equipped with prof
|
||||||
|
if (prof == 0){
|
||||||
|
str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//- print prof
|
||||||
|
if (prof != 0){
|
||||||
|
Temp scratch = temp_begin(dev->arena);
|
||||||
|
|
||||||
|
//- make flat array
|
||||||
|
U64 note_count = prof->count;
|
||||||
|
ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count);
|
||||||
|
{
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (ArenaProfNode *node = prof->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next, note_ptr += 1){
|
||||||
|
*note_ptr = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- file name size
|
||||||
|
U64 max_file_name_size = 0;
|
||||||
|
{
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||||
|
max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sort (> size, < [address])
|
||||||
|
for (U64 i = 0; i < note_count; i += 1){
|
||||||
|
ArenaProfNode **i_note = notes + i;
|
||||||
|
ArenaProfNode **min_note = i_note;
|
||||||
|
for (U64 j = i + 1; j < note_count; j += 1){
|
||||||
|
ArenaProfNode **j_note = notes + j;
|
||||||
|
if ((**j_note).size > (**min_note).size ||
|
||||||
|
((**j_note).size == (**min_note).size && *j_note < *min_note)){
|
||||||
|
min_note = j_note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (min_note != i_note){
|
||||||
|
ArenaProfNode *t = *i_note;
|
||||||
|
*i_note = *min_note;
|
||||||
|
*min_note = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- total size
|
||||||
|
U64 total_size = 0;
|
||||||
|
{
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||||
|
ArenaProfNode *note = *note_ptr;
|
||||||
|
total_size += note->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- print
|
||||||
|
{
|
||||||
|
str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size);
|
||||||
|
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||||
|
ArenaProfNode *note = *note_ptr;
|
||||||
|
String8 location = push_str8f(scratch.arena, "%S:%5llu:",
|
||||||
|
note->file_name, note->line);
|
||||||
|
F32 percent = 100.f*((F32)note->size)/total_size;
|
||||||
|
str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n",
|
||||||
|
max_file_name_size + 7, str8_varg(location),
|
||||||
|
note->size, percent, note->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- restore dev
|
||||||
|
arena->dev = dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line,
|
||||||
|
U64 size, U64 count){
|
||||||
|
// find existing profile node
|
||||||
|
ArenaProfNode *prof_node = 0;
|
||||||
|
for (ArenaProfNode *node = prof->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
if (node->line == line && str8_match(file_name, node->file_name, 0)){
|
||||||
|
prof_node = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// make new histogram node if necessary
|
||||||
|
if (prof_node == 0){
|
||||||
|
prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node));
|
||||||
|
SLLQueuePush(prof->first, prof->last, prof_node);
|
||||||
|
prof->count += 1;
|
||||||
|
prof_node->file_name = file_name;
|
||||||
|
prof_node->line = line;
|
||||||
|
}
|
||||||
|
// record this allocation
|
||||||
|
prof_node->size += size;
|
||||||
|
prof_node->count += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_ARENA_DEV_H
|
||||||
|
#define BASE_ARENA_DEV_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): Dev Arena Types
|
||||||
|
|
||||||
|
typedef struct ArenaDev ArenaDev;
|
||||||
|
struct ArenaDev
|
||||||
|
{
|
||||||
|
Arena *arena;
|
||||||
|
struct ArenaProf *prof;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ArenaProf ArenaProf;
|
||||||
|
struct ArenaProf
|
||||||
|
{
|
||||||
|
struct ArenaProfNode *first;
|
||||||
|
struct ArenaProfNode *last;
|
||||||
|
U64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ArenaProfNode ArenaProfNode;
|
||||||
|
struct ArenaProfNode
|
||||||
|
{
|
||||||
|
ArenaProfNode *next;
|
||||||
|
String8 file_name;
|
||||||
|
U64 line;
|
||||||
|
U64 size;
|
||||||
|
U64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): Dev Arena Functions
|
||||||
|
|
||||||
|
#if ENABLE_DEV
|
||||||
|
internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr);
|
||||||
|
internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub);
|
||||||
|
internal ArenaDev* arena_equip__dev(Arena *arena);
|
||||||
|
internal void arena_equip_profile__dev(Arena *arena);
|
||||||
|
internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out);
|
||||||
|
internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BASE_ARENA_DEV_H
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set16(U16 val)
|
||||||
|
{
|
||||||
|
return __popcnt16(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set32(U32 val)
|
||||||
|
{
|
||||||
|
return __popcnt(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set64(U64 val)
|
||||||
|
{
|
||||||
|
return __popcnt64(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ctz32(U32 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanForward(&idx, mask);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ctz64(U64 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanForward64(&idx, mask);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz32(U32 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanReverse(&idx, mask);
|
||||||
|
return 31 - idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz64(U64 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanReverse64(&idx, mask);
|
||||||
|
return 63 - idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set16(U16 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set32(U32 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set64(U64 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ctz32(U32 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz32(U32 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz64(U64 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error "bits not defined for this target"
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_BITS_H
|
||||||
|
#define BASE_BITS_H
|
||||||
|
|
||||||
|
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
|
||||||
|
|
||||||
|
internal U64 count_bits_set16(U16 val);
|
||||||
|
internal U64 count_bits_set32(U32 val);
|
||||||
|
internal U64 count_bits_set64(U64 val);
|
||||||
|
|
||||||
|
internal U64 ctz32(U32 val);
|
||||||
|
internal U64 ctz64(U64 val);
|
||||||
|
internal U64 clz32(U32 val);
|
||||||
|
internal U64 clz64(U64 val);
|
||||||
|
|
||||||
|
#endif // BASE_BITS_H
|
||||||
+229
-228
@@ -1,228 +1,229 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Command Line Parsing Functions
|
//~ NOTE(rjf): Command Line Option Parsing
|
||||||
|
|
||||||
internal CmdLineOpt **
|
internal U64
|
||||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
cmd_line_hash_from_string(String8 string)
|
||||||
{
|
{
|
||||||
CmdLineOpt **slot = 0;
|
U64 result = 5381;
|
||||||
if(cmd_line->option_table_size != 0)
|
for(U64 i = 0; i < string.size; i += 1)
|
||||||
{
|
{
|
||||||
U64 hash = u64_hash_from_str8(string);
|
result = ((result << 5) + result) + string.str[i];
|
||||||
U64 bucket = hash % cmd_line->option_table_size;
|
}
|
||||||
slot = &cmd_line->option_table[bucket];
|
return result;
|
||||||
}
|
}
|
||||||
return slot;
|
|
||||||
}
|
internal CmdLineOpt **
|
||||||
|
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||||
internal CmdLineOpt *
|
{
|
||||||
cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string)
|
CmdLineOpt **slot = 0;
|
||||||
{
|
if(cmd_line->option_table_size != 0)
|
||||||
CmdLineOpt *result = 0;
|
{
|
||||||
for(CmdLineOpt *var = *slot; var; var = var->hash_next)
|
U64 hash = cmd_line_hash_from_string(string);
|
||||||
{
|
U64 bucket = hash % cmd_line->option_table_size;
|
||||||
if(str8_match(string, var->string, 0))
|
slot = &cmd_line->option_table[bucket];
|
||||||
{
|
}
|
||||||
result = var;
|
return slot;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
internal CmdLineOpt *
|
||||||
return result;
|
cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string)
|
||||||
}
|
{
|
||||||
|
CmdLineOpt *result = 0;
|
||||||
internal void
|
for(CmdLineOpt *var = *slot; var; var = var->hash_next)
|
||||||
cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var)
|
{
|
||||||
{
|
if(str8_match(string, var->string, 0))
|
||||||
SLLQueuePush(list->first, list->last, var);
|
{
|
||||||
list->count += 1;
|
result = var;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
internal CmdLineOpt *
|
}
|
||||||
cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values)
|
return result;
|
||||||
{
|
}
|
||||||
CmdLineOpt *var = 0;
|
|
||||||
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
|
internal void
|
||||||
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
|
cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var)
|
||||||
if(existing_var != 0)
|
{
|
||||||
{
|
SLLQueuePush(list->first, list->last, var);
|
||||||
var = existing_var;
|
list->count += 1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
internal CmdLineOpt *
|
||||||
var = push_array(arena, CmdLineOpt, 1);
|
cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values)
|
||||||
var->hash_next = *slot;
|
{
|
||||||
var->hash = u64_hash_from_str8(string);
|
CmdLineOpt *var = 0;
|
||||||
var->string = push_str8_copy(arena, string);
|
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
|
||||||
var->value_strings = values;
|
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
|
||||||
StringJoin join = {0};
|
if(existing_var != 0)
|
||||||
join.pre = str8_lit("");
|
{
|
||||||
join.sep = str8_lit(",");
|
var = existing_var;
|
||||||
join.post = str8_lit("");
|
}
|
||||||
var->value_string = str8_list_join(arena, &var->value_strings, &join);
|
else
|
||||||
*slot = var;
|
{
|
||||||
cmd_line_push_opt(&cmd_line->options, var);
|
var = push_array(arena, CmdLineOpt, 1);
|
||||||
}
|
var->hash_next = *slot;
|
||||||
return var;
|
var->hash = cmd_line_hash_from_string(string);
|
||||||
}
|
var->string = push_str8_copy(arena, string);
|
||||||
|
var->value_strings = values;
|
||||||
internal CmdLine
|
StringJoin join = {0};
|
||||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
join.pre = str8_lit("");
|
||||||
{
|
join.sep = str8_lit(",");
|
||||||
CmdLine parsed = {0};
|
join.post = str8_lit("");
|
||||||
parsed.exe_name = command_line.first->string;
|
var->value_string = str8_list_join(arena, &var->value_strings, &join);
|
||||||
parsed.option_table_size = 64;
|
*slot = var;
|
||||||
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
cmd_line_push_opt(&cmd_line->options, var);
|
||||||
|
}
|
||||||
//- rjf: parse options / inputs
|
return var;
|
||||||
B32 after_passthrough_option = 0;
|
}
|
||||||
B32 first_passthrough = 1;
|
|
||||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
internal CmdLine
|
||||||
{
|
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||||
next = node->next;
|
{
|
||||||
|
CmdLine parsed = {0};
|
||||||
//- rjf: look at --, -, or / (only on Windows) at the start of an
|
|
||||||
// argument to determine if it's a flag option. all arguments after a
|
// NOTE(rjf): Set up config option table.
|
||||||
// single "--" (with no trailing string on the command line will be
|
{
|
||||||
// considered as passthrough input strings.
|
parsed.option_table_size = 4096;
|
||||||
B32 is_option = 0;
|
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
||||||
String8 option_name = node->string;
|
}
|
||||||
if(!after_passthrough_option)
|
|
||||||
{
|
// NOTE(rjf): Parse command line.
|
||||||
is_option = 1;
|
B32 after_passthrough_option = 0;
|
||||||
if(str8_match(node->string, str8_lit("--"), 0))
|
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||||
{
|
{
|
||||||
after_passthrough_option = 1;
|
next = node->next;
|
||||||
is_option = 0;
|
String8 option_name = node->string;
|
||||||
}
|
|
||||||
else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0))
|
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's
|
||||||
{
|
// a flag option. All arguments after a single "--" (with no trailing string
|
||||||
option_name = str8_skip(option_name, 2);
|
// on the command line will be considered as input files.
|
||||||
}
|
B32 is_option = 1;
|
||||||
else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0))
|
if(after_passthrough_option == 0)
|
||||||
{
|
{
|
||||||
option_name = str8_skip(option_name, 1);
|
if(str8_match(node->string, str8_lit("--"), 0))
|
||||||
}
|
{
|
||||||
else if(OperatingSystem_CURRENT == OperatingSystem_Windows &&
|
after_passthrough_option = 1;
|
||||||
str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0))
|
is_option = 0;
|
||||||
{
|
}
|
||||||
option_name = str8_skip(option_name, 1);
|
else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0))
|
||||||
}
|
{
|
||||||
else
|
option_name = str8_skip(option_name, 2);
|
||||||
{
|
}
|
||||||
is_option = 0;
|
else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0))
|
||||||
}
|
{
|
||||||
}
|
option_name = str8_skip(option_name, 1);
|
||||||
|
}
|
||||||
//- rjf: string is an option
|
else
|
||||||
if(is_option)
|
{
|
||||||
{
|
is_option = 0;
|
||||||
// rjf: unpack option prefix
|
}
|
||||||
B32 has_values = 0;
|
}
|
||||||
U64 value_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
else
|
||||||
U64 value_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
{
|
||||||
U64 value_signifier_position = Min(value_signifier_position1, value_signifier_position2);
|
is_option = 0;
|
||||||
String8 value_portion_this_string = str8_skip(option_name, value_signifier_position+1);
|
}
|
||||||
if(value_signifier_position < option_name.size)
|
|
||||||
{
|
// NOTE(rjf): This string is an option.
|
||||||
has_values = 1;
|
if(is_option)
|
||||||
}
|
{
|
||||||
option_name = str8_prefix(option_name, value_signifier_position);
|
B32 has_arguments = 0;
|
||||||
|
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||||
// rjf: parse option's values
|
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||||
String8List values = {0};
|
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||||
if(has_values)
|
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||||
{
|
if(arg_signifier_position < option_name.size)
|
||||||
for(String8Node *n = node; n; n = n->next)
|
{
|
||||||
{
|
has_arguments = 1;
|
||||||
next = n->next;
|
}
|
||||||
String8 string = n->string;
|
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||||
if(n == node)
|
|
||||||
{
|
String8List arguments = {0};
|
||||||
string = value_portion_this_string;
|
|
||||||
}
|
// NOTE(rjf): Parse arguments.
|
||||||
U8 splits[] = { ',' };
|
if(has_arguments)
|
||||||
String8List values_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
{
|
||||||
for(String8Node *sub_val = values_in_this_string.first; sub_val; sub_val = sub_val->next)
|
for(String8Node *n = node; n; n = n->next)
|
||||||
{
|
{
|
||||||
str8_list_push(arena, &values, sub_val->string);
|
next = n->next;
|
||||||
}
|
|
||||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
String8 string = n->string;
|
||||||
(n != node || value_portion_this_string.size != 0))
|
if(n == node)
|
||||||
{
|
{
|
||||||
break;
|
string = arg_portion_this_string;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
U8 splits[] = { ',' };
|
||||||
|
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||||
// rjf: store
|
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||||
cmd_line_insert_opt(arena, &parsed, option_name, values);
|
{
|
||||||
}
|
str8_list_push(arena, &arguments, sub_arg->string);
|
||||||
|
}
|
||||||
//- rjf: default path - treat as a passthrough input
|
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
(n != node || arg_portion_this_string.size != 0))
|
||||||
{
|
{
|
||||||
str8_list_push(arena, &parsed.inputs, node->string);
|
break;
|
||||||
first_passthrough = 0;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: fill argc/argv
|
// NOTE(rjf): Register config variable.
|
||||||
parsed.argc = command_line.node_count;
|
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||||
parsed.argv = push_array(arena, char *, parsed.argc);
|
}
|
||||||
{
|
|
||||||
U64 idx = 0;
|
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||||
for(String8Node *n = command_line.first; n != 0; n = n->next)
|
// handled by tool-specific code.
|
||||||
{
|
else if(!str8_match(node->string, str8_lit("--"), 0))
|
||||||
parsed.argv[idx] = (char *)push_str8_copy(arena, n->string).str;
|
{
|
||||||
idx += 1;
|
str8_list_push(arena, &parsed.inputs, node->string);
|
||||||
}
|
after_passthrough_option = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return parsed;
|
|
||||||
}
|
return parsed;
|
||||||
|
}
|
||||||
internal CmdLineOpt *
|
|
||||||
cmd_line_opt_from_string(CmdLine *cmd_line, String8 name)
|
internal CmdLineOpt *
|
||||||
{
|
cmd_line_opt_from_string(CmdLine *cmd_line, String8 name)
|
||||||
return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name);
|
{
|
||||||
}
|
return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name);
|
||||||
|
}
|
||||||
internal String8List
|
|
||||||
cmd_line_strings(CmdLine *cmd_line, String8 name)
|
internal String8List
|
||||||
{
|
cmd_line_strings(CmdLine *cmd_line, String8 name)
|
||||||
String8List result = {0};
|
{
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
String8List result = {0};
|
||||||
if(var != 0)
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
{
|
if(var != 0)
|
||||||
result = var->value_strings;
|
{
|
||||||
}
|
result = var->value_strings;
|
||||||
return result;
|
}
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
internal String8
|
|
||||||
cmd_line_string(CmdLine *cmd_line, String8 name)
|
internal String8
|
||||||
{
|
cmd_line_string(CmdLine *cmd_line, String8 name)
|
||||||
String8 result = {0};
|
{
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
String8 result = {0};
|
||||||
if(var != 0)
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
{
|
if(var != 0)
|
||||||
result = var->value_string;
|
{
|
||||||
}
|
result = var->value_string;
|
||||||
return result;
|
}
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
internal B32
|
|
||||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
internal B32
|
||||||
{
|
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
{
|
||||||
return (var != 0);
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
}
|
return(var != 0);
|
||||||
|
}
|
||||||
internal B32
|
|
||||||
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
internal B32
|
||||||
{
|
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
{
|
||||||
return (var != 0 && var->value_strings.node_count > 0);
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
}
|
return(var != 0 && var->value_strings.node_count > 0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,55 +1,53 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_COMMAND_LINE_H
|
#ifndef BASE_COMMAND_LINE_H
|
||||||
#define BASE_COMMAND_LINE_H
|
#define BASE_COMMAND_LINE_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Parsed Command Line Types
|
//~ rjf: Parsed Command Line Types
|
||||||
|
|
||||||
typedef struct CmdLineOpt CmdLineOpt;
|
typedef struct CmdLineOpt CmdLineOpt;
|
||||||
struct CmdLineOpt
|
struct CmdLineOpt
|
||||||
{
|
{
|
||||||
CmdLineOpt *next;
|
CmdLineOpt *next;
|
||||||
CmdLineOpt *hash_next;
|
CmdLineOpt *hash_next;
|
||||||
U64 hash;
|
U64 hash;
|
||||||
String8 string;
|
String8 string;
|
||||||
String8List value_strings;
|
String8List value_strings;
|
||||||
String8 value_string;
|
String8 value_string;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct CmdLineOptList CmdLineOptList;
|
typedef struct CmdLineOptList CmdLineOptList;
|
||||||
struct CmdLineOptList
|
struct CmdLineOptList
|
||||||
{
|
{
|
||||||
U64 count;
|
U64 count;
|
||||||
CmdLineOpt *first;
|
CmdLineOpt *first;
|
||||||
CmdLineOpt *last;
|
CmdLineOpt *last;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct CmdLine CmdLine;
|
typedef struct CmdLine CmdLine;
|
||||||
struct CmdLine
|
struct CmdLine
|
||||||
{
|
{
|
||||||
String8 exe_name;
|
CmdLineOptList options;
|
||||||
CmdLineOptList options;
|
String8List inputs;
|
||||||
String8List inputs;
|
U64 option_table_size;
|
||||||
U64 option_table_size;
|
CmdLineOpt **option_table;
|
||||||
CmdLineOpt **option_table;
|
};
|
||||||
U64 argc;
|
|
||||||
char **argv;
|
////////////////////////////////
|
||||||
};
|
//~ NOTE(rjf): Command Line Option Parsing
|
||||||
|
|
||||||
////////////////////////////////
|
internal U64 cmd_line_hash_from_string(String8 string);
|
||||||
//~ rjf: Command Line Parsing Functions
|
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||||
|
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values);
|
||||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments);
|
||||||
internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values);
|
internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name);
|
||||||
internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments);
|
internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name);
|
||||||
internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name);
|
internal String8 cmd_line_string(CmdLine *cmd_line, String8 name);
|
||||||
internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name);
|
internal B32 cmd_line_has_flag(CmdLine *cmd_line, String8 name);
|
||||||
internal String8 cmd_line_string(CmdLine *cmd_line, String8 name);
|
internal B32 cmd_line_has_argument(CmdLine *cmd_line, String8 name);
|
||||||
internal B32 cmd_line_has_flag(CmdLine *cmd_line, String8 name);
|
|
||||||
internal B32 cmd_line_has_argument(CmdLine *cmd_line, String8 name);
|
#endif // BASE_COMMAND_LINE_H
|
||||||
|
|
||||||
#endif // BASE_COMMAND_LINE_H
|
|
||||||
|
|||||||
+144
-247
@@ -1,247 +1,144 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_CONTEXT_CRACKING_H
|
#ifndef BASE_CONTEXT_CRACKING_H
|
||||||
#define BASE_CONTEXT_CRACKING_H
|
#define BASE_CONTEXT_CRACKING_H
|
||||||
|
|
||||||
////////////////////////////////
|
#if defined(__clang__)
|
||||||
//~ rjf: Clang OS/Arch Cracking
|
|
||||||
|
# define COMPILER_CLANG 1
|
||||||
#if defined(__clang__)
|
|
||||||
|
# if defined(_WIN32)
|
||||||
# define COMPILER_CLANG 1
|
# define OS_WINDOWS 1
|
||||||
|
# elif defined(__gnu_linux__) || defined(__linux__)
|
||||||
# if defined(_WIN32)
|
# define OS_LINUX 1
|
||||||
# define OS_WINDOWS 1
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
# elif defined(__gnu_linux__) || defined(__linux__)
|
# define OS_MAC 1
|
||||||
# define OS_LINUX 1
|
# else
|
||||||
# elif defined(__APPLE__) && defined(__MACH__)
|
# error This compiler/platform combo is not supported yet
|
||||||
# define OS_MAC 1
|
# endif
|
||||||
# else
|
|
||||||
# error This compiler/OS combo is not supported.
|
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||||
# endif
|
# define ARCH_X64 1
|
||||||
|
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
# define ARCH_X86 1
|
||||||
# define ARCH_X64 1
|
# elif defined(__aarch64__)
|
||||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
# define ARCH_ARM64 1
|
||||||
# define ARCH_X86 1
|
# elif defined(__arm__)
|
||||||
# elif defined(__aarch64__)
|
# define ARCH_ARM32 1
|
||||||
# define ARCH_ARM64 1
|
# else
|
||||||
# elif defined(__arm__)
|
# error architecture not supported yet
|
||||||
# define ARCH_ARM32 1
|
# endif
|
||||||
# else
|
|
||||||
# error Architecture not supported.
|
#elif defined(_MSC_VER)
|
||||||
# endif
|
|
||||||
|
# define COMPILER_CL 1
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MSVC OS/Arch Cracking
|
# if defined(_WIN32)
|
||||||
|
# define OS_WINDOWS 1
|
||||||
#elif defined(_MSC_VER)
|
# else
|
||||||
|
# error This compiler/platform combo is not supported yet
|
||||||
# define COMPILER_MSVC 1
|
# endif
|
||||||
|
|
||||||
# if _MSC_VER >= 1920
|
# if defined(_M_AMD64)
|
||||||
# define COMPILER_MSVC_YEAR 2019
|
# define ARCH_X64 1
|
||||||
# elif _MSC_VER >= 1910
|
# elif defined(_M_IX86)
|
||||||
# define COMPILER_MSVC_YEAR 2017
|
# define ARCH_X86 1
|
||||||
# elif _MSC_VER >= 1900
|
# elif defined(_M_ARM64)
|
||||||
# define COMPILER_MSVC_YEAR 2015
|
# define ARCH_ARM64 1
|
||||||
# elif _MSC_VER >= 1800
|
# elif defined(_M_ARM)
|
||||||
# define COMPILER_MSVC_YEAR 2013
|
# define ARCH_ARM32 1
|
||||||
# elif _MSC_VER >= 1700
|
# else
|
||||||
# define COMPILER_MSVC_YEAR 2012
|
# error architecture not supported yet
|
||||||
# elif _MSC_VER >= 1600
|
# endif
|
||||||
# define COMPILER_MSVC_YEAR 2010
|
|
||||||
# elif _MSC_VER >= 1500
|
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||||
# define COMPILER_MSVC_YEAR 2008
|
|
||||||
# elif _MSC_VER >= 1400
|
# define COMPILER_GCC 1
|
||||||
# define COMPILER_MSVC_YEAR 2005
|
|
||||||
# else
|
# if defined(__gnu_linux__) || defined(__linux__)
|
||||||
# define COMPILER_MSVC_YEAR 0
|
# define OS_LINUX 1
|
||||||
# endif
|
# else
|
||||||
|
# error This compiler/platform combo is not supported yet
|
||||||
# if defined(_WIN32)
|
# endif
|
||||||
# define OS_WINDOWS 1
|
|
||||||
# else
|
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||||
# error This compiler/OS combo is not supported.
|
# define ARCH_X64 1
|
||||||
# endif
|
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||||
|
# define ARCH_X86 1
|
||||||
# if defined(_M_AMD64)
|
# elif defined(__aarch64__)
|
||||||
# define ARCH_X64 1
|
# define ARCH_ARM64 1
|
||||||
# elif defined(_M_IX86)
|
# elif defined(__arm__)
|
||||||
# define ARCH_X86 1
|
# define ARCH_ARM32 1
|
||||||
# elif defined(_M_ARM64)
|
# else
|
||||||
# define ARCH_ARM64 1
|
# error architecture not supported yet
|
||||||
# elif defined(_M_ARM)
|
# endif
|
||||||
# define ARCH_ARM32 1
|
|
||||||
# else
|
#else
|
||||||
# error Architecture not supported.
|
# error This compiler is not supported yet
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
#if defined(ARCH_X64)
|
||||||
//~ rjf: GCC OS/Arch Cracking
|
# define ARCH_64BIT 1
|
||||||
|
#elif defined(ARCH_X86)
|
||||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
# define ARCH_32BIT 1
|
||||||
|
#endif
|
||||||
# define COMPILER_GCC 1
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
# if defined(__gnu_linux__) || defined(__linux__)
|
# define LANG_CPP 1
|
||||||
# define OS_LINUX 1
|
#else
|
||||||
# else
|
# define LANG_C 1
|
||||||
# error This compiler/OS combo is not supported.
|
#endif
|
||||||
# endif
|
|
||||||
|
// zeroify
|
||||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
|
||||||
# define ARCH_X64 1
|
#if !defined(ARCH_32BIT)
|
||||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
# define ARCH_32BIT 0
|
||||||
# define ARCH_X86 1
|
#endif
|
||||||
# elif defined(__aarch64__)
|
#if !defined(ARCH_64BIT)
|
||||||
# define ARCH_ARM64 1
|
# define ARCH_64BIT 0
|
||||||
# elif defined(__arm__)
|
#endif
|
||||||
# define ARCH_ARM32 1
|
#if !defined(ARCH_X64)
|
||||||
# else
|
# define ARCH_X64 0
|
||||||
# error Architecture not supported.
|
#endif
|
||||||
# endif
|
#if !defined(ARCH_X86)
|
||||||
|
# define ARCH_X86 0
|
||||||
#else
|
#endif
|
||||||
# error Compiler not supported.
|
#if !defined(ARCH_ARM64)
|
||||||
#endif
|
# define ARCH_ARM64 0
|
||||||
|
#endif
|
||||||
////////////////////////////////
|
#if !defined(ARCH_ARM32)
|
||||||
//~ rjf: Arch Cracking
|
# define ARCH_ARM32 0
|
||||||
|
#endif
|
||||||
#if defined(ARCH_X64)
|
#if !defined(COMPILER_CL)
|
||||||
# define ARCH_64BIT 1
|
# define COMPILER_CL 0
|
||||||
#elif defined(ARCH_X86)
|
#endif
|
||||||
# define ARCH_32BIT 1
|
#if !defined(COMPILER_GCC)
|
||||||
#endif
|
# define COMPILER_GCC 0
|
||||||
|
#endif
|
||||||
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
#if !defined(COMPILER_CLANG)
|
||||||
# define ARCH_LITTLE_ENDIAN 1
|
# define COMPILER_CLANG 0
|
||||||
#else
|
#endif
|
||||||
# error Endianness of this architecture not understood by context cracker.
|
#if !defined(OS_WINDOWS)
|
||||||
#endif
|
# define OS_WINDOWS 0
|
||||||
|
#endif
|
||||||
////////////////////////////////
|
#if !defined(OS_LINUX)
|
||||||
//~ rjf: Language Cracking
|
# define OS_LINUX 0
|
||||||
|
#endif
|
||||||
#if defined(__cplusplus)
|
#if !defined(OS_MAC)
|
||||||
# define LANG_CPP 1
|
# define OS_MAC 0
|
||||||
#else
|
#endif
|
||||||
# define LANG_C 1
|
#if !defined(LANG_CPP)
|
||||||
#endif
|
# define LANG_CPP 0
|
||||||
|
#endif
|
||||||
////////////////////////////////
|
#if !defined(LANG_C)
|
||||||
//~ rjf: Build Option Cracking
|
# define LANG_C 0
|
||||||
|
#endif
|
||||||
#if !defined(BUILD_DEBUG)
|
|
||||||
# define BUILD_DEBUG 1
|
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
||||||
#endif
|
# define ARCH_LITTLE_ENDIAN 1
|
||||||
|
#else
|
||||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
# error Endianness of this architecture not understood by context cracker
|
||||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
#endif
|
||||||
#endif
|
|
||||||
|
#endif // BASE_CONTEXT_CRACKING_H
|
||||||
#if !defined(BUILD_ENTRY_DEFINING_UNIT)
|
|
||||||
# define BUILD_ENTRY_DEFINING_UNIT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_CONSOLE_INTERFACE)
|
|
||||||
# define BUILD_CONSOLE_INTERFACE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_MAJOR)
|
|
||||||
# define BUILD_VERSION_MAJOR 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_MINOR)
|
|
||||||
# define BUILD_VERSION_MINOR 9
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_PATCH)
|
|
||||||
# define BUILD_VERSION_PATCH 24
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
|
||||||
#if BUILD_DEBUG
|
|
||||||
# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]"
|
|
||||||
#else
|
|
||||||
# define BUILD_MODE_STRING_LITERAL_APPEND ""
|
|
||||||
#endif
|
|
||||||
#if defined(BUILD_GIT_HASH)
|
|
||||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]"
|
|
||||||
#else
|
|
||||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_TITLE)
|
|
||||||
# define BUILD_TITLE "Untitled"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL)
|
|
||||||
# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
|
|
||||||
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGamesExt/raddebugger/issues"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Zero All Undefined Options
|
|
||||||
|
|
||||||
#if !defined(ARCH_32BIT)
|
|
||||||
# define ARCH_32BIT 0
|
|
||||||
#endif
|
|
||||||
#if !defined(ARCH_64BIT)
|
|
||||||
# define ARCH_64BIT 0
|
|
||||||
#endif
|
|
||||||
#if !defined(ARCH_X64)
|
|
||||||
# define ARCH_X64 0
|
|
||||||
#endif
|
|
||||||
#if !defined(ARCH_X86)
|
|
||||||
# define ARCH_X86 0
|
|
||||||
#endif
|
|
||||||
#if !defined(ARCH_ARM64)
|
|
||||||
# define ARCH_ARM64 0
|
|
||||||
#endif
|
|
||||||
#if !defined(ARCH_ARM32)
|
|
||||||
# define ARCH_ARM32 0
|
|
||||||
#endif
|
|
||||||
#if !defined(COMPILER_MSVC)
|
|
||||||
# define COMPILER_MSVC 0
|
|
||||||
#endif
|
|
||||||
#if !defined(COMPILER_GCC)
|
|
||||||
# define COMPILER_GCC 0
|
|
||||||
#endif
|
|
||||||
#if !defined(COMPILER_CLANG)
|
|
||||||
# define COMPILER_CLANG 0
|
|
||||||
#endif
|
|
||||||
#if !defined(OS_WINDOWS)
|
|
||||||
# define OS_WINDOWS 0
|
|
||||||
#endif
|
|
||||||
#if !defined(OS_LINUX)
|
|
||||||
# define OS_LINUX 0
|
|
||||||
#endif
|
|
||||||
#if !defined(OS_MAC)
|
|
||||||
# define OS_MAC 0
|
|
||||||
#endif
|
|
||||||
#if !defined(LANG_CPP)
|
|
||||||
# define LANG_CPP 0
|
|
||||||
#endif
|
|
||||||
#if !defined(LANG_C)
|
|
||||||
# define LANG_C 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Unsupported Errors
|
|
||||||
|
|
||||||
#if ARCH_X86
|
|
||||||
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
|
|
||||||
#endif
|
|
||||||
#if !ARCH_X64
|
|
||||||
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BASE_CONTEXT_CRACKING_H
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,234 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
global U64 global_update_tick_idx = 0;
|
|
||||||
global U64 async_threads_count = 0;
|
|
||||||
global CondVar async_tick_start_cond_var = {0};
|
|
||||||
global Mutex async_tick_start_mutex = {0};
|
|
||||||
global Mutex async_tick_stop_mutex = {0};
|
|
||||||
global B32 async_loop_again = 0;
|
|
||||||
global B32 async_loop_again_high_priority = 0;
|
|
||||||
global B32 global_async_exit = 0;
|
|
||||||
thread_static B32 is_async_thread = 0;
|
|
||||||
|
|
||||||
internal void
|
|
||||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
|
||||||
{
|
|
||||||
ThreadNameF("main_thread");
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
//- rjf: set up async thread group info
|
|
||||||
async_tick_start_cond_var = cond_var_alloc();
|
|
||||||
async_tick_start_mutex = mutex_alloc();
|
|
||||||
async_tick_stop_mutex = mutex_alloc();
|
|
||||||
|
|
||||||
//- rjf: set up telemetry
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
local_persist char tm_data[MB(64)];
|
|
||||||
tmLoadLibrary(TM_RELEASE);
|
|
||||||
tmSetMaxThreadCount(256);
|
|
||||||
tmInitialize(sizeof(tm_data), tm_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: set up spall
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
spall_profile = spall_init_file_ex("spall_capture", 1, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: parse command line
|
|
||||||
String8List command_line_argument_strings = {0};
|
|
||||||
{
|
|
||||||
for EachIndex(idx, arguments_count)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &command_line_argument_strings, str8_cstring(arguments[idx]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
|
||||||
|
|
||||||
//- rjf: begin captures
|
|
||||||
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
|
|
||||||
if(capture)
|
|
||||||
{
|
|
||||||
ProfBeginCapture(arguments[0]);
|
|
||||||
ProfMsg(BUILD_TITLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: initialize all included layers
|
|
||||||
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
|
|
||||||
ac_init();
|
|
||||||
#endif
|
|
||||||
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
|
|
||||||
async_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
|
|
||||||
c_init();
|
|
||||||
#endif
|
|
||||||
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
|
|
||||||
fs_init();
|
|
||||||
#endif
|
|
||||||
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
|
|
||||||
mtx_init();
|
|
||||||
#endif
|
|
||||||
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
|
|
||||||
di_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
|
||||||
dmn_init();
|
|
||||||
#endif
|
|
||||||
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
|
|
||||||
ctrl_init();
|
|
||||||
#endif
|
|
||||||
#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL)
|
|
||||||
os_gfx_init();
|
|
||||||
#endif
|
|
||||||
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
|
||||||
fp_init();
|
|
||||||
#endif
|
|
||||||
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
|
|
||||||
r_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
|
|
||||||
fnt_init();
|
|
||||||
#endif
|
|
||||||
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
|
|
||||||
d_init();
|
|
||||||
#endif
|
|
||||||
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
|
|
||||||
rd_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: launch async threads
|
|
||||||
Thread *async_threads = 0;
|
|
||||||
U64 lane_broadcast_val = 0;
|
|
||||||
{
|
|
||||||
U64 num_main_threads = 1;
|
|
||||||
#if defined(CTRL_CORE_H)
|
|
||||||
num_main_threads += 1;
|
|
||||||
#endif
|
|
||||||
U64 num_async_threads = os_get_system_info()->logical_processor_count;
|
|
||||||
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
|
|
||||||
num_async_threads -= num_main_threads_clamped;
|
|
||||||
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
|
|
||||||
if(num_async_threads_string.size != 0)
|
|
||||||
{
|
|
||||||
try_u64_from_str8_c_rules(num_async_threads_string, &num_async_threads);
|
|
||||||
}
|
|
||||||
num_async_threads = Max(1, num_async_threads);
|
|
||||||
Barrier barrier = barrier_alloc(num_async_threads);
|
|
||||||
LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads);
|
|
||||||
async_threads_count = num_async_threads;
|
|
||||||
async_threads = push_array(scratch.arena, Thread, async_threads_count);
|
|
||||||
for EachIndex(idx, num_async_threads)
|
|
||||||
{
|
|
||||||
lane_ctxs[idx].lane_idx = idx;
|
|
||||||
lane_ctxs[idx].lane_count = async_threads_count;
|
|
||||||
lane_ctxs[idx].barrier = barrier;
|
|
||||||
lane_ctxs[idx].broadcast_memory = &lane_broadcast_val;
|
|
||||||
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: call into entry point
|
|
||||||
entry_point(&cmdline);
|
|
||||||
|
|
||||||
//- rjf: join async threads
|
|
||||||
ins_atomic_u32_inc_eval(&global_async_exit);
|
|
||||||
cond_var_broadcast(async_tick_start_cond_var);
|
|
||||||
for EachIndex(idx, async_threads_count)
|
|
||||||
{
|
|
||||||
thread_join(async_threads[idx], max_U64);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: end captures
|
|
||||||
if(capture)
|
|
||||||
{
|
|
||||||
ProfEndCapture();
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_alloc();
|
|
||||||
tctx_select(tctx);
|
|
||||||
entry_point(params);
|
|
||||||
tctx_release(tctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
update_tick_idx(void)
|
|
||||||
{
|
|
||||||
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
update(void)
|
|
||||||
{
|
|
||||||
ProfTick(0);
|
|
||||||
ins_atomic_u64_inc_eval(&global_update_tick_idx);
|
|
||||||
#if defined(FONT_CACHE_H)
|
|
||||||
fnt_frame();
|
|
||||||
#endif
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
|
||||||
B32 result = frame();
|
|
||||||
#else
|
|
||||||
B32 result = 0;
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
async_thread_entry_point(void *params)
|
|
||||||
{
|
|
||||||
LaneCtx lctx = *(LaneCtx *)params;
|
|
||||||
lane_ctx(lctx);
|
|
||||||
is_async_thread = 1;
|
|
||||||
ThreadNameF("async_thread_%I64u", lane_idx());
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// rjf: wait for signal if we need, otherwise reset loop signal & continue
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 0);
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
// rjf: do all ticks for all layers
|
|
||||||
ProfScope("async tick")
|
|
||||||
{
|
|
||||||
#if defined(ARTIFACT_CACHE_H)
|
|
||||||
ac_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(CONTENT_H)
|
|
||||||
c_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(FILE_STREAM_H)
|
|
||||||
fs_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(DBG_INFO_H)
|
|
||||||
di_async_tick();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: take exit signal; break if set
|
|
||||||
lane_sync();
|
|
||||||
B32 need_exit = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
need_exit = ins_atomic_u32_eval(&global_async_exit);
|
|
||||||
}
|
|
||||||
lane_sync_u64(&need_exit, 0);
|
|
||||||
if(need_exit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_ENTRY_POINT_H
|
|
||||||
#define BASE_ENTRY_POINT_H
|
|
||||||
|
|
||||||
internal void main_thread_base_entry_point(int argc, char **argv);
|
|
||||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
|
||||||
internal U64 update_tick_idx(void);
|
|
||||||
internal B32 update(void);
|
|
||||||
internal void async_thread_entry_point(void *params);
|
|
||||||
|
|
||||||
#endif // BASE_ENTRY_POINT_H
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MD5
|
|
||||||
|
|
||||||
#include "third_party/martins_hash/md5.h"
|
|
||||||
|
|
||||||
internal MD5
|
|
||||||
md5_from_data(String8 data)
|
|
||||||
{
|
|
||||||
md5_ctx ctx = {0};
|
|
||||||
md5_init(&ctx);
|
|
||||||
md5_update(&ctx, (void*)data.str, data.size);
|
|
||||||
MD5 result = {0};
|
|
||||||
md5_finish(&ctx, result.u8);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: SHA
|
|
||||||
|
|
||||||
#include "third_party/martins_hash/sha1.h"
|
|
||||||
#include "third_party/martins_hash/sha256.h"
|
|
||||||
|
|
||||||
internal SHA1
|
|
||||||
sha1_from_data(String8 data)
|
|
||||||
{
|
|
||||||
SHA1 result = {0};
|
|
||||||
{
|
|
||||||
sha1_ctx ctx = {0};
|
|
||||||
sha1_init(&ctx);
|
|
||||||
sha1_update(&ctx, data.str, data.size);
|
|
||||||
sha1_finish(&ctx, result.u8);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal SHA256
|
|
||||||
sha256_from_data(String8 data)
|
|
||||||
{
|
|
||||||
SHA256 result = {0};
|
|
||||||
{
|
|
||||||
sha256_ctx ctx = {0};
|
|
||||||
sha256_init(&ctx);
|
|
||||||
sha256_update(&ctx, data.str, data.size);
|
|
||||||
sha256_finish(&ctx, result.u8);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_HASH_H
|
|
||||||
#define BASE_HASH_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Hash Result Types
|
|
||||||
|
|
||||||
typedef union MD5 MD5;
|
|
||||||
union MD5
|
|
||||||
{
|
|
||||||
U8 u8[16];
|
|
||||||
U16 u16[8];
|
|
||||||
U32 u32[4];
|
|
||||||
U64 u64[2];
|
|
||||||
U128 u128;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union SHA1 SHA1;
|
|
||||||
union SHA1
|
|
||||||
{
|
|
||||||
U8 u8[20];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union SHA256 SHA256;
|
|
||||||
union SHA256
|
|
||||||
{
|
|
||||||
U8 u8[32];
|
|
||||||
U16 u16[16];
|
|
||||||
U32 u32[8];
|
|
||||||
U64 u64[4];
|
|
||||||
U128 u128[2];
|
|
||||||
U256 u256;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MD5
|
|
||||||
|
|
||||||
internal MD5 md5_from_data(String8 data);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: SHA
|
|
||||||
|
|
||||||
internal SHA1 sha1_from_data(String8 data);
|
|
||||||
internal SHA256 sha256_from_data(String8 data);
|
|
||||||
|
|
||||||
#endif // BASE_HASH_H
|
|
||||||
+18
-22
@@ -1,22 +1,18 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Base Includes
|
//~ rjf: Base Includes
|
||||||
|
|
||||||
#undef LAYER_COLOR
|
#undef RADDBG_LAYER_COLOR
|
||||||
#define LAYER_COLOR 0x3399ccff
|
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||||
|
|
||||||
#include "base_core.c"
|
#include "base_types.c"
|
||||||
#include "base_profile.c"
|
#include "base_markup.c"
|
||||||
#include "base_arena.c"
|
#include "base_arena.c"
|
||||||
#include "base_math.c"
|
#include "base_math.c"
|
||||||
#include "base_strings.c"
|
#include "base_string.c"
|
||||||
#include "base_hash.c"
|
#include "base_thread_context.c"
|
||||||
#include "base_threads.c"
|
#include "base_command_line.c"
|
||||||
#include "base_thread_context.c"
|
#include "base_arena_dev.c"
|
||||||
#include "base_command_line.c"
|
#include "base_bits.c"
|
||||||
#include "base_markup.c"
|
|
||||||
#include "base_meta.c"
|
|
||||||
#include "base_log.c"
|
|
||||||
#include "base_entry_point.c"
|
|
||||||
|
|||||||
+23
-26
@@ -1,26 +1,23 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_INC_H
|
#ifndef BASE_INC_H
|
||||||
#define BASE_INC_H
|
#define BASE_INC_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Base Includes
|
//~ rjf: Base Includes
|
||||||
|
|
||||||
#include "base_context_cracking.h"
|
#include "base_context_cracking.h"
|
||||||
|
#include "base_types.h"
|
||||||
#include "base_core.h"
|
#include "base_markup.h"
|
||||||
#include "base_profile.h"
|
#include "base_ins.h"
|
||||||
#include "base_arena.h"
|
#include "base_linked_lists.h"
|
||||||
#include "base_math.h"
|
#include "base_arena.h"
|
||||||
#include "base_strings.h"
|
#include "base_math.h"
|
||||||
#include "base_hash.h"
|
#include "base_string.h"
|
||||||
#include "base_threads.h"
|
#include "base_thread_context.h"
|
||||||
#include "base_thread_context.h"
|
#include "base_command_line.h"
|
||||||
#include "base_command_line.h"
|
#include "base_arena_dev.h"
|
||||||
#include "base_markup.h"
|
#include "base_bits.h"
|
||||||
#include "base_meta.h"
|
|
||||||
#include "base_log.h"
|
#endif // BASE_INC_H
|
||||||
#include "base_entry_point.h"
|
|
||||||
|
|
||||||
#endif // BASE_INC_H
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_INS_H
|
||||||
|
#define BASE_INS_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Implementations of Intrinsics
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
|
||||||
|
# include <windows.h>
|
||||||
|
# include <tmmintrin.h>
|
||||||
|
# include <wmmintrin.h>
|
||||||
|
# include <intrin.h>
|
||||||
|
|
||||||
|
# if ARCH_X64
|
||||||
|
# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(x), 0)
|
||||||
|
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||||
|
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||||
|
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||||
|
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
|
||||||
|
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||||
|
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
|
||||||
|
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif OS_LINUX
|
||||||
|
|
||||||
|
# if ARCH_X64
|
||||||
|
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
// TODO(allen):
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Intrinsic Checks
|
||||||
|
|
||||||
|
#if ARCH_X64
|
||||||
|
|
||||||
|
# if !defined(ins_atomic_u64_inc_eval)
|
||||||
|
# error missing: ins_atomic_u64_inc_eval
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error the intrinsic set for this arch is not developed
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif //BASE_INS_H
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_LINKED_LIST_H
|
||||||
|
#define BASE_LINKED_LIST_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helpers
|
||||||
|
|
||||||
|
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
|
||||||
|
#define SetNil(nil,p) ((p) = nil)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Base Macros
|
||||||
|
|
||||||
|
//- rjf: Base Doubly-Linked-List Macros
|
||||||
|
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
|
||||||
|
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
|
||||||
|
CheckNil(nil,p) ? \
|
||||||
|
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
|
||||||
|
((p)==(l)) ? \
|
||||||
|
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
|
||||||
|
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
|
||||||
|
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
|
||||||
|
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
|
||||||
|
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
|
||||||
|
((n) == (l) ? (l) = (l)->prev : (0)),\
|
||||||
|
(CheckNil(nil,(n)->prev) ? (0) :\
|
||||||
|
((n)->prev->next = (n)->next)),\
|
||||||
|
(CheckNil(nil,(n)->next) ? (0) :\
|
||||||
|
((n)->next->prev = (n)->prev)))
|
||||||
|
|
||||||
|
//- rjf: Base Singly-Linked-List Queue Macros
|
||||||
|
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||||
|
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||||
|
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
|
||||||
|
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||||
|
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||||
|
((n)->next=(f),(f)=(n)))
|
||||||
|
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
|
||||||
|
(SetNil(nil,f),SetNil(nil,l)):\
|
||||||
|
((f)=(f)->next))
|
||||||
|
|
||||||
|
//- rjf: Base Singly-Linked-List Stack Macros
|
||||||
|
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
|
||||||
|
#define SLLStackPop_N(f,next) ((f)=(f)->next)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Convenience Wrappers
|
||||||
|
|
||||||
|
//- rjf: Doubly-Linked-List Wrappers
|
||||||
|
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||||
|
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||||
|
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||||
|
|
||||||
|
//- rjf: Singly-Linked-List Queue Wrappers
|
||||||
|
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
|
||||||
|
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
|
||||||
|
|
||||||
|
//- rjf: Singly-Linked-List Stack Wrappers
|
||||||
|
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
|
||||||
|
#define SLLStackPop(f) SLLStackPop_N(f,next)
|
||||||
|
|
||||||
|
#endif //BASE_LINKED_LIST_H
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals/Thread-Locals
|
|
||||||
|
|
||||||
C_LINKAGE thread_static Log *log_active;
|
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
|
||||||
C_LINKAGE thread_static Log *log_active = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Creation/Selection
|
|
||||||
|
|
||||||
internal Log *
|
|
||||||
log_alloc(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
Log *log = push_array(arena, Log, 1);
|
|
||||||
log->arena = arena;
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_release(Log *log)
|
|
||||||
{
|
|
||||||
arena_release(log->arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_select(Log *log)
|
|
||||||
{
|
|
||||||
log_active = log;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Building/Clearing
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_msg(LogMsgKind kind, String8 string)
|
|
||||||
{
|
|
||||||
if(log_active != 0 && log_active->top_scope != 0)
|
|
||||||
{
|
|
||||||
String8 string_copy = push_str8_copy(log_active->arena, string);
|
|
||||||
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_msgf(LogMsgKind kind, char *fmt, ...)
|
|
||||||
{
|
|
||||||
if(log_active != 0)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
log_msg(kind, string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Scopes
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_scope_begin(void)
|
|
||||||
{
|
|
||||||
if(log_active != 0)
|
|
||||||
{
|
|
||||||
U64 pos = arena_pos(log_active->arena);
|
|
||||||
LogScope *scope = push_array(log_active->arena, LogScope, 1);
|
|
||||||
scope->pos = pos;
|
|
||||||
SLLStackPush(log_active->top_scope, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal LogScopeResult
|
|
||||||
log_scope_end(Arena *arena)
|
|
||||||
{
|
|
||||||
LogScopeResult result = {0};
|
|
||||||
if(log_active != 0)
|
|
||||||
{
|
|
||||||
LogScope *scope = log_active->top_scope;
|
|
||||||
if(scope != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(log_active->top_scope);
|
|
||||||
if(arena != 0)
|
|
||||||
{
|
|
||||||
for EachEnumVal(LogMsgKind, kind)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
|
|
||||||
result.strings[kind] = indented_from_string(arena, result_unindented);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arena_pop_to(log_active->arena, scope->pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_LOG_H
|
|
||||||
#define BASE_LOG_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Types
|
|
||||||
|
|
||||||
typedef enum LogMsgKind
|
|
||||||
{
|
|
||||||
LogMsgKind_Info,
|
|
||||||
LogMsgKind_UserError,
|
|
||||||
LogMsgKind_COUNT
|
|
||||||
}
|
|
||||||
LogMsgKind;
|
|
||||||
|
|
||||||
typedef struct LogScope LogScope;
|
|
||||||
struct LogScope
|
|
||||||
{
|
|
||||||
LogScope *next;
|
|
||||||
U64 pos;
|
|
||||||
String8List strings[LogMsgKind_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct LogScopeResult LogScopeResult;
|
|
||||||
struct LogScopeResult
|
|
||||||
{
|
|
||||||
String8 strings[LogMsgKind_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Log Log;
|
|
||||||
struct Log
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
LogScope *top_scope;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Creation/Selection
|
|
||||||
|
|
||||||
internal Log *log_alloc(void);
|
|
||||||
internal void log_release(Log *log);
|
|
||||||
internal void log_select(Log *log);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Building
|
|
||||||
|
|
||||||
internal void log_msg(LogMsgKind kind, String8 string);
|
|
||||||
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
|
|
||||||
#define log_info(s) log_msg(LogMsgKind_Info, (s))
|
|
||||||
#define log_infof(...) log_msgf(LogMsgKind_Info, __VA_ARGS__)
|
|
||||||
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
|
|
||||||
#define log_user_errorf(...) log_msgf(LogMsgKind_UserError, __VA_ARGS__)
|
|
||||||
|
|
||||||
#define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
|
|
||||||
#define LogInfoNamedBlockF(...) DeferLoop((log_infof(__VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Scopes
|
|
||||||
|
|
||||||
internal void log_scope_begin(void);
|
|
||||||
internal LogScopeResult log_scope_end(Arena *arena);
|
|
||||||
|
|
||||||
#endif // BASE_LOG_H
|
|
||||||
+2
-21
@@ -1,21 +1,2 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 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);
|
|
||||||
}
|
|
||||||
|
|||||||
+79
-22
@@ -1,22 +1,79 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_MARKUP_H
|
#ifndef BASE_MARKUP_H
|
||||||
#define BASE_MARKUP_H
|
#define BASE_MARKUP_H
|
||||||
|
|
||||||
#define RADDBG_MARKUP_IMPLEMENTATION
|
////////////////////////////////
|
||||||
#define RADDBG_MARKUP_VSNPRINTF raddbg_vsnprintf
|
//~ rjf: Zero Settings
|
||||||
#if OS_LINUX
|
|
||||||
# define RADDBG_MARKUP_STUBS
|
#if !defined(PROFILE_TELEMETRY)
|
||||||
#endif
|
# define PROFILE_TELEMETRY 0
|
||||||
#include "lib_raddbg_markup/raddbg_markup.h"
|
#endif
|
||||||
|
|
||||||
#if !defined(LAYER_COLOR)
|
#if !defined(MARKUP_LAYER_COLOR)
|
||||||
# define LAYER_COLOR 0x404040ff
|
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
internal void set_thread_name(String8 string);
|
////////////////////////////////
|
||||||
internal void set_thread_namef(char *fmt, ...);
|
//~ rjf: Third Party Includes
|
||||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
|
|
||||||
|
#if PROFILE_TELEMETRY
|
||||||
#endif // BASE_MARKUP_H
|
# include "rad_tm.h"
|
||||||
|
# if OS_WINDOWS
|
||||||
|
# pragma comment(lib, "rad_tm_win64.lib")
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Telemetry Profile Defines
|
||||||
|
|
||||||
|
#if PROFILE_TELEMETRY
|
||||||
|
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
||||||
|
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||||
|
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
||||||
|
# define ProfTick(...) tmTick(0)
|
||||||
|
# define ProfIsCapturing(...) tmRunning()
|
||||||
|
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
||||||
|
# define ProfEndCapture(...) tmClose(0)
|
||||||
|
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
||||||
|
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||||
|
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
||||||
|
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
||||||
|
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||||
|
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||||
|
# define ProfColor(color) tmZoneColorSticky(color)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Zeroify Undefined Defines
|
||||||
|
|
||||||
|
#if !defined(ProfBegin)
|
||||||
|
# define ProfBegin(...) (0)
|
||||||
|
# define ProfBeginDynamic(...) (0)
|
||||||
|
# define ProfEnd(...) (0)
|
||||||
|
# define ProfTick(...) (0)
|
||||||
|
# define ProfIsCapturing(...) (0)
|
||||||
|
# define ProfBeginCapture(...) (0)
|
||||||
|
# define ProfEndCapture(...) (0)
|
||||||
|
# define ProfThreadName(...) (0)
|
||||||
|
# define ProfMsg(...) (0)
|
||||||
|
# define ProfBeginLockWait(...) (0)
|
||||||
|
# define ProfEndLockWait(...) (0)
|
||||||
|
# define ProfLockTake(...) (0)
|
||||||
|
# define ProfLockDrop(...) (0)
|
||||||
|
# define ProfColor(...) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helper Wrappers
|
||||||
|
|
||||||
|
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
||||||
|
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: General Markup
|
||||||
|
|
||||||
|
#define ThreadName(...) (ProfThreadName(__VA_ARGS__))
|
||||||
|
|
||||||
|
#endif // BASE_MARKUP_H
|
||||||
|
|||||||
+616
-830
File diff suppressed because it is too large
Load Diff
+16
-62
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_MATH_H
|
#ifndef BASE_MATH_H
|
||||||
@@ -327,29 +327,7 @@ union Rng2S64
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range List Types
|
//~ rjf: List Types
|
||||||
|
|
||||||
typedef struct Rng1U64Node Rng1U64Node;
|
|
||||||
struct Rng1U64Node
|
|
||||||
{
|
|
||||||
Rng1U64Node *next;
|
|
||||||
Rng1U64 v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1U64List Rng1U64List;
|
|
||||||
struct Rng1U64List
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
Rng1U64Node *first;
|
|
||||||
Rng1U64Node *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1U64Array Rng1U64Array;
|
|
||||||
struct Rng1U64Array
|
|
||||||
{
|
|
||||||
Rng1U64 *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1S64Node Rng1S64Node;
|
typedef struct Rng1S64Node Rng1S64Node;
|
||||||
struct Rng1S64Node
|
struct Rng1S64Node
|
||||||
@@ -374,20 +352,19 @@ struct Rng1S64Array
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Scalar Math Ops
|
//~ rjf: Scalar Ops
|
||||||
|
|
||||||
#define abs_s64(v) (S64)llabs(v)
|
#define abs_s64(v) (S64)llabs(v)
|
||||||
|
|
||||||
#define sqrt_f32(v) sqrtf(v)
|
#define sqrt_f32(v) sqrtf(v)
|
||||||
#define cbrt_f32(v) cbrtf(v)
|
|
||||||
#define mod_f32(a, b) fmodf((a), (b))
|
#define mod_f32(a, b) fmodf((a), (b))
|
||||||
#define pow_f32(b, e) powf((b), (e))
|
#define pow_f32(b, e) powf((b), (e))
|
||||||
#define ceil_f32(v) ceilf(v)
|
#define ceil_f32(v) ceilf(v)
|
||||||
#define floor_f32(v) floorf(v)
|
#define floor_f32(v) floorf(v)
|
||||||
#define round_f32(v) roundf(v)
|
#define round_f32(v) roundf(v)
|
||||||
#define abs_f32(v) fabsf(v)
|
#define abs_f32(v) fabsf(v)
|
||||||
#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f))
|
#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f)
|
||||||
#define turns_from_radians_f32(v) ((v)/(2*3.1415926535897f))
|
#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f)
|
||||||
#define degrees_from_turns_f32(v) ((v)*360.f)
|
#define degrees_from_turns_f32(v) ((v)*360.f)
|
||||||
#define turns_from_degrees_f32(v) ((v)/360.f)
|
#define turns_from_degrees_f32(v) ((v)/360.f)
|
||||||
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
|
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
|
||||||
@@ -397,15 +374,14 @@ struct Rng1S64Array
|
|||||||
#define tan_f32(v) tanf(radians_from_turns_f32(v))
|
#define tan_f32(v) tanf(radians_from_turns_f32(v))
|
||||||
|
|
||||||
#define sqrt_f64(v) sqrt(v)
|
#define sqrt_f64(v) sqrt(v)
|
||||||
#define cbrt_f64(v) cbrt(v)
|
|
||||||
#define mod_f64(a, b) fmod((a), (b))
|
#define mod_f64(a, b) fmod((a), (b))
|
||||||
#define pow_f64(b, e) pow((b), (e))
|
#define pow_f64(b, e) pow((b), (e))
|
||||||
#define ceil_f64(v) ceil(v)
|
#define ceil_f64(v) ceil(v)
|
||||||
#define floor_f64(v) floor(v)
|
#define floor_f64(v) floor(v)
|
||||||
#define round_f64(v) round(v)
|
#define round_f64(v) round(v)
|
||||||
#define abs_f64(v) fabs(v)
|
#define abs_f64(v) fabs(v)
|
||||||
#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897))
|
#define radians_from_turns_f64(v) ((v)*2*3.1415926535897)
|
||||||
#define turns_from_radians_f64(v) ((v)/(2*3.1415926535897))
|
#define turns_from_radians_f64(v) ((v)/2*3.1415926535897)
|
||||||
#define degrees_from_turns_f64(v) ((v)*360.0)
|
#define degrees_from_turns_f64(v) ((v)*360.0)
|
||||||
#define turns_from_degrees_f64(v) ((v)/360.0)
|
#define turns_from_degrees_f64(v) ((v)/360.0)
|
||||||
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
|
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
|
||||||
@@ -443,6 +419,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s);
|
|||||||
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
|
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
|
||||||
internal S64 length_squared_2s64(Vec2S64 v);
|
internal S64 length_squared_2s64(Vec2S64 v);
|
||||||
internal S64 length_2s64(Vec2S64 v);
|
internal S64 length_2s64(Vec2S64 v);
|
||||||
|
internal Vec2S64 normalize_2s64(Vec2S64 v);
|
||||||
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
|
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
|
||||||
|
|
||||||
#define v2s32(x, y) vec_2s32((x), (y))
|
#define v2s32(x, y) vec_2s32((x), (y))
|
||||||
@@ -455,6 +432,7 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s);
|
|||||||
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
|
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
|
||||||
internal S32 length_squared_2s32(Vec2S32 v);
|
internal S32 length_squared_2s32(Vec2S32 v);
|
||||||
internal S32 length_2s32(Vec2S32 v);
|
internal S32 length_2s32(Vec2S32 v);
|
||||||
|
internal Vec2S32 normalize_2s32(Vec2S32 v);
|
||||||
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
|
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
|
||||||
|
|
||||||
#define v2s16(x, y) vec_2s16((x), (y))
|
#define v2s16(x, y) vec_2s16((x), (y))
|
||||||
@@ -467,6 +445,7 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s);
|
|||||||
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
|
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
|
||||||
internal S16 length_squared_2s16(Vec2S16 v);
|
internal S16 length_squared_2s16(Vec2S16 v);
|
||||||
internal S16 length_2s16(Vec2S16 v);
|
internal S16 length_2s16(Vec2S16 v);
|
||||||
|
internal Vec2S16 normalize_2s16(Vec2S16 v);
|
||||||
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
|
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
|
||||||
|
|
||||||
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
|
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
|
||||||
@@ -482,7 +461,6 @@ internal F32 length_3f32(Vec3F32 v);
|
|||||||
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
||||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
||||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
||||||
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m);
|
|
||||||
|
|
||||||
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
||||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
||||||
@@ -494,6 +472,7 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s);
|
|||||||
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
|
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
|
||||||
internal S32 length_squared_3s32(Vec3S32 v);
|
internal S32 length_squared_3s32(Vec3S32 v);
|
||||||
internal S32 length_3s32(Vec3S32 v);
|
internal S32 length_3s32(Vec3S32 v);
|
||||||
|
internal Vec3S32 normalize_3s32(Vec3S32 v);
|
||||||
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
|
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
|
||||||
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
|
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
|
||||||
|
|
||||||
@@ -520,6 +499,7 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s);
|
|||||||
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
|
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
|
||||||
internal S32 length_squared_4s32(Vec4S32 v);
|
internal S32 length_squared_4s32(Vec4S32 v);
|
||||||
internal S32 length_4s32(Vec4S32 v);
|
internal S32 length_4s32(Vec4S32 v);
|
||||||
|
internal Vec4S32 normalize_4s32(Vec4S32 v);
|
||||||
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
|
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -541,7 +521,6 @@ internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b);
|
|||||||
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
||||||
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
||||||
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
||||||
internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range Ops
|
//~ rjf: Range Ops
|
||||||
@@ -650,46 +629,21 @@ internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b);
|
|||||||
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
|
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Color Operations
|
//~ rjf: Miscellaneous Ops
|
||||||
|
|
||||||
//- rjf: hsv <-> rgb
|
|
||||||
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
|
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
|
||||||
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
|
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
|
||||||
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
|
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
|
||||||
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
|
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
|
||||||
|
|
||||||
//- rjf: srgb <-> linear
|
|
||||||
internal Vec3F32 linear_from_srgb(Vec3F32 srgb);
|
|
||||||
internal Vec3F32 srgb_from_linear(Vec3F32 linear);
|
|
||||||
internal Vec4F32 linear_from_srgba(Vec4F32 srgba);
|
|
||||||
internal Vec4F32 srgba_from_linear(Vec4F32 linear);
|
|
||||||
|
|
||||||
//- rjf: oklab <-> linear
|
|
||||||
internal Vec3F32 oklab_from_linear(Vec3F32 linear);
|
|
||||||
internal Vec3F32 linear_from_oklab(Vec3F32 oklab);
|
|
||||||
internal Vec4F32 oklab_from_lineara(Vec4F32 lineara);
|
|
||||||
internal Vec4F32 lineara_from_oklab(Vec4F32 oklab);
|
|
||||||
|
|
||||||
//- rjf: rgba <-> u32
|
|
||||||
internal U32 u32_from_rgba(Vec4F32 rgba);
|
|
||||||
internal Vec4F32 rgba_from_u32(U32 hex);
|
internal Vec4F32 rgba_from_u32(U32 hex);
|
||||||
|
internal U32 u32_from_rgba(Vec4F32 rgba);
|
||||||
|
|
||||||
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
|
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: List Type Functions
|
//~ rjf: List Type Functions
|
||||||
|
|
||||||
internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
|
|
||||||
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
|
|
||||||
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
|
|
||||||
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
|
|
||||||
internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value);
|
|
||||||
|
|
||||||
internal 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);
|
||||||
|
|
||||||
////////////////////////////////
|
#endif // BASE_MATH_H
|
||||||
//~ rjf: N -> M Element Subdivision
|
|
||||||
|
|
||||||
internal Rng1U64 m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count);
|
|
||||||
|
|
||||||
#endif //BASE_MATH_H
|
|
||||||
|
|||||||
@@ -1,421 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Lookups
|
|
||||||
|
|
||||||
internal Member *
|
|
||||||
member_from_name(Type *type, String8 name)
|
|
||||||
{
|
|
||||||
Member *member = &member_nil;
|
|
||||||
if(type->members != 0 && name.size != 0)
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < type->count; idx += 1)
|
|
||||||
{
|
|
||||||
if(str8_match(type->members[idx].name, name, 0))
|
|
||||||
{
|
|
||||||
member = &type->members[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info * Instance Operations
|
|
||||||
|
|
||||||
internal void
|
|
||||||
typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
typedef struct RebaseTypeTask RebaseTypeTask;
|
|
||||||
struct RebaseTypeTask
|
|
||||||
{
|
|
||||||
RebaseTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U8 *ptr;
|
|
||||||
};
|
|
||||||
RebaseTypeTask start_task = {0, type, data.str};
|
|
||||||
RebaseTypeTask *first_task = &start_task;
|
|
||||||
RebaseTypeTask *last_task = first_task;
|
|
||||||
for(RebaseTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
*(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr));
|
|
||||||
}break;
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
|
||||||
{
|
|
||||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->ptr = t->ptr + t->type->direct->size * idx;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
|
||||||
{
|
|
||||||
Member *member = &t->type->members[idx];
|
|
||||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
|
||||||
task->type = member->type;
|
|
||||||
task->ptr = t->ptr + member->value;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List strings = {0};
|
|
||||||
str8_serial_begin(scratch.arena, &strings);
|
|
||||||
{
|
|
||||||
typedef struct SerializeTypeTask SerializeTypeTask;
|
|
||||||
struct SerializeTypeTask
|
|
||||||
{
|
|
||||||
SerializeTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U64 count;
|
|
||||||
U8 *src;
|
|
||||||
Type *containing_type;
|
|
||||||
U8 *containing_ptr;
|
|
||||||
B32 is_post_header;
|
|
||||||
};
|
|
||||||
SerializeTypeTask start_task = {0, type, 1, data.str};
|
|
||||||
SerializeTypeTask *first_task = &start_task;
|
|
||||||
SerializeTypeTask *last_task = first_task;
|
|
||||||
for(SerializeTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
//- rjf: leaf -> just copy the data directly
|
|
||||||
default:
|
|
||||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
|
||||||
{
|
|
||||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise just write as plain data
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
// rjf: unpack info about this pointer
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
|
||||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
|
||||||
{
|
|
||||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
|
||||||
{
|
|
||||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: indexification -> subtract base, divide direct size, write index
|
|
||||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size);
|
|
||||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: offsetification -> subtract base, write offsets
|
|
||||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base);
|
|
||||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
|
||||||
// delimit our size, so push a new post-header task for pointer.
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type;
|
|
||||||
task->count = t->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
task->is_post_header = 1;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
|
||||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
|
||||||
// destination contents
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
|
||||||
{
|
|
||||||
// rjf: determine count of this pointer
|
|
||||||
U64 count = 0;
|
|
||||||
{
|
|
||||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
|
||||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push task
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = count;
|
|
||||||
task->src = *(void **)t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: catch-all: write pointer value
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: arrays -> descend to underlying type, + count
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->type->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: struct -> descend to members
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
U64 off = 0;
|
|
||||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
|
||||||
{
|
|
||||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
|
||||||
{
|
|
||||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->members[member_idx].type;
|
|
||||||
task->count = 1;
|
|
||||||
task->src = t->src + idx*t->type->size + t->type->members[member_idx].value;
|
|
||||||
task->containing_type = t->type;
|
|
||||||
task->containing_ptr = t->src;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: enum -> descend to basic type interpretation
|
|
||||||
case TypeKind_Enum:
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String8 result = str8_serial_end(arena, &strings);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
result.size = type->size;
|
|
||||||
result.str = push_array(arena, U8, result.size);
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
typedef struct DeserializeTypeTask DeserializeTypeTask;
|
|
||||||
struct DeserializeTypeTask
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U64 count;
|
|
||||||
U8 *dst;
|
|
||||||
Type *containing_type;
|
|
||||||
U8 *containing_ptr;
|
|
||||||
B32 is_post_header;
|
|
||||||
};
|
|
||||||
U64 read_off = 0;
|
|
||||||
DeserializeTypeTask start_task = {0, type, 1, result.str};
|
|
||||||
DeserializeTypeTask *first_task = &start_task;
|
|
||||||
DeserializeTypeTask *last_task = first_task;
|
|
||||||
for(DeserializeTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
U8 *t_src = data.str + read_off;
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
//- rjf: leaf -> copy the data directly
|
|
||||||
default:
|
|
||||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
|
||||||
{
|
|
||||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
|
||||||
read_off += t->type->size*t->count;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
// rjf: unpack info about this pointer
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
|
||||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
|
||||||
{
|
|
||||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
|
||||||
{
|
|
||||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: indexification -> add base, multiply direct size
|
|
||||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size;
|
|
||||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
|
||||||
read_off += sizeof(ptr_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: offsetification -> subtract base, write offsets
|
|
||||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base;
|
|
||||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
|
||||||
read_off += sizeof(ptr_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
|
||||||
// delimit our size, so push a new post-header task for pointer.
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type;
|
|
||||||
task->count = t->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
task->is_post_header = 1;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
|
||||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
|
||||||
// destination contents
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
|
||||||
{
|
|
||||||
// rjf: determine count of this pointer
|
|
||||||
U64 count = 0;
|
|
||||||
{
|
|
||||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
|
||||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: allocate buffer for pointer destination; write address into pointer value slot
|
|
||||||
U64 ptr_dest_buffer_size = (count+1)*t->type->direct->size;
|
|
||||||
U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size);
|
|
||||||
MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer));
|
|
||||||
|
|
||||||
// rjf: push task
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = count;
|
|
||||||
task->dst = ptr_dest_buffer;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: catch-all: read pointer value
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
|
||||||
read_off += t->type->size*t->count;
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: arrays -> descend to underlying type, + count
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->type->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: struct -> descend to members
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
|
||||||
{
|
|
||||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
|
||||||
{
|
|
||||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->members[member_idx].type;
|
|
||||||
task->count = 1;
|
|
||||||
task->dst = t->dst + idx*t->type->size + t->type->members[member_idx].value;
|
|
||||||
task->containing_type = t->type;
|
|
||||||
task->containing_ptr = t->dst;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: enum -> descend to basic type interpretation
|
|
||||||
case TypeKind_Enum:
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(params->advance_out != 0)
|
|
||||||
{
|
|
||||||
params->advance_out[0] = read_off;
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 data_srlz = serialized_from_typed_data(scratch.arena, type, data, params);
|
|
||||||
String8 data_copy = deserialized_from_typed_data(arena, type, data_srlz, params);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return data_copy;
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_META_H
|
|
||||||
#define BASE_META_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Meta Markup Features
|
|
||||||
|
|
||||||
#define EmbedFile(name, path)
|
|
||||||
#define TweakB32(name, default) (TWEAK_##name)
|
|
||||||
#define TweakF32(name, default, min, max) (TWEAK_##name)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Tweak Info Tables
|
|
||||||
|
|
||||||
typedef struct TweakB32Info TweakB32Info;
|
|
||||||
struct TweakB32Info
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
B32 default_value;
|
|
||||||
B32 *value_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakF32Info TweakF32Info;
|
|
||||||
struct TweakF32Info
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
F32 default_value;
|
|
||||||
Rng1F32 value_range;
|
|
||||||
F32 *value_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakB32InfoTable TweakB32InfoTable;
|
|
||||||
struct TweakB32InfoTable
|
|
||||||
{
|
|
||||||
TweakB32Info *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakF32InfoTable TweakF32InfoTable;
|
|
||||||
struct TweakF32InfoTable
|
|
||||||
{
|
|
||||||
TweakF32Info *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct EmbedInfo EmbedInfo;
|
|
||||||
struct EmbedInfo
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 *data;
|
|
||||||
U128 *hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct EmbedInfoTable EmbedInfoTable;
|
|
||||||
struct EmbedInfoTable
|
|
||||||
{
|
|
||||||
EmbedInfo *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Types
|
|
||||||
|
|
||||||
typedef enum TypeKind
|
|
||||||
{
|
|
||||||
TypeKind_Null,
|
|
||||||
|
|
||||||
// rjf: leaves
|
|
||||||
TypeKind_Void, TypeKind_FirstLeaf = TypeKind_Void,
|
|
||||||
TypeKind_U8,
|
|
||||||
TypeKind_U16,
|
|
||||||
TypeKind_U32,
|
|
||||||
TypeKind_U64,
|
|
||||||
TypeKind_S8,
|
|
||||||
TypeKind_S16,
|
|
||||||
TypeKind_S32,
|
|
||||||
TypeKind_S64,
|
|
||||||
TypeKind_B8,
|
|
||||||
TypeKind_B16,
|
|
||||||
TypeKind_B32,
|
|
||||||
TypeKind_B64,
|
|
||||||
TypeKind_F32,
|
|
||||||
TypeKind_F64, TypeKind_LastLeaf = TypeKind_F64,
|
|
||||||
|
|
||||||
// rjf: operators
|
|
||||||
TypeKind_Ptr,
|
|
||||||
TypeKind_Array,
|
|
||||||
|
|
||||||
// rjf: user-defined-types
|
|
||||||
TypeKind_Struct,
|
|
||||||
TypeKind_Union,
|
|
||||||
TypeKind_Enum,
|
|
||||||
|
|
||||||
TypeKind_COUNT
|
|
||||||
}
|
|
||||||
TypeKind;
|
|
||||||
|
|
||||||
typedef U32 TypeFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
TypeFlag_IsPlainText = (1<<0),
|
|
||||||
TypeFlag_IsCodeText = (1<<1),
|
|
||||||
TypeFlag_IsPathText = (1<<2),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef U32 MemberFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
MemberFlag_DoNotSerialize = (1<<0),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Type Type;
|
|
||||||
typedef struct Member Member;
|
|
||||||
struct Member
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 pretty_name;
|
|
||||||
Type *type;
|
|
||||||
U64 value;
|
|
||||||
MemberFlags flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Type Type;
|
|
||||||
struct Type
|
|
||||||
{
|
|
||||||
TypeKind kind;
|
|
||||||
TypeFlags flags;
|
|
||||||
U64 size;
|
|
||||||
Type *direct;
|
|
||||||
String8 name;
|
|
||||||
String8 count_delimiter_name; // gathered from surrounding members, turns *->[1] into *->[N]
|
|
||||||
U64 count;
|
|
||||||
Member *members;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Serialization Parameters
|
|
||||||
|
|
||||||
typedef struct TypeSerializePtrRefInfo TypeSerializePtrRefInfo;
|
|
||||||
struct TypeSerializePtrRefInfo
|
|
||||||
{
|
|
||||||
Type *type; // pointers to this
|
|
||||||
void *indexify_base; // can be indexified using this
|
|
||||||
void *offsetify_base; // can be offsetified using this
|
|
||||||
void *nil_ptr; // is terminal if matching 0 or this
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TypeSerializeParams TypeSerializeParams;
|
|
||||||
struct TypeSerializeParams
|
|
||||||
{
|
|
||||||
U64 *advance_out;
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_infos;
|
|
||||||
U64 ptr_ref_infos_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Name -> Type Info
|
|
||||||
|
|
||||||
#define type(T) (&T##__type)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Table Initializer Helpers
|
|
||||||
|
|
||||||
#define member_lit_comp(S, ti, m, ...) {str8_lit_comp(#m), {0}, (ti), OffsetOf(S, m), __VA_ARGS__}
|
|
||||||
#define struct_members(S) read_only global Member S##__members[] =
|
|
||||||
#define struct_type(S, ...) read_only global Type S##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#S), {0}, ArrayCount(S##__members), S##__members, __VA_ARGS__}
|
|
||||||
#define named_struct_type(name, S, ...) read_only global Type name##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#name), {0}, ArrayCount(name##__members), name##__members, __VA_ARGS__}
|
|
||||||
#define ptr_type(name, ti, ...) read_only global Type name = {TypeKind_Ptr, 0, sizeof(void *), (ti), __VA_ARGS__}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
read_only global Type type_nil = {TypeKind_Null, 0, 0, &type_nil};
|
|
||||||
read_only global Member member_nil = {{0}, {0}, &type_nil};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Built-In Types
|
|
||||||
|
|
||||||
//- rjf: leaves
|
|
||||||
read_only global Type void__type = {TypeKind_Void, 0, 0, &type_nil, str8_lit_comp("void")};
|
|
||||||
read_only global Type U8__type = {TypeKind_U8, 0, sizeof(U8), &type_nil, str8_lit_comp("U8")};
|
|
||||||
read_only global Type U16__type = {TypeKind_U16, 0, sizeof(U16), &type_nil, str8_lit_comp("U16")};
|
|
||||||
read_only global Type U32__type = {TypeKind_U32, 0, sizeof(U32), &type_nil, str8_lit_comp("U32")};
|
|
||||||
read_only global Type U64__type = {TypeKind_U64, 0, sizeof(U64), &type_nil, str8_lit_comp("U64")};
|
|
||||||
read_only global Type S8__type = {TypeKind_S8, 0, sizeof(S8), &type_nil, str8_lit_comp("S8")};
|
|
||||||
read_only global Type S16__type = {TypeKind_S16, 0, sizeof(S16), &type_nil, str8_lit_comp("S16")};
|
|
||||||
read_only global Type S32__type = {TypeKind_S32, 0, sizeof(S32), &type_nil, str8_lit_comp("S32")};
|
|
||||||
read_only global Type S64__type = {TypeKind_S64, 0, sizeof(S64), &type_nil, str8_lit_comp("S64")};
|
|
||||||
read_only global Type B8__type = {TypeKind_B8, 0, sizeof(B8), &type_nil, str8_lit_comp("B8")};
|
|
||||||
read_only global Type B16__type = {TypeKind_B16, 0, sizeof(B16), &type_nil, str8_lit_comp("B16")};
|
|
||||||
read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, str8_lit_comp("B32")};
|
|
||||||
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")};
|
|
||||||
read_only global Type F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
|
|
||||||
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
|
|
||||||
read_only global Type *type_kind_type_table[] =
|
|
||||||
{
|
|
||||||
&type_nil,
|
|
||||||
type(void),
|
|
||||||
type(U8),
|
|
||||||
type(U16),
|
|
||||||
type(U32),
|
|
||||||
type(U64),
|
|
||||||
type(S8),
|
|
||||||
type(S16),
|
|
||||||
type(S32),
|
|
||||||
type(S64),
|
|
||||||
type(B8),
|
|
||||||
type(B16),
|
|
||||||
type(B32),
|
|
||||||
type(B64),
|
|
||||||
type(F32),
|
|
||||||
type(F64),
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
//- rjf: Rng1U64
|
|
||||||
struct_members(Rng1U64)
|
|
||||||
{
|
|
||||||
member_lit_comp(Rng1U64, type(U64), min),
|
|
||||||
member_lit_comp(Rng1U64, type(U64), max),
|
|
||||||
};
|
|
||||||
struct_type(Rng1U64);
|
|
||||||
|
|
||||||
//- rjf: String8
|
|
||||||
ptr_type(String8__str_ptr_type, type(U8), str8_lit_comp("size"));
|
|
||||||
struct_members(String8)
|
|
||||||
{
|
|
||||||
member_lit_comp(String8, &String8__str_ptr_type, str),
|
|
||||||
member_lit_comp(String8, type(U64), size),
|
|
||||||
};
|
|
||||||
struct_type(String8);
|
|
||||||
|
|
||||||
//- rjf: String8Node
|
|
||||||
extern Type String8Node__type;
|
|
||||||
Type String8Node__ptr_type = {TypeKind_Ptr, 0, sizeof(void *), &String8Node__type};
|
|
||||||
Member String8Node__members[] =
|
|
||||||
{
|
|
||||||
{str8_lit_comp("next"), {0}, &String8Node__ptr_type, OffsetOf(String8Node, next)},
|
|
||||||
{str8_lit_comp("string"), {0}, type(String8), OffsetOf(String8Node, string)},
|
|
||||||
};
|
|
||||||
Type String8Node__type =
|
|
||||||
{
|
|
||||||
TypeKind_Struct,
|
|
||||||
0,
|
|
||||||
sizeof(String8Node),
|
|
||||||
&type_nil,
|
|
||||||
str8_lit_comp("String8Node"),
|
|
||||||
{0},
|
|
||||||
ArrayCount(String8Node__members),
|
|
||||||
String8Node__members,
|
|
||||||
};
|
|
||||||
|
|
||||||
//- rjf: String8List
|
|
||||||
Member String8List__members[] =
|
|
||||||
{
|
|
||||||
{str8_lit_comp("first"), {0}, &String8Node__ptr_type, OffsetOf(String8List, first)},
|
|
||||||
{str8_lit_comp("last"), {0}, &String8Node__ptr_type, OffsetOf(String8List, last), MemberFlag_DoNotSerialize},
|
|
||||||
{str8_lit_comp("node_count"), {0}, type(U64), OffsetOf(String8List, node_count)},
|
|
||||||
{str8_lit_comp("total_size"), {0}, type(U64), OffsetOf(String8List, total_size)},
|
|
||||||
};
|
|
||||||
Type String8List__type =
|
|
||||||
{
|
|
||||||
TypeKind_Struct,
|
|
||||||
0,
|
|
||||||
sizeof(String8List),
|
|
||||||
&type_nil,
|
|
||||||
str8_lit_comp("String8List"),
|
|
||||||
{0},
|
|
||||||
ArrayCount(String8List__members),
|
|
||||||
String8List__members,
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Lookups
|
|
||||||
|
|
||||||
internal Member *member_from_name(Type *type, String8 name);
|
|
||||||
#define EachMember(T, it) (Member *it = (type(T))->members; it != 0 && it < (type(T))->members + (type(T))->count; it += 1)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info * Instance Operations
|
|
||||||
|
|
||||||
internal void typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr);
|
|
||||||
internal String8 serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
internal String8 deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
internal String8 deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
#define struct_rebase_ptrs(T, ptr, base) typed_data_rebase_ptrs(type(T), str8_struct(ptr), (base))
|
|
||||||
#define serialized_from_struct(arena, T, ptr, ...) serialized_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__})
|
|
||||||
#define struct_from_serialized(arena, T, string, ...) (T *)deserialized_from_typed_data((arena), type(T), (string), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
|
||||||
#define deep_copy_from_struct(arena, T, ptr, ...) (T *)deep_copy_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
|
||||||
|
|
||||||
#endif // BASE_META_H
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
internal inline void
|
|
||||||
spall_begin(char *fmt, ...)
|
|
||||||
{
|
|
||||||
if(spall_buffer.data == 0)
|
|
||||||
{
|
|
||||||
spall_buffer.length = MB(1);
|
|
||||||
spall_buffer.data = os_reserve(spall_buffer.length);
|
|
||||||
os_commit(spall_buffer.data, spall_buffer.length);
|
|
||||||
spall_buffer_init(&spall_profile, &spall_buffer);
|
|
||||||
}
|
|
||||||
if(spall_pid == 0)
|
|
||||||
{
|
|
||||||
spall_pid = os_get_process_info()->pid;
|
|
||||||
}
|
|
||||||
if(spall_tid == 0)
|
|
||||||
{
|
|
||||||
spall_tid = os_tid();
|
|
||||||
}
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, os_now_microseconds(), spall_tid, spall_pid);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_PROFILE_H
|
|
||||||
#define BASE_PROFILE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Zero Settings
|
|
||||||
|
|
||||||
#if !defined(PROFILE_TELEMETRY)
|
|
||||||
# define PROFILE_TELEMETRY 0
|
|
||||||
#endif
|
|
||||||
#if !defined(PROFILE_SPALL)
|
|
||||||
# define PROFILE_SPALL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Third Party Includes
|
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
# include "rad_tm.h"
|
|
||||||
# if OS_WINDOWS
|
|
||||||
# pragma comment(lib, "ws2_32.lib")
|
|
||||||
# pragma comment(lib, "rad_tm_win64.lib")
|
|
||||||
# endif
|
|
||||||
#elif PROFILE_SPALL
|
|
||||||
# include "spall.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Telemetry Profile Defines
|
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
|
||||||
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
|
||||||
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
|
||||||
# define ProfTick(...) tmTick(0)
|
|
||||||
# define ProfIsCapturing(...) tmRunning()
|
|
||||||
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
|
||||||
# define ProfEndCapture(...) tmClose(0)
|
|
||||||
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
|
||||||
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
|
||||||
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
|
||||||
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
|
||||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
|
||||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
|
||||||
# define ProfColor(color) tmZoneColor((((color) & 0xff000000) >> 24) / 255.f, (((color) & 0x00ff0000) >> 16) / 255.f, (((color) & 0x0000ff00) >> 8) / 255.f)
|
|
||||||
# define ProfBeginV(...) \
|
|
||||||
if (TM_API_PTR) { \
|
|
||||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
|
||||||
Temp scratch = scratch_begin(0,0); \
|
|
||||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
|
||||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
|
||||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
|
||||||
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
|
|
||||||
scratch_end(scratch); \
|
|
||||||
}
|
|
||||||
# define ProfNoteV(...) \
|
|
||||||
if (TM_API_PTR) { \
|
|
||||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
|
||||||
Temp scratch = scratch_begin(0,0); \
|
|
||||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
|
||||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
|
||||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
|
||||||
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
|
|
||||||
scratch_end(scratch); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Spall Profile Defines
|
|
||||||
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
global U64 spall_capturing = 0;
|
|
||||||
global SpallProfile spall_profile = {0};
|
|
||||||
thread_static SpallBuffer spall_buffer = {0};
|
|
||||||
thread_static U32 spall_tid = 0;
|
|
||||||
thread_static U32 spall_pid = 0;
|
|
||||||
internal inline void spall_begin(char *fmt, ...);
|
|
||||||
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
|
||||||
# define ProfBeginDynamic(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
|
||||||
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, os_now_microseconds(), spall_tid, spall_pid)), 0 : 0)
|
|
||||||
# define ProfTick(...)
|
|
||||||
# define ProfIsCapturing(...) (!!spall_capturing)
|
|
||||||
# define ProfBeginCapture(...) (spall_capturing = 1)
|
|
||||||
# define ProfEndCapture(...) (spall_capturing = 0, spall_flush(&spall_profile))
|
|
||||||
# define ProfThreadName(...)
|
|
||||||
# define ProfMsg(...)
|
|
||||||
# define ProfBeginLockWait(...)
|
|
||||||
# define ProfEndLockWait(...)
|
|
||||||
# define ProfLockTake(...)
|
|
||||||
# define ProfLockDrop(...)
|
|
||||||
# define ProfColor(color)
|
|
||||||
# define ProfBeginV(...)
|
|
||||||
# define ProfNoteV(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Zeroify Undefined Defines
|
|
||||||
|
|
||||||
#if !defined(ProfBegin)
|
|
||||||
# define ProfBegin(...) (0)
|
|
||||||
# define ProfBeginDynamic(...) (0)
|
|
||||||
# define ProfEnd(...) (0)
|
|
||||||
# define ProfTick(...) (0)
|
|
||||||
# define ProfIsCapturing(...) (0)
|
|
||||||
# define ProfBeginCapture(...) (0)
|
|
||||||
# define ProfEndCapture(...) (0)
|
|
||||||
# define ProfThreadName(...) (0)
|
|
||||||
# define ProfMsg(...) (0)
|
|
||||||
# define ProfBeginLockWait(...) (0)
|
|
||||||
# define ProfEndLockWait(...) (0)
|
|
||||||
# define ProfLockTake(...) (0)
|
|
||||||
# define ProfLockDrop(...) (0)
|
|
||||||
# define ProfColor(...) (0)
|
|
||||||
# define ProfBeginV(...) (0)
|
|
||||||
# define ProfNoteV(...) (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Helper Wrappers
|
|
||||||
|
|
||||||
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
|
||||||
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
|
||||||
|
|
||||||
#endif // BASE_PROFILE_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,412 +1,371 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_STRINGS_H
|
#ifndef BASE_STRING_H
|
||||||
#define BASE_STRINGS_H
|
#define BASE_STRING_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Third Party Includes
|
//~ rjf: Third Party Includes
|
||||||
|
|
||||||
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||||
#include "third_party/stb/stb_sprintf.h"
|
#include "third_party/stb/stb_sprintf.h"
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Types
|
//~ rjf: String Types
|
||||||
|
|
||||||
typedef struct String8 String8;
|
typedef struct String8 String8;
|
||||||
struct String8
|
struct String8
|
||||||
{
|
{
|
||||||
U8 *str;
|
U8 *str;
|
||||||
U64 size;
|
U64 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct String16 String16;
|
typedef struct String16 String16;
|
||||||
struct String16
|
struct String16
|
||||||
{
|
{
|
||||||
U16 *str;
|
U16 *str;
|
||||||
U64 size;
|
U64 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct String32 String32;
|
typedef struct String32 String32;
|
||||||
struct String32
|
struct String32
|
||||||
{
|
{
|
||||||
U32 *str;
|
U32 *str;
|
||||||
U64 size;
|
U64 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String List & Array Types
|
//~ rjf: String List & Array Types
|
||||||
|
|
||||||
typedef struct String8Node String8Node;
|
typedef struct String8Node String8Node;
|
||||||
struct String8Node
|
struct String8Node
|
||||||
{
|
{
|
||||||
String8Node *next;
|
String8Node *next;
|
||||||
String8 string;
|
String8 string;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct String8MetaNode String8MetaNode;
|
typedef struct String8MetaNode String8MetaNode;
|
||||||
struct String8MetaNode
|
struct String8MetaNode
|
||||||
{
|
{
|
||||||
String8MetaNode *next;
|
String8MetaNode *next;
|
||||||
String8Node *node;
|
String8Node *node;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct String8List String8List;
|
typedef struct String8List String8List;
|
||||||
struct String8List
|
struct String8List
|
||||||
{
|
{
|
||||||
String8Node *first;
|
String8Node *first;
|
||||||
String8Node *last;
|
String8Node *last;
|
||||||
U64 node_count;
|
U64 node_count;
|
||||||
U64 total_size;
|
U64 total_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct String8Array String8Array;
|
typedef struct String8Array String8Array;
|
||||||
struct String8Array
|
struct String8Array
|
||||||
{
|
{
|
||||||
String8 *v;
|
String8 *strings;
|
||||||
U64 count;
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Matching, Splitting, & Joining Types
|
//~ rjf: String Matching, Splitting, & Joining Types
|
||||||
|
|
||||||
typedef U32 StringMatchFlags;
|
typedef U32 StringMatchFlags;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
StringMatchFlag_CaseInsensitive = (1 << 0),
|
StringMatchFlag_CaseInsensitive = (1 << 0),
|
||||||
StringMatchFlag_RightSideSloppy = (1 << 1),
|
StringMatchFlag_RightSideSloppy = (1 << 1),
|
||||||
StringMatchFlag_SlashInsensitive = (1 << 2),
|
StringMatchFlag_SlashInsensitive = (1 << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef U32 StringSplitFlags;
|
typedef U32 StringSplitFlags;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
StringSplitFlag_KeepEmpties = (1 << 0),
|
StringSplitFlag_KeepEmpties = (1 << 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum PathStyle
|
typedef enum PathStyle
|
||||||
{
|
{
|
||||||
PathStyle_Null,
|
PathStyle_Relative,
|
||||||
PathStyle_Relative,
|
PathStyle_WindowsAbsolute,
|
||||||
PathStyle_WindowsAbsolute,
|
PathStyle_UnixAbsolute,
|
||||||
PathStyle_UnixAbsolute,
|
|
||||||
|
#if OS_WINDOWS
|
||||||
#if OS_WINDOWS
|
PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute
|
||||||
PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute
|
#elif OS_LINUX
|
||||||
#elif OS_LINUX
|
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
#else
|
||||||
#else
|
# error "absolute path style is undefined for this OS"
|
||||||
# error "absolute path style is undefined for this OS"
|
#endif
|
||||||
#endif
|
}
|
||||||
}
|
PathStyle;
|
||||||
PathStyle;
|
|
||||||
|
typedef struct StringJoin StringJoin;
|
||||||
typedef struct StringJoin StringJoin;
|
struct StringJoin
|
||||||
struct StringJoin
|
{
|
||||||
{
|
String8 pre;
|
||||||
String8 pre;
|
String8 sep;
|
||||||
String8 sep;
|
String8 post;
|
||||||
String8 post;
|
};
|
||||||
};
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf: String Pair Types
|
||||||
//~ rjf: String Pair Types
|
|
||||||
|
typedef struct String8TxtPtPair String8TxtPtPair;
|
||||||
typedef struct String8TxtPtPair String8TxtPtPair;
|
struct String8TxtPtPair
|
||||||
struct String8TxtPtPair
|
{
|
||||||
{
|
String8 string;
|
||||||
String8 string;
|
TxtPt pt;
|
||||||
TxtPt pt;
|
};
|
||||||
};
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf: UTF Decoding Types
|
||||||
//~ rjf: UTF Decoding Types
|
|
||||||
|
typedef struct UnicodeDecode UnicodeDecode;
|
||||||
typedef struct UnicodeDecode UnicodeDecode;
|
struct UnicodeDecode
|
||||||
struct UnicodeDecode
|
{
|
||||||
{
|
U32 inc;
|
||||||
U32 inc;
|
U32 codepoint;
|
||||||
U32 codepoint;
|
};
|
||||||
};
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf: String Fuzzy Matching Types
|
||||||
//~ rjf: String Fuzzy Matching Types
|
|
||||||
|
typedef struct FuzzyMatchRangeNode FuzzyMatchRangeNode;
|
||||||
typedef struct FuzzyMatchRangeNode FuzzyMatchRangeNode;
|
struct FuzzyMatchRangeNode
|
||||||
struct FuzzyMatchRangeNode
|
{
|
||||||
{
|
FuzzyMatchRangeNode *next;
|
||||||
FuzzyMatchRangeNode *next;
|
Rng1U64 range;
|
||||||
Rng1U64 range;
|
};
|
||||||
};
|
|
||||||
|
typedef struct FuzzyMatchRangeList FuzzyMatchRangeList;
|
||||||
typedef struct FuzzyMatchRangeList FuzzyMatchRangeList;
|
struct FuzzyMatchRangeList
|
||||||
struct FuzzyMatchRangeList
|
{
|
||||||
{
|
FuzzyMatchRangeNode *first;
|
||||||
FuzzyMatchRangeNode *first;
|
FuzzyMatchRangeNode *last;
|
||||||
FuzzyMatchRangeNode *last;
|
U64 count;
|
||||||
U64 count;
|
U64 needle_part_count;
|
||||||
U64 needle_part_count;
|
U64 total_dim;
|
||||||
U64 total_dim;
|
};
|
||||||
};
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf: Character Classification & Conversion Functions
|
||||||
//~ rjf: Character Classification & Conversion Functions
|
|
||||||
|
internal B32 char_is_space(U8 c);
|
||||||
internal B32 char_is_space(U8 c);
|
internal B32 char_is_upper(U8 c);
|
||||||
internal B32 char_is_upper(U8 c);
|
internal B32 char_is_lower(U8 c);
|
||||||
internal B32 char_is_lower(U8 c);
|
internal B32 char_is_alpha(U8 c);
|
||||||
internal B32 char_is_alpha(U8 c);
|
internal B32 char_is_slash(U8 c);
|
||||||
internal B32 char_is_slash(U8 c);
|
internal B32 char_is_digit(U8 c, U32 base);
|
||||||
internal B32 char_is_digit(U8 c, U32 base);
|
internal U8 char_to_lower(U8 c);
|
||||||
internal U8 char_to_lower(U8 c);
|
internal U8 char_to_upper(U8 c);
|
||||||
internal U8 char_to_upper(U8 c);
|
internal U8 char_to_correct_slash(U8 c);
|
||||||
internal U8 char_to_correct_slash(U8 c);
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf: C-String Measurement
|
||||||
//~ rjf: C-String Measurement
|
|
||||||
|
internal U64 cstring8_length(U8 *c);
|
||||||
internal U64 cstring8_length(U8 *c);
|
internal U64 cstring16_length(U16 *c);
|
||||||
internal U64 cstring16_length(U16 *c);
|
internal U64 cstring32_length(U32 *c);
|
||||||
internal U64 cstring32_length(U32 *c);
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf: String Constructors
|
||||||
//~ rjf: String Constructors
|
|
||||||
|
#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_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))
|
#define str8_array_fixed(S) str8((U8*)(S), sizeof(S))
|
||||||
#define str8_array_fixed(S) str8((U8*)(S), sizeof(S))
|
#define str8_struct(S) str8((U8*)(S), sizeof(*(S)))
|
||||||
#define str8_struct(S) str8((U8*)(S), sizeof(*(S)))
|
|
||||||
|
internal String8 str8(U8 *str, U64 size);
|
||||||
internal String8 str8(U8 *str, U64 size);
|
internal String8 str8_range(U8 *first, U8 *one_past_last);
|
||||||
internal String8 str8_range(U8 *first, U8 *one_past_last);
|
internal String8 str8_zero(void);
|
||||||
internal String8 str8_zero(void);
|
internal String16 str16(U16 *str, U64 size);
|
||||||
internal String16 str16(U16 *str, U64 size);
|
internal String16 str16_range(U16 *first, U16 *one_past_last);
|
||||||
internal String16 str16_range(U16 *first, U16 *one_past_last);
|
internal String16 str16_zero(void);
|
||||||
internal String16 str16_zero(void);
|
internal String32 str32(U32 *str, U64 size);
|
||||||
internal String32 str32(U32 *str, U64 size);
|
internal String32 str32_range(U32 *first, U32 *one_past_last);
|
||||||
internal String32 str32_range(U32 *first, U32 *one_past_last);
|
internal String32 str32_zero(void);
|
||||||
internal String32 str32_zero(void);
|
internal String8 str8_cstring(char *c);
|
||||||
internal String8 str8_cstring(char *c);
|
internal String16 str16_cstring(U16 *c);
|
||||||
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 String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
|
//~ rjf: String Stylization
|
||||||
|
|
||||||
////////////////////////////////
|
internal String8 upper_from_str8(Arena *arena, String8 string);
|
||||||
//~ rjf: String Stylization
|
internal String8 lower_from_str8(Arena *arena, String8 string);
|
||||||
|
internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
||||||
internal String8 upper_from_str8(Arena *arena, String8 string);
|
|
||||||
internal String8 lower_from_str8(Arena *arena, String8 string);
|
////////////////////////////////
|
||||||
internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
//~ rjf: String Matching
|
||||||
|
|
||||||
////////////////////////////////
|
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||||
//~ rjf: String Matching
|
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||||
|
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
||||||
internal B32 str8_match(String8 a, String8 b, 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);
|
//~ rjf: String Slicing
|
||||||
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
|
||||||
|
internal String8 str8_substr(String8 str, Rng1U64 range);
|
||||||
////////////////////////////////
|
internal String8 str8_prefix(String8 str, U64 size);
|
||||||
//~ rjf: String Slicing
|
internal String8 str8_skip(String8 str, U64 amt);
|
||||||
|
internal String8 str8_postfix(String8 str, U64 size);
|
||||||
internal String8 str8_substr(String8 str, Rng1U64 range);
|
internal String8 str8_chop(String8 str, U64 amt);
|
||||||
internal String8 str8_prefix(String8 str, U64 size);
|
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||||
internal String8 str8_skip(String8 str, U64 amt);
|
|
||||||
internal String8 str8_postfix(String8 str, U64 size);
|
////////////////////////////////
|
||||||
internal String8 str8_chop(String8 str, U64 amt);
|
//~ rjf: String Formatting & Copying
|
||||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
|
||||||
|
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||||
////////////////////////////////
|
internal String8 push_str8_copy(Arena *arena, String8 s);
|
||||||
//~ rjf: String Formatting & Copying
|
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
||||||
|
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||||
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
|
||||||
internal String8 push_str8_copy(Arena *arena, String8 s);
|
////////////////////////////////
|
||||||
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
//~ rjf: String <=> Integer Conversions
|
||||||
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
|
||||||
|
//- rjf: string -> integer
|
||||||
////////////////////////////////
|
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||||
//~ rjf: String <=> Integer Conversions
|
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||||
|
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||||
//- rjf: string -> integer
|
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||||
|
|
||||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
//- rjf: integer -> string
|
||||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||||
internal U32 u32_from_str8(String8 string, U32 radix);
|
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||||
internal S32 s32_from_str8(String8 string, U32 radix);
|
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||||
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
|
||||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
////////////////////////////////
|
||||||
|
//~ rjf: String <=> Float Conversions
|
||||||
//- rjf: integer -> string
|
|
||||||
internal String8 str8_from_memory_size(Arena *arena, U64 size);
|
internal F64 f64_from_str8(String8 string);
|
||||||
internal String8 str8_from_count(Arena *arena, U64 count);
|
|
||||||
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
|
////////////////////////////////
|
||||||
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
|
//~ rjf: String List Construction Functions
|
||||||
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
|
||||||
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
internal String8Node* str8_list_push_node(String8List *list, String8Node *node);
|
||||||
|
internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
||||||
////////////////////////////////
|
internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node);
|
||||||
//~ rjf: String <=> Float Conversions
|
internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
||||||
|
internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string);
|
||||||
internal F64 f64_from_str8(String8 string);
|
internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
||||||
|
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
||||||
////////////////////////////////
|
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
||||||
//~ rjf: String List Construction Functions
|
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_node(String8List *list, String8Node *node);
|
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||||
internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||||
internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node);
|
|
||||||
internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
////////////////////////////////
|
||||||
internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string);
|
//~ rjf: String Splitting & Joining
|
||||||
internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
|
||||||
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||||
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
||||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
||||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf; String Arrays
|
||||||
//~ rjf: String Splitting & Joining
|
|
||||||
|
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||||
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
|
||||||
internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
////////////////////////////////
|
||||||
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
//~ rjf: String Path Helpers
|
||||||
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
|
||||||
|
internal String8 str8_chop_last_slash(String8 string);
|
||||||
////////////////////////////////
|
internal String8 str8_skip_last_slash(String8 string);
|
||||||
//~ rjf; String Arrays
|
internal String8 str8_chop_last_dot(String8 string);
|
||||||
|
internal String8 str8_skip_last_dot(String8 string);
|
||||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
|
||||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
internal PathStyle path_style_from_str8(String8 string);
|
||||||
|
internal String8List str8_split_path(Arena *arena, String8 string);
|
||||||
////////////////////////////////
|
internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style);
|
||||||
//~ rjf: String Path Helpers
|
internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style);
|
||||||
|
|
||||||
internal String8 str8_chop_last_slash(String8 string);
|
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||||
internal String8 str8_skip_last_slash(String8 string);
|
|
||||||
internal String8 str8_chop_last_dot(String8 string);
|
////////////////////////////////
|
||||||
internal String8 str8_skip_last_dot(String8 string);
|
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||||
|
|
||||||
internal PathStyle path_style_from_str8(String8 string);
|
internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
||||||
internal String8List str8_split_path(Arena *arena, String8 string);
|
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||||
internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style);
|
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||||
internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style);
|
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||||
|
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
|
||||||
|
////////////////////////////////
|
||||||
////////////////////////////////
|
//~ rjf: Unicode String Conversions
|
||||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
|
||||||
|
internal String8 str8_from_16(Arena *arena, String16 in);
|
||||||
internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
internal String16 str16_from_8(Arena *arena, String8 in);
|
||||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
|
||||||
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
////////////////////////////////
|
||||||
|
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Unicode String Conversions
|
internal String8 string_from_dimension(Dimension dimension);
|
||||||
|
internal String8 string_from_side(Side side);
|
||||||
internal String8 str8_from_16(Arena *arena, String16 in);
|
internal String8 string_from_operating_system(OperatingSystem os);
|
||||||
internal String16 str16_from_8(Arena *arena, String8 in);
|
internal String8 string_from_architecture(Architecture arch);
|
||||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
|
||||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
////////////////////////////////
|
||||||
|
//~ rjf: Time Types -> String
|
||||||
////////////////////////////////
|
|
||||||
//~ String -> Enum Conversions
|
internal String8 string_from_week_day(WeekDay week_day);
|
||||||
|
internal String8 string_from_month(Month month);
|
||||||
internal OperatingSystem operating_system_from_string(String8 string);
|
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||||
|
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||||
////////////////////////////////
|
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
|
||||||
|
////////////////////////////////
|
||||||
internal String8 string_from_dimension(Dimension dimension);
|
//~ rjf: String <-> Color
|
||||||
internal String8 string_from_side(Side side);
|
|
||||||
internal String8 string_from_operating_system(OperatingSystem os);
|
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
||||||
internal String8 string_from_arch(Arch arch);
|
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Time Types -> String
|
//~ rjf: String Fuzzy Matching
|
||||||
|
|
||||||
internal String8 string_from_week_day(WeekDay week_day);
|
internal FuzzyMatchRangeList fuzzy_match_find(Arena *arena, String8 needle, String8 haystack);
|
||||||
internal String8 string_from_month(Month month);
|
internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src);
|
||||||
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
|
||||||
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
////////////////////////////////
|
||||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
//~ NOTE(allen): Serialization Helpers
|
||||||
|
|
||||||
////////////////////////////////
|
internal void str8_serial_begin(Arena *arena, String8List *srl);
|
||||||
//~ Globally Unique Ids
|
internal String8 str8_serial_end(Arena *arena, String8List *srl);
|
||||||
|
internal void str8_serial_write_to_dst(String8List *srl, void *out);
|
||||||
internal String8 string_from_guid(Arena *arena, Guid guid);
|
internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 align);
|
||||||
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
|
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
||||||
internal Guid guid_from_string(String8 string);
|
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
||||||
|
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
||||||
////////////////////////////////
|
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
||||||
//~ rjf: Basic Text Indentation
|
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 String8 indented_from_string(Arena *arena, String8 string);
|
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
||||||
|
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||||
////////////////////////////////
|
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
||||||
//~ rjf: Text Escaping
|
#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)
|
||||||
internal String8 escaped_from_raw_str8(Arena *arena, String8 string);
|
|
||||||
internal String8 raw_from_escaped_str8(Arena *arena, String8 string);
|
////////////////////////////////
|
||||||
|
//~ rjf: Deserialization Helpers
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Text Wrapping
|
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
||||||
|
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
||||||
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
||||||
|
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
||||||
////////////////////////////////
|
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
||||||
//~ rjf: String <-> Color
|
#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((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
|
||||||
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
|
||||||
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
#endif // BASE_STRING_H
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: String Fuzzy Matching
|
|
||||||
|
|
||||||
internal FuzzyMatchRangeList fuzzy_match_find(Arena *arena, String8 needle, String8 haystack);
|
|
||||||
internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ NOTE(allen): Serialization Helpers
|
|
||||||
|
|
||||||
internal void str8_serial_begin(Arena *arena, String8List *srl);
|
|
||||||
internal String8 str8_serial_end(Arena *arena, String8List *srl);
|
|
||||||
internal void str8_serial_write_to_dst(String8List *srl, void *out);
|
|
||||||
internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 align);
|
|
||||||
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
|
||||||
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
|
||||||
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
|
||||||
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
|
||||||
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
|
||||||
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
|
||||||
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
|
||||||
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
|
||||||
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
|
||||||
#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)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Deserialization Helpers
|
|
||||||
|
|
||||||
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
|
||||||
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
|
||||||
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);
|
|
||||||
internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
|
||||||
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
|
||||||
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
|
||||||
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);
|
|
||||||
#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)
|
|
||||||
|
|
||||||
#endif // BASE_STRINGS_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
+78
-225
@@ -1,225 +1,78 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Globals
|
// NOTE(allen): Thread Context Functions
|
||||||
|
|
||||||
C_LINKAGE thread_static TCTX *tctx_thread_local;
|
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
#if !SUPPLEMENT_UNIT
|
||||||
C_LINKAGE thread_static TCTX *tctx_thread_local = 0;
|
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
internal void
|
||||||
//~ rjf: Thread Context Functions
|
tctx_init_and_equip(TCTX *tctx){
|
||||||
|
MemoryZeroStruct(tctx);
|
||||||
//- rjf: thread-context allocation & selection
|
Arena **arena_ptr = tctx->arenas;
|
||||||
|
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||||
internal TCTX *
|
*arena_ptr = arena_alloc();
|
||||||
tctx_alloc(void)
|
}
|
||||||
{
|
tctx_thread_local = tctx;
|
||||||
Arena *arena = arena_alloc();
|
}
|
||||||
TCTX *tctx = push_array(arena, TCTX, 1);
|
|
||||||
tctx->arenas[0] = arena;
|
internal TCTX*
|
||||||
tctx->arenas[1] = arena_alloc();
|
tctx_get_equipped(void){
|
||||||
tctx->lane_ctx.lane_count = 1;
|
return(tctx_thread_local);
|
||||||
return tctx;
|
}
|
||||||
}
|
|
||||||
|
internal Arena*
|
||||||
internal void
|
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||||
tctx_release(TCTX *tctx)
|
TCTX *tctx = tctx_get_equipped();
|
||||||
{
|
|
||||||
arena_release(tctx->arenas[1]);
|
Arena *result = 0;
|
||||||
arena_release(tctx->arenas[0]);
|
Arena **arena_ptr = tctx->arenas;
|
||||||
}
|
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||||
|
Arena **conflict_ptr = conflicts;
|
||||||
internal void
|
B32 has_conflict = 0;
|
||||||
tctx_select(TCTX *tctx)
|
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||||
{
|
if (*arena_ptr == *conflict_ptr){
|
||||||
tctx_thread_local = tctx;
|
has_conflict = 1;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
internal TCTX *
|
}
|
||||||
tctx_selected(void)
|
if (!has_conflict){
|
||||||
{
|
result = *arena_ptr;
|
||||||
return tctx_thread_local;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//- rjf: scratch arenas
|
|
||||||
|
return(result);
|
||||||
internal Arena *
|
}
|
||||||
tctx_get_scratch(Arena **conflicts, U64 count)
|
|
||||||
{
|
internal void
|
||||||
TCTX *tctx = tctx_selected();
|
tctx_set_thread_name(String8 string){
|
||||||
Arena *result = 0;
|
TCTX *tctx = tctx_get_equipped();
|
||||||
Arena **arena_ptr = tctx->arenas;
|
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
||||||
for(U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1)
|
MemoryCopy(tctx->thread_name, string.str, size);
|
||||||
{
|
tctx->thread_name_size = size;
|
||||||
Arena **conflict_ptr = conflicts;
|
}
|
||||||
B32 has_conflict = 0;
|
|
||||||
for(U64 j = 0; j < count; j += 1, conflict_ptr += 1)
|
internal String8
|
||||||
{
|
tctx_get_thread_name(void){
|
||||||
if(*arena_ptr == *conflict_ptr)
|
TCTX *tctx = tctx_get_equipped();
|
||||||
{
|
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||||
has_conflict = 1;
|
return(result);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
internal void
|
||||||
if(!has_conflict)
|
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
result = *arena_ptr;
|
tctx->file_name = file_name;
|
||||||
break;
|
tctx->line_number = line_number;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result;
|
internal void
|
||||||
}
|
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||||
|
TCTX *tctx = tctx_get_equipped();
|
||||||
//- rjf: lane metadata
|
*file_name = tctx->file_name;
|
||||||
|
*line_number = tctx->line_number;
|
||||||
internal LaneCtx
|
}
|
||||||
tctx_set_lane_ctx(LaneCtx lane_ctx)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
LaneCtx restore = tctx->lane_ctx;
|
|
||||||
tctx->lane_ctx = lane_ctx;
|
|
||||||
return restore;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
ProfColor(0x00000ff);
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> copy to broadcast memory on source lane
|
|
||||||
U64 broadcast_size_clamped = ClampTop(broadcast_size, sizeof(tctx->lane_ctx.broadcast_memory[0]));
|
|
||||||
if(broadcast_ptr != 0 && lane_idx() == broadcast_src_lane_idx)
|
|
||||||
{
|
|
||||||
MemoryCopy(tctx->lane_ctx.broadcast_memory, broadcast_ptr, broadcast_size_clamped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: all cases: barrier
|
|
||||||
os_barrier_wait(tctx->lane_ctx.barrier);
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> copy from broadcast memory on destination lanes
|
|
||||||
if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx)
|
|
||||||
{
|
|
||||||
MemoryCopy(broadcast_ptr, tctx->lane_ctx.broadcast_memory, broadcast_size_clamped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> barrier on all lanes
|
|
||||||
if(broadcast_ptr != 0)
|
|
||||||
{
|
|
||||||
os_barrier_wait(tctx->lane_ctx.barrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: thread names
|
|
||||||
|
|
||||||
internal void
|
|
||||||
tctx_set_thread_name(String8 string)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
|
||||||
MemoryCopy(tctx->thread_name, string.str, size);
|
|
||||||
tctx->thread_name_size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
tctx_get_thread_name(void)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: thread source-locations
|
|
||||||
|
|
||||||
internal void
|
|
||||||
tctx_write_srcloc(char *file_name, U64 line_number)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
tctx->file_name = file_name;
|
|
||||||
tctx->line_number = line_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
tctx_read_srcloc(char **file_name, U64 *line_number)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
*file_name = tctx->file_name;
|
|
||||||
*line_number = tctx->line_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Touch Scope Functions
|
|
||||||
|
|
||||||
internal Access *
|
|
||||||
access_open(void)
|
|
||||||
{
|
|
||||||
if(tctx_thread_local->access_arena == 0)
|
|
||||||
{
|
|
||||||
tctx_thread_local->access_arena = arena_alloc();
|
|
||||||
}
|
|
||||||
Access *access = tctx_thread_local->free_access;
|
|
||||||
if(access != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(tctx_thread_local->free_access);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
access = push_array_no_zero(tctx_thread_local->access_arena, Access, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(access);
|
|
||||||
return access;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
access_close(Access *access)
|
|
||||||
{
|
|
||||||
for(Touch *touch = access->top_touch, *next = 0; touch != 0; touch = next)
|
|
||||||
{
|
|
||||||
next = touch->next;
|
|
||||||
ins_atomic_u64_dec_eval(&touch->pt->access_refcount);
|
|
||||||
if(touch->cv.u64[0] != 0) { cond_var_broadcast(touch->cv); }
|
|
||||||
SLLStackPush(tctx_thread_local->free_touch, touch);
|
|
||||||
}
|
|
||||||
SLLStackPush(tctx_thread_local->free_access, access);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
access_touch(Access *access, AccessPt *pt, CondVar cv)
|
|
||||||
{
|
|
||||||
ins_atomic_u64_inc_eval(&pt->access_refcount);
|
|
||||||
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, os_now_microseconds());
|
|
||||||
ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx());
|
|
||||||
Touch *touch = tctx_thread_local->free_touch;
|
|
||||||
if(touch != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(tctx_thread_local->free_touch);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
touch = push_array_no_zero(tctx_thread_local->access_arena, Touch, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(touch);
|
|
||||||
SLLStackPush(access->top_touch, touch);
|
|
||||||
touch->cv = cv;
|
|
||||||
touch->pt = pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: access points
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params)
|
|
||||||
{
|
|
||||||
U64 access_refcount = ins_atomic_u64_eval(&pt->access_refcount);
|
|
||||||
U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us);
|
|
||||||
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
|
|
||||||
B32 result = (access_refcount == 0 &&
|
|
||||||
last_time_touched_us + params->time <= os_now_microseconds() &&
|
|
||||||
last_update_idx_touched + params->update_idxs <= update_tick_idx());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
+40
-132
@@ -1,132 +1,40 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_THREAD_CONTEXT_H
|
#ifndef BASE_THREAD_CONTEXT_H
|
||||||
#define BASE_THREAD_CONTEXT_H
|
#define BASE_THREAD_CONTEXT_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Lane Context
|
// NOTE(allen): Thread Context
|
||||||
|
|
||||||
typedef struct LaneCtx LaneCtx;
|
typedef struct TCTX TCTX;
|
||||||
struct LaneCtx
|
struct TCTX
|
||||||
{
|
{
|
||||||
U64 lane_idx;
|
Arena *arenas[2];
|
||||||
U64 lane_count;
|
|
||||||
Barrier barrier;
|
U8 thread_name[32];
|
||||||
U64 *broadcast_memory;
|
U64 thread_name_size;
|
||||||
};
|
|
||||||
|
char *file_name;
|
||||||
////////////////////////////////
|
U64 line_number;
|
||||||
//~ rjf: Access Scopes
|
};
|
||||||
|
|
||||||
typedef struct AccessPt AccessPt;
|
////////////////////////////////
|
||||||
struct AccessPt
|
// NOTE(allen): Thread Context Functions
|
||||||
{
|
|
||||||
U64 access_refcount;
|
internal void tctx_init_and_equip(TCTX *tctx);
|
||||||
U64 last_time_touched_us;
|
internal TCTX* tctx_get_equipped(void);
|
||||||
U64 last_update_idx_touched;
|
|
||||||
};
|
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
|
||||||
|
|
||||||
typedef struct AccessPtExpireParams AccessPtExpireParams;
|
internal void tctx_set_thread_name(String8 name);
|
||||||
struct AccessPtExpireParams
|
internal String8 tctx_get_thread_name(void);
|
||||||
{
|
|
||||||
U64 time;
|
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
||||||
U64 update_idxs;
|
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
||||||
};
|
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
||||||
|
|
||||||
typedef struct Touch Touch;
|
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
||||||
struct Touch
|
#define scratch_end(scratch) temp_end(scratch)
|
||||||
{
|
|
||||||
Touch *next;
|
#endif //BASE_THREAD_CONTEXT_H
|
||||||
AccessPt *pt;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Access Access;
|
|
||||||
struct Access
|
|
||||||
{
|
|
||||||
Access *next;
|
|
||||||
Touch *top_touch;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Base Per-Thread State Bundle
|
|
||||||
|
|
||||||
typedef struct TCTX TCTX;
|
|
||||||
struct TCTX
|
|
||||||
{
|
|
||||||
// rjf: scratch arenas
|
|
||||||
Arena *arenas[2];
|
|
||||||
|
|
||||||
// rjf: thread name
|
|
||||||
U8 thread_name[32];
|
|
||||||
U64 thread_name_size;
|
|
||||||
|
|
||||||
// rjf: lane context
|
|
||||||
LaneCtx lane_ctx;
|
|
||||||
|
|
||||||
// rjf: source location info
|
|
||||||
char *file_name;
|
|
||||||
U64 line_number;
|
|
||||||
|
|
||||||
// rjf: accesses
|
|
||||||
Arena *access_arena;
|
|
||||||
Access *free_access;
|
|
||||||
Touch *free_touch;
|
|
||||||
|
|
||||||
// rjf: progress
|
|
||||||
U64 *progress_counter_ptr;
|
|
||||||
U64 *progress_target_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Context Functions
|
|
||||||
|
|
||||||
//- rjf: thread-context allocation & selection
|
|
||||||
internal TCTX *tctx_alloc(void);
|
|
||||||
internal void tctx_release(TCTX *tctx);
|
|
||||||
internal void tctx_select(TCTX *tctx);
|
|
||||||
internal TCTX *tctx_selected(void);
|
|
||||||
|
|
||||||
//- rjf: scratch arenas
|
|
||||||
internal Arena *tctx_get_scratch(Arena **conflicts, U64 count);
|
|
||||||
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
|
||||||
#define scratch_end(scratch) temp_end(scratch)
|
|
||||||
|
|
||||||
//- rjf: lane metadata
|
|
||||||
internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx);
|
|
||||||
internal void tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx);
|
|
||||||
#define lane_idx() (tctx_selected()->lane_ctx.lane_idx)
|
|
||||||
#define lane_count() (tctx_selected()->lane_ctx.lane_count)
|
|
||||||
#define lane_from_task_idx(idx) ((idx)%lane_count())
|
|
||||||
#define lane_ctx(ctx) tctx_set_lane_ctx((ctx))
|
|
||||||
#define lane_sync() tctx_lane_barrier_wait(0, 0, 0)
|
|
||||||
#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(*(ptr)), (src_lane_idx))
|
|
||||||
#define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count))
|
|
||||||
|
|
||||||
//- rjf: thread names
|
|
||||||
internal void tctx_set_thread_name(String8 name);
|
|
||||||
internal String8 tctx_get_thread_name(void);
|
|
||||||
|
|
||||||
//- rjf: thread source-locations
|
|
||||||
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
|
||||||
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
|
||||||
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
|
||||||
|
|
||||||
//- rjf: access scopes
|
|
||||||
internal Access *access_open(void);
|
|
||||||
internal void access_close(Access *access);
|
|
||||||
internal void access_touch(Access *access, AccessPt *pt, CondVar cv);
|
|
||||||
|
|
||||||
//- rjf: access points
|
|
||||||
internal B32 access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params);
|
|
||||||
#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 2, __VA_ARGS__})
|
|
||||||
|
|
||||||
//- rjf: progress counters
|
|
||||||
#define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr))
|
|
||||||
#define set_progress_target_ptr(ptr) (tctx_selected()->progress_target_ptr = (ptr))
|
|
||||||
#define set_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
|
||||||
#define add_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_add_eval(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
|
||||||
#define set_progress_target(val) (tctx_selected()->progress_target_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_target_ptr, (val)) : (void)0)
|
|
||||||
|
|
||||||
#endif // BASE_THREAD_CONTEXT_H
|
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Functions
|
|
||||||
|
|
||||||
internal Thread
|
|
||||||
thread_launch(ThreadEntryPointFunctionType *f, void *p)
|
|
||||||
{
|
|
||||||
Thread thread = os_thread_launch(f, p);
|
|
||||||
return thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
thread_join(Thread thread, U64 endt_us)
|
|
||||||
{
|
|
||||||
B32 result = os_thread_join(thread, endt_us);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
thread_detach(Thread thread)
|
|
||||||
{
|
|
||||||
os_thread_detach(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: recursive mutexes
|
|
||||||
|
|
||||||
internal Mutex mutex_alloc(void) {return os_mutex_alloc();}
|
|
||||||
internal void mutex_release(Mutex mutex) {os_mutex_release(mutex);}
|
|
||||||
internal void mutex_take(Mutex mutex) {os_mutex_take(mutex);}
|
|
||||||
internal void mutex_drop(Mutex mutex) {os_mutex_drop(mutex);}
|
|
||||||
|
|
||||||
//- rjf: reader/writer mutexes
|
|
||||||
|
|
||||||
internal RWMutex rw_mutex_alloc(void) {return os_rw_mutex_alloc();}
|
|
||||||
internal void rw_mutex_release(RWMutex mutex) {os_rw_mutex_release(mutex);}
|
|
||||||
internal void rw_mutex_take(RWMutex mutex, B32 write_mode) {os_rw_mutex_take(mutex, write_mode);}
|
|
||||||
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode) {os_rw_mutex_drop(mutex, write_mode);}
|
|
||||||
|
|
||||||
//- rjf: condition variables
|
|
||||||
|
|
||||||
internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();}
|
|
||||||
internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);}
|
|
||||||
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);}
|
|
||||||
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) {return os_cond_var_wait_rw(cv, mutex_rw, write_mode, endt_us);}
|
|
||||||
internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);}
|
|
||||||
internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);}
|
|
||||||
|
|
||||||
//- rjf: cross-process semaphores
|
|
||||||
|
|
||||||
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name) {return os_semaphore_alloc(initial_count, max_count, name);}
|
|
||||||
internal void semaphore_release(Semaphore semaphore) {os_semaphore_release(semaphore);}
|
|
||||||
internal Semaphore semaphore_open(String8 name) {return os_semaphore_open(name);}
|
|
||||||
internal void semaphore_close(Semaphore semaphore) {os_semaphore_close(semaphore);}
|
|
||||||
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us) {return os_semaphore_take(semaphore, endt_us);}
|
|
||||||
internal void semaphore_drop(Semaphore semaphore) {os_semaphore_drop(semaphore);}
|
|
||||||
|
|
||||||
//- rjf: barriers
|
|
||||||
|
|
||||||
internal Barrier barrier_alloc(U64 count) {return os_barrier_alloc(count);}
|
|
||||||
internal void barrier_release(Barrier barrier) {os_barrier_release(barrier);}
|
|
||||||
internal void barrier_wait(Barrier barrier) {os_barrier_wait(barrier);}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripe Functions
|
|
||||||
|
|
||||||
internal StripeArray
|
|
||||||
stripe_array_alloc(Arena *arena)
|
|
||||||
{
|
|
||||||
StripeArray array = {0};
|
|
||||||
array.count = os_get_system_info()->logical_processor_count;
|
|
||||||
array.v = push_array(arena, Stripe, array.count);
|
|
||||||
for EachIndex(idx, array.count)
|
|
||||||
{
|
|
||||||
array.v[idx].arena = arena_alloc();
|
|
||||||
array.v[idx].rw_mutex = rw_mutex_alloc();
|
|
||||||
array.v[idx].cv = cond_var_alloc();
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
stripe_array_release(StripeArray *stripes)
|
|
||||||
{
|
|
||||||
for EachIndex(idx, stripes->count)
|
|
||||||
{
|
|
||||||
arena_release(stripes->v[idx].arena);
|
|
||||||
rw_mutex_release(stripes->v[idx].rw_mutex);
|
|
||||||
cond_var_release(stripes->v[idx].cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Stripe *
|
|
||||||
stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx)
|
|
||||||
{
|
|
||||||
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
|
|
||||||
return stripe;
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_THREADS_H
|
|
||||||
#define BASE_THREADS_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Types
|
|
||||||
|
|
||||||
typedef struct Thread Thread;
|
|
||||||
struct Thread
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
typedef void ThreadEntryPointFunctionType(void *p);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Synchronization Primitive Types
|
|
||||||
|
|
||||||
typedef struct Mutex Mutex;
|
|
||||||
struct Mutex
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct RWMutex RWMutex;
|
|
||||||
struct RWMutex
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CondVar CondVar;
|
|
||||||
struct CondVar
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Semaphore Semaphore;
|
|
||||||
struct Semaphore
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Barrier Barrier;
|
|
||||||
struct Barrier
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripes
|
|
||||||
|
|
||||||
typedef struct Stripe Stripe;
|
|
||||||
struct Stripe
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
RWMutex rw_mutex;
|
|
||||||
CondVar cv;
|
|
||||||
void *free;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct StripeArray StripeArray;
|
|
||||||
struct StripeArray
|
|
||||||
{
|
|
||||||
Stripe *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Functions
|
|
||||||
|
|
||||||
internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
|
|
||||||
internal B32 thread_join(Thread thread, U64 endt_us);
|
|
||||||
internal void thread_detach(Thread thread);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: recursive mutexes
|
|
||||||
internal Mutex mutex_alloc(void);
|
|
||||||
internal void mutex_release(Mutex mutex);
|
|
||||||
internal void mutex_take(Mutex mutex);
|
|
||||||
internal void mutex_drop(Mutex mutex);
|
|
||||||
|
|
||||||
//- rjf: reader/writer mutexes
|
|
||||||
internal RWMutex rw_mutex_alloc(void);
|
|
||||||
internal void rw_mutex_release(RWMutex mutex);
|
|
||||||
internal void rw_mutex_take(RWMutex mutex, B32 write_mode);
|
|
||||||
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode);
|
|
||||||
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
|
|
||||||
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
|
|
||||||
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
|
|
||||||
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
|
|
||||||
|
|
||||||
//- rjf: condition variables
|
|
||||||
internal CondVar cond_var_alloc(void);
|
|
||||||
internal void cond_var_release(CondVar cv);
|
|
||||||
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
|
|
||||||
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us);
|
|
||||||
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us);
|
|
||||||
#define cond_var_wait_rw_r(cv, m, endt) cond_var_wait_rw((cv), (m), (0), (endt))
|
|
||||||
#define cond_var_wait_rw_w(cv, m, endt) cond_var_wait_rw((cv), (m), (1), (endt))
|
|
||||||
internal void cond_var_signal(CondVar cv);
|
|
||||||
internal void cond_var_broadcast(CondVar cv);
|
|
||||||
|
|
||||||
//- rjf: cross-process semaphores
|
|
||||||
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
|
|
||||||
internal void semaphore_release(Semaphore semaphore);
|
|
||||||
internal Semaphore semaphore_open(String8 name);
|
|
||||||
internal void semaphore_close(Semaphore semaphore);
|
|
||||||
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
|
|
||||||
internal void semaphore_drop(Semaphore semaphore);
|
|
||||||
|
|
||||||
//- rjf: barriers
|
|
||||||
internal Barrier barrier_alloc(U64 count);
|
|
||||||
internal void barrier_release(Barrier barrier);
|
|
||||||
internal void barrier_wait(Barrier barrier);
|
|
||||||
|
|
||||||
//- rjf: scope macros
|
|
||||||
#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex))
|
|
||||||
#define RWMutexScope(mutex, write_mode) DeferLoop(rw_mutex_take((mutex), (write_mode)), rw_mutex_drop((mutex), (write_mode)))
|
|
||||||
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
|
|
||||||
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(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
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
#endif // BASE_THREADS_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,630 +0,0 @@
|
|||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Numerics
|
|
||||||
|
|
||||||
@table(name val)
|
|
||||||
CV_NumericKindTable:
|
|
||||||
{
|
|
||||||
{CHAR 0x8000}
|
|
||||||
{SHORT 0x8001}
|
|
||||||
{USHORT 0x8002}
|
|
||||||
{LONG 0x8003}
|
|
||||||
{ULONG 0x8004}
|
|
||||||
{FLOAT32 0x8005}
|
|
||||||
{FLOAT64 0x8006}
|
|
||||||
{FLOAT80 0x8007}
|
|
||||||
{FLOAT128 0x8008}
|
|
||||||
{QUADWORD 0x8009}
|
|
||||||
{UQUADWORD 0x800a}
|
|
||||||
{FLOAT48 0x800b}
|
|
||||||
{COMPLEX32 0x800c}
|
|
||||||
{COMPLEX64 0x800d}
|
|
||||||
{COMPLEX80 0x800e}
|
|
||||||
{COMPLEX128 0x800f}
|
|
||||||
{VARSTRING 0x8010}
|
|
||||||
{OCTWORD 0x8017}
|
|
||||||
{UOCTWORD 0x8018}
|
|
||||||
{DECIMAL 0x8019}
|
|
||||||
{DATE 0x801a}
|
|
||||||
{UTF8STRING 0x801b}
|
|
||||||
{FLOAT16 0x801c}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_NumericKind:
|
|
||||||
{
|
|
||||||
@expand(CV_NumericKindTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_NumericKind)
|
|
||||||
cv_string_from_numeric_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_NumericKindTable a) `case CV_NumericKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Architectures
|
|
||||||
|
|
||||||
@table(name val)
|
|
||||||
CV_ArchTable:
|
|
||||||
{
|
|
||||||
{8080 0x00}
|
|
||||||
{8086 0x01}
|
|
||||||
{80286 0x02}
|
|
||||||
{80386 0x03}
|
|
||||||
{80486 0x04}
|
|
||||||
{PENTIUM 0x05}
|
|
||||||
{PENTIUMII 0x06}
|
|
||||||
{PENTIUMIII 0x07}
|
|
||||||
{MIPS 0x10}
|
|
||||||
{MIPS16 0x11}
|
|
||||||
{MIPS32 0x12}
|
|
||||||
{MIPS64 0x13}
|
|
||||||
{MIPSI 0x14}
|
|
||||||
{MIPSII 0x15}
|
|
||||||
{MIPSIII 0x16}
|
|
||||||
{MIPSIV 0x17}
|
|
||||||
{MIPSV 0x18}
|
|
||||||
{M68000 0x20}
|
|
||||||
{M68010 0x21}
|
|
||||||
{M68020 0x22}
|
|
||||||
{M68030 0x23}
|
|
||||||
{M68040 0x24}
|
|
||||||
{ALPHA 0x30}
|
|
||||||
{ALPHA_21164 0x31}
|
|
||||||
{ALPHA_21164A 0x32}
|
|
||||||
{ALPHA_21264 0x33}
|
|
||||||
{ALPHA_21364 0x34}
|
|
||||||
{PPC601 0x40}
|
|
||||||
{PPC603 0x41}
|
|
||||||
{PPC604 0x42}
|
|
||||||
{PPC620 0x43}
|
|
||||||
{PPCFP 0x44}
|
|
||||||
{PPCBE 0x45}
|
|
||||||
{SH3 0x50}
|
|
||||||
{SH3E 0x51}
|
|
||||||
{SH3DSP 0x52}
|
|
||||||
{SH4 0x53}
|
|
||||||
{SHMEDIA 0x54}
|
|
||||||
{ARM3 0x60}
|
|
||||||
{ARM4 0x61}
|
|
||||||
{ARM4T 0x62}
|
|
||||||
{ARM5 0x63}
|
|
||||||
{ARM5T 0x64}
|
|
||||||
{ARM6 0x65}
|
|
||||||
{ARM_XMAC 0x66}
|
|
||||||
{ARM_WMMX 0x67}
|
|
||||||
{ARM7 0x68}
|
|
||||||
{OMNI 0x70}
|
|
||||||
{IA64_1 0x80}
|
|
||||||
{IA64_2 0x81}
|
|
||||||
{CEE 0x90}
|
|
||||||
{AM33 0xA0}
|
|
||||||
{M32R 0xB0}
|
|
||||||
{TRICORE 0xC0}
|
|
||||||
{X64 0xD0}
|
|
||||||
{EBC 0xE0}
|
|
||||||
{THUMB 0xF0}
|
|
||||||
{ARMNT 0xF4}
|
|
||||||
{ARM64 0xF6}
|
|
||||||
{D3D11_SHADER 0x100}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_Arch:
|
|
||||||
{
|
|
||||||
@expand(CV_ArchTable a) `$(a.name) = $(a.val)`,
|
|
||||||
`IA64 = CV_Arch_IA64_1`,
|
|
||||||
`PENTIUMPRO = CV_Arch_PENTIUMII`,
|
|
||||||
`MIPSR4000 = CV_Arch_MIPS`,
|
|
||||||
`ALPHA_21064 = CV_Arch_ALPHA`,
|
|
||||||
`AMD64 = CV_Arch_X64`,
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_Arch)
|
|
||||||
cv_string_from_arch:
|
|
||||||
{
|
|
||||||
@expand(CV_ArchTable a) `case CV_Arch_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Registers
|
|
||||||
|
|
||||||
@table(name val) CV_AllRegTable:
|
|
||||||
{
|
|
||||||
{ERR 30000}
|
|
||||||
{TEB 30001}
|
|
||||||
{TIMER 30002}
|
|
||||||
{EFAD1 30003}
|
|
||||||
{EFAD2 30004}
|
|
||||||
{EFAD3 30005}
|
|
||||||
{VFRAME 30006}
|
|
||||||
{HANDLE 30007}
|
|
||||||
{PARAMS 30008}
|
|
||||||
{LOCALS 30009}
|
|
||||||
{TID 30010}
|
|
||||||
{ENV 30011}
|
|
||||||
{CMDLN 30012}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_AllReg:
|
|
||||||
{
|
|
||||||
@expand(CV_AllRegTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Sym Kinds
|
|
||||||
|
|
||||||
@table(name header_type_name val) CV_SymKindTable:
|
|
||||||
{
|
|
||||||
{COMPILE Compile 0x0001}
|
|
||||||
{REGISTER_16t - 0x0002}
|
|
||||||
{CONSTANT_16t - 0x0003}
|
|
||||||
{UDT_16t - 0x0004}
|
|
||||||
{SSEARCH StartSearch 0x0005}
|
|
||||||
{END - 0x0006}
|
|
||||||
{SKIP - 0x0007}
|
|
||||||
{CVRESERVE - 0x0008}
|
|
||||||
{OBJNAME_ST - 0x0009}
|
|
||||||
{ENDARG - 0x000a}
|
|
||||||
{COBOLUDT_16t - 0x000b}
|
|
||||||
{MANYREG_16t - 0x000c}
|
|
||||||
{RETURN Return 0x000d}
|
|
||||||
{ENTRYTHIS - 0x000e}
|
|
||||||
{BPREL16 - 0x0100}
|
|
||||||
{LDATA16 - 0x0101}
|
|
||||||
{GDATA16 - 0x0102}
|
|
||||||
{PUB16 - 0x0103}
|
|
||||||
{LPROC16 - 0x0104}
|
|
||||||
{GPROC16 - 0x0105}
|
|
||||||
{THUNK16 - 0x0106}
|
|
||||||
{BLOCK16 - 0x0107}
|
|
||||||
{WITH16 - 0x0108}
|
|
||||||
{LABEL16 - 0x0109}
|
|
||||||
{CEXMODEL16 - 0x010a}
|
|
||||||
{VFTABLE16 - 0x010b}
|
|
||||||
{REGREL16 - 0x010c}
|
|
||||||
{BPREL32_16t - 0x0200}
|
|
||||||
{LDATA32_16t - 0x0201}
|
|
||||||
{GDATA32_16t - 0x0202}
|
|
||||||
{PUB32_16t - 0x0203}
|
|
||||||
{LPROC32_16t - 0x0204}
|
|
||||||
{GPROC32_16t - 0x0205}
|
|
||||||
{THUNK32_ST - 0x0206}
|
|
||||||
{BLOCK32_ST - 0x0207}
|
|
||||||
{WITH32_ST - 0x0208}
|
|
||||||
{LABEL32_ST - 0x0209}
|
|
||||||
{CEXMODEL32 - 0x020a}
|
|
||||||
{VFTABLE32_16t - 0x020b}
|
|
||||||
{REGREL32_16t - 0x020c}
|
|
||||||
{LTHREAD32_16t - 0x020d}
|
|
||||||
{GTHREAD32_16t - 0x020e}
|
|
||||||
{SLINK32 SLink32 0x020f}
|
|
||||||
{LPROCMIPS_16t - 0x0300}
|
|
||||||
{GPROCMIPS_16t - 0x0301}
|
|
||||||
{PROCREF_ST - 0x0400}
|
|
||||||
{DATAREF_ST - 0x0401}
|
|
||||||
{ALIGN - 0x0402}
|
|
||||||
{LPROCREF_ST - 0x0403}
|
|
||||||
{OEM OEM 0x0404}
|
|
||||||
{TI16_MAX - 0x1000}
|
|
||||||
{CONSTANT_ST - 0x1002}
|
|
||||||
{UDT_ST - 0x1003}
|
|
||||||
{COBOLUDT_ST - 0x1004}
|
|
||||||
{MANYREG_ST - 0x1005}
|
|
||||||
{BPREL32_ST - 0x1006}
|
|
||||||
{LDATA32_ST - 0x1007}
|
|
||||||
{GDATA32_ST - 0x1008}
|
|
||||||
{PUB32_ST - 0x1009}
|
|
||||||
{LPROC32_ST - 0x100a}
|
|
||||||
{GPROC32_ST - 0x100b}
|
|
||||||
{VFTABLE32 VPath32 0x100c}
|
|
||||||
{REGREL32_ST - 0x100d}
|
|
||||||
{LTHREAD32_ST - 0x100e}
|
|
||||||
{GTHREAD32_ST - 0x100f}
|
|
||||||
{LPROCMIPS_ST - 0x1010}
|
|
||||||
{GPROCMIPS_ST - 0x1011}
|
|
||||||
{FRAMEPROC Frameproc 0x1012}
|
|
||||||
{COMPILE2_ST - 0x1013}
|
|
||||||
{MANYREG2_ST - 0x1014}
|
|
||||||
{LPROCIA64_ST - 0x1015}
|
|
||||||
{GPROCIA64_ST - 0x1016}
|
|
||||||
{LOCALSLOT_ST - 0x1017}
|
|
||||||
{PARAMSLOT_ST - 0x1018}
|
|
||||||
{ANNOTATION Annotation 0x1019}
|
|
||||||
{GMANPROC_ST - 0x101a}
|
|
||||||
{LMANPROC_ST - 0x101b}
|
|
||||||
{RESERVED1 - 0x101c}
|
|
||||||
{RESERVED2 - 0x101d}
|
|
||||||
{RESERVED3 - 0x101e}
|
|
||||||
{RESERVED4 - 0x101f}
|
|
||||||
{LMANDATA_ST - 0x1020}
|
|
||||||
{GMANDATA_ST - 0x1021}
|
|
||||||
{MANFRAMEREL_ST - 0x1022}
|
|
||||||
{MANREGISTER_ST - 0x1023}
|
|
||||||
{MANSLOT_ST - 0x1024}
|
|
||||||
{MANMANYREG_ST - 0x1025}
|
|
||||||
{MANREGREL_ST - 0x1026}
|
|
||||||
{MANMANYREG2_ST - 0x1027}
|
|
||||||
{MANTYPREF - 0x1028}
|
|
||||||
{UNAMESPACE_ST - 0x1029}
|
|
||||||
{ST_MAX - 0x1100}
|
|
||||||
{OBJNAME ObjName 0x1101}
|
|
||||||
{THUNK32 Thunk32 0x1102}
|
|
||||||
{BLOCK32 Block32 0x1103}
|
|
||||||
{WITH32 - 0x1104}
|
|
||||||
{LABEL32 Label32 0x1105}
|
|
||||||
{REGISTER Register 0x1106}
|
|
||||||
{CONSTANT Constant 0x1107}
|
|
||||||
{UDT UDT 0x1108}
|
|
||||||
{COBOLUDT - 0x1109}
|
|
||||||
{MANYREG Manyreg 0x110a}
|
|
||||||
{BPREL32 BPRel32 0x110b}
|
|
||||||
{LDATA32 Data32 0x110c}
|
|
||||||
{GDATA32 Data32 0x110d}
|
|
||||||
{PUB32 Pub32 0x110e}
|
|
||||||
{LPROC32 Proc32 0x110f}
|
|
||||||
{GPROC32 Proc32 0x1110}
|
|
||||||
{REGREL32 Regrel32 0x1111}
|
|
||||||
{LTHREAD32 Thread32 0x1112}
|
|
||||||
{GTHREAD32 Thread32 0x1113}
|
|
||||||
{LPROCMIPS - 0x1114}
|
|
||||||
{GPROCMIPS - 0x1115}
|
|
||||||
{COMPILE2 Compile2 0x1116}
|
|
||||||
{MANYREG2 Manyreg2 0x1117}
|
|
||||||
{LPROCIA64 - 0x1118}
|
|
||||||
{GPROCIA64 - 0x1119}
|
|
||||||
{LOCALSLOT Slot 0x111a}
|
|
||||||
{PARAMSLOT - 0x111b}
|
|
||||||
{LMANDATA - 0x111c}
|
|
||||||
{GMANDATA - 0x111d}
|
|
||||||
{MANFRAMEREL AttrFrameRel 0x111e}
|
|
||||||
{MANREGISTER AttrReg 0x111f}
|
|
||||||
{MANSLOT - 0x1120}
|
|
||||||
{MANMANYREG AttrManyReg 0x1121}
|
|
||||||
{MANREGREL AttrRegRel 0x1122}
|
|
||||||
{MANMANYREG2 - 0x1123}
|
|
||||||
{UNAMESPACE UNamespace 0x1124}
|
|
||||||
{PROCREF Ref2 0x1125}
|
|
||||||
{DATAREF Ref2 0x1126}
|
|
||||||
{LPROCREF Ref2 0x1127}
|
|
||||||
{ANNOTATIONREF - 0x1128}
|
|
||||||
{TOKENREF - 0x1129}
|
|
||||||
{GMANPROC - 0x112a}
|
|
||||||
{LMANPROC - 0x112b}
|
|
||||||
{TRAMPOLINE Trampoline 0x112c}
|
|
||||||
{MANCONSTANT - 0x112d}
|
|
||||||
{ATTR_FRAMEREL AttrFrameRel 0x112e}
|
|
||||||
{ATTR_REGISTER AttrReg 0x112f}
|
|
||||||
{ATTR_REGREL AttrRegRel 0x1130}
|
|
||||||
{ATTR_MANYREG AttrManyReg 0x1131}
|
|
||||||
{SEPCODE Sepcode 0x1132}
|
|
||||||
{DEFRANGE_2005 - 0x1134}
|
|
||||||
{DEFRANGE2_2005 - 0x1135}
|
|
||||||
{SECTION Section 0x1136}
|
|
||||||
{COFFGROUP CoffGroup 0x1137}
|
|
||||||
{EXPORT Export 0x1138}
|
|
||||||
{CALLSITEINFO CallSiteInfo 0x1139}
|
|
||||||
{FRAMECOOKIE FrameCookie 0x113a}
|
|
||||||
{DISCARDED Discarded 0x113b}
|
|
||||||
{COMPILE3 Compile3 0x113c}
|
|
||||||
{ENVBLOCK EnvBlock 0x113d}
|
|
||||||
{LOCAL Local 0x113e}
|
|
||||||
{DEFRANGE - 0x113f}
|
|
||||||
{DEFRANGE_SUBFIELD DefrangeSubfield 0x1140}
|
|
||||||
{DEFRANGE_REGISTER DefrangeRegister 0x1141}
|
|
||||||
{DEFRANGE_FRAMEPOINTER_REL DefrangeFramepointerRel 0x1142}
|
|
||||||
{DEFRANGE_SUBFIELD_REGISTER DefrangeSubfieldRegister 0x1143}
|
|
||||||
{DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE DefrangeFramepointerRelFullScope 0x1144}
|
|
||||||
{DEFRANGE_REGISTER_REL DefrangeRegisterRel 0x1145}
|
|
||||||
{LPROC32_ID - 0x1146}
|
|
||||||
{GPROC32_ID - 0x1147}
|
|
||||||
{LPROCMIPS_ID - 0x1148}
|
|
||||||
{GPROCMIPS_ID - 0x1149}
|
|
||||||
{LPROCIA64_ID - 0x114a}
|
|
||||||
{GPROCIA64_ID - 0x114b}
|
|
||||||
{BUILDINFO BuildInfo 0x114c}
|
|
||||||
{INLINESITE InlineSite 0x114d}
|
|
||||||
{INLINESITE_END - 0x114e}
|
|
||||||
{PROC_ID_END - 0x114f}
|
|
||||||
{DEFRANGE_HLSL - 0x1150}
|
|
||||||
{GDATA_HLSL - 0x1151}
|
|
||||||
{LDATA_HLSL - 0x1152}
|
|
||||||
{FILESTATIC FileStatic 0x1153}
|
|
||||||
{LPROC32_DPC - 0x1155}
|
|
||||||
{LPROC32_DPC_ID - 0x1156}
|
|
||||||
{DEFRANGE_DPC_PTR_TAG - 0x1157}
|
|
||||||
{DPC_SYM_TAG_MAP - 0x1158}
|
|
||||||
{ARMSWITCHTABLE - 0x1159}
|
|
||||||
{CALLEES FunctionList 0x115a}
|
|
||||||
{CALLERS FunctionList 0x115b}
|
|
||||||
{POGODATA PogoInfo 0x115c}
|
|
||||||
{INLINESITE2 InlineSite2 0x115d}
|
|
||||||
{HEAPALLOCSITE HeapAllocSite 0x115e}
|
|
||||||
{MOD_TYPEREF ModTypeRef 0x115f}
|
|
||||||
{REF_MINIPDB RefMiniPdb 0x1160}
|
|
||||||
{PDBMAP - 0x1161}
|
|
||||||
{GDATA_HLSL32 - 0x1162}
|
|
||||||
{LDATA_HLSL32 - 0x1163}
|
|
||||||
{GDATA_HLSL32_EX - 0x1164}
|
|
||||||
{LDATA_HLSL32_EX - 0x1165}
|
|
||||||
{FASTLINK FastLink 0x1167}
|
|
||||||
{INLINEES Inlinees 0x1168}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_SymKind:
|
|
||||||
{
|
|
||||||
@expand(CV_SymKindTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_SymKind)
|
|
||||||
cv_string_from_sym_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_SymKindTable a) `case CV_SymKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions)
|
|
||||||
{
|
|
||||||
`internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions) @c_file
|
|
||||||
{
|
|
||||||
`internal U64`;
|
|
||||||
`cv_header_struct_size_from_sym_kind(CV_SymKind v)`;
|
|
||||||
`{`;
|
|
||||||
`U64 result = 0;`;
|
|
||||||
`switch(v)`;
|
|
||||||
`{`;
|
|
||||||
`default:{}break;`;
|
|
||||||
@expand(CV_SymKindTable a) `$(a.header_type_name != "-" -> "case CV_SymKind_"..a.name..":{result = sizeof(CV_Sym"..a.header_type_name..");}break;")`;
|
|
||||||
`}`;
|
|
||||||
`return result;`;
|
|
||||||
`}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Basic Types
|
|
||||||
|
|
||||||
@table(name val type_name)
|
|
||||||
CV_BasicTypeTable:
|
|
||||||
{
|
|
||||||
{NOTYPE 0x00 "" }
|
|
||||||
{ABS 0x01 "" }
|
|
||||||
{SEGMENT 0x02 "" }
|
|
||||||
{VOID 0x03 "void" }
|
|
||||||
{CURRENCY 0x04 "" }
|
|
||||||
{NBASICSTR 0x05 "" }
|
|
||||||
{FBASICSTR 0x06 "" }
|
|
||||||
{NOTTRANS 0x07 "" }
|
|
||||||
{HRESULT 0x08 "HRESULT" }
|
|
||||||
{CHAR 0x10 "CHAR" }
|
|
||||||
{SHORT 0x11 "SHORT" }
|
|
||||||
{LONG 0x12 "LONG" }
|
|
||||||
{QUAD 0x13 "QUAD" }
|
|
||||||
{OCT 0x14 "OCT" }
|
|
||||||
{UCHAR 0x20 "UCHAR" }
|
|
||||||
{USHORT 0x21 "USHORT" }
|
|
||||||
{ULONG 0x22 "ULONG" }
|
|
||||||
{UQUAD 0x23 "UQUAD" }
|
|
||||||
{UOCT 0x24 "UOCT" }
|
|
||||||
{BOOL8 0x30 "BOOL8" }
|
|
||||||
{BOOL16 0x31 "BOOL16" }
|
|
||||||
{BOOL32 0x32 "BOOL32" }
|
|
||||||
{BOOL64 0x33 "BOOL64" }
|
|
||||||
{FLOAT32 0x40 "FLOAT32" }
|
|
||||||
{FLOAT64 0x41 "FLOAT64" }
|
|
||||||
{FLOAT80 0x42 "FLOAT80" }
|
|
||||||
{FLOAT128 0x43 "FLOAT128" }
|
|
||||||
{FLOAT48 0x44 "FLOAT48" }
|
|
||||||
{FLOAT32PP 0x45 "FLOAT32PP" }
|
|
||||||
{FLOAT16 0x46 "FLOAT16" }
|
|
||||||
{COMPLEX32 0x50 "ComplexF32" }
|
|
||||||
{COMPLEX64 0x51 "ComplexF64" }
|
|
||||||
{COMPLEX80 0x52 "ComplexF80" }
|
|
||||||
{COMPLEX128 0x53 "ComplexF128" }
|
|
||||||
{BIT 0x60 "" }
|
|
||||||
{PASCHAR 0x61 "" }
|
|
||||||
{BOOL32FF 0x62 "BOOL32FF" }
|
|
||||||
{INT8 0x68 "int8" }
|
|
||||||
{UINT8 0x69 "uint8" }
|
|
||||||
{RCHAR 0x70 "char" }
|
|
||||||
{WCHAR 0x71 "WCHAR" }
|
|
||||||
{INT16 0x72 "int16" }
|
|
||||||
{UINT16 0x73 "uint16" }
|
|
||||||
{INT32 0x74 "int32" }
|
|
||||||
{UINT32 0x75 "uint32" }
|
|
||||||
{INT64 0x76 "int64" }
|
|
||||||
{UINT64 0x77 "uint64" }
|
|
||||||
{INT128 0x78 "int128" }
|
|
||||||
{UINT128 0x79 "uint128" }
|
|
||||||
{CHAR16 0x7a "char16" }
|
|
||||||
{CHAR32 0x7b "char32" }
|
|
||||||
{CHAR8 0x7c "char" }
|
|
||||||
{PTR 0xf0 "PTR" }
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U8) CV_BasicType:
|
|
||||||
{
|
|
||||||
@expand(CV_BasicTypeTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_BasicType) cv_string_from_basic_type:
|
|
||||||
{
|
|
||||||
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.name)");}break`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_BasicType) cv_type_name_from_basic_type:
|
|
||||||
{
|
|
||||||
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.type_name)");}break`
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Leaf Kinds
|
|
||||||
|
|
||||||
@table(name header_type_name val)
|
|
||||||
CV_LeafKindTable:
|
|
||||||
{
|
|
||||||
{NOTYPE - 0x0000}
|
|
||||||
{MODIFIER_16t - 0x0001}
|
|
||||||
{POINTER_16t - 0x0002}
|
|
||||||
{ARRAY_16t - 0x0003}
|
|
||||||
{CLASS_16t - 0x0004}
|
|
||||||
{STRUCTURE_16t - 0x0005}
|
|
||||||
{UNION_16t - 0x0006}
|
|
||||||
{ENUM_16t - 0x0007}
|
|
||||||
{PROCEDURE_16t - 0x0008}
|
|
||||||
{MFUNCTION_16t - 0x0009}
|
|
||||||
{VTSHAPE VTShape 0x000a}
|
|
||||||
{COBOL0_16t - 0x000b}
|
|
||||||
{COBOL1 - 0x000c}
|
|
||||||
{BARRAY_16t - 0x000d}
|
|
||||||
{LABEL Label 0x000e}
|
|
||||||
{NULL - 0x000f}
|
|
||||||
{NOTTRAN - 0x0010}
|
|
||||||
{DIMARRAY_16t - 0x0011}
|
|
||||||
{VFTPATH_16t - 0x0012}
|
|
||||||
{PRECOMP_16t - 0x0013}
|
|
||||||
{ENDPRECOMP - 0x0014}
|
|
||||||
{OEM_16t - 0x0015}
|
|
||||||
{TYPESERVER_ST - 0x0016}
|
|
||||||
{SKIP_16t - 0x0200}
|
|
||||||
{ARGLIST_16t - 0x0201}
|
|
||||||
{DEFARG_16t - 0x0202}
|
|
||||||
{LIST - 0x0203}
|
|
||||||
{FIELDLIST_16t - 0x0204}
|
|
||||||
{DERIVED_16t - 0x0205}
|
|
||||||
{BITFIELD_16t - 0x0206}
|
|
||||||
{METHODLIST_16t - 0x0207}
|
|
||||||
{DIMCONU_16t - 0x0208}
|
|
||||||
{DIMCONLU_16t - 0x0209}
|
|
||||||
{DIMVARU_16t - 0x020a}
|
|
||||||
{DIMVARLU_16t - 0x020b}
|
|
||||||
{REFSYM - 0x020c}
|
|
||||||
{BCLASS_16t - 0x0400}
|
|
||||||
{VBCLASS_16t - 0x0401}
|
|
||||||
{IVBCLASS_16t - 0x0402}
|
|
||||||
{ENUMERATE_ST - 0x0403}
|
|
||||||
{FRIENDFCN_16t - 0x0404}
|
|
||||||
{INDEX_16t - 0x0405}
|
|
||||||
{MEMBER_16t - 0x0406}
|
|
||||||
{STMEMBER_16t - 0x0407}
|
|
||||||
{METHOD_16t - 0x0408}
|
|
||||||
{NESTTYPE_16t - 0x0409}
|
|
||||||
{VFUNCTAB_16t - 0x040a}
|
|
||||||
{FRIENDCLS_16t - 0x040b}
|
|
||||||
{ONEMETHOD_16t - 0x040c}
|
|
||||||
{VFUNCOFF_16t - 0x040d}
|
|
||||||
{TI16_MAX - 0x1000}
|
|
||||||
{MODIFIER Modifier 0x1001}
|
|
||||||
{POINTER Pointer 0x1002}
|
|
||||||
{ARRAY_ST - 0x1003}
|
|
||||||
{CLASS_ST - 0x1004}
|
|
||||||
{STRUCTURE_ST - 0x1005}
|
|
||||||
{UNION_ST - 0x1006}
|
|
||||||
{ENUM_ST - 0x1007}
|
|
||||||
{PROCEDURE Procedure 0x1008}
|
|
||||||
{MFUNCTION MFunction 0x1009}
|
|
||||||
{COBOL0 - 0x100a}
|
|
||||||
{BARRAY - 0x100b}
|
|
||||||
{DIMARRAY_ST - 0x100c}
|
|
||||||
{VFTPATH VFPath 0x100d}
|
|
||||||
{PRECOMP_ST - 0x100e}
|
|
||||||
{OEM - 0x100f}
|
|
||||||
{ALIAS_ST - 0x1010}
|
|
||||||
{OEM2 - 0x1011}
|
|
||||||
{SKIP Skip 0x1200}
|
|
||||||
{ARGLIST ArgList 0x1201}
|
|
||||||
{DEFARG_ST - 0x1202}
|
|
||||||
{FIELDLIST - 0x1203}
|
|
||||||
{DERIVED - 0x1204}
|
|
||||||
{BITFIELD BitField 0x1205}
|
|
||||||
{METHODLIST MethodListMember 0x1206}
|
|
||||||
{DIMCONU - 0x1207}
|
|
||||||
{DIMCONLU - 0x1208}
|
|
||||||
{DIMVARU - 0x1209}
|
|
||||||
{DIMVARLU - 0x120a}
|
|
||||||
{BCLASS BClass 0x1400}
|
|
||||||
{VBCLASS VBClass 0x1401}
|
|
||||||
{IVBCLASS - 0x1402}
|
|
||||||
{FRIENDFCN_ST - 0x1403}
|
|
||||||
{INDEX Index 0x1404}
|
|
||||||
{MEMBER_ST - 0x1405}
|
|
||||||
{STMEMBER_ST - 0x1406}
|
|
||||||
{METHOD_ST - 0x1407}
|
|
||||||
{NESTTYPE_ST - 0x1408}
|
|
||||||
{VFUNCTAB VFuncTab 0x1409}
|
|
||||||
{FRIENDCLS - 0x140a}
|
|
||||||
{ONEMETHOD_ST - 0x140b}
|
|
||||||
{VFUNCOFF VFuncOff 0x140c}
|
|
||||||
{NESTTYPEEX_ST - 0x140d}
|
|
||||||
{MEMBERMODIFY_ST - 0x140e}
|
|
||||||
{MANAGED_ST - 0x140f}
|
|
||||||
{ST_MAX - 0x1500}
|
|
||||||
{TYPESERVER TypeServer 0x1501}
|
|
||||||
{ENUMERATE Enumerate 0x1502}
|
|
||||||
{ARRAY Array 0x1503}
|
|
||||||
{CLASS Struct 0x1504}
|
|
||||||
{STRUCTURE Struct 0x1505}
|
|
||||||
{UNION Union 0x1506}
|
|
||||||
{ENUM Enum 0x1507}
|
|
||||||
{DIMARRAY - 0x1508}
|
|
||||||
{PRECOMP PreComp 0x1509}
|
|
||||||
{ALIAS Alias 0x150a}
|
|
||||||
{DEFARG - 0x150b}
|
|
||||||
{FRIENDFCN - 0x150c}
|
|
||||||
{MEMBER Member 0x150d}
|
|
||||||
{STMEMBER StMember 0x150e}
|
|
||||||
{METHOD Method 0x150f}
|
|
||||||
{NESTTYPE NestType 0x1510}
|
|
||||||
{ONEMETHOD OneMethod 0x1511}
|
|
||||||
{NESTTYPEEX NestTypeEx 0x1512}
|
|
||||||
{MEMBERMODIFY - 0x1513}
|
|
||||||
{MANAGED - 0x1514}
|
|
||||||
{TYPESERVER2 TypeServer2 0x1515}
|
|
||||||
{STRIDED_ARRAY - 0x1516}
|
|
||||||
{HLSL - 0x1517}
|
|
||||||
{MODIFIER_EX - 0x1518}
|
|
||||||
{INTERFACE Struct 0x1519}
|
|
||||||
{BINTERFACE - 0x151a}
|
|
||||||
{VECTOR - 0x151b}
|
|
||||||
{MATRIX - 0x151c}
|
|
||||||
{VFTABLE - 0x151d}
|
|
||||||
{FUNC_ID FuncId 0x1601}
|
|
||||||
{MFUNC_ID MFuncId 0x1602}
|
|
||||||
{BUILDINFO BuildInfo 0x1603}
|
|
||||||
{SUBSTR_LIST SubstrList 0x1604}
|
|
||||||
{STRING_ID StringId 0x1605}
|
|
||||||
{UDT_SRC_LINE UDTSrcLine 0x1606}
|
|
||||||
{UDT_MOD_SRC_LINE UDTModSrcLine 0x1607}
|
|
||||||
{CLASS2 Struct2 0x1608}
|
|
||||||
{STRUCT2 Struct2 0x1609}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_LeafKind:
|
|
||||||
{
|
|
||||||
@expand(CV_LeafKindTable a) `$(a.name) = $(a.val)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_LeafKind)
|
|
||||||
cv_string_from_leaf_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_LeafKindTable a) `case CV_LeafKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions)
|
|
||||||
{
|
|
||||||
`internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions) @c_file
|
|
||||||
{
|
|
||||||
`internal U64`;
|
|
||||||
`cv_header_struct_size_from_leaf_kind(CV_LeafKind v)`;
|
|
||||||
`{`;
|
|
||||||
`U64 result = 0;`;
|
|
||||||
`switch(v)`;
|
|
||||||
`{`;
|
|
||||||
`default:{}break;`;
|
|
||||||
@expand(CV_LeafKindTable a) `$(a.header_type_name != "-" -> "case CV_LeafKind_"..a.name..":{result = sizeof(CV_Leaf"..a.header_type_name..");}break;")`;
|
|
||||||
`}`;
|
|
||||||
`return result;`;
|
|
||||||
`}`;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_numeric(Arena *arena, CV_NumericParsed num)
|
|
||||||
{
|
|
||||||
String8 result = str8_zero();
|
|
||||||
switch (num.kind) {
|
|
||||||
case CV_NumericKind_FLOAT16: NotImplemented; break; // TODO: format float16
|
|
||||||
case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break;
|
|
||||||
case CV_NumericKind_FLOAT48: NotImplemented; break; // TODO: format float48
|
|
||||||
case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break;
|
|
||||||
case CV_NumericKind_FLOAT80: NotImplemented; break; // TODO: format float80
|
|
||||||
case CV_NumericKind_FLOAT128: NotImplemented; break; // TODO: format float128
|
|
||||||
case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break;
|
|
||||||
case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break;
|
|
||||||
case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break;
|
|
||||||
case CV_NumericKind_QUADWORD: result = push_str8f(arena, "%lld", *(S64*)num.val); break;
|
|
||||||
case CV_NumericKind_USHORT: result = push_str8f(arena, "%u", *(U16*)num.val); break;
|
|
||||||
case CV_NumericKind_ULONG: result = push_str8f(arena, "%u", *(U32*)num.val); break;
|
|
||||||
case CV_NumericKind_UQUADWORD: result = push_str8f(arena, "%llu", *(U64*)num.val); break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CODEVIEW_DUMP_H
|
|
||||||
#define CODEVIEW_DUMP_H
|
|
||||||
|
|
||||||
internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num);
|
|
||||||
|
|
||||||
#endif // CODEVIEW_DUMP_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,305 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CODEVIEW_PARSE_H
|
|
||||||
#define CODEVIEW_PARSE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Common Parser Types
|
|
||||||
|
|
||||||
// CV_Numeric layout
|
|
||||||
// x: U16
|
|
||||||
// buf: U8[]
|
|
||||||
// case (x < 0x8000): kind=U16 val=x
|
|
||||||
// case (x >= 0x8000): kind=x val=buf
|
|
||||||
|
|
||||||
typedef struct CV_NumericParsed CV_NumericParsed;
|
|
||||||
struct CV_NumericParsed
|
|
||||||
{
|
|
||||||
CV_NumericKind kind;
|
|
||||||
U8 *val;
|
|
||||||
U64 encoded_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_RecRange CV_RecRange;
|
|
||||||
struct CV_RecRange
|
|
||||||
{
|
|
||||||
U32 off;
|
|
||||||
CV_RecHeader hdr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CV_REC_RANGE_CHUNK_SIZE 511
|
|
||||||
|
|
||||||
typedef struct CV_RecRangeChunk CV_RecRangeChunk;
|
|
||||||
struct CV_RecRangeChunk
|
|
||||||
{
|
|
||||||
struct CV_RecRangeChunk *next;
|
|
||||||
CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_RecRangeStream CV_RecRangeStream;
|
|
||||||
struct CV_RecRangeStream
|
|
||||||
{
|
|
||||||
CV_RecRangeChunk *first_chunk;
|
|
||||||
CV_RecRangeChunk *last_chunk;
|
|
||||||
U64 total_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_RecRangeArray CV_RecRangeArray;
|
|
||||||
struct CV_RecRangeArray
|
|
||||||
{
|
|
||||||
CV_RecRange *ranges;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Sym Parser Types
|
|
||||||
|
|
||||||
typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo;
|
|
||||||
struct CV_SymTopLevelInfo
|
|
||||||
{
|
|
||||||
CV_Arch arch;
|
|
||||||
CV_Language language;
|
|
||||||
String8 compiler_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_SymParsed CV_SymParsed;
|
|
||||||
struct CV_SymParsed
|
|
||||||
{
|
|
||||||
// source information
|
|
||||||
String8 data;
|
|
||||||
U64 sym_align;
|
|
||||||
|
|
||||||
// sym index derived from source
|
|
||||||
CV_RecRangeArray sym_ranges;
|
|
||||||
|
|
||||||
// top-level info derived from the syms
|
|
||||||
CV_SymTopLevelInfo info;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Leaf Parser Types
|
|
||||||
|
|
||||||
typedef struct CV_LeafParsed CV_LeafParsed;
|
|
||||||
struct CV_LeafParsed
|
|
||||||
{
|
|
||||||
// source information
|
|
||||||
String8 data;
|
|
||||||
CV_TypeId itype_first;
|
|
||||||
CV_TypeId itype_opl;
|
|
||||||
|
|
||||||
// leaf index derived from source
|
|
||||||
CV_RecRangeArray leaf_ranges;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView C13 Info Parser Types
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineSiteDecoder CV_C13InlineSiteDecoder;
|
|
||||||
struct CV_C13InlineSiteDecoder
|
|
||||||
{
|
|
||||||
U64 cursor;
|
|
||||||
U64 parent_voff;
|
|
||||||
CV_InlineRangeKind range_kind;
|
|
||||||
U32 code_length;
|
|
||||||
U32 code_offset;
|
|
||||||
U32 file_off;
|
|
||||||
S32 ln;
|
|
||||||
S32 cn;
|
|
||||||
U64 code_offset_lo;
|
|
||||||
B32 code_offset_changed;
|
|
||||||
B32 code_offset_lo_changed;
|
|
||||||
B32 code_length_changed;
|
|
||||||
B32 ln_changed;
|
|
||||||
B32 file_off_changed;
|
|
||||||
Rng1U64 last_range;
|
|
||||||
U32 file_count;
|
|
||||||
Rng1U64 file_last_range;
|
|
||||||
U64 file_line_count;
|
|
||||||
U64 file_last_ln;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef U32 CV_C13InlineSiteDecoderStepFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_EmitRange = (1 << 0),
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_ExtendLastRange = (1 << 1),
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_EmitFile = (1 << 2),
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_EmitLine = (1 << 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineSiteDecoderStep CV_C13InlineSiteDecoderStep;
|
|
||||||
struct CV_C13InlineSiteDecoderStep
|
|
||||||
{
|
|
||||||
CV_C13InlineSiteDecoderStepFlags flags;
|
|
||||||
Rng1U64 range;
|
|
||||||
U64 line_voff;
|
|
||||||
U64 line_voff_end;
|
|
||||||
U64 ln;
|
|
||||||
U64 cn;
|
|
||||||
U32 file_off;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13LinesParsed CV_C13LinesParsed;
|
|
||||||
struct CV_C13LinesParsed
|
|
||||||
{
|
|
||||||
// raw info
|
|
||||||
U32 sec_idx;
|
|
||||||
U32 file_off;
|
|
||||||
U64 secrel_base_off;
|
|
||||||
|
|
||||||
// parsed info
|
|
||||||
String8 file_name;
|
|
||||||
CV_C13ChecksumKind checksum_kind;
|
|
||||||
String8 checksum;
|
|
||||||
U64 *voffs; // [line_count + 1]
|
|
||||||
U32 *line_nums; // [line_count]
|
|
||||||
U16 *col_nums; // [2*line_count]
|
|
||||||
U32 line_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode;
|
|
||||||
struct CV_C13LinesParsedNode
|
|
||||||
{
|
|
||||||
CV_C13LinesParsedNode *next;
|
|
||||||
CV_C13LinesParsed v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed;
|
|
||||||
struct CV_C13InlineeLinesParsed
|
|
||||||
{
|
|
||||||
CV_ItemId inlinee;
|
|
||||||
U32 file_off;
|
|
||||||
String8 file_name;
|
|
||||||
CV_C13ChecksumKind checksum_kind;
|
|
||||||
String8 checksum;
|
|
||||||
U32 first_source_ln;
|
|
||||||
U32 extra_file_count;
|
|
||||||
U32 *extra_files;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode;
|
|
||||||
struct CV_C13InlineeLinesParsedNode
|
|
||||||
{
|
|
||||||
CV_C13InlineeLinesParsedNode *next;
|
|
||||||
CV_C13InlineeLinesParsedNode *hash_next;
|
|
||||||
CV_C13InlineeLinesParsed v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13SubSectionNode CV_C13SubSectionNode;
|
|
||||||
struct CV_C13SubSectionNode
|
|
||||||
{
|
|
||||||
struct CV_C13SubSectionNode *next;
|
|
||||||
CV_C13SubSectionKind kind;
|
|
||||||
U32 off;
|
|
||||||
U32 size;
|
|
||||||
CV_C13LinesParsedNode *lines_first;
|
|
||||||
CV_C13LinesParsedNode *lines_last;
|
|
||||||
CV_C13InlineeLinesParsedNode *inlinee_lines_first;
|
|
||||||
CV_C13InlineeLinesParsedNode *inlinee_lines_last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13Parsed CV_C13Parsed;
|
|
||||||
struct CV_C13Parsed
|
|
||||||
{
|
|
||||||
// rjf: source data
|
|
||||||
String8 data;
|
|
||||||
|
|
||||||
// rjf: full sub-section list
|
|
||||||
CV_C13SubSectionNode *first_sub_section;
|
|
||||||
CV_C13SubSectionNode *last_sub_section;
|
|
||||||
U64 sub_section_count;
|
|
||||||
|
|
||||||
// rjf: fastpath to file checksums section
|
|
||||||
CV_C13SubSectionNode *file_chksms_sub_section;
|
|
||||||
|
|
||||||
// rjf: fastpath to map inlinee CV_ItemId -> CV_InlineeLinesParsed quickly
|
|
||||||
CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots;
|
|
||||||
U64 inlinee_lines_parsed_slots_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_UDTInfo CV_UDTInfo;
|
|
||||||
struct CV_UDTInfo
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 unique_name;
|
|
||||||
CV_TypeProps props;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Compound Types
|
|
||||||
|
|
||||||
typedef struct CV_TypeIdArray CV_TypeIdArray;
|
|
||||||
struct CV_TypeIdArray
|
|
||||||
{
|
|
||||||
CV_TypeId *itypes;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
//- Hasher
|
|
||||||
|
|
||||||
internal U64 cv_hash_from_string(String8 string);
|
|
||||||
internal U64 cv_hash_from_item_id(CV_ItemId item_id);
|
|
||||||
|
|
||||||
//- Numeric Decoder
|
|
||||||
|
|
||||||
internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl);
|
|
||||||
internal U64 cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out);
|
|
||||||
|
|
||||||
internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num);
|
|
||||||
internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num);
|
|
||||||
internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num);
|
|
||||||
|
|
||||||
internal U64 cv_u64_from_numeric(CV_NumericParsed *num);
|
|
||||||
internal S64 cv_s64_from_numeric(CV_NumericParsed *num);
|
|
||||||
internal F64 cv_f64_from_numeric(CV_NumericParsed *num);
|
|
||||||
|
|
||||||
//- Inlinee Lines Binary Annot Decoder
|
|
||||||
|
|
||||||
internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value);
|
|
||||||
internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value);
|
|
||||||
internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value);
|
|
||||||
|
|
||||||
internal CV_C13InlineSiteDecoder cv_c13_inline_site_decoder_init(U32 file_off, U32 first_source_ln, U32 parent_voff);
|
|
||||||
internal CV_C13InlineSiteDecoderStep cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots);
|
|
||||||
|
|
||||||
//- Symbol/Leaf Helpers
|
|
||||||
|
|
||||||
internal B32 cv_is_udt_name_anon(String8 name);
|
|
||||||
|
|
||||||
internal B32 cv_is_global_symbol(CV_SymKind kind);
|
|
||||||
internal B32 cv_is_typedef(CV_SymKind kind);
|
|
||||||
internal B32 cv_is_scope_symbol(CV_SymKind kind);
|
|
||||||
internal B32 cv_is_end_symbol(CV_SymKind kind);
|
|
||||||
|
|
||||||
internal B32 cv_is_udt(CV_LeafKind kind);
|
|
||||||
internal B32 cv_is_leaf_type_server(CV_LeafKind kind);
|
|
||||||
internal B32 cv_is_leaf_pch(CV_LeafKind kind);
|
|
||||||
internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind);
|
|
||||||
|
|
||||||
internal CV_TypeIndexInfoList cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data);
|
|
||||||
internal CV_TypeIndexInfoList cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data);
|
|
||||||
internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data);
|
|
||||||
internal String8Array cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data);
|
|
||||||
|
|
||||||
internal U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data);
|
|
||||||
internal String8 cv_name_from_symbol(CV_SymKind kind, String8 data);
|
|
||||||
|
|
||||||
internal CV_UDTInfo cv_get_udt_info(CV_LeafKind kind, String8 data);
|
|
||||||
internal String8 cv_name_from_udt_info(CV_UDTInfo udt_info);
|
|
||||||
|
|
||||||
//- rjf: record range stream parsing
|
|
||||||
internal CV_RecRangeStream * cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align);
|
|
||||||
internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream);
|
|
||||||
|
|
||||||
//- rjf: sym stream parsing
|
|
||||||
internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align);
|
|
||||||
|
|
||||||
//- rjf: leaf stream parsing
|
|
||||||
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);
|
|
||||||
|
|
||||||
#endif // CODEVIEW_PARSE_H
|
|
||||||
|
|
||||||
@@ -1,718 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
//- GENERATED CODE
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_numeric_kind(CV_NumericKind v)
|
|
||||||
{
|
|
||||||
String8 result = str8_lit("<Unknown CV_NumericKind>");
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_NumericKind_CHAR:{result = str8_lit("CHAR");}break;
|
|
||||||
case CV_NumericKind_SHORT:{result = str8_lit("SHORT");}break;
|
|
||||||
case CV_NumericKind_USHORT:{result = str8_lit("USHORT");}break;
|
|
||||||
case CV_NumericKind_LONG:{result = str8_lit("LONG");}break;
|
|
||||||
case CV_NumericKind_ULONG:{result = str8_lit("ULONG");}break;
|
|
||||||
case CV_NumericKind_FLOAT32:{result = str8_lit("FLOAT32");}break;
|
|
||||||
case CV_NumericKind_FLOAT64:{result = str8_lit("FLOAT64");}break;
|
|
||||||
case CV_NumericKind_FLOAT80:{result = str8_lit("FLOAT80");}break;
|
|
||||||
case CV_NumericKind_FLOAT128:{result = str8_lit("FLOAT128");}break;
|
|
||||||
case CV_NumericKind_QUADWORD:{result = str8_lit("QUADWORD");}break;
|
|
||||||
case CV_NumericKind_UQUADWORD:{result = str8_lit("UQUADWORD");}break;
|
|
||||||
case CV_NumericKind_FLOAT48:{result = str8_lit("FLOAT48");}break;
|
|
||||||
case CV_NumericKind_COMPLEX32:{result = str8_lit("COMPLEX32");}break;
|
|
||||||
case CV_NumericKind_COMPLEX64:{result = str8_lit("COMPLEX64");}break;
|
|
||||||
case CV_NumericKind_COMPLEX80:{result = str8_lit("COMPLEX80");}break;
|
|
||||||
case CV_NumericKind_COMPLEX128:{result = str8_lit("COMPLEX128");}break;
|
|
||||||
case CV_NumericKind_VARSTRING:{result = str8_lit("VARSTRING");}break;
|
|
||||||
case CV_NumericKind_OCTWORD:{result = str8_lit("OCTWORD");}break;
|
|
||||||
case CV_NumericKind_UOCTWORD:{result = str8_lit("UOCTWORD");}break;
|
|
||||||
case CV_NumericKind_DECIMAL:{result = str8_lit("DECIMAL");}break;
|
|
||||||
case CV_NumericKind_DATE:{result = str8_lit("DATE");}break;
|
|
||||||
case CV_NumericKind_UTF8STRING:{result = str8_lit("UTF8STRING");}break;
|
|
||||||
case CV_NumericKind_FLOAT16:{result = str8_lit("FLOAT16");}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_arch(CV_Arch v)
|
|
||||||
{
|
|
||||||
String8 result = str8_lit("<Unknown CV_Arch>");
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_Arch_8080:{result = str8_lit("8080");}break;
|
|
||||||
case CV_Arch_8086:{result = str8_lit("8086");}break;
|
|
||||||
case CV_Arch_80286:{result = str8_lit("80286");}break;
|
|
||||||
case CV_Arch_80386:{result = str8_lit("80386");}break;
|
|
||||||
case CV_Arch_80486:{result = str8_lit("80486");}break;
|
|
||||||
case CV_Arch_PENTIUM:{result = str8_lit("PENTIUM");}break;
|
|
||||||
case CV_Arch_PENTIUMII:{result = str8_lit("PENTIUMII");}break;
|
|
||||||
case CV_Arch_PENTIUMIII:{result = str8_lit("PENTIUMIII");}break;
|
|
||||||
case CV_Arch_MIPS:{result = str8_lit("MIPS");}break;
|
|
||||||
case CV_Arch_MIPS16:{result = str8_lit("MIPS16");}break;
|
|
||||||
case CV_Arch_MIPS32:{result = str8_lit("MIPS32");}break;
|
|
||||||
case CV_Arch_MIPS64:{result = str8_lit("MIPS64");}break;
|
|
||||||
case CV_Arch_MIPSI:{result = str8_lit("MIPSI");}break;
|
|
||||||
case CV_Arch_MIPSII:{result = str8_lit("MIPSII");}break;
|
|
||||||
case CV_Arch_MIPSIII:{result = str8_lit("MIPSIII");}break;
|
|
||||||
case CV_Arch_MIPSIV:{result = str8_lit("MIPSIV");}break;
|
|
||||||
case CV_Arch_MIPSV:{result = str8_lit("MIPSV");}break;
|
|
||||||
case CV_Arch_M68000:{result = str8_lit("M68000");}break;
|
|
||||||
case CV_Arch_M68010:{result = str8_lit("M68010");}break;
|
|
||||||
case CV_Arch_M68020:{result = str8_lit("M68020");}break;
|
|
||||||
case CV_Arch_M68030:{result = str8_lit("M68030");}break;
|
|
||||||
case CV_Arch_M68040:{result = str8_lit("M68040");}break;
|
|
||||||
case CV_Arch_ALPHA:{result = str8_lit("ALPHA");}break;
|
|
||||||
case CV_Arch_ALPHA_21164:{result = str8_lit("ALPHA_21164");}break;
|
|
||||||
case CV_Arch_ALPHA_21164A:{result = str8_lit("ALPHA_21164A");}break;
|
|
||||||
case CV_Arch_ALPHA_21264:{result = str8_lit("ALPHA_21264");}break;
|
|
||||||
case CV_Arch_ALPHA_21364:{result = str8_lit("ALPHA_21364");}break;
|
|
||||||
case CV_Arch_PPC601:{result = str8_lit("PPC601");}break;
|
|
||||||
case CV_Arch_PPC603:{result = str8_lit("PPC603");}break;
|
|
||||||
case CV_Arch_PPC604:{result = str8_lit("PPC604");}break;
|
|
||||||
case CV_Arch_PPC620:{result = str8_lit("PPC620");}break;
|
|
||||||
case CV_Arch_PPCFP:{result = str8_lit("PPCFP");}break;
|
|
||||||
case CV_Arch_PPCBE:{result = str8_lit("PPCBE");}break;
|
|
||||||
case CV_Arch_SH3:{result = str8_lit("SH3");}break;
|
|
||||||
case CV_Arch_SH3E:{result = str8_lit("SH3E");}break;
|
|
||||||
case CV_Arch_SH3DSP:{result = str8_lit("SH3DSP");}break;
|
|
||||||
case CV_Arch_SH4:{result = str8_lit("SH4");}break;
|
|
||||||
case CV_Arch_SHMEDIA:{result = str8_lit("SHMEDIA");}break;
|
|
||||||
case CV_Arch_ARM3:{result = str8_lit("ARM3");}break;
|
|
||||||
case CV_Arch_ARM4:{result = str8_lit("ARM4");}break;
|
|
||||||
case CV_Arch_ARM4T:{result = str8_lit("ARM4T");}break;
|
|
||||||
case CV_Arch_ARM5:{result = str8_lit("ARM5");}break;
|
|
||||||
case CV_Arch_ARM5T:{result = str8_lit("ARM5T");}break;
|
|
||||||
case CV_Arch_ARM6:{result = str8_lit("ARM6");}break;
|
|
||||||
case CV_Arch_ARM_XMAC:{result = str8_lit("ARM_XMAC");}break;
|
|
||||||
case CV_Arch_ARM_WMMX:{result = str8_lit("ARM_WMMX");}break;
|
|
||||||
case CV_Arch_ARM7:{result = str8_lit("ARM7");}break;
|
|
||||||
case CV_Arch_OMNI:{result = str8_lit("OMNI");}break;
|
|
||||||
case CV_Arch_IA64_1:{result = str8_lit("IA64_1");}break;
|
|
||||||
case CV_Arch_IA64_2:{result = str8_lit("IA64_2");}break;
|
|
||||||
case CV_Arch_CEE:{result = str8_lit("CEE");}break;
|
|
||||||
case CV_Arch_AM33:{result = str8_lit("AM33");}break;
|
|
||||||
case CV_Arch_M32R:{result = str8_lit("M32R");}break;
|
|
||||||
case CV_Arch_TRICORE:{result = str8_lit("TRICORE");}break;
|
|
||||||
case CV_Arch_X64:{result = str8_lit("X64");}break;
|
|
||||||
case CV_Arch_EBC:{result = str8_lit("EBC");}break;
|
|
||||||
case CV_Arch_THUMB:{result = str8_lit("THUMB");}break;
|
|
||||||
case CV_Arch_ARMNT:{result = str8_lit("ARMNT");}break;
|
|
||||||
case CV_Arch_ARM64:{result = str8_lit("ARM64");}break;
|
|
||||||
case CV_Arch_D3D11_SHADER:{result = str8_lit("D3D11_SHADER");}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_sym_kind(CV_SymKind v)
|
|
||||||
{
|
|
||||||
String8 result = str8_lit("<Unknown CV_SymKind>");
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_SymKind_COMPILE:{result = str8_lit("COMPILE");}break;
|
|
||||||
case CV_SymKind_REGISTER_16t:{result = str8_lit("REGISTER_16t");}break;
|
|
||||||
case CV_SymKind_CONSTANT_16t:{result = str8_lit("CONSTANT_16t");}break;
|
|
||||||
case CV_SymKind_UDT_16t:{result = str8_lit("UDT_16t");}break;
|
|
||||||
case CV_SymKind_SSEARCH:{result = str8_lit("SSEARCH");}break;
|
|
||||||
case CV_SymKind_END:{result = str8_lit("END");}break;
|
|
||||||
case CV_SymKind_SKIP:{result = str8_lit("SKIP");}break;
|
|
||||||
case CV_SymKind_CVRESERVE:{result = str8_lit("CVRESERVE");}break;
|
|
||||||
case CV_SymKind_OBJNAME_ST:{result = str8_lit("OBJNAME_ST");}break;
|
|
||||||
case CV_SymKind_ENDARG:{result = str8_lit("ENDARG");}break;
|
|
||||||
case CV_SymKind_COBOLUDT_16t:{result = str8_lit("COBOLUDT_16t");}break;
|
|
||||||
case CV_SymKind_MANYREG_16t:{result = str8_lit("MANYREG_16t");}break;
|
|
||||||
case CV_SymKind_RETURN:{result = str8_lit("RETURN");}break;
|
|
||||||
case CV_SymKind_ENTRYTHIS:{result = str8_lit("ENTRYTHIS");}break;
|
|
||||||
case CV_SymKind_BPREL16:{result = str8_lit("BPREL16");}break;
|
|
||||||
case CV_SymKind_LDATA16:{result = str8_lit("LDATA16");}break;
|
|
||||||
case CV_SymKind_GDATA16:{result = str8_lit("GDATA16");}break;
|
|
||||||
case CV_SymKind_PUB16:{result = str8_lit("PUB16");}break;
|
|
||||||
case CV_SymKind_LPROC16:{result = str8_lit("LPROC16");}break;
|
|
||||||
case CV_SymKind_GPROC16:{result = str8_lit("GPROC16");}break;
|
|
||||||
case CV_SymKind_THUNK16:{result = str8_lit("THUNK16");}break;
|
|
||||||
case CV_SymKind_BLOCK16:{result = str8_lit("BLOCK16");}break;
|
|
||||||
case CV_SymKind_WITH16:{result = str8_lit("WITH16");}break;
|
|
||||||
case CV_SymKind_LABEL16:{result = str8_lit("LABEL16");}break;
|
|
||||||
case CV_SymKind_CEXMODEL16:{result = str8_lit("CEXMODEL16");}break;
|
|
||||||
case CV_SymKind_VFTABLE16:{result = str8_lit("VFTABLE16");}break;
|
|
||||||
case CV_SymKind_REGREL16:{result = str8_lit("REGREL16");}break;
|
|
||||||
case CV_SymKind_BPREL32_16t:{result = str8_lit("BPREL32_16t");}break;
|
|
||||||
case CV_SymKind_LDATA32_16t:{result = str8_lit("LDATA32_16t");}break;
|
|
||||||
case CV_SymKind_GDATA32_16t:{result = str8_lit("GDATA32_16t");}break;
|
|
||||||
case CV_SymKind_PUB32_16t:{result = str8_lit("PUB32_16t");}break;
|
|
||||||
case CV_SymKind_LPROC32_16t:{result = str8_lit("LPROC32_16t");}break;
|
|
||||||
case CV_SymKind_GPROC32_16t:{result = str8_lit("GPROC32_16t");}break;
|
|
||||||
case CV_SymKind_THUNK32_ST:{result = str8_lit("THUNK32_ST");}break;
|
|
||||||
case CV_SymKind_BLOCK32_ST:{result = str8_lit("BLOCK32_ST");}break;
|
|
||||||
case CV_SymKind_WITH32_ST:{result = str8_lit("WITH32_ST");}break;
|
|
||||||
case CV_SymKind_LABEL32_ST:{result = str8_lit("LABEL32_ST");}break;
|
|
||||||
case CV_SymKind_CEXMODEL32:{result = str8_lit("CEXMODEL32");}break;
|
|
||||||
case CV_SymKind_VFTABLE32_16t:{result = str8_lit("VFTABLE32_16t");}break;
|
|
||||||
case CV_SymKind_REGREL32_16t:{result = str8_lit("REGREL32_16t");}break;
|
|
||||||
case CV_SymKind_LTHREAD32_16t:{result = str8_lit("LTHREAD32_16t");}break;
|
|
||||||
case CV_SymKind_GTHREAD32_16t:{result = str8_lit("GTHREAD32_16t");}break;
|
|
||||||
case CV_SymKind_SLINK32:{result = str8_lit("SLINK32");}break;
|
|
||||||
case CV_SymKind_LPROCMIPS_16t:{result = str8_lit("LPROCMIPS_16t");}break;
|
|
||||||
case CV_SymKind_GPROCMIPS_16t:{result = str8_lit("GPROCMIPS_16t");}break;
|
|
||||||
case CV_SymKind_PROCREF_ST:{result = str8_lit("PROCREF_ST");}break;
|
|
||||||
case CV_SymKind_DATAREF_ST:{result = str8_lit("DATAREF_ST");}break;
|
|
||||||
case CV_SymKind_ALIGN:{result = str8_lit("ALIGN");}break;
|
|
||||||
case CV_SymKind_LPROCREF_ST:{result = str8_lit("LPROCREF_ST");}break;
|
|
||||||
case CV_SymKind_OEM:{result = str8_lit("OEM");}break;
|
|
||||||
case CV_SymKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break;
|
|
||||||
case CV_SymKind_CONSTANT_ST:{result = str8_lit("CONSTANT_ST");}break;
|
|
||||||
case CV_SymKind_UDT_ST:{result = str8_lit("UDT_ST");}break;
|
|
||||||
case CV_SymKind_COBOLUDT_ST:{result = str8_lit("COBOLUDT_ST");}break;
|
|
||||||
case CV_SymKind_MANYREG_ST:{result = str8_lit("MANYREG_ST");}break;
|
|
||||||
case CV_SymKind_BPREL32_ST:{result = str8_lit("BPREL32_ST");}break;
|
|
||||||
case CV_SymKind_LDATA32_ST:{result = str8_lit("LDATA32_ST");}break;
|
|
||||||
case CV_SymKind_GDATA32_ST:{result = str8_lit("GDATA32_ST");}break;
|
|
||||||
case CV_SymKind_PUB32_ST:{result = str8_lit("PUB32_ST");}break;
|
|
||||||
case CV_SymKind_LPROC32_ST:{result = str8_lit("LPROC32_ST");}break;
|
|
||||||
case CV_SymKind_GPROC32_ST:{result = str8_lit("GPROC32_ST");}break;
|
|
||||||
case CV_SymKind_VFTABLE32:{result = str8_lit("VFTABLE32");}break;
|
|
||||||
case CV_SymKind_REGREL32_ST:{result = str8_lit("REGREL32_ST");}break;
|
|
||||||
case CV_SymKind_LTHREAD32_ST:{result = str8_lit("LTHREAD32_ST");}break;
|
|
||||||
case CV_SymKind_GTHREAD32_ST:{result = str8_lit("GTHREAD32_ST");}break;
|
|
||||||
case CV_SymKind_LPROCMIPS_ST:{result = str8_lit("LPROCMIPS_ST");}break;
|
|
||||||
case CV_SymKind_GPROCMIPS_ST:{result = str8_lit("GPROCMIPS_ST");}break;
|
|
||||||
case CV_SymKind_FRAMEPROC:{result = str8_lit("FRAMEPROC");}break;
|
|
||||||
case CV_SymKind_COMPILE2_ST:{result = str8_lit("COMPILE2_ST");}break;
|
|
||||||
case CV_SymKind_MANYREG2_ST:{result = str8_lit("MANYREG2_ST");}break;
|
|
||||||
case CV_SymKind_LPROCIA64_ST:{result = str8_lit("LPROCIA64_ST");}break;
|
|
||||||
case CV_SymKind_GPROCIA64_ST:{result = str8_lit("GPROCIA64_ST");}break;
|
|
||||||
case CV_SymKind_LOCALSLOT_ST:{result = str8_lit("LOCALSLOT_ST");}break;
|
|
||||||
case CV_SymKind_PARAMSLOT_ST:{result = str8_lit("PARAMSLOT_ST");}break;
|
|
||||||
case CV_SymKind_ANNOTATION:{result = str8_lit("ANNOTATION");}break;
|
|
||||||
case CV_SymKind_GMANPROC_ST:{result = str8_lit("GMANPROC_ST");}break;
|
|
||||||
case CV_SymKind_LMANPROC_ST:{result = str8_lit("LMANPROC_ST");}break;
|
|
||||||
case CV_SymKind_RESERVED1:{result = str8_lit("RESERVED1");}break;
|
|
||||||
case CV_SymKind_RESERVED2:{result = str8_lit("RESERVED2");}break;
|
|
||||||
case CV_SymKind_RESERVED3:{result = str8_lit("RESERVED3");}break;
|
|
||||||
case CV_SymKind_RESERVED4:{result = str8_lit("RESERVED4");}break;
|
|
||||||
case CV_SymKind_LMANDATA_ST:{result = str8_lit("LMANDATA_ST");}break;
|
|
||||||
case CV_SymKind_GMANDATA_ST:{result = str8_lit("GMANDATA_ST");}break;
|
|
||||||
case CV_SymKind_MANFRAMEREL_ST:{result = str8_lit("MANFRAMEREL_ST");}break;
|
|
||||||
case CV_SymKind_MANREGISTER_ST:{result = str8_lit("MANREGISTER_ST");}break;
|
|
||||||
case CV_SymKind_MANSLOT_ST:{result = str8_lit("MANSLOT_ST");}break;
|
|
||||||
case CV_SymKind_MANMANYREG_ST:{result = str8_lit("MANMANYREG_ST");}break;
|
|
||||||
case CV_SymKind_MANREGREL_ST:{result = str8_lit("MANREGREL_ST");}break;
|
|
||||||
case CV_SymKind_MANMANYREG2_ST:{result = str8_lit("MANMANYREG2_ST");}break;
|
|
||||||
case CV_SymKind_MANTYPREF:{result = str8_lit("MANTYPREF");}break;
|
|
||||||
case CV_SymKind_UNAMESPACE_ST:{result = str8_lit("UNAMESPACE_ST");}break;
|
|
||||||
case CV_SymKind_ST_MAX:{result = str8_lit("ST_MAX");}break;
|
|
||||||
case CV_SymKind_OBJNAME:{result = str8_lit("OBJNAME");}break;
|
|
||||||
case CV_SymKind_THUNK32:{result = str8_lit("THUNK32");}break;
|
|
||||||
case CV_SymKind_BLOCK32:{result = str8_lit("BLOCK32");}break;
|
|
||||||
case CV_SymKind_WITH32:{result = str8_lit("WITH32");}break;
|
|
||||||
case CV_SymKind_LABEL32:{result = str8_lit("LABEL32");}break;
|
|
||||||
case CV_SymKind_REGISTER:{result = str8_lit("REGISTER");}break;
|
|
||||||
case CV_SymKind_CONSTANT:{result = str8_lit("CONSTANT");}break;
|
|
||||||
case CV_SymKind_UDT:{result = str8_lit("UDT");}break;
|
|
||||||
case CV_SymKind_COBOLUDT:{result = str8_lit("COBOLUDT");}break;
|
|
||||||
case CV_SymKind_MANYREG:{result = str8_lit("MANYREG");}break;
|
|
||||||
case CV_SymKind_BPREL32:{result = str8_lit("BPREL32");}break;
|
|
||||||
case CV_SymKind_LDATA32:{result = str8_lit("LDATA32");}break;
|
|
||||||
case CV_SymKind_GDATA32:{result = str8_lit("GDATA32");}break;
|
|
||||||
case CV_SymKind_PUB32:{result = str8_lit("PUB32");}break;
|
|
||||||
case CV_SymKind_LPROC32:{result = str8_lit("LPROC32");}break;
|
|
||||||
case CV_SymKind_GPROC32:{result = str8_lit("GPROC32");}break;
|
|
||||||
case CV_SymKind_REGREL32:{result = str8_lit("REGREL32");}break;
|
|
||||||
case CV_SymKind_LTHREAD32:{result = str8_lit("LTHREAD32");}break;
|
|
||||||
case CV_SymKind_GTHREAD32:{result = str8_lit("GTHREAD32");}break;
|
|
||||||
case CV_SymKind_LPROCMIPS:{result = str8_lit("LPROCMIPS");}break;
|
|
||||||
case CV_SymKind_GPROCMIPS:{result = str8_lit("GPROCMIPS");}break;
|
|
||||||
case CV_SymKind_COMPILE2:{result = str8_lit("COMPILE2");}break;
|
|
||||||
case CV_SymKind_MANYREG2:{result = str8_lit("MANYREG2");}break;
|
|
||||||
case CV_SymKind_LPROCIA64:{result = str8_lit("LPROCIA64");}break;
|
|
||||||
case CV_SymKind_GPROCIA64:{result = str8_lit("GPROCIA64");}break;
|
|
||||||
case CV_SymKind_LOCALSLOT:{result = str8_lit("LOCALSLOT");}break;
|
|
||||||
case CV_SymKind_PARAMSLOT:{result = str8_lit("PARAMSLOT");}break;
|
|
||||||
case CV_SymKind_LMANDATA:{result = str8_lit("LMANDATA");}break;
|
|
||||||
case CV_SymKind_GMANDATA:{result = str8_lit("GMANDATA");}break;
|
|
||||||
case CV_SymKind_MANFRAMEREL:{result = str8_lit("MANFRAMEREL");}break;
|
|
||||||
case CV_SymKind_MANREGISTER:{result = str8_lit("MANREGISTER");}break;
|
|
||||||
case CV_SymKind_MANSLOT:{result = str8_lit("MANSLOT");}break;
|
|
||||||
case CV_SymKind_MANMANYREG:{result = str8_lit("MANMANYREG");}break;
|
|
||||||
case CV_SymKind_MANREGREL:{result = str8_lit("MANREGREL");}break;
|
|
||||||
case CV_SymKind_MANMANYREG2:{result = str8_lit("MANMANYREG2");}break;
|
|
||||||
case CV_SymKind_UNAMESPACE:{result = str8_lit("UNAMESPACE");}break;
|
|
||||||
case CV_SymKind_PROCREF:{result = str8_lit("PROCREF");}break;
|
|
||||||
case CV_SymKind_DATAREF:{result = str8_lit("DATAREF");}break;
|
|
||||||
case CV_SymKind_LPROCREF:{result = str8_lit("LPROCREF");}break;
|
|
||||||
case CV_SymKind_ANNOTATIONREF:{result = str8_lit("ANNOTATIONREF");}break;
|
|
||||||
case CV_SymKind_TOKENREF:{result = str8_lit("TOKENREF");}break;
|
|
||||||
case CV_SymKind_GMANPROC:{result = str8_lit("GMANPROC");}break;
|
|
||||||
case CV_SymKind_LMANPROC:{result = str8_lit("LMANPROC");}break;
|
|
||||||
case CV_SymKind_TRAMPOLINE:{result = str8_lit("TRAMPOLINE");}break;
|
|
||||||
case CV_SymKind_MANCONSTANT:{result = str8_lit("MANCONSTANT");}break;
|
|
||||||
case CV_SymKind_ATTR_FRAMEREL:{result = str8_lit("ATTR_FRAMEREL");}break;
|
|
||||||
case CV_SymKind_ATTR_REGISTER:{result = str8_lit("ATTR_REGISTER");}break;
|
|
||||||
case CV_SymKind_ATTR_REGREL:{result = str8_lit("ATTR_REGREL");}break;
|
|
||||||
case CV_SymKind_ATTR_MANYREG:{result = str8_lit("ATTR_MANYREG");}break;
|
|
||||||
case CV_SymKind_SEPCODE:{result = str8_lit("SEPCODE");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_2005:{result = str8_lit("DEFRANGE_2005");}break;
|
|
||||||
case CV_SymKind_DEFRANGE2_2005:{result = str8_lit("DEFRANGE2_2005");}break;
|
|
||||||
case CV_SymKind_SECTION:{result = str8_lit("SECTION");}break;
|
|
||||||
case CV_SymKind_COFFGROUP:{result = str8_lit("COFFGROUP");}break;
|
|
||||||
case CV_SymKind_EXPORT:{result = str8_lit("EXPORT");}break;
|
|
||||||
case CV_SymKind_CALLSITEINFO:{result = str8_lit("CALLSITEINFO");}break;
|
|
||||||
case CV_SymKind_FRAMECOOKIE:{result = str8_lit("FRAMECOOKIE");}break;
|
|
||||||
case CV_SymKind_DISCARDED:{result = str8_lit("DISCARDED");}break;
|
|
||||||
case CV_SymKind_COMPILE3:{result = str8_lit("COMPILE3");}break;
|
|
||||||
case CV_SymKind_ENVBLOCK:{result = str8_lit("ENVBLOCK");}break;
|
|
||||||
case CV_SymKind_LOCAL:{result = str8_lit("LOCAL");}break;
|
|
||||||
case CV_SymKind_DEFRANGE:{result = str8_lit("DEFRANGE");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_SUBFIELD:{result = str8_lit("DEFRANGE_SUBFIELD");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_REGISTER:{result = str8_lit("DEFRANGE_REGISTER");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = str8_lit("DEFRANGE_SUBFIELD_REGISTER");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_REGISTER_REL:{result = str8_lit("DEFRANGE_REGISTER_REL");}break;
|
|
||||||
case CV_SymKind_LPROC32_ID:{result = str8_lit("LPROC32_ID");}break;
|
|
||||||
case CV_SymKind_GPROC32_ID:{result = str8_lit("GPROC32_ID");}break;
|
|
||||||
case CV_SymKind_LPROCMIPS_ID:{result = str8_lit("LPROCMIPS_ID");}break;
|
|
||||||
case CV_SymKind_GPROCMIPS_ID:{result = str8_lit("GPROCMIPS_ID");}break;
|
|
||||||
case CV_SymKind_LPROCIA64_ID:{result = str8_lit("LPROCIA64_ID");}break;
|
|
||||||
case CV_SymKind_GPROCIA64_ID:{result = str8_lit("GPROCIA64_ID");}break;
|
|
||||||
case CV_SymKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
|
|
||||||
case CV_SymKind_INLINESITE:{result = str8_lit("INLINESITE");}break;
|
|
||||||
case CV_SymKind_INLINESITE_END:{result = str8_lit("INLINESITE_END");}break;
|
|
||||||
case CV_SymKind_PROC_ID_END:{result = str8_lit("PROC_ID_END");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_HLSL:{result = str8_lit("DEFRANGE_HLSL");}break;
|
|
||||||
case CV_SymKind_GDATA_HLSL:{result = str8_lit("GDATA_HLSL");}break;
|
|
||||||
case CV_SymKind_LDATA_HLSL:{result = str8_lit("LDATA_HLSL");}break;
|
|
||||||
case CV_SymKind_FILESTATIC:{result = str8_lit("FILESTATIC");}break;
|
|
||||||
case CV_SymKind_LPROC32_DPC:{result = str8_lit("LPROC32_DPC");}break;
|
|
||||||
case CV_SymKind_LPROC32_DPC_ID:{result = str8_lit("LPROC32_DPC_ID");}break;
|
|
||||||
case CV_SymKind_DEFRANGE_DPC_PTR_TAG:{result = str8_lit("DEFRANGE_DPC_PTR_TAG");}break;
|
|
||||||
case CV_SymKind_DPC_SYM_TAG_MAP:{result = str8_lit("DPC_SYM_TAG_MAP");}break;
|
|
||||||
case CV_SymKind_ARMSWITCHTABLE:{result = str8_lit("ARMSWITCHTABLE");}break;
|
|
||||||
case CV_SymKind_CALLEES:{result = str8_lit("CALLEES");}break;
|
|
||||||
case CV_SymKind_CALLERS:{result = str8_lit("CALLERS");}break;
|
|
||||||
case CV_SymKind_POGODATA:{result = str8_lit("POGODATA");}break;
|
|
||||||
case CV_SymKind_INLINESITE2:{result = str8_lit("INLINESITE2");}break;
|
|
||||||
case CV_SymKind_HEAPALLOCSITE:{result = str8_lit("HEAPALLOCSITE");}break;
|
|
||||||
case CV_SymKind_MOD_TYPEREF:{result = str8_lit("MOD_TYPEREF");}break;
|
|
||||||
case CV_SymKind_REF_MINIPDB:{result = str8_lit("REF_MINIPDB");}break;
|
|
||||||
case CV_SymKind_PDBMAP:{result = str8_lit("PDBMAP");}break;
|
|
||||||
case CV_SymKind_GDATA_HLSL32:{result = str8_lit("GDATA_HLSL32");}break;
|
|
||||||
case CV_SymKind_LDATA_HLSL32:{result = str8_lit("LDATA_HLSL32");}break;
|
|
||||||
case CV_SymKind_GDATA_HLSL32_EX:{result = str8_lit("GDATA_HLSL32_EX");}break;
|
|
||||||
case CV_SymKind_LDATA_HLSL32_EX:{result = str8_lit("LDATA_HLSL32_EX");}break;
|
|
||||||
case CV_SymKind_FASTLINK:{result = str8_lit("FASTLINK");}break;
|
|
||||||
case CV_SymKind_INLINEES:{result = str8_lit("INLINEES");}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_basic_type(CV_BasicType v)
|
|
||||||
{
|
|
||||||
String8 result = str8_lit("<Unknown CV_BasicType>");
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_BasicType_NOTYPE:{result = str8_lit("NOTYPE");}break;
|
|
||||||
case CV_BasicType_ABS:{result = str8_lit("ABS");}break;
|
|
||||||
case CV_BasicType_SEGMENT:{result = str8_lit("SEGMENT");}break;
|
|
||||||
case CV_BasicType_VOID:{result = str8_lit("VOID");}break;
|
|
||||||
case CV_BasicType_CURRENCY:{result = str8_lit("CURRENCY");}break;
|
|
||||||
case CV_BasicType_NBASICSTR:{result = str8_lit("NBASICSTR");}break;
|
|
||||||
case CV_BasicType_FBASICSTR:{result = str8_lit("FBASICSTR");}break;
|
|
||||||
case CV_BasicType_NOTTRANS:{result = str8_lit("NOTTRANS");}break;
|
|
||||||
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
|
|
||||||
case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break;
|
|
||||||
case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break;
|
|
||||||
case CV_BasicType_LONG:{result = str8_lit("LONG");}break;
|
|
||||||
case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break;
|
|
||||||
case CV_BasicType_OCT:{result = str8_lit("OCT");}break;
|
|
||||||
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
|
|
||||||
case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break;
|
|
||||||
case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break;
|
|
||||||
case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break;
|
|
||||||
case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break;
|
|
||||||
case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break;
|
|
||||||
case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break;
|
|
||||||
case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break;
|
|
||||||
case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break;
|
|
||||||
case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break;
|
|
||||||
case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break;
|
|
||||||
case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break;
|
|
||||||
case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break;
|
|
||||||
case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break;
|
|
||||||
case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break;
|
|
||||||
case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break;
|
|
||||||
case CV_BasicType_COMPLEX32:{result = str8_lit("COMPLEX32");}break;
|
|
||||||
case CV_BasicType_COMPLEX64:{result = str8_lit("COMPLEX64");}break;
|
|
||||||
case CV_BasicType_COMPLEX80:{result = str8_lit("COMPLEX80");}break;
|
|
||||||
case CV_BasicType_COMPLEX128:{result = str8_lit("COMPLEX128");}break;
|
|
||||||
case CV_BasicType_BIT:{result = str8_lit("BIT");}break;
|
|
||||||
case CV_BasicType_PASCHAR:{result = str8_lit("PASCHAR");}break;
|
|
||||||
case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break;
|
|
||||||
case CV_BasicType_INT8:{result = str8_lit("INT8");}break;
|
|
||||||
case CV_BasicType_UINT8:{result = str8_lit("UINT8");}break;
|
|
||||||
case CV_BasicType_RCHAR:{result = str8_lit("RCHAR");}break;
|
|
||||||
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
|
|
||||||
case CV_BasicType_INT16:{result = str8_lit("INT16");}break;
|
|
||||||
case CV_BasicType_UINT16:{result = str8_lit("UINT16");}break;
|
|
||||||
case CV_BasicType_INT32:{result = str8_lit("INT32");}break;
|
|
||||||
case CV_BasicType_UINT32:{result = str8_lit("UINT32");}break;
|
|
||||||
case CV_BasicType_INT64:{result = str8_lit("INT64");}break;
|
|
||||||
case CV_BasicType_UINT64:{result = str8_lit("UINT64");}break;
|
|
||||||
case CV_BasicType_INT128:{result = str8_lit("INT128");}break;
|
|
||||||
case CV_BasicType_UINT128:{result = str8_lit("UINT128");}break;
|
|
||||||
case CV_BasicType_CHAR16:{result = str8_lit("CHAR16");}break;
|
|
||||||
case CV_BasicType_CHAR32:{result = str8_lit("CHAR32");}break;
|
|
||||||
case CV_BasicType_CHAR8:{result = str8_lit("CHAR8");}break;
|
|
||||||
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_type_name_from_basic_type(CV_BasicType v)
|
|
||||||
{
|
|
||||||
String8 result = str8_lit("<Unknown CV_BasicType>");
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_BasicType_NOTYPE:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_ABS:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_SEGMENT:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_VOID:{result = str8_lit("void");}break;
|
|
||||||
case CV_BasicType_CURRENCY:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_NBASICSTR:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_FBASICSTR:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_NOTTRANS:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
|
|
||||||
case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break;
|
|
||||||
case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break;
|
|
||||||
case CV_BasicType_LONG:{result = str8_lit("LONG");}break;
|
|
||||||
case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break;
|
|
||||||
case CV_BasicType_OCT:{result = str8_lit("OCT");}break;
|
|
||||||
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
|
|
||||||
case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break;
|
|
||||||
case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break;
|
|
||||||
case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break;
|
|
||||||
case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break;
|
|
||||||
case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break;
|
|
||||||
case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break;
|
|
||||||
case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break;
|
|
||||||
case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break;
|
|
||||||
case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break;
|
|
||||||
case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break;
|
|
||||||
case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break;
|
|
||||||
case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break;
|
|
||||||
case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break;
|
|
||||||
case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break;
|
|
||||||
case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break;
|
|
||||||
case CV_BasicType_COMPLEX32:{result = str8_lit("ComplexF32");}break;
|
|
||||||
case CV_BasicType_COMPLEX64:{result = str8_lit("ComplexF64");}break;
|
|
||||||
case CV_BasicType_COMPLEX80:{result = str8_lit("ComplexF80");}break;
|
|
||||||
case CV_BasicType_COMPLEX128:{result = str8_lit("ComplexF128");}break;
|
|
||||||
case CV_BasicType_BIT:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_PASCHAR:{result = str8_lit("");}break;
|
|
||||||
case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break;
|
|
||||||
case CV_BasicType_INT8:{result = str8_lit("int8");}break;
|
|
||||||
case CV_BasicType_UINT8:{result = str8_lit("uint8");}break;
|
|
||||||
case CV_BasicType_RCHAR:{result = str8_lit("char");}break;
|
|
||||||
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
|
|
||||||
case CV_BasicType_INT16:{result = str8_lit("int16");}break;
|
|
||||||
case CV_BasicType_UINT16:{result = str8_lit("uint16");}break;
|
|
||||||
case CV_BasicType_INT32:{result = str8_lit("int32");}break;
|
|
||||||
case CV_BasicType_UINT32:{result = str8_lit("uint32");}break;
|
|
||||||
case CV_BasicType_INT64:{result = str8_lit("int64");}break;
|
|
||||||
case CV_BasicType_UINT64:{result = str8_lit("uint64");}break;
|
|
||||||
case CV_BasicType_INT128:{result = str8_lit("int128");}break;
|
|
||||||
case CV_BasicType_UINT128:{result = str8_lit("uint128");}break;
|
|
||||||
case CV_BasicType_CHAR16:{result = str8_lit("char16");}break;
|
|
||||||
case CV_BasicType_CHAR32:{result = str8_lit("char32");}break;
|
|
||||||
case CV_BasicType_CHAR8:{result = str8_lit("char");}break;
|
|
||||||
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_leaf_kind(CV_LeafKind v)
|
|
||||||
{
|
|
||||||
String8 result = str8_lit("<Unknown CV_LeafKind>");
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_LeafKind_NOTYPE:{result = str8_lit("NOTYPE");}break;
|
|
||||||
case CV_LeafKind_MODIFIER_16t:{result = str8_lit("MODIFIER_16t");}break;
|
|
||||||
case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break;
|
|
||||||
case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break;
|
|
||||||
case CV_LeafKind_CLASS_16t:{result = str8_lit("CLASS_16t");}break;
|
|
||||||
case CV_LeafKind_STRUCTURE_16t:{result = str8_lit("STRUCTURE_16t");}break;
|
|
||||||
case CV_LeafKind_UNION_16t:{result = str8_lit("UNION_16t");}break;
|
|
||||||
case CV_LeafKind_ENUM_16t:{result = str8_lit("ENUM_16t");}break;
|
|
||||||
case CV_LeafKind_PROCEDURE_16t:{result = str8_lit("PROCEDURE_16t");}break;
|
|
||||||
case CV_LeafKind_MFUNCTION_16t:{result = str8_lit("MFUNCTION_16t");}break;
|
|
||||||
case CV_LeafKind_VTSHAPE:{result = str8_lit("VTSHAPE");}break;
|
|
||||||
case CV_LeafKind_COBOL0_16t:{result = str8_lit("COBOL0_16t");}break;
|
|
||||||
case CV_LeafKind_COBOL1:{result = str8_lit("COBOL1");}break;
|
|
||||||
case CV_LeafKind_BARRAY_16t:{result = str8_lit("BARRAY_16t");}break;
|
|
||||||
case CV_LeafKind_LABEL:{result = str8_lit("LABEL");}break;
|
|
||||||
case CV_LeafKind_NULL:{result = str8_lit("NULL");}break;
|
|
||||||
case CV_LeafKind_NOTTRAN:{result = str8_lit("NOTTRAN");}break;
|
|
||||||
case CV_LeafKind_DIMARRAY_16t:{result = str8_lit("DIMARRAY_16t");}break;
|
|
||||||
case CV_LeafKind_VFTPATH_16t:{result = str8_lit("VFTPATH_16t");}break;
|
|
||||||
case CV_LeafKind_PRECOMP_16t:{result = str8_lit("PRECOMP_16t");}break;
|
|
||||||
case CV_LeafKind_ENDPRECOMP:{result = str8_lit("ENDPRECOMP");}break;
|
|
||||||
case CV_LeafKind_OEM_16t:{result = str8_lit("OEM_16t");}break;
|
|
||||||
case CV_LeafKind_TYPESERVER_ST:{result = str8_lit("TYPESERVER_ST");}break;
|
|
||||||
case CV_LeafKind_SKIP_16t:{result = str8_lit("SKIP_16t");}break;
|
|
||||||
case CV_LeafKind_ARGLIST_16t:{result = str8_lit("ARGLIST_16t");}break;
|
|
||||||
case CV_LeafKind_DEFARG_16t:{result = str8_lit("DEFARG_16t");}break;
|
|
||||||
case CV_LeafKind_LIST:{result = str8_lit("LIST");}break;
|
|
||||||
case CV_LeafKind_FIELDLIST_16t:{result = str8_lit("FIELDLIST_16t");}break;
|
|
||||||
case CV_LeafKind_DERIVED_16t:{result = str8_lit("DERIVED_16t");}break;
|
|
||||||
case CV_LeafKind_BITFIELD_16t:{result = str8_lit("BITFIELD_16t");}break;
|
|
||||||
case CV_LeafKind_METHODLIST_16t:{result = str8_lit("METHODLIST_16t");}break;
|
|
||||||
case CV_LeafKind_DIMCONU_16t:{result = str8_lit("DIMCONU_16t");}break;
|
|
||||||
case CV_LeafKind_DIMCONLU_16t:{result = str8_lit("DIMCONLU_16t");}break;
|
|
||||||
case CV_LeafKind_DIMVARU_16t:{result = str8_lit("DIMVARU_16t");}break;
|
|
||||||
case CV_LeafKind_DIMVARLU_16t:{result = str8_lit("DIMVARLU_16t");}break;
|
|
||||||
case CV_LeafKind_REFSYM:{result = str8_lit("REFSYM");}break;
|
|
||||||
case CV_LeafKind_BCLASS_16t:{result = str8_lit("BCLASS_16t");}break;
|
|
||||||
case CV_LeafKind_VBCLASS_16t:{result = str8_lit("VBCLASS_16t");}break;
|
|
||||||
case CV_LeafKind_IVBCLASS_16t:{result = str8_lit("IVBCLASS_16t");}break;
|
|
||||||
case CV_LeafKind_ENUMERATE_ST:{result = str8_lit("ENUMERATE_ST");}break;
|
|
||||||
case CV_LeafKind_FRIENDFCN_16t:{result = str8_lit("FRIENDFCN_16t");}break;
|
|
||||||
case CV_LeafKind_INDEX_16t:{result = str8_lit("INDEX_16t");}break;
|
|
||||||
case CV_LeafKind_MEMBER_16t:{result = str8_lit("MEMBER_16t");}break;
|
|
||||||
case CV_LeafKind_STMEMBER_16t:{result = str8_lit("STMEMBER_16t");}break;
|
|
||||||
case CV_LeafKind_METHOD_16t:{result = str8_lit("METHOD_16t");}break;
|
|
||||||
case CV_LeafKind_NESTTYPE_16t:{result = str8_lit("NESTTYPE_16t");}break;
|
|
||||||
case CV_LeafKind_VFUNCTAB_16t:{result = str8_lit("VFUNCTAB_16t");}break;
|
|
||||||
case CV_LeafKind_FRIENDCLS_16t:{result = str8_lit("FRIENDCLS_16t");}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD_16t:{result = str8_lit("ONEMETHOD_16t");}break;
|
|
||||||
case CV_LeafKind_VFUNCOFF_16t:{result = str8_lit("VFUNCOFF_16t");}break;
|
|
||||||
case CV_LeafKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break;
|
|
||||||
case CV_LeafKind_MODIFIER:{result = str8_lit("MODIFIER");}break;
|
|
||||||
case CV_LeafKind_POINTER:{result = str8_lit("POINTER");}break;
|
|
||||||
case CV_LeafKind_ARRAY_ST:{result = str8_lit("ARRAY_ST");}break;
|
|
||||||
case CV_LeafKind_CLASS_ST:{result = str8_lit("CLASS_ST");}break;
|
|
||||||
case CV_LeafKind_STRUCTURE_ST:{result = str8_lit("STRUCTURE_ST");}break;
|
|
||||||
case CV_LeafKind_UNION_ST:{result = str8_lit("UNION_ST");}break;
|
|
||||||
case CV_LeafKind_ENUM_ST:{result = str8_lit("ENUM_ST");}break;
|
|
||||||
case CV_LeafKind_PROCEDURE:{result = str8_lit("PROCEDURE");}break;
|
|
||||||
case CV_LeafKind_MFUNCTION:{result = str8_lit("MFUNCTION");}break;
|
|
||||||
case CV_LeafKind_COBOL0:{result = str8_lit("COBOL0");}break;
|
|
||||||
case CV_LeafKind_BARRAY:{result = str8_lit("BARRAY");}break;
|
|
||||||
case CV_LeafKind_DIMARRAY_ST:{result = str8_lit("DIMARRAY_ST");}break;
|
|
||||||
case CV_LeafKind_VFTPATH:{result = str8_lit("VFTPATH");}break;
|
|
||||||
case CV_LeafKind_PRECOMP_ST:{result = str8_lit("PRECOMP_ST");}break;
|
|
||||||
case CV_LeafKind_OEM:{result = str8_lit("OEM");}break;
|
|
||||||
case CV_LeafKind_ALIAS_ST:{result = str8_lit("ALIAS_ST");}break;
|
|
||||||
case CV_LeafKind_OEM2:{result = str8_lit("OEM2");}break;
|
|
||||||
case CV_LeafKind_SKIP:{result = str8_lit("SKIP");}break;
|
|
||||||
case CV_LeafKind_ARGLIST:{result = str8_lit("ARGLIST");}break;
|
|
||||||
case CV_LeafKind_DEFARG_ST:{result = str8_lit("DEFARG_ST");}break;
|
|
||||||
case CV_LeafKind_FIELDLIST:{result = str8_lit("FIELDLIST");}break;
|
|
||||||
case CV_LeafKind_DERIVED:{result = str8_lit("DERIVED");}break;
|
|
||||||
case CV_LeafKind_BITFIELD:{result = str8_lit("BITFIELD");}break;
|
|
||||||
case CV_LeafKind_METHODLIST:{result = str8_lit("METHODLIST");}break;
|
|
||||||
case CV_LeafKind_DIMCONU:{result = str8_lit("DIMCONU");}break;
|
|
||||||
case CV_LeafKind_DIMCONLU:{result = str8_lit("DIMCONLU");}break;
|
|
||||||
case CV_LeafKind_DIMVARU:{result = str8_lit("DIMVARU");}break;
|
|
||||||
case CV_LeafKind_DIMVARLU:{result = str8_lit("DIMVARLU");}break;
|
|
||||||
case CV_LeafKind_BCLASS:{result = str8_lit("BCLASS");}break;
|
|
||||||
case CV_LeafKind_VBCLASS:{result = str8_lit("VBCLASS");}break;
|
|
||||||
case CV_LeafKind_IVBCLASS:{result = str8_lit("IVBCLASS");}break;
|
|
||||||
case CV_LeafKind_FRIENDFCN_ST:{result = str8_lit("FRIENDFCN_ST");}break;
|
|
||||||
case CV_LeafKind_INDEX:{result = str8_lit("INDEX");}break;
|
|
||||||
case CV_LeafKind_MEMBER_ST:{result = str8_lit("MEMBER_ST");}break;
|
|
||||||
case CV_LeafKind_STMEMBER_ST:{result = str8_lit("STMEMBER_ST");}break;
|
|
||||||
case CV_LeafKind_METHOD_ST:{result = str8_lit("METHOD_ST");}break;
|
|
||||||
case CV_LeafKind_NESTTYPE_ST:{result = str8_lit("NESTTYPE_ST");}break;
|
|
||||||
case CV_LeafKind_VFUNCTAB:{result = str8_lit("VFUNCTAB");}break;
|
|
||||||
case CV_LeafKind_FRIENDCLS:{result = str8_lit("FRIENDCLS");}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD_ST:{result = str8_lit("ONEMETHOD_ST");}break;
|
|
||||||
case CV_LeafKind_VFUNCOFF:{result = str8_lit("VFUNCOFF");}break;
|
|
||||||
case CV_LeafKind_NESTTYPEEX_ST:{result = str8_lit("NESTTYPEEX_ST");}break;
|
|
||||||
case CV_LeafKind_MEMBERMODIFY_ST:{result = str8_lit("MEMBERMODIFY_ST");}break;
|
|
||||||
case CV_LeafKind_MANAGED_ST:{result = str8_lit("MANAGED_ST");}break;
|
|
||||||
case CV_LeafKind_ST_MAX:{result = str8_lit("ST_MAX");}break;
|
|
||||||
case CV_LeafKind_TYPESERVER:{result = str8_lit("TYPESERVER");}break;
|
|
||||||
case CV_LeafKind_ENUMERATE:{result = str8_lit("ENUMERATE");}break;
|
|
||||||
case CV_LeafKind_ARRAY:{result = str8_lit("ARRAY");}break;
|
|
||||||
case CV_LeafKind_CLASS:{result = str8_lit("CLASS");}break;
|
|
||||||
case CV_LeafKind_STRUCTURE:{result = str8_lit("STRUCTURE");}break;
|
|
||||||
case CV_LeafKind_UNION:{result = str8_lit("UNION");}break;
|
|
||||||
case CV_LeafKind_ENUM:{result = str8_lit("ENUM");}break;
|
|
||||||
case CV_LeafKind_DIMARRAY:{result = str8_lit("DIMARRAY");}break;
|
|
||||||
case CV_LeafKind_PRECOMP:{result = str8_lit("PRECOMP");}break;
|
|
||||||
case CV_LeafKind_ALIAS:{result = str8_lit("ALIAS");}break;
|
|
||||||
case CV_LeafKind_DEFARG:{result = str8_lit("DEFARG");}break;
|
|
||||||
case CV_LeafKind_FRIENDFCN:{result = str8_lit("FRIENDFCN");}break;
|
|
||||||
case CV_LeafKind_MEMBER:{result = str8_lit("MEMBER");}break;
|
|
||||||
case CV_LeafKind_STMEMBER:{result = str8_lit("STMEMBER");}break;
|
|
||||||
case CV_LeafKind_METHOD:{result = str8_lit("METHOD");}break;
|
|
||||||
case CV_LeafKind_NESTTYPE:{result = str8_lit("NESTTYPE");}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD:{result = str8_lit("ONEMETHOD");}break;
|
|
||||||
case CV_LeafKind_NESTTYPEEX:{result = str8_lit("NESTTYPEEX");}break;
|
|
||||||
case CV_LeafKind_MEMBERMODIFY:{result = str8_lit("MEMBERMODIFY");}break;
|
|
||||||
case CV_LeafKind_MANAGED:{result = str8_lit("MANAGED");}break;
|
|
||||||
case CV_LeafKind_TYPESERVER2:{result = str8_lit("TYPESERVER2");}break;
|
|
||||||
case CV_LeafKind_STRIDED_ARRAY:{result = str8_lit("STRIDED_ARRAY");}break;
|
|
||||||
case CV_LeafKind_HLSL:{result = str8_lit("HLSL");}break;
|
|
||||||
case CV_LeafKind_MODIFIER_EX:{result = str8_lit("MODIFIER_EX");}break;
|
|
||||||
case CV_LeafKind_INTERFACE:{result = str8_lit("INTERFACE");}break;
|
|
||||||
case CV_LeafKind_BINTERFACE:{result = str8_lit("BINTERFACE");}break;
|
|
||||||
case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break;
|
|
||||||
case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break;
|
|
||||||
case CV_LeafKind_VFTABLE:{result = str8_lit("VFTABLE");}break;
|
|
||||||
case CV_LeafKind_FUNC_ID:{result = str8_lit("FUNC_ID");}break;
|
|
||||||
case CV_LeafKind_MFUNC_ID:{result = str8_lit("MFUNC_ID");}break;
|
|
||||||
case CV_LeafKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
|
|
||||||
case CV_LeafKind_SUBSTR_LIST:{result = str8_lit("SUBSTR_LIST");}break;
|
|
||||||
case CV_LeafKind_STRING_ID:{result = str8_lit("STRING_ID");}break;
|
|
||||||
case CV_LeafKind_UDT_SRC_LINE:{result = str8_lit("UDT_SRC_LINE");}break;
|
|
||||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = str8_lit("UDT_MOD_SRC_LINE");}break;
|
|
||||||
case CV_LeafKind_CLASS2:{result = str8_lit("CLASS2");}break;
|
|
||||||
case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
cv_header_struct_size_from_sym_kind(CV_SymKind v)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_SymKind_COMPILE:{result = sizeof(CV_SymCompile);}break;
|
|
||||||
case CV_SymKind_SSEARCH:{result = sizeof(CV_SymStartSearch);}break;
|
|
||||||
case CV_SymKind_RETURN:{result = sizeof(CV_SymReturn);}break;
|
|
||||||
case CV_SymKind_SLINK32:{result = sizeof(CV_SymSLink32);}break;
|
|
||||||
case CV_SymKind_OEM:{result = sizeof(CV_SymOEM);}break;
|
|
||||||
case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break;
|
|
||||||
case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break;
|
|
||||||
case CV_SymKind_ANNOTATION:{result = sizeof(CV_SymAnnotation);}break;
|
|
||||||
case CV_SymKind_OBJNAME:{result = sizeof(CV_SymObjName);}break;
|
|
||||||
case CV_SymKind_THUNK32:{result = sizeof(CV_SymThunk32);}break;
|
|
||||||
case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break;
|
|
||||||
case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break;
|
|
||||||
case CV_SymKind_REGISTER:{result = sizeof(CV_SymRegister);}break;
|
|
||||||
case CV_SymKind_CONSTANT:{result = sizeof(CV_SymConstant);}break;
|
|
||||||
case CV_SymKind_UDT:{result = sizeof(CV_SymUDT);}break;
|
|
||||||
case CV_SymKind_MANYREG:{result = sizeof(CV_SymManyreg);}break;
|
|
||||||
case CV_SymKind_BPREL32:{result = sizeof(CV_SymBPRel32);}break;
|
|
||||||
case CV_SymKind_LDATA32:{result = sizeof(CV_SymData32);}break;
|
|
||||||
case CV_SymKind_GDATA32:{result = sizeof(CV_SymData32);}break;
|
|
||||||
case CV_SymKind_PUB32:{result = sizeof(CV_SymPub32);}break;
|
|
||||||
case CV_SymKind_LPROC32:{result = sizeof(CV_SymProc32);}break;
|
|
||||||
case CV_SymKind_GPROC32:{result = sizeof(CV_SymProc32);}break;
|
|
||||||
case CV_SymKind_REGREL32:{result = sizeof(CV_SymRegrel32);}break;
|
|
||||||
case CV_SymKind_LTHREAD32:{result = sizeof(CV_SymThread32);}break;
|
|
||||||
case CV_SymKind_GTHREAD32:{result = sizeof(CV_SymThread32);}break;
|
|
||||||
case CV_SymKind_COMPILE2:{result = sizeof(CV_SymCompile2);}break;
|
|
||||||
case CV_SymKind_MANYREG2:{result = sizeof(CV_SymManyreg2);}break;
|
|
||||||
case CV_SymKind_LOCALSLOT:{result = sizeof(CV_SymSlot);}break;
|
|
||||||
case CV_SymKind_MANFRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
|
|
||||||
case CV_SymKind_MANREGISTER:{result = sizeof(CV_SymAttrReg);}break;
|
|
||||||
case CV_SymKind_MANMANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
|
|
||||||
case CV_SymKind_MANREGREL:{result = sizeof(CV_SymAttrRegRel);}break;
|
|
||||||
case CV_SymKind_UNAMESPACE:{result = sizeof(CV_SymUNamespace);}break;
|
|
||||||
case CV_SymKind_PROCREF:{result = sizeof(CV_SymRef2);}break;
|
|
||||||
case CV_SymKind_DATAREF:{result = sizeof(CV_SymRef2);}break;
|
|
||||||
case CV_SymKind_LPROCREF:{result = sizeof(CV_SymRef2);}break;
|
|
||||||
case CV_SymKind_TRAMPOLINE:{result = sizeof(CV_SymTrampoline);}break;
|
|
||||||
case CV_SymKind_ATTR_FRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
|
|
||||||
case CV_SymKind_ATTR_REGISTER:{result = sizeof(CV_SymAttrReg);}break;
|
|
||||||
case CV_SymKind_ATTR_REGREL:{result = sizeof(CV_SymAttrRegRel);}break;
|
|
||||||
case CV_SymKind_ATTR_MANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
|
|
||||||
case CV_SymKind_SEPCODE:{result = sizeof(CV_SymSepcode);}break;
|
|
||||||
case CV_SymKind_SECTION:{result = sizeof(CV_SymSection);}break;
|
|
||||||
case CV_SymKind_COFFGROUP:{result = sizeof(CV_SymCoffGroup);}break;
|
|
||||||
case CV_SymKind_EXPORT:{result = sizeof(CV_SymExport);}break;
|
|
||||||
case CV_SymKind_CALLSITEINFO:{result = sizeof(CV_SymCallSiteInfo);}break;
|
|
||||||
case CV_SymKind_FRAMECOOKIE:{result = sizeof(CV_SymFrameCookie);}break;
|
|
||||||
case CV_SymKind_DISCARDED:{result = sizeof(CV_SymDiscarded);}break;
|
|
||||||
case CV_SymKind_COMPILE3:{result = sizeof(CV_SymCompile3);}break;
|
|
||||||
case CV_SymKind_ENVBLOCK:{result = sizeof(CV_SymEnvBlock);}break;
|
|
||||||
case CV_SymKind_LOCAL:{result = sizeof(CV_SymLocal);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_SUBFIELD:{result = sizeof(CV_SymDefrangeSubfield);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_REGISTER:{result = sizeof(CV_SymDefrangeRegister);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = sizeof(CV_SymDefrangeFramepointerRel);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = sizeof(CV_SymDefrangeSubfieldRegister);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = sizeof(CV_SymDefrangeFramepointerRelFullScope);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_REGISTER_REL:{result = sizeof(CV_SymDefrangeRegisterRel);}break;
|
|
||||||
case CV_SymKind_BUILDINFO:{result = sizeof(CV_SymBuildInfo);}break;
|
|
||||||
case CV_SymKind_INLINESITE:{result = sizeof(CV_SymInlineSite);}break;
|
|
||||||
case CV_SymKind_FILESTATIC:{result = sizeof(CV_SymFileStatic);}break;
|
|
||||||
case CV_SymKind_CALLEES:{result = sizeof(CV_SymFunctionList);}break;
|
|
||||||
case CV_SymKind_CALLERS:{result = sizeof(CV_SymFunctionList);}break;
|
|
||||||
case CV_SymKind_POGODATA:{result = sizeof(CV_SymPogoInfo);}break;
|
|
||||||
case CV_SymKind_INLINESITE2:{result = sizeof(CV_SymInlineSite2);}break;
|
|
||||||
case CV_SymKind_HEAPALLOCSITE:{result = sizeof(CV_SymHeapAllocSite);}break;
|
|
||||||
case CV_SymKind_MOD_TYPEREF:{result = sizeof(CV_SymModTypeRef);}break;
|
|
||||||
case CV_SymKind_REF_MINIPDB:{result = sizeof(CV_SymRefMiniPdb);}break;
|
|
||||||
case CV_SymKind_FASTLINK:{result = sizeof(CV_SymFastLink);}break;
|
|
||||||
case CV_SymKind_INLINEES:{result = sizeof(CV_SymInlinees);}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
internal U64
|
|
||||||
cv_header_struct_size_from_leaf_kind(CV_LeafKind v)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_LeafKind_VTSHAPE:{result = sizeof(CV_LeafVTShape);}break;
|
|
||||||
case CV_LeafKind_LABEL:{result = sizeof(CV_LeafLabel);}break;
|
|
||||||
case CV_LeafKind_MODIFIER:{result = sizeof(CV_LeafModifier);}break;
|
|
||||||
case CV_LeafKind_POINTER:{result = sizeof(CV_LeafPointer);}break;
|
|
||||||
case CV_LeafKind_PROCEDURE:{result = sizeof(CV_LeafProcedure);}break;
|
|
||||||
case CV_LeafKind_MFUNCTION:{result = sizeof(CV_LeafMFunction);}break;
|
|
||||||
case CV_LeafKind_VFTPATH:{result = sizeof(CV_LeafVFPath);}break;
|
|
||||||
case CV_LeafKind_SKIP:{result = sizeof(CV_LeafSkip);}break;
|
|
||||||
case CV_LeafKind_ARGLIST:{result = sizeof(CV_LeafArgList);}break;
|
|
||||||
case CV_LeafKind_BITFIELD:{result = sizeof(CV_LeafBitField);}break;
|
|
||||||
case CV_LeafKind_METHODLIST:{result = sizeof(CV_LeafMethodListMember);}break;
|
|
||||||
case CV_LeafKind_BCLASS:{result = sizeof(CV_LeafBClass);}break;
|
|
||||||
case CV_LeafKind_VBCLASS:{result = sizeof(CV_LeafVBClass);}break;
|
|
||||||
case CV_LeafKind_INDEX:{result = sizeof(CV_LeafIndex);}break;
|
|
||||||
case CV_LeafKind_VFUNCTAB:{result = sizeof(CV_LeafVFuncTab);}break;
|
|
||||||
case CV_LeafKind_VFUNCOFF:{result = sizeof(CV_LeafVFuncOff);}break;
|
|
||||||
case CV_LeafKind_TYPESERVER:{result = sizeof(CV_LeafTypeServer);}break;
|
|
||||||
case CV_LeafKind_ENUMERATE:{result = sizeof(CV_LeafEnumerate);}break;
|
|
||||||
case CV_LeafKind_ARRAY:{result = sizeof(CV_LeafArray);}break;
|
|
||||||
case CV_LeafKind_CLASS:{result = sizeof(CV_LeafStruct);}break;
|
|
||||||
case CV_LeafKind_STRUCTURE:{result = sizeof(CV_LeafStruct);}break;
|
|
||||||
case CV_LeafKind_UNION:{result = sizeof(CV_LeafUnion);}break;
|
|
||||||
case CV_LeafKind_ENUM:{result = sizeof(CV_LeafEnum);}break;
|
|
||||||
case CV_LeafKind_PRECOMP:{result = sizeof(CV_LeafPreComp);}break;
|
|
||||||
case CV_LeafKind_ALIAS:{result = sizeof(CV_LeafAlias);}break;
|
|
||||||
case CV_LeafKind_MEMBER:{result = sizeof(CV_LeafMember);}break;
|
|
||||||
case CV_LeafKind_STMEMBER:{result = sizeof(CV_LeafStMember);}break;
|
|
||||||
case CV_LeafKind_METHOD:{result = sizeof(CV_LeafMethod);}break;
|
|
||||||
case CV_LeafKind_NESTTYPE:{result = sizeof(CV_LeafNestType);}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD:{result = sizeof(CV_LeafOneMethod);}break;
|
|
||||||
case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break;
|
|
||||||
case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break;
|
|
||||||
case CV_LeafKind_INTERFACE:{result = sizeof(CV_LeafStruct);}break;
|
|
||||||
case CV_LeafKind_FUNC_ID:{result = sizeof(CV_LeafFuncId);}break;
|
|
||||||
case CV_LeafKind_MFUNC_ID:{result = sizeof(CV_LeafMFuncId);}break;
|
|
||||||
case CV_LeafKind_BUILDINFO:{result = sizeof(CV_LeafBuildInfo);}break;
|
|
||||||
case CV_LeafKind_SUBSTR_LIST:{result = sizeof(CV_LeafSubstrList);}break;
|
|
||||||
case CV_LeafKind_STRING_ID:{result = sizeof(CV_LeafStringId);}break;
|
|
||||||
case CV_LeafKind_UDT_SRC_LINE:{result = sizeof(CV_LeafUDTSrcLine);}break;
|
|
||||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = sizeof(CV_LeafUDTModSrcLine);}break;
|
|
||||||
case CV_LeafKind_CLASS2:{result = sizeof(CV_LeafStruct2);}break;
|
|
||||||
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,528 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
//- GENERATED CODE
|
|
||||||
|
|
||||||
#ifndef CODEVIEW_META_H
|
|
||||||
#define CODEVIEW_META_H
|
|
||||||
|
|
||||||
typedef U16 CV_NumericKind;
|
|
||||||
typedef enum CV_NumericKindEnum
|
|
||||||
{
|
|
||||||
CV_NumericKind_CHAR = 0x8000,
|
|
||||||
CV_NumericKind_SHORT = 0x8001,
|
|
||||||
CV_NumericKind_USHORT = 0x8002,
|
|
||||||
CV_NumericKind_LONG = 0x8003,
|
|
||||||
CV_NumericKind_ULONG = 0x8004,
|
|
||||||
CV_NumericKind_FLOAT32 = 0x8005,
|
|
||||||
CV_NumericKind_FLOAT64 = 0x8006,
|
|
||||||
CV_NumericKind_FLOAT80 = 0x8007,
|
|
||||||
CV_NumericKind_FLOAT128 = 0x8008,
|
|
||||||
CV_NumericKind_QUADWORD = 0x8009,
|
|
||||||
CV_NumericKind_UQUADWORD = 0x800a,
|
|
||||||
CV_NumericKind_FLOAT48 = 0x800b,
|
|
||||||
CV_NumericKind_COMPLEX32 = 0x800c,
|
|
||||||
CV_NumericKind_COMPLEX64 = 0x800d,
|
|
||||||
CV_NumericKind_COMPLEX80 = 0x800e,
|
|
||||||
CV_NumericKind_COMPLEX128 = 0x800f,
|
|
||||||
CV_NumericKind_VARSTRING = 0x8010,
|
|
||||||
CV_NumericKind_OCTWORD = 0x8017,
|
|
||||||
CV_NumericKind_UOCTWORD = 0x8018,
|
|
||||||
CV_NumericKind_DECIMAL = 0x8019,
|
|
||||||
CV_NumericKind_DATE = 0x801a,
|
|
||||||
CV_NumericKind_UTF8STRING = 0x801b,
|
|
||||||
CV_NumericKind_FLOAT16 = 0x801c,
|
|
||||||
} CV_NumericKindEnum;
|
|
||||||
|
|
||||||
typedef U16 CV_Arch;
|
|
||||||
typedef enum CV_ArchEnum
|
|
||||||
{
|
|
||||||
CV_Arch_8080 = 0x00,
|
|
||||||
CV_Arch_8086 = 0x01,
|
|
||||||
CV_Arch_80286 = 0x02,
|
|
||||||
CV_Arch_80386 = 0x03,
|
|
||||||
CV_Arch_80486 = 0x04,
|
|
||||||
CV_Arch_PENTIUM = 0x05,
|
|
||||||
CV_Arch_PENTIUMII = 0x06,
|
|
||||||
CV_Arch_PENTIUMIII = 0x07,
|
|
||||||
CV_Arch_MIPS = 0x10,
|
|
||||||
CV_Arch_MIPS16 = 0x11,
|
|
||||||
CV_Arch_MIPS32 = 0x12,
|
|
||||||
CV_Arch_MIPS64 = 0x13,
|
|
||||||
CV_Arch_MIPSI = 0x14,
|
|
||||||
CV_Arch_MIPSII = 0x15,
|
|
||||||
CV_Arch_MIPSIII = 0x16,
|
|
||||||
CV_Arch_MIPSIV = 0x17,
|
|
||||||
CV_Arch_MIPSV = 0x18,
|
|
||||||
CV_Arch_M68000 = 0x20,
|
|
||||||
CV_Arch_M68010 = 0x21,
|
|
||||||
CV_Arch_M68020 = 0x22,
|
|
||||||
CV_Arch_M68030 = 0x23,
|
|
||||||
CV_Arch_M68040 = 0x24,
|
|
||||||
CV_Arch_ALPHA = 0x30,
|
|
||||||
CV_Arch_ALPHA_21164 = 0x31,
|
|
||||||
CV_Arch_ALPHA_21164A = 0x32,
|
|
||||||
CV_Arch_ALPHA_21264 = 0x33,
|
|
||||||
CV_Arch_ALPHA_21364 = 0x34,
|
|
||||||
CV_Arch_PPC601 = 0x40,
|
|
||||||
CV_Arch_PPC603 = 0x41,
|
|
||||||
CV_Arch_PPC604 = 0x42,
|
|
||||||
CV_Arch_PPC620 = 0x43,
|
|
||||||
CV_Arch_PPCFP = 0x44,
|
|
||||||
CV_Arch_PPCBE = 0x45,
|
|
||||||
CV_Arch_SH3 = 0x50,
|
|
||||||
CV_Arch_SH3E = 0x51,
|
|
||||||
CV_Arch_SH3DSP = 0x52,
|
|
||||||
CV_Arch_SH4 = 0x53,
|
|
||||||
CV_Arch_SHMEDIA = 0x54,
|
|
||||||
CV_Arch_ARM3 = 0x60,
|
|
||||||
CV_Arch_ARM4 = 0x61,
|
|
||||||
CV_Arch_ARM4T = 0x62,
|
|
||||||
CV_Arch_ARM5 = 0x63,
|
|
||||||
CV_Arch_ARM5T = 0x64,
|
|
||||||
CV_Arch_ARM6 = 0x65,
|
|
||||||
CV_Arch_ARM_XMAC = 0x66,
|
|
||||||
CV_Arch_ARM_WMMX = 0x67,
|
|
||||||
CV_Arch_ARM7 = 0x68,
|
|
||||||
CV_Arch_OMNI = 0x70,
|
|
||||||
CV_Arch_IA64_1 = 0x80,
|
|
||||||
CV_Arch_IA64_2 = 0x81,
|
|
||||||
CV_Arch_CEE = 0x90,
|
|
||||||
CV_Arch_AM33 = 0xA0,
|
|
||||||
CV_Arch_M32R = 0xB0,
|
|
||||||
CV_Arch_TRICORE = 0xC0,
|
|
||||||
CV_Arch_X64 = 0xD0,
|
|
||||||
CV_Arch_EBC = 0xE0,
|
|
||||||
CV_Arch_THUMB = 0xF0,
|
|
||||||
CV_Arch_ARMNT = 0xF4,
|
|
||||||
CV_Arch_ARM64 = 0xF6,
|
|
||||||
CV_Arch_D3D11_SHADER = 0x100,
|
|
||||||
CV_Arch_IA64 = CV_Arch_IA64_1,
|
|
||||||
CV_Arch_PENTIUMPRO = CV_Arch_PENTIUMII,
|
|
||||||
CV_Arch_MIPSR4000 = CV_Arch_MIPS,
|
|
||||||
CV_Arch_ALPHA_21064 = CV_Arch_ALPHA,
|
|
||||||
CV_Arch_AMD64 = CV_Arch_X64,
|
|
||||||
} CV_ArchEnum;
|
|
||||||
|
|
||||||
typedef U16 CV_AllReg;
|
|
||||||
typedef enum CV_AllRegEnum
|
|
||||||
{
|
|
||||||
CV_AllReg_ERR = 30000,
|
|
||||||
CV_AllReg_TEB = 30001,
|
|
||||||
CV_AllReg_TIMER = 30002,
|
|
||||||
CV_AllReg_EFAD1 = 30003,
|
|
||||||
CV_AllReg_EFAD2 = 30004,
|
|
||||||
CV_AllReg_EFAD3 = 30005,
|
|
||||||
CV_AllReg_VFRAME = 30006,
|
|
||||||
CV_AllReg_HANDLE = 30007,
|
|
||||||
CV_AllReg_PARAMS = 30008,
|
|
||||||
CV_AllReg_LOCALS = 30009,
|
|
||||||
CV_AllReg_TID = 30010,
|
|
||||||
CV_AllReg_ENV = 30011,
|
|
||||||
CV_AllReg_CMDLN = 30012,
|
|
||||||
} CV_AllRegEnum;
|
|
||||||
|
|
||||||
typedef U16 CV_SymKind;
|
|
||||||
typedef enum CV_SymKindEnum
|
|
||||||
{
|
|
||||||
CV_SymKind_COMPILE = 0x0001,
|
|
||||||
CV_SymKind_REGISTER_16t = 0x0002,
|
|
||||||
CV_SymKind_CONSTANT_16t = 0x0003,
|
|
||||||
CV_SymKind_UDT_16t = 0x0004,
|
|
||||||
CV_SymKind_SSEARCH = 0x0005,
|
|
||||||
CV_SymKind_END = 0x0006,
|
|
||||||
CV_SymKind_SKIP = 0x0007,
|
|
||||||
CV_SymKind_CVRESERVE = 0x0008,
|
|
||||||
CV_SymKind_OBJNAME_ST = 0x0009,
|
|
||||||
CV_SymKind_ENDARG = 0x000a,
|
|
||||||
CV_SymKind_COBOLUDT_16t = 0x000b,
|
|
||||||
CV_SymKind_MANYREG_16t = 0x000c,
|
|
||||||
CV_SymKind_RETURN = 0x000d,
|
|
||||||
CV_SymKind_ENTRYTHIS = 0x000e,
|
|
||||||
CV_SymKind_BPREL16 = 0x0100,
|
|
||||||
CV_SymKind_LDATA16 = 0x0101,
|
|
||||||
CV_SymKind_GDATA16 = 0x0102,
|
|
||||||
CV_SymKind_PUB16 = 0x0103,
|
|
||||||
CV_SymKind_LPROC16 = 0x0104,
|
|
||||||
CV_SymKind_GPROC16 = 0x0105,
|
|
||||||
CV_SymKind_THUNK16 = 0x0106,
|
|
||||||
CV_SymKind_BLOCK16 = 0x0107,
|
|
||||||
CV_SymKind_WITH16 = 0x0108,
|
|
||||||
CV_SymKind_LABEL16 = 0x0109,
|
|
||||||
CV_SymKind_CEXMODEL16 = 0x010a,
|
|
||||||
CV_SymKind_VFTABLE16 = 0x010b,
|
|
||||||
CV_SymKind_REGREL16 = 0x010c,
|
|
||||||
CV_SymKind_BPREL32_16t = 0x0200,
|
|
||||||
CV_SymKind_LDATA32_16t = 0x0201,
|
|
||||||
CV_SymKind_GDATA32_16t = 0x0202,
|
|
||||||
CV_SymKind_PUB32_16t = 0x0203,
|
|
||||||
CV_SymKind_LPROC32_16t = 0x0204,
|
|
||||||
CV_SymKind_GPROC32_16t = 0x0205,
|
|
||||||
CV_SymKind_THUNK32_ST = 0x0206,
|
|
||||||
CV_SymKind_BLOCK32_ST = 0x0207,
|
|
||||||
CV_SymKind_WITH32_ST = 0x0208,
|
|
||||||
CV_SymKind_LABEL32_ST = 0x0209,
|
|
||||||
CV_SymKind_CEXMODEL32 = 0x020a,
|
|
||||||
CV_SymKind_VFTABLE32_16t = 0x020b,
|
|
||||||
CV_SymKind_REGREL32_16t = 0x020c,
|
|
||||||
CV_SymKind_LTHREAD32_16t = 0x020d,
|
|
||||||
CV_SymKind_GTHREAD32_16t = 0x020e,
|
|
||||||
CV_SymKind_SLINK32 = 0x020f,
|
|
||||||
CV_SymKind_LPROCMIPS_16t = 0x0300,
|
|
||||||
CV_SymKind_GPROCMIPS_16t = 0x0301,
|
|
||||||
CV_SymKind_PROCREF_ST = 0x0400,
|
|
||||||
CV_SymKind_DATAREF_ST = 0x0401,
|
|
||||||
CV_SymKind_ALIGN = 0x0402,
|
|
||||||
CV_SymKind_LPROCREF_ST = 0x0403,
|
|
||||||
CV_SymKind_OEM = 0x0404,
|
|
||||||
CV_SymKind_TI16_MAX = 0x1000,
|
|
||||||
CV_SymKind_CONSTANT_ST = 0x1002,
|
|
||||||
CV_SymKind_UDT_ST = 0x1003,
|
|
||||||
CV_SymKind_COBOLUDT_ST = 0x1004,
|
|
||||||
CV_SymKind_MANYREG_ST = 0x1005,
|
|
||||||
CV_SymKind_BPREL32_ST = 0x1006,
|
|
||||||
CV_SymKind_LDATA32_ST = 0x1007,
|
|
||||||
CV_SymKind_GDATA32_ST = 0x1008,
|
|
||||||
CV_SymKind_PUB32_ST = 0x1009,
|
|
||||||
CV_SymKind_LPROC32_ST = 0x100a,
|
|
||||||
CV_SymKind_GPROC32_ST = 0x100b,
|
|
||||||
CV_SymKind_VFTABLE32 = 0x100c,
|
|
||||||
CV_SymKind_REGREL32_ST = 0x100d,
|
|
||||||
CV_SymKind_LTHREAD32_ST = 0x100e,
|
|
||||||
CV_SymKind_GTHREAD32_ST = 0x100f,
|
|
||||||
CV_SymKind_LPROCMIPS_ST = 0x1010,
|
|
||||||
CV_SymKind_GPROCMIPS_ST = 0x1011,
|
|
||||||
CV_SymKind_FRAMEPROC = 0x1012,
|
|
||||||
CV_SymKind_COMPILE2_ST = 0x1013,
|
|
||||||
CV_SymKind_MANYREG2_ST = 0x1014,
|
|
||||||
CV_SymKind_LPROCIA64_ST = 0x1015,
|
|
||||||
CV_SymKind_GPROCIA64_ST = 0x1016,
|
|
||||||
CV_SymKind_LOCALSLOT_ST = 0x1017,
|
|
||||||
CV_SymKind_PARAMSLOT_ST = 0x1018,
|
|
||||||
CV_SymKind_ANNOTATION = 0x1019,
|
|
||||||
CV_SymKind_GMANPROC_ST = 0x101a,
|
|
||||||
CV_SymKind_LMANPROC_ST = 0x101b,
|
|
||||||
CV_SymKind_RESERVED1 = 0x101c,
|
|
||||||
CV_SymKind_RESERVED2 = 0x101d,
|
|
||||||
CV_SymKind_RESERVED3 = 0x101e,
|
|
||||||
CV_SymKind_RESERVED4 = 0x101f,
|
|
||||||
CV_SymKind_LMANDATA_ST = 0x1020,
|
|
||||||
CV_SymKind_GMANDATA_ST = 0x1021,
|
|
||||||
CV_SymKind_MANFRAMEREL_ST = 0x1022,
|
|
||||||
CV_SymKind_MANREGISTER_ST = 0x1023,
|
|
||||||
CV_SymKind_MANSLOT_ST = 0x1024,
|
|
||||||
CV_SymKind_MANMANYREG_ST = 0x1025,
|
|
||||||
CV_SymKind_MANREGREL_ST = 0x1026,
|
|
||||||
CV_SymKind_MANMANYREG2_ST = 0x1027,
|
|
||||||
CV_SymKind_MANTYPREF = 0x1028,
|
|
||||||
CV_SymKind_UNAMESPACE_ST = 0x1029,
|
|
||||||
CV_SymKind_ST_MAX = 0x1100,
|
|
||||||
CV_SymKind_OBJNAME = 0x1101,
|
|
||||||
CV_SymKind_THUNK32 = 0x1102,
|
|
||||||
CV_SymKind_BLOCK32 = 0x1103,
|
|
||||||
CV_SymKind_WITH32 = 0x1104,
|
|
||||||
CV_SymKind_LABEL32 = 0x1105,
|
|
||||||
CV_SymKind_REGISTER = 0x1106,
|
|
||||||
CV_SymKind_CONSTANT = 0x1107,
|
|
||||||
CV_SymKind_UDT = 0x1108,
|
|
||||||
CV_SymKind_COBOLUDT = 0x1109,
|
|
||||||
CV_SymKind_MANYREG = 0x110a,
|
|
||||||
CV_SymKind_BPREL32 = 0x110b,
|
|
||||||
CV_SymKind_LDATA32 = 0x110c,
|
|
||||||
CV_SymKind_GDATA32 = 0x110d,
|
|
||||||
CV_SymKind_PUB32 = 0x110e,
|
|
||||||
CV_SymKind_LPROC32 = 0x110f,
|
|
||||||
CV_SymKind_GPROC32 = 0x1110,
|
|
||||||
CV_SymKind_REGREL32 = 0x1111,
|
|
||||||
CV_SymKind_LTHREAD32 = 0x1112,
|
|
||||||
CV_SymKind_GTHREAD32 = 0x1113,
|
|
||||||
CV_SymKind_LPROCMIPS = 0x1114,
|
|
||||||
CV_SymKind_GPROCMIPS = 0x1115,
|
|
||||||
CV_SymKind_COMPILE2 = 0x1116,
|
|
||||||
CV_SymKind_MANYREG2 = 0x1117,
|
|
||||||
CV_SymKind_LPROCIA64 = 0x1118,
|
|
||||||
CV_SymKind_GPROCIA64 = 0x1119,
|
|
||||||
CV_SymKind_LOCALSLOT = 0x111a,
|
|
||||||
CV_SymKind_PARAMSLOT = 0x111b,
|
|
||||||
CV_SymKind_LMANDATA = 0x111c,
|
|
||||||
CV_SymKind_GMANDATA = 0x111d,
|
|
||||||
CV_SymKind_MANFRAMEREL = 0x111e,
|
|
||||||
CV_SymKind_MANREGISTER = 0x111f,
|
|
||||||
CV_SymKind_MANSLOT = 0x1120,
|
|
||||||
CV_SymKind_MANMANYREG = 0x1121,
|
|
||||||
CV_SymKind_MANREGREL = 0x1122,
|
|
||||||
CV_SymKind_MANMANYREG2 = 0x1123,
|
|
||||||
CV_SymKind_UNAMESPACE = 0x1124,
|
|
||||||
CV_SymKind_PROCREF = 0x1125,
|
|
||||||
CV_SymKind_DATAREF = 0x1126,
|
|
||||||
CV_SymKind_LPROCREF = 0x1127,
|
|
||||||
CV_SymKind_ANNOTATIONREF = 0x1128,
|
|
||||||
CV_SymKind_TOKENREF = 0x1129,
|
|
||||||
CV_SymKind_GMANPROC = 0x112a,
|
|
||||||
CV_SymKind_LMANPROC = 0x112b,
|
|
||||||
CV_SymKind_TRAMPOLINE = 0x112c,
|
|
||||||
CV_SymKind_MANCONSTANT = 0x112d,
|
|
||||||
CV_SymKind_ATTR_FRAMEREL = 0x112e,
|
|
||||||
CV_SymKind_ATTR_REGISTER = 0x112f,
|
|
||||||
CV_SymKind_ATTR_REGREL = 0x1130,
|
|
||||||
CV_SymKind_ATTR_MANYREG = 0x1131,
|
|
||||||
CV_SymKind_SEPCODE = 0x1132,
|
|
||||||
CV_SymKind_DEFRANGE_2005 = 0x1134,
|
|
||||||
CV_SymKind_DEFRANGE2_2005 = 0x1135,
|
|
||||||
CV_SymKind_SECTION = 0x1136,
|
|
||||||
CV_SymKind_COFFGROUP = 0x1137,
|
|
||||||
CV_SymKind_EXPORT = 0x1138,
|
|
||||||
CV_SymKind_CALLSITEINFO = 0x1139,
|
|
||||||
CV_SymKind_FRAMECOOKIE = 0x113a,
|
|
||||||
CV_SymKind_DISCARDED = 0x113b,
|
|
||||||
CV_SymKind_COMPILE3 = 0x113c,
|
|
||||||
CV_SymKind_ENVBLOCK = 0x113d,
|
|
||||||
CV_SymKind_LOCAL = 0x113e,
|
|
||||||
CV_SymKind_DEFRANGE = 0x113f,
|
|
||||||
CV_SymKind_DEFRANGE_SUBFIELD = 0x1140,
|
|
||||||
CV_SymKind_DEFRANGE_REGISTER = 0x1141,
|
|
||||||
CV_SymKind_DEFRANGE_FRAMEPOINTER_REL = 0x1142,
|
|
||||||
CV_SymKind_DEFRANGE_SUBFIELD_REGISTER = 0x1143,
|
|
||||||
CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 0x1144,
|
|
||||||
CV_SymKind_DEFRANGE_REGISTER_REL = 0x1145,
|
|
||||||
CV_SymKind_LPROC32_ID = 0x1146,
|
|
||||||
CV_SymKind_GPROC32_ID = 0x1147,
|
|
||||||
CV_SymKind_LPROCMIPS_ID = 0x1148,
|
|
||||||
CV_SymKind_GPROCMIPS_ID = 0x1149,
|
|
||||||
CV_SymKind_LPROCIA64_ID = 0x114a,
|
|
||||||
CV_SymKind_GPROCIA64_ID = 0x114b,
|
|
||||||
CV_SymKind_BUILDINFO = 0x114c,
|
|
||||||
CV_SymKind_INLINESITE = 0x114d,
|
|
||||||
CV_SymKind_INLINESITE_END = 0x114e,
|
|
||||||
CV_SymKind_PROC_ID_END = 0x114f,
|
|
||||||
CV_SymKind_DEFRANGE_HLSL = 0x1150,
|
|
||||||
CV_SymKind_GDATA_HLSL = 0x1151,
|
|
||||||
CV_SymKind_LDATA_HLSL = 0x1152,
|
|
||||||
CV_SymKind_FILESTATIC = 0x1153,
|
|
||||||
CV_SymKind_LPROC32_DPC = 0x1155,
|
|
||||||
CV_SymKind_LPROC32_DPC_ID = 0x1156,
|
|
||||||
CV_SymKind_DEFRANGE_DPC_PTR_TAG = 0x1157,
|
|
||||||
CV_SymKind_DPC_SYM_TAG_MAP = 0x1158,
|
|
||||||
CV_SymKind_ARMSWITCHTABLE = 0x1159,
|
|
||||||
CV_SymKind_CALLEES = 0x115a,
|
|
||||||
CV_SymKind_CALLERS = 0x115b,
|
|
||||||
CV_SymKind_POGODATA = 0x115c,
|
|
||||||
CV_SymKind_INLINESITE2 = 0x115d,
|
|
||||||
CV_SymKind_HEAPALLOCSITE = 0x115e,
|
|
||||||
CV_SymKind_MOD_TYPEREF = 0x115f,
|
|
||||||
CV_SymKind_REF_MINIPDB = 0x1160,
|
|
||||||
CV_SymKind_PDBMAP = 0x1161,
|
|
||||||
CV_SymKind_GDATA_HLSL32 = 0x1162,
|
|
||||||
CV_SymKind_LDATA_HLSL32 = 0x1163,
|
|
||||||
CV_SymKind_GDATA_HLSL32_EX = 0x1164,
|
|
||||||
CV_SymKind_LDATA_HLSL32_EX = 0x1165,
|
|
||||||
CV_SymKind_FASTLINK = 0x1167,
|
|
||||||
CV_SymKind_INLINEES = 0x1168,
|
|
||||||
} CV_SymKindEnum;
|
|
||||||
|
|
||||||
typedef U8 CV_BasicType;
|
|
||||||
typedef enum CV_BasicTypeEnum
|
|
||||||
{
|
|
||||||
CV_BasicType_NOTYPE = 0x00,
|
|
||||||
CV_BasicType_ABS = 0x01,
|
|
||||||
CV_BasicType_SEGMENT = 0x02,
|
|
||||||
CV_BasicType_VOID = 0x03,
|
|
||||||
CV_BasicType_CURRENCY = 0x04,
|
|
||||||
CV_BasicType_NBASICSTR = 0x05,
|
|
||||||
CV_BasicType_FBASICSTR = 0x06,
|
|
||||||
CV_BasicType_NOTTRANS = 0x07,
|
|
||||||
CV_BasicType_HRESULT = 0x08,
|
|
||||||
CV_BasicType_CHAR = 0x10,
|
|
||||||
CV_BasicType_SHORT = 0x11,
|
|
||||||
CV_BasicType_LONG = 0x12,
|
|
||||||
CV_BasicType_QUAD = 0x13,
|
|
||||||
CV_BasicType_OCT = 0x14,
|
|
||||||
CV_BasicType_UCHAR = 0x20,
|
|
||||||
CV_BasicType_USHORT = 0x21,
|
|
||||||
CV_BasicType_ULONG = 0x22,
|
|
||||||
CV_BasicType_UQUAD = 0x23,
|
|
||||||
CV_BasicType_UOCT = 0x24,
|
|
||||||
CV_BasicType_BOOL8 = 0x30,
|
|
||||||
CV_BasicType_BOOL16 = 0x31,
|
|
||||||
CV_BasicType_BOOL32 = 0x32,
|
|
||||||
CV_BasicType_BOOL64 = 0x33,
|
|
||||||
CV_BasicType_FLOAT32 = 0x40,
|
|
||||||
CV_BasicType_FLOAT64 = 0x41,
|
|
||||||
CV_BasicType_FLOAT80 = 0x42,
|
|
||||||
CV_BasicType_FLOAT128 = 0x43,
|
|
||||||
CV_BasicType_FLOAT48 = 0x44,
|
|
||||||
CV_BasicType_FLOAT32PP = 0x45,
|
|
||||||
CV_BasicType_FLOAT16 = 0x46,
|
|
||||||
CV_BasicType_COMPLEX32 = 0x50,
|
|
||||||
CV_BasicType_COMPLEX64 = 0x51,
|
|
||||||
CV_BasicType_COMPLEX80 = 0x52,
|
|
||||||
CV_BasicType_COMPLEX128 = 0x53,
|
|
||||||
CV_BasicType_BIT = 0x60,
|
|
||||||
CV_BasicType_PASCHAR = 0x61,
|
|
||||||
CV_BasicType_BOOL32FF = 0x62,
|
|
||||||
CV_BasicType_INT8 = 0x68,
|
|
||||||
CV_BasicType_UINT8 = 0x69,
|
|
||||||
CV_BasicType_RCHAR = 0x70,
|
|
||||||
CV_BasicType_WCHAR = 0x71,
|
|
||||||
CV_BasicType_INT16 = 0x72,
|
|
||||||
CV_BasicType_UINT16 = 0x73,
|
|
||||||
CV_BasicType_INT32 = 0x74,
|
|
||||||
CV_BasicType_UINT32 = 0x75,
|
|
||||||
CV_BasicType_INT64 = 0x76,
|
|
||||||
CV_BasicType_UINT64 = 0x77,
|
|
||||||
CV_BasicType_INT128 = 0x78,
|
|
||||||
CV_BasicType_UINT128 = 0x79,
|
|
||||||
CV_BasicType_CHAR16 = 0x7a,
|
|
||||||
CV_BasicType_CHAR32 = 0x7b,
|
|
||||||
CV_BasicType_CHAR8 = 0x7c,
|
|
||||||
CV_BasicType_PTR = 0xf0,
|
|
||||||
} CV_BasicTypeEnum;
|
|
||||||
|
|
||||||
typedef U16 CV_LeafKind;
|
|
||||||
typedef enum CV_LeafKindEnum
|
|
||||||
{
|
|
||||||
CV_LeafKind_NOTYPE = 0x0000,
|
|
||||||
CV_LeafKind_MODIFIER_16t = 0x0001,
|
|
||||||
CV_LeafKind_POINTER_16t = 0x0002,
|
|
||||||
CV_LeafKind_ARRAY_16t = 0x0003,
|
|
||||||
CV_LeafKind_CLASS_16t = 0x0004,
|
|
||||||
CV_LeafKind_STRUCTURE_16t = 0x0005,
|
|
||||||
CV_LeafKind_UNION_16t = 0x0006,
|
|
||||||
CV_LeafKind_ENUM_16t = 0x0007,
|
|
||||||
CV_LeafKind_PROCEDURE_16t = 0x0008,
|
|
||||||
CV_LeafKind_MFUNCTION_16t = 0x0009,
|
|
||||||
CV_LeafKind_VTSHAPE = 0x000a,
|
|
||||||
CV_LeafKind_COBOL0_16t = 0x000b,
|
|
||||||
CV_LeafKind_COBOL1 = 0x000c,
|
|
||||||
CV_LeafKind_BARRAY_16t = 0x000d,
|
|
||||||
CV_LeafKind_LABEL = 0x000e,
|
|
||||||
CV_LeafKind_NULL = 0x000f,
|
|
||||||
CV_LeafKind_NOTTRAN = 0x0010,
|
|
||||||
CV_LeafKind_DIMARRAY_16t = 0x0011,
|
|
||||||
CV_LeafKind_VFTPATH_16t = 0x0012,
|
|
||||||
CV_LeafKind_PRECOMP_16t = 0x0013,
|
|
||||||
CV_LeafKind_ENDPRECOMP = 0x0014,
|
|
||||||
CV_LeafKind_OEM_16t = 0x0015,
|
|
||||||
CV_LeafKind_TYPESERVER_ST = 0x0016,
|
|
||||||
CV_LeafKind_SKIP_16t = 0x0200,
|
|
||||||
CV_LeafKind_ARGLIST_16t = 0x0201,
|
|
||||||
CV_LeafKind_DEFARG_16t = 0x0202,
|
|
||||||
CV_LeafKind_LIST = 0x0203,
|
|
||||||
CV_LeafKind_FIELDLIST_16t = 0x0204,
|
|
||||||
CV_LeafKind_DERIVED_16t = 0x0205,
|
|
||||||
CV_LeafKind_BITFIELD_16t = 0x0206,
|
|
||||||
CV_LeafKind_METHODLIST_16t = 0x0207,
|
|
||||||
CV_LeafKind_DIMCONU_16t = 0x0208,
|
|
||||||
CV_LeafKind_DIMCONLU_16t = 0x0209,
|
|
||||||
CV_LeafKind_DIMVARU_16t = 0x020a,
|
|
||||||
CV_LeafKind_DIMVARLU_16t = 0x020b,
|
|
||||||
CV_LeafKind_REFSYM = 0x020c,
|
|
||||||
CV_LeafKind_BCLASS_16t = 0x0400,
|
|
||||||
CV_LeafKind_VBCLASS_16t = 0x0401,
|
|
||||||
CV_LeafKind_IVBCLASS_16t = 0x0402,
|
|
||||||
CV_LeafKind_ENUMERATE_ST = 0x0403,
|
|
||||||
CV_LeafKind_FRIENDFCN_16t = 0x0404,
|
|
||||||
CV_LeafKind_INDEX_16t = 0x0405,
|
|
||||||
CV_LeafKind_MEMBER_16t = 0x0406,
|
|
||||||
CV_LeafKind_STMEMBER_16t = 0x0407,
|
|
||||||
CV_LeafKind_METHOD_16t = 0x0408,
|
|
||||||
CV_LeafKind_NESTTYPE_16t = 0x0409,
|
|
||||||
CV_LeafKind_VFUNCTAB_16t = 0x040a,
|
|
||||||
CV_LeafKind_FRIENDCLS_16t = 0x040b,
|
|
||||||
CV_LeafKind_ONEMETHOD_16t = 0x040c,
|
|
||||||
CV_LeafKind_VFUNCOFF_16t = 0x040d,
|
|
||||||
CV_LeafKind_TI16_MAX = 0x1000,
|
|
||||||
CV_LeafKind_MODIFIER = 0x1001,
|
|
||||||
CV_LeafKind_POINTER = 0x1002,
|
|
||||||
CV_LeafKind_ARRAY_ST = 0x1003,
|
|
||||||
CV_LeafKind_CLASS_ST = 0x1004,
|
|
||||||
CV_LeafKind_STRUCTURE_ST = 0x1005,
|
|
||||||
CV_LeafKind_UNION_ST = 0x1006,
|
|
||||||
CV_LeafKind_ENUM_ST = 0x1007,
|
|
||||||
CV_LeafKind_PROCEDURE = 0x1008,
|
|
||||||
CV_LeafKind_MFUNCTION = 0x1009,
|
|
||||||
CV_LeafKind_COBOL0 = 0x100a,
|
|
||||||
CV_LeafKind_BARRAY = 0x100b,
|
|
||||||
CV_LeafKind_DIMARRAY_ST = 0x100c,
|
|
||||||
CV_LeafKind_VFTPATH = 0x100d,
|
|
||||||
CV_LeafKind_PRECOMP_ST = 0x100e,
|
|
||||||
CV_LeafKind_OEM = 0x100f,
|
|
||||||
CV_LeafKind_ALIAS_ST = 0x1010,
|
|
||||||
CV_LeafKind_OEM2 = 0x1011,
|
|
||||||
CV_LeafKind_SKIP = 0x1200,
|
|
||||||
CV_LeafKind_ARGLIST = 0x1201,
|
|
||||||
CV_LeafKind_DEFARG_ST = 0x1202,
|
|
||||||
CV_LeafKind_FIELDLIST = 0x1203,
|
|
||||||
CV_LeafKind_DERIVED = 0x1204,
|
|
||||||
CV_LeafKind_BITFIELD = 0x1205,
|
|
||||||
CV_LeafKind_METHODLIST = 0x1206,
|
|
||||||
CV_LeafKind_DIMCONU = 0x1207,
|
|
||||||
CV_LeafKind_DIMCONLU = 0x1208,
|
|
||||||
CV_LeafKind_DIMVARU = 0x1209,
|
|
||||||
CV_LeafKind_DIMVARLU = 0x120a,
|
|
||||||
CV_LeafKind_BCLASS = 0x1400,
|
|
||||||
CV_LeafKind_VBCLASS = 0x1401,
|
|
||||||
CV_LeafKind_IVBCLASS = 0x1402,
|
|
||||||
CV_LeafKind_FRIENDFCN_ST = 0x1403,
|
|
||||||
CV_LeafKind_INDEX = 0x1404,
|
|
||||||
CV_LeafKind_MEMBER_ST = 0x1405,
|
|
||||||
CV_LeafKind_STMEMBER_ST = 0x1406,
|
|
||||||
CV_LeafKind_METHOD_ST = 0x1407,
|
|
||||||
CV_LeafKind_NESTTYPE_ST = 0x1408,
|
|
||||||
CV_LeafKind_VFUNCTAB = 0x1409,
|
|
||||||
CV_LeafKind_FRIENDCLS = 0x140a,
|
|
||||||
CV_LeafKind_ONEMETHOD_ST = 0x140b,
|
|
||||||
CV_LeafKind_VFUNCOFF = 0x140c,
|
|
||||||
CV_LeafKind_NESTTYPEEX_ST = 0x140d,
|
|
||||||
CV_LeafKind_MEMBERMODIFY_ST = 0x140e,
|
|
||||||
CV_LeafKind_MANAGED_ST = 0x140f,
|
|
||||||
CV_LeafKind_ST_MAX = 0x1500,
|
|
||||||
CV_LeafKind_TYPESERVER = 0x1501,
|
|
||||||
CV_LeafKind_ENUMERATE = 0x1502,
|
|
||||||
CV_LeafKind_ARRAY = 0x1503,
|
|
||||||
CV_LeafKind_CLASS = 0x1504,
|
|
||||||
CV_LeafKind_STRUCTURE = 0x1505,
|
|
||||||
CV_LeafKind_UNION = 0x1506,
|
|
||||||
CV_LeafKind_ENUM = 0x1507,
|
|
||||||
CV_LeafKind_DIMARRAY = 0x1508,
|
|
||||||
CV_LeafKind_PRECOMP = 0x1509,
|
|
||||||
CV_LeafKind_ALIAS = 0x150a,
|
|
||||||
CV_LeafKind_DEFARG = 0x150b,
|
|
||||||
CV_LeafKind_FRIENDFCN = 0x150c,
|
|
||||||
CV_LeafKind_MEMBER = 0x150d,
|
|
||||||
CV_LeafKind_STMEMBER = 0x150e,
|
|
||||||
CV_LeafKind_METHOD = 0x150f,
|
|
||||||
CV_LeafKind_NESTTYPE = 0x1510,
|
|
||||||
CV_LeafKind_ONEMETHOD = 0x1511,
|
|
||||||
CV_LeafKind_NESTTYPEEX = 0x1512,
|
|
||||||
CV_LeafKind_MEMBERMODIFY = 0x1513,
|
|
||||||
CV_LeafKind_MANAGED = 0x1514,
|
|
||||||
CV_LeafKind_TYPESERVER2 = 0x1515,
|
|
||||||
CV_LeafKind_STRIDED_ARRAY = 0x1516,
|
|
||||||
CV_LeafKind_HLSL = 0x1517,
|
|
||||||
CV_LeafKind_MODIFIER_EX = 0x1518,
|
|
||||||
CV_LeafKind_INTERFACE = 0x1519,
|
|
||||||
CV_LeafKind_BINTERFACE = 0x151a,
|
|
||||||
CV_LeafKind_VECTOR = 0x151b,
|
|
||||||
CV_LeafKind_MATRIX = 0x151c,
|
|
||||||
CV_LeafKind_VFTABLE = 0x151d,
|
|
||||||
CV_LeafKind_FUNC_ID = 0x1601,
|
|
||||||
CV_LeafKind_MFUNC_ID = 0x1602,
|
|
||||||
CV_LeafKind_BUILDINFO = 0x1603,
|
|
||||||
CV_LeafKind_SUBSTR_LIST = 0x1604,
|
|
||||||
CV_LeafKind_STRING_ID = 0x1605,
|
|
||||||
CV_LeafKind_UDT_SRC_LINE = 0x1606,
|
|
||||||
CV_LeafKind_UDT_MOD_SRC_LINE = 0x1607,
|
|
||||||
CV_LeafKind_CLASS2 = 0x1608,
|
|
||||||
CV_LeafKind_STRUCT2 = 0x1609,
|
|
||||||
} CV_LeafKindEnum;
|
|
||||||
|
|
||||||
internal String8 cv_string_from_numeric_kind(CV_NumericKind v);
|
|
||||||
internal String8 cv_string_from_arch(CV_Arch v);
|
|
||||||
internal String8 cv_string_from_sym_kind(CV_SymKind v);
|
|
||||||
internal String8 cv_string_from_basic_type(CV_BasicType v);
|
|
||||||
internal String8 cv_type_name_from_basic_type(CV_BasicType v);
|
|
||||||
internal String8 cv_string_from_leaf_kind(CV_LeafKind v);
|
|
||||||
internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);
|
|
||||||
internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);
|
|
||||||
#endif // CODEVIEW_META_H
|
|
||||||
+1119
-954
File diff suppressed because it is too large
Load Diff
+717
-502
File diff suppressed because it is too large
Load Diff
@@ -1,819 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
internal void
|
|
||||||
coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp);
|
|
||||||
|
|
||||||
rd_printf("Name : %S" , header.name );
|
|
||||||
rd_printf("Time Stamp: (%#x) %S" , header.time_stamp, time_stamp );
|
|
||||||
rd_printf("User ID : %u" , header.user_id );
|
|
||||||
rd_printf("Group ID : %u" , header.group_id);
|
|
||||||
rd_printf("Mode : %S" , header.mode );
|
|
||||||
rd_printf("Data : [%#llx-%#llx)", header.data_range.min, header.data_range.max);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_section_table(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 string_table,
|
|
||||||
COFF_Symbol32Array symbol_table,
|
|
||||||
U64 section_count,
|
|
||||||
COFF_SectionHeader *section_table)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 *symlinks = push_array(scratch.arena, String8, section_count);
|
|
||||||
for (U64 i = 0; i < symbol_table.count; ++i) {
|
|
||||||
COFF_Symbol32 *symbol = symbol_table.v+i;
|
|
||||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class);
|
|
||||||
if (interp == COFF_SymbolValueInterp_Regular &&
|
|
||||||
symbol->aux_symbol_count == 0 &&
|
|
||||||
(symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) {
|
|
||||||
if (symbol->section_number > 0 && symbol->section_number <= symbol_table.count) {
|
|
||||||
COFF_SectionHeader *header = section_table+(symbol->section_number-1);
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
|
||||||
symlinks[symbol->section_number-1] = coff_read_symbol_name(string_table, &symbol->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += symbol->aux_symbol_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section_count) {
|
|
||||||
rd_printf("# Section Table");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s",
|
|
||||||
"No.",
|
|
||||||
"Name",
|
|
||||||
"VirtSize",
|
|
||||||
"VirtOff",
|
|
||||||
"FileSize",
|
|
||||||
"FileOff",
|
|
||||||
"RelocOff",
|
|
||||||
"LinesOff",
|
|
||||||
"RelocCnt",
|
|
||||||
"LineCnt",
|
|
||||||
"Align",
|
|
||||||
"Flags",
|
|
||||||
"Symlink");
|
|
||||||
|
|
||||||
for (U64 i = 0; i < section_count; ++i) {
|
|
||||||
COFF_SectionHeader *header = section_table+i;
|
|
||||||
|
|
||||||
String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name));
|
|
||||||
String8 full_name = coff_name_from_section_header(string_table, header);
|
|
||||||
|
|
||||||
String8 align;
|
|
||||||
{
|
|
||||||
U64 align_size = coff_align_size_from_section_flags(header->flags);
|
|
||||||
align = push_str8f(scratch.arena, "%u", align_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
String8 flags;
|
|
||||||
{
|
|
||||||
String8List mem_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_MemRead) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "r");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemWrite) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "w");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemExecute) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "x");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List cnt_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_CntCode) {
|
|
||||||
str8_list_pushf(scratch.arena, &cnt_flags, "c");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_CntInitializedData) {
|
|
||||||
str8_list_pushf(scratch.arena, &cnt_flags, "d");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_CntUninitializedData) {
|
|
||||||
str8_list_pushf(scratch.arena, &cnt_flags, "u");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List mem_extra_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_MemShared) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "s");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_Mem16Bit) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "h");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemLocked) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "l");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemDiscardable) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "d");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemNotCached) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "c");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemNotPaged) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "p");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List lnk_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkRemove) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "r");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "c");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkOther) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "o");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkInfo) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "i");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "f");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List other_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_TypeNoPad) {
|
|
||||||
str8_list_pushf(scratch.arena, &other_flags, "n");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_GpRel) {
|
|
||||||
str8_list_pushf(scratch.arena, &other_flags, "g");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8 mem = str8_list_join(scratch.arena, &mem_flags, 0);
|
|
||||||
String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0);
|
|
||||||
String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0);
|
|
||||||
String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0);
|
|
||||||
String8 oth = str8_list_join(scratch.arena, &other_flags, 0);
|
|
||||||
|
|
||||||
String8List f = {0};
|
|
||||||
str8_list_push(scratch.arena, &f, mem);
|
|
||||||
str8_list_push(scratch.arena, &f, cnt);
|
|
||||||
str8_list_push(scratch.arena, &f, ext);
|
|
||||||
str8_list_push(scratch.arena, &f, lnk);
|
|
||||||
str8_list_push(scratch.arena, &f, oth);
|
|
||||||
|
|
||||||
flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") });
|
|
||||||
|
|
||||||
if (!flags.size) {
|
|
||||||
flags = str8_lit("none");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List l = {0};
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-4x", i+1 );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-8S", name );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->vsize );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->voff );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->fsize );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->foff );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff);
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count);
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->line_count );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-5S", align );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-10S", flags );
|
|
||||||
if (symlinks[i].size > 0) {
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]);
|
|
||||||
} else {
|
|
||||||
str8_list_pushf(scratch.arena, &l, "[no symlink]");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), });
|
|
||||||
rd_printf("%S", line);
|
|
||||||
|
|
||||||
if (full_name.size != name.size) {
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Full Name: %S", full_name);
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_newline();
|
|
||||||
rd_printf("Flags:");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("r = MemRead w = MemWrite x = MemExecute");
|
|
||||||
rd_printf("c = CntCode d = InitializedData u = UninitializedData");
|
|
||||||
rd_printf("s = MemShared h = Mem16bit l = MemLocked d = MemDiscardable c = MemNotCached p = MemNotPaged");
|
|
||||||
rd_printf("r = LnkRemove c = LnkComdat o = LnkOther i = LnkInfo f = LnkNRelocOvfl");
|
|
||||||
rd_printf("g = GpRel n = TypeNoPad");
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_disasm_sections(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
U64 image_base,
|
|
||||||
B32 is_obj,
|
|
||||||
RD_MarkerArray *section_markers,
|
|
||||||
U64 section_count,
|
|
||||||
COFF_SectionHeader *sections)
|
|
||||||
{
|
|
||||||
if (section_count) {
|
|
||||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
|
||||||
COFF_SectionHeader *sect = sections+sect_idx;
|
|
||||||
if (sect->flags & COFF_SectionFlag_CntCode) {
|
|
||||||
U64 sect_off = is_obj ? sect->foff : sect->voff;
|
|
||||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
|
||||||
String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
|
||||||
U64 sect_number = sect_idx+1;
|
|
||||||
RD_MarkerArray markers = section_markers[sect_number];
|
|
||||||
|
|
||||||
rd_printf("# Disassembly [Section No. %#llx]", sect_number);
|
|
||||||
rd_indent();
|
|
||||||
rd_print_disasm(arena, out, indent, arch_from_coff_machine(machine), image_base, sect_off, markers.count, markers.v, raw_code);
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_raw_data_sections(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
B32 is_obj,
|
|
||||||
RD_MarkerArray *section_markers,
|
|
||||||
U64 section_count,
|
|
||||||
COFF_SectionHeader *section_table)
|
|
||||||
{
|
|
||||||
if (section_count) {
|
|
||||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
|
||||||
COFF_SectionHeader *sect = section_table+sect_idx;
|
|
||||||
if (sect->fsize > 0) {
|
|
||||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
|
||||||
String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
|
||||||
RD_MarkerArray markers = section_markers[sect_idx];
|
|
||||||
|
|
||||||
rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1));
|
|
||||||
rd_indent();
|
|
||||||
rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect);
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_relocs(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
String8 string_table,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
U64 sect_count,
|
|
||||||
COFF_SectionHeader *sect_headers,
|
|
||||||
COFF_Symbol32Array symbols)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
B32 print_header = 1;
|
|
||||||
|
|
||||||
for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) {
|
|
||||||
COFF_SectionHeader *sect_header = sect_headers+sect_idx;
|
|
||||||
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header);
|
|
||||||
|
|
||||||
if (reloc_info.count) {
|
|
||||||
if (print_header) {
|
|
||||||
print_header = 0;
|
|
||||||
rd_printf("# Relocations");
|
|
||||||
rd_indent();
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_printf("## Section %llx", sect_idx);
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName");
|
|
||||||
|
|
||||||
for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) {
|
|
||||||
COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx;
|
|
||||||
String8 type = coff_string_from_reloc(machine, reloc->type);
|
|
||||||
U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type);
|
|
||||||
|
|
||||||
U64 apply_foff = sect_header->foff + reloc->apply_off;
|
|
||||||
if (apply_foff + apply_size > raw_data.size) {
|
|
||||||
rd_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 raw_apply;
|
|
||||||
AssertAlways(apply_size <= sizeof(raw_apply));
|
|
||||||
MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size);
|
|
||||||
S64 apply = extend_sign64(raw_apply, apply_size);
|
|
||||||
|
|
||||||
if (reloc->isymbol > symbols.count) {
|
|
||||||
rd_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
COFF_Symbol32 *symbol = symbols.v+reloc->isymbol;
|
|
||||||
String8 symbol_name = coff_read_symbol_name(string_table, &symbol->name);
|
|
||||||
|
|
||||||
String8List line = {0};
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off);
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-16S", type );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%016x", apply );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%S", symbol_name );
|
|
||||||
|
|
||||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")});
|
|
||||||
rd_printf("%S", l);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!print_header) {
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
rd_newline();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_symbol_table(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
B32 is_big_obj,
|
|
||||||
String8 string_table,
|
|
||||||
COFF_Symbol32Array symbols)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
if (symbols.count) {
|
|
||||||
rd_printf("# Symbol Table");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s",
|
|
||||||
"No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name");
|
|
||||||
|
|
||||||
for (U64 i = 0; i < symbols.count; ++i) {
|
|
||||||
COFF_Symbol32 *symbol = &symbols.v[i];
|
|
||||||
String8 name = coff_read_symbol_name(string_table, &symbol->name);
|
|
||||||
String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb);
|
|
||||||
String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb);
|
|
||||||
String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class);
|
|
||||||
String8 section_number;
|
|
||||||
switch (symbol->section_number) {
|
|
||||||
case COFF_Symbol_UndefinedSection: section_number = str8_lit("Undef"); break;
|
|
||||||
case COFF_Symbol_AbsSection32: section_number = str8_lit("Abs"); break;
|
|
||||||
case COFF_Symbol_DebugSection32: section_number = str8_lit("Debug"); break;
|
|
||||||
default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List line = {0};
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4x", i );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%08x", symbol->value );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-10S", section_number );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count);
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4S", msb );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4S", lsb );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-16S", storage_class );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%S", name );
|
|
||||||
|
|
||||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")});
|
|
||||||
rd_printf("%S", l);
|
|
||||||
|
|
||||||
rd_indent();
|
|
||||||
for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) {
|
|
||||||
void *raw_aux = &symbols.v[k];
|
|
||||||
switch (symbol->storage_class) {
|
|
||||||
case COFF_SymStorageClass_External: {
|
|
||||||
COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k];
|
|
||||||
rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x",
|
|
||||||
func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_Function: {
|
|
||||||
COFF_SymbolFunc *func = raw_aux;
|
|
||||||
rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_WeakExternal: {
|
|
||||||
COFF_SymbolWeakExt *weak = raw_aux;
|
|
||||||
String8 type = coff_string_from_weak_ext_type(weak->characteristics);
|
|
||||||
rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_File: {
|
|
||||||
COFF_SymbolFile *file = raw_aux;
|
|
||||||
String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name));
|
|
||||||
rd_printf("Name %S", name);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_Static: {
|
|
||||||
COFF_SymbolSecDef *sd = raw_aux;
|
|
||||||
String8 selection = coff_string_from_comdat_select_type(sd->selection);
|
|
||||||
U32 number = sd->number_lo;
|
|
||||||
if (is_big_obj) {
|
|
||||||
number |= (U32)sd->number_hi << 16;
|
|
||||||
}
|
|
||||||
if (number) {
|
|
||||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S",
|
|
||||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection);
|
|
||||||
} else {
|
|
||||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x",
|
|
||||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
rd_printf("???");
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i += symbol->aux_symbol_count;
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
|
||||||
String8 machine = coff_string_from_machine_type(header->machine);
|
|
||||||
|
|
||||||
rd_printf("# Big Obj");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp);
|
|
||||||
rd_printf("Machine : %#x (%S)", header->machine, machine );
|
|
||||||
rd_printf("Section Count: %u", header->section_count );
|
|
||||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff);
|
|
||||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
|
||||||
String8 machine = coff_string_from_machine_type(header->machine);
|
|
||||||
String8 flags = coff_string_from_flags(scratch.arena, header->flags);
|
|
||||||
|
|
||||||
rd_printf("# COFF File Header");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp );
|
|
||||||
rd_printf("Machine : %#x %S", header->machine, machine );
|
|
||||||
rd_printf("Section Count : %u", header->section_count );
|
|
||||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff );
|
|
||||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
|
||||||
rd_printf("Optional Header Size: %#x (%m)", header->optional_header_size, header->optional_header_size);
|
|
||||||
rd_printf("Flags : %#x (%S)", header->flags, flags );
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 machine = coff_string_from_machine_type(header->machine);
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
|
||||||
|
|
||||||
rd_printf("# Import");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Version : %u", header->version );
|
|
||||||
rd_printf("Machine : %S", machine );
|
|
||||||
rd_printf("Time Stamp: %#x (%S)", header->time_stamp, time_stamp );
|
|
||||||
rd_printf("Data Size : %#x (%m)", header->data_size, header->data_size);
|
|
||||||
rd_printf("Hint : %u", header->hint_or_ordinal);
|
|
||||||
rd_printf("Type : %u", header->type );
|
|
||||||
rd_printf("Import By : %u", header->import_by );
|
|
||||||
rd_printf("Function : %S", header->func_name );
|
|
||||||
rd_printf("DLL : %S", header->dll_name );
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
|
||||||
|
|
||||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
|
||||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
|
||||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
|
||||||
|
|
||||||
COFF_BigObjHeader *big_obj = (COFF_BigObjHeader *)raw_header.str;
|
|
||||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
|
||||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_32(scratch.arena, raw_data, header_info.symbol_table_range.min, big_obj->symbol_count);
|
|
||||||
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
coff_print_big_obj_header(arena, out, indent, big_obj);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Sections) {
|
|
||||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count);
|
|
||||||
Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count);
|
|
||||||
|
|
||||||
if (sect_headers_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read big obj section headers");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (big_obj->symbol_count) {
|
|
||||||
if (symbols_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read big obj symbol table");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
|
||||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
|
||||||
rd_errorf("section headers and symbol table ranges overlap");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, big_obj->section_count, section_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Relocs) {
|
|
||||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, big_obj->machine, big_obj->section_count, section_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Symbols) {
|
|
||||||
coff_print_symbol_table(arena, out, indent, raw_data, 1, raw_string_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
|
||||||
|
|
||||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
|
||||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
|
||||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
|
||||||
|
|
||||||
COFF_FileHeader *header = (COFF_FileHeader *)raw_header.str;
|
|
||||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
|
||||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_16(scratch.arena, raw_data, header_info.symbol_table_range.min, header->symbol_count);
|
|
||||||
Arch arch = arch_from_coff_machine(header->machine);
|
|
||||||
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
coff_print_file_header(arena, out, indent, header);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Sections) {
|
|
||||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count);
|
|
||||||
Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count);
|
|
||||||
|
|
||||||
if (sect_headers_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read obj section headers");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (header->symbol_count) {
|
|
||||||
if (symbols_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read obj symbol table");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
|
||||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
|
||||||
rd_errorf("section headers and symbol table ranges overlap");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, header->section_count, section_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Relocs) {
|
|
||||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, header->machine, header->section_count, section_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Symbols) {
|
|
||||||
coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
RD_MarkerArray *section_markers = 0;
|
|
||||||
if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) {
|
|
||||||
section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, header->section_count, symbol_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Rawdata) {
|
|
||||||
coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, section_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Disasm) {
|
|
||||||
coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, section_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Codeview) {
|
|
||||||
cv_format_debug_sections(arena, out, indent, raw_data, raw_string_table, header->section_count, section_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
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_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive);
|
|
||||||
|
|
||||||
if (archive_parse.error.size) {
|
|
||||||
rd_errorf("%S", archive_parse.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
COFF_ArchiveFirstMember first_member = archive_parse.first_member;
|
|
||||||
{
|
|
||||||
rd_printf("# First Header");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("Symbol Count : %u", first_member.symbol_count);
|
|
||||||
rd_printf("String Table Size: %#llx (%M)", first_member.string_table.size, first_member.string_table.size);
|
|
||||||
|
|
||||||
rd_printf("Members:");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0);
|
|
||||||
|
|
||||||
if (string_table.node_count == first_member.member_offset_count) {
|
|
||||||
String8Node *string_n = string_table.first;
|
|
||||||
|
|
||||||
for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) {
|
|
||||||
U32 offset = from_be_u32(first_member.member_offsets[i]);
|
|
||||||
rd_printf("[%4u] %#08x %S", i, offset, string_n->string);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rd_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (archive_parse.has_second_header) {
|
|
||||||
COFF_ArchiveSecondMember second_member = archive_parse.second_member;
|
|
||||||
|
|
||||||
rd_printf("# Second Header");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("Member Count : %u", second_member.member_count);
|
|
||||||
rd_printf("Symbol Count : %u", second_member.symbol_count);
|
|
||||||
rd_printf("String Table Size: %#llx (%M)", second_member.string_table.size, second_member.string_table.size);
|
|
||||||
|
|
||||||
String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0);
|
|
||||||
|
|
||||||
rd_printf("Members:");
|
|
||||||
rd_indent();
|
|
||||||
if (second_member.symbol_index_count == second_member.symbol_count) {
|
|
||||||
String8Node *string_n = string_table.first;
|
|
||||||
for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) {
|
|
||||||
U16 symbol_number = second_member.symbol_indices[i];
|
|
||||||
if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) {
|
|
||||||
U16 symbol_idx = symbol_number - 1;
|
|
||||||
U32 member_offset = second_member.member_offsets[i];
|
|
||||||
rd_printf("[%4u] %#08x %S", i, member_offset, string_n->string);
|
|
||||||
} else {
|
|
||||||
rd_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rd_errorf("Symbol index count %u doesn't match symbol count %u",
|
|
||||||
second_member.symbol_index_count, second_member.symbol_count);
|
|
||||||
}
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (archive_parse.has_long_names && opts & RD_Option_LongNames) {
|
|
||||||
rd_printf("# Long Names");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0);
|
|
||||||
U64 name_idx = 0;
|
|
||||||
for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) {
|
|
||||||
U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str);
|
|
||||||
rd_printf("[%-4u] %#08x %S", name_idx, offset, name_n->string);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 member_offset_count = 0;
|
|
||||||
U32 *member_offsets = 0;
|
|
||||||
if (archive_parse.has_second_header) {
|
|
||||||
member_offset_count = archive_parse.second_member.member_offset_count;
|
|
||||||
member_offsets = archive_parse.second_member.member_offsets;
|
|
||||||
} else {
|
|
||||||
HashTable *ht = hash_table_init(scratch.arena, 0x1000);
|
|
||||||
for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) {
|
|
||||||
U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]);
|
|
||||||
if (!hash_table_search_u32(ht, member_offset)) {
|
|
||||||
hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
member_offset_count = ht->count;
|
|
||||||
member_offsets = keys_from_hash_table_u32(scratch.arena, ht);
|
|
||||||
radsort(member_offsets, member_offset_count, u32_is_before);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_printf("# Members");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
for (U64 i = 0; i < member_offset_count; ++i) {
|
|
||||||
U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size;
|
|
||||||
U64 member_offset = member_offsets[i];
|
|
||||||
String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset));
|
|
||||||
COFF_ArchiveMember member = coff_archive_member_from_data(raw_member);
|
|
||||||
COFF_DataType member_type = coff_data_type_from_data(member.data);
|
|
||||||
|
|
||||||
rd_printf("Member @ %#llx", member_offset);
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (member_type) {
|
|
||||||
case COFF_DataType_Obj: {
|
|
||||||
coff_print_obj(arena, out, indent, member.data, opts);
|
|
||||||
} break;
|
|
||||||
case COFF_DataType_BigObj: {
|
|
||||||
coff_print_big_obj(arena, out, indent, member.data, opts);
|
|
||||||
} break;
|
|
||||||
case COFF_DataType_Import: {
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
COFF_ParsedArchiveImportHeader header = {0};
|
|
||||||
U64 parse_size = coff_parse_import(member.data, 0, &header);
|
|
||||||
if (parse_size) {
|
|
||||||
coff_print_import(arena, out, indent, &header);
|
|
||||||
} else {
|
|
||||||
rd_errorf("not enough bytes to parse import header");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case COFF_DataType_Null: {
|
|
||||||
rd_errorf("unknown member format", member_offset);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef COFF_DUMP_H
|
|
||||||
#define COFF_DUMP_H
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names);
|
|
||||||
internal void coff_print_section_table (Arena *arena, String8List *out, String8 indent, String8 string_table, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers);
|
|
||||||
internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
|
|
||||||
internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
|
|
||||||
internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 string_table, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols);
|
|
||||||
internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, String8 string_table, COFF_Symbol32Array symbols);
|
|
||||||
internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header);
|
|
||||||
internal void coff_print_file_header (Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header);
|
|
||||||
internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header);
|
|
||||||
internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
|
|
||||||
internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
|
|
||||||
internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // COFF_DUMP_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#include "coff/coff.c"
|
|
||||||
#include "coff/coff_parse.c"
|
|
||||||
#include "coff/coff_dump.c"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef COFF_INC_H
|
|
||||||
#define COFF_INC_H
|
|
||||||
|
|
||||||
#include "coff/coff.h"
|
|
||||||
#include "coff/coff_parse.h"
|
|
||||||
#include "coff/coff_dump.h"
|
|
||||||
|
|
||||||
#endif // COFF_INC_H
|
|
||||||
@@ -1,387 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal COFF_LibWriterSymbolNode *
|
|
||||||
coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol)
|
|
||||||
{
|
|
||||||
COFF_LibWriterSymbolNode *node = push_array_no_zero(arena, COFF_LibWriterSymbolNode, 1);
|
|
||||||
node->next = 0;
|
|
||||||
node->data = symbol;
|
|
||||||
SLLQueuePush(list->first, list->last, node);
|
|
||||||
list->count += 1;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_LibWriterMemberNode *
|
|
||||||
coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member)
|
|
||||||
{
|
|
||||||
COFF_LibWriterMemberNode *node = push_array_no_zero(arena, COFF_LibWriterMemberNode, 1);
|
|
||||||
node->next = 0;
|
|
||||||
node->data = member;
|
|
||||||
SLLQueuePush(list->first, list->last, node);
|
|
||||||
list->count += 1;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_LibWriterSymbol *
|
|
||||||
coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list)
|
|
||||||
{
|
|
||||||
COFF_LibWriterSymbol *arr = push_array_no_zero(arena, COFF_LibWriterSymbol, list.count + 2);
|
|
||||||
COFF_LibWriterSymbol *ptr = arr + 1;
|
|
||||||
for (COFF_LibWriterSymbolNode *i = list.first; i != 0; i = i->next, ptr += 1) {
|
|
||||||
*ptr = i->data;
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(&arr[0]);
|
|
||||||
MemoryZeroStruct(&arr[list.count+1]);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_LibWriterMember *
|
|
||||||
coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list)
|
|
||||||
{
|
|
||||||
COFF_LibWriterMember *arr = push_array_no_zero(arena, COFF_LibWriterMember, list.count);
|
|
||||||
COFF_LibWriterMember *ptr = arr;
|
|
||||||
for (COFF_LibWriterMemberNode *i = list.first; i != 0; i = i->next, ptr += 1) {
|
|
||||||
ptr->name = push_str8_copy(arena, i->data.name);
|
|
||||||
ptr->data = push_str8_copy(arena, i->data.data);
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal int
|
|
||||||
coff_lib_writer_symbol_name_compar(const void *raw_a, const void *raw_b)
|
|
||||||
{
|
|
||||||
const COFF_LibWriterSymbol *sa = raw_a;
|
|
||||||
const COFF_LibWriterSymbol *sb = raw_b;
|
|
||||||
return str8_compar_case_sensitive(&sa->name, &sb->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal int
|
|
||||||
coff_lib_writer_symbol_is_before_name(void *raw_a, void *raw_b)
|
|
||||||
{
|
|
||||||
return coff_lib_writer_symbol_name_compar(raw_a, raw_b) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal int
|
|
||||||
coff_lib_writer_symbol_is_before_member_idx(void *raw_a, void *raw_b)
|
|
||||||
{
|
|
||||||
COFF_LibWriterSymbol *a = raw_a, *b = raw_b;
|
|
||||||
return a->member_idx < b->member_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count)
|
|
||||||
{
|
|
||||||
Assert(count >= 2);
|
|
||||||
radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count)
|
|
||||||
{
|
|
||||||
Assert(count >= 2);
|
|
||||||
radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_member_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_LibWriter *
|
|
||||||
coff_lib_writer_alloc(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
COFF_LibWriter *writer = push_array(arena, COFF_LibWriter, 1);
|
|
||||||
writer->arena = arena;
|
|
||||||
return writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_lib_writer_release(COFF_LibWriter **writer_ptr)
|
|
||||||
{
|
|
||||||
arena_release((*writer_ptr)->arena);
|
|
||||||
*writer_ptr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data)
|
|
||||||
{
|
|
||||||
U64 member_idx = writer->member_list.count;
|
|
||||||
|
|
||||||
// push obj member
|
|
||||||
COFF_LibWriterMember member = { .name = obj_path, .data = obj_data };
|
|
||||||
COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member);
|
|
||||||
|
|
||||||
// push external symbols
|
|
||||||
COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data);
|
|
||||||
String8 string_table = str8_substr(obj_data, obj_header.string_table_range);
|
|
||||||
String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range);
|
|
||||||
COFF_ParsedSymbol symbol;
|
|
||||||
for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
|
|
||||||
symbol = coff_parse_symbol(obj_header, string_table, symbol_table, symbol_idx);
|
|
||||||
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
|
|
||||||
if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) {
|
|
||||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
|
||||||
COFF_LibWriterSymbol lib_symbol = { .name = symbol.name, .member_idx = member_idx };
|
|
||||||
coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return member_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type)
|
|
||||||
{
|
|
||||||
U64 member_idx = lib_writer->member_list.count;
|
|
||||||
|
|
||||||
String8 member_data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type);
|
|
||||||
COFF_LibWriterMember member = { .name = dll_name, .data = member_data };
|
|
||||||
COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member);
|
|
||||||
|
|
||||||
if (name.size) {
|
|
||||||
switch (import_type) {
|
|
||||||
case COFF_ImportHeader_Code: {
|
|
||||||
COFF_LibWriterSymbol thunk_symbol = {0};
|
|
||||||
thunk_symbol.name = push_str8_copy(lib_writer->arena, name);
|
|
||||||
thunk_symbol.member_idx = member_idx;
|
|
||||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, thunk_symbol);
|
|
||||||
|
|
||||||
COFF_LibWriterSymbol imp_symbol = {0};
|
|
||||||
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
|
|
||||||
imp_symbol.member_idx = member_idx;
|
|
||||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
|
|
||||||
} break;
|
|
||||||
case COFF_ImportHeader_Data: {
|
|
||||||
COFF_LibWriterSymbol imp_symbol = {0};
|
|
||||||
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
|
|
||||||
imp_symbol.member_idx = member_idx;
|
|
||||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
|
|
||||||
} break;
|
|
||||||
case COFF_ImportHeader_Const: { NotImplemented; } break;
|
|
||||||
default: { InvalidPath; } break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
// member lists -> arrays
|
|
||||||
U64 member_count = lib_writer->member_list.count;
|
|
||||||
COFF_LibWriterMember *member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list);
|
|
||||||
|
|
||||||
// serialize members
|
|
||||||
U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count);
|
|
||||||
String8List long_names_list = {0};
|
|
||||||
String8List member_data_list = {0};
|
|
||||||
{
|
|
||||||
HashTable *name_ht = hash_table_init(scratch.arena, 1024);
|
|
||||||
for EachIndex(member_idx, member_count) {
|
|
||||||
COFF_LibWriterMember *member = &member_array[member_idx];
|
|
||||||
|
|
||||||
// make member name
|
|
||||||
String8 name;
|
|
||||||
U64 name_with_slash_size = member->name.size + 1;
|
|
||||||
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
|
|
||||||
// have we seen this member name before?
|
|
||||||
KeyValuePair *is_present = hash_table_search_string(name_ht, member->name);
|
|
||||||
if (is_present) {
|
|
||||||
name = is_present->value_string;
|
|
||||||
} else {
|
|
||||||
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
|
|
||||||
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
|
|
||||||
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
name = push_str8f(scratch.arena, "%S/", member->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
member_offsets[member_idx] = member_data_list.total_size;
|
|
||||||
|
|
||||||
String8 member_data = member->data;
|
|
||||||
String8 member_header = coff_make_lib_member_header(scratch.arena, name, time_stamp, 0, 0, mode, member_data.size);
|
|
||||||
|
|
||||||
str8_list_push(scratch.arena, &member_data_list, member_header);
|
|
||||||
str8_list_push(scratch.arena, &member_data_list, member_data);
|
|
||||||
{
|
|
||||||
U64 pad_size = AlignPadPow2(member_data_list.total_size, COFF_Archive_MemberAlign);
|
|
||||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
|
||||||
str8_list_push(scratch.arena, &member_data_list, str8(pad, pad_size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write long names member
|
|
||||||
if (long_names_list.total_size) {
|
|
||||||
String8 header = coff_make_lib_member_header(scratch.arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size);
|
|
||||||
String8 data = str8_list_join(scratch.arena, &long_names_list, 0);
|
|
||||||
U64 member_offset = member_data_list.total_size + data.size + header.size;
|
|
||||||
{
|
|
||||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
|
||||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
|
|
||||||
}
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, data);
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute size for symbol string table
|
|
||||||
U32 name_buffer_size = 0;
|
|
||||||
for (COFF_LibWriterSymbolNode *node = lib_writer->symbol_list.first; node != 0; node = node->next) {
|
|
||||||
name_buffer_size += node->data.name.size;
|
|
||||||
name_buffer_size += 1; // null
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute members base offset
|
|
||||||
U64 members_base_offset;
|
|
||||||
{
|
|
||||||
U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * lib_writer->symbol_list.count + name_buffer_size;
|
|
||||||
U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * lib_writer->symbol_list.count + name_buffer_size;
|
|
||||||
U64 sizeof_long_names = sizeof(COFF_ArchiveMemberHeader) + long_names_list.total_size;
|
|
||||||
|
|
||||||
sizeof_first_header = AlignPow2(sizeof_first_header, COFF_Archive_MemberAlign);
|
|
||||||
sizeof_second_header = AlignPow2(sizeof_second_header, COFF_Archive_MemberAlign);
|
|
||||||
sizeof_long_names = AlignPow2(sizeof_long_names, COFF_Archive_MemberAlign);
|
|
||||||
|
|
||||||
members_base_offset = sizeof(g_coff_archive_sig);
|
|
||||||
members_base_offset += sizeof_first_header;
|
|
||||||
if (emit_second_member) {
|
|
||||||
members_base_offset += sizeof_second_header;
|
|
||||||
}
|
|
||||||
if (long_names_list.total_size) {
|
|
||||||
members_base_offset += sizeof_long_names;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write second linker member
|
|
||||||
if (emit_second_member) {
|
|
||||||
U64 symbols_count;
|
|
||||||
COFF_LibWriterSymbol *symbols;
|
|
||||||
{
|
|
||||||
U64 symbols_count_with_null = lib_writer->symbol_list.count + 2;
|
|
||||||
COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list);
|
|
||||||
coff_lib_writer_symbol_array_sort_on_name(symbols_with_null, symbols_count_with_null);
|
|
||||||
|
|
||||||
symbols_count = symbols_count_with_null - 2;
|
|
||||||
symbols = symbols_with_null + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write symbol name buffer
|
|
||||||
U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size);
|
|
||||||
{
|
|
||||||
U64 name_cursor = 0;
|
|
||||||
for EachIndex(symbol_idx, symbols_count) {
|
|
||||||
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
|
|
||||||
MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size);
|
|
||||||
name_buffer[name_cursor + symbol->name.size] = '\0';
|
|
||||||
name_cursor += symbol->name.size + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 member_count32 = safe_cast_u32(member_count);
|
|
||||||
U32 symbol_count32 = safe_cast_u32(symbols_count);
|
|
||||||
|
|
||||||
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, member_count);
|
|
||||||
U16 *member_idx16_arr = push_array_no_zero(scratch.arena, U16, symbols_count);
|
|
||||||
|
|
||||||
// write member offset array
|
|
||||||
for EachIndex(member_idx, member_count) {
|
|
||||||
U64 member_offset = members_base_offset + member_offsets[member_idx];
|
|
||||||
U32 member_off32 = safe_cast_u32(member_offset);
|
|
||||||
member_off32_arr[member_idx] = member_off32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write member offset indices for each symbol
|
|
||||||
for EachIndex(symbol_idx, symbols_count) {
|
|
||||||
// member offset indices are 1-based
|
|
||||||
U64 member_idx = symbols[symbol_idx].member_idx + 1;
|
|
||||||
U16 member_idx16 = safe_cast_u16(member_idx);
|
|
||||||
member_idx16_arr[symbol_idx] = member_idx16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// layout second member data
|
|
||||||
String8List second_member_data_list = {0};
|
|
||||||
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&member_count32));
|
|
||||||
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_off32_arr, member_count));
|
|
||||||
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&symbol_count32));
|
|
||||||
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_idx16_arr, symbols_count));
|
|
||||||
str8_list_push(scratch.arena, &second_member_data_list, str8(name_buffer, name_buffer_size));
|
|
||||||
|
|
||||||
String8 member_data = str8_list_join(scratch.arena, &second_member_data_list, 0);
|
|
||||||
String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
|
|
||||||
|
|
||||||
U64 member_offset = member_data_list.total_size + member_data.size + member_header.size;
|
|
||||||
{
|
|
||||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
|
||||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
|
|
||||||
}
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, member_data);
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, member_header);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write first linker member (obsolete, but kept for compatability reasons)
|
|
||||||
{
|
|
||||||
U64 symbols_count;
|
|
||||||
COFF_LibWriterSymbol *symbols;
|
|
||||||
{
|
|
||||||
U64 symbols_count_with_null = lib_writer->symbol_list.count + 2;
|
|
||||||
COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list);
|
|
||||||
coff_lib_writer_symbol_array_sort_on_member_idx(symbols_with_null, symbols_count_with_null);
|
|
||||||
|
|
||||||
symbols_count = symbols_count_with_null - 2;
|
|
||||||
symbols = symbols_with_null + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write symbol name buffer
|
|
||||||
U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size);
|
|
||||||
{
|
|
||||||
U64 name_cursor = 0;
|
|
||||||
for EachIndex(symbol_idx, symbols_count) {
|
|
||||||
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
|
|
||||||
MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size);
|
|
||||||
name_buffer[name_cursor + symbol->name.size] = '\0';
|
|
||||||
name_cursor += symbol->name.size + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 symbol_count_be = from_be_u32(symbols_count);
|
|
||||||
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, symbols_count);
|
|
||||||
|
|
||||||
for EachIndex(symbol_idx, symbols_count) {
|
|
||||||
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
|
|
||||||
|
|
||||||
// write big endian member offset
|
|
||||||
U64 member_offset = members_base_offset + member_offsets[symbol->member_idx];
|
|
||||||
U32 member_off32 = from_be_u32(safe_cast_u32(member_offset));
|
|
||||||
member_off32_arr[symbol_idx] = member_off32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// layout first member data
|
|
||||||
String8List first_member_data_list = {0};
|
|
||||||
str8_list_push(scratch.arena, &first_member_data_list, str8_struct(&symbol_count_be));
|
|
||||||
str8_list_push(scratch.arena, &first_member_data_list, str8_array(member_off32_arr, symbols_count));
|
|
||||||
str8_list_push(scratch.arena, &first_member_data_list, str8(name_buffer, name_buffer_size));
|
|
||||||
|
|
||||||
String8 member_data = str8_list_join(scratch.arena, &first_member_data_list, 0);
|
|
||||||
String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
|
|
||||||
|
|
||||||
U64 member_offset = sizeof(g_coff_archive_sig) + member_header.size + member_data.size;
|
|
||||||
{
|
|
||||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
|
||||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
|
|
||||||
}
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, member_data);
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, member_header);
|
|
||||||
}
|
|
||||||
|
|
||||||
// archive signature
|
|
||||||
str8_list_push_front(scratch.arena, &member_data_list, str8_struct(&g_coff_archive_sig));
|
|
||||||
|
|
||||||
String8 raw_lib = str8_list_join(arena, &member_data_list, 0);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return raw_lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef COFF_LIB_WRITER_H
|
|
||||||
#define COFF_LIB_WRITER_H
|
|
||||||
|
|
||||||
typedef struct COFF_LibWriterMember
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 data;
|
|
||||||
} COFF_LibWriterMember;
|
|
||||||
|
|
||||||
typedef struct COFF_LibWriterMemberNode
|
|
||||||
{
|
|
||||||
COFF_LibWriterMember data;
|
|
||||||
struct COFF_LibWriterMemberNode *next;
|
|
||||||
} COFF_LibWriterMemberNode;
|
|
||||||
|
|
||||||
typedef struct COFF_LibWriterMemberList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_LibWriterMemberNode *first;
|
|
||||||
COFF_LibWriterMemberNode *last;
|
|
||||||
} COFF_LibWriterMemberList;
|
|
||||||
|
|
||||||
typedef struct COFF_LibWriterSymbol
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
U64 member_idx;
|
|
||||||
} COFF_LibWriterSymbol;
|
|
||||||
|
|
||||||
typedef struct COFF_LibWriterSymbolNode
|
|
||||||
{
|
|
||||||
COFF_LibWriterSymbol data;
|
|
||||||
struct COFF_LibWriterSymbolNode *next;
|
|
||||||
} COFF_LibWriterSymbolNode;
|
|
||||||
|
|
||||||
typedef struct COFF_LibWriterSymbolList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_LibWriterSymbolNode *first;
|
|
||||||
COFF_LibWriterSymbolNode *last;
|
|
||||||
} COFF_LibWriterSymbolList;
|
|
||||||
|
|
||||||
typedef struct COFF_LibWriter
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
COFF_LibWriterMemberList member_list;
|
|
||||||
COFF_LibWriterSymbolList symbol_list;
|
|
||||||
} COFF_LibWriter;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal COFF_LibWriterSymbolNode * coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol);
|
|
||||||
internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member);
|
|
||||||
|
|
||||||
internal COFF_LibWriterSymbol * coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list);
|
|
||||||
internal COFF_LibWriterMember * coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list);
|
|
||||||
|
|
||||||
internal void coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count);
|
|
||||||
internal void coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count);
|
|
||||||
|
|
||||||
internal COFF_LibWriter * coff_lib_writer_alloc(void);
|
|
||||||
internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr);
|
|
||||||
internal U64 coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data);
|
|
||||||
internal void coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type);
|
|
||||||
internal String8 coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member);
|
|
||||||
|
|
||||||
#endif // COFF_LIB_WRITER_H
|
|
||||||
|
|
||||||
@@ -1,500 +0,0 @@
|
|||||||
internal COFF_ObjWriter*
|
|
||||||
coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1);
|
|
||||||
obj_writer->arena = arena;
|
|
||||||
obj_writer->time_stamp = time_stamp;
|
|
||||||
obj_writer->machine = machine;
|
|
||||||
return obj_writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_obj_writer_release(COFF_ObjWriter **obj_writer)
|
|
||||||
{
|
|
||||||
arena_release((*obj_writer)->arena);
|
|
||||||
*obj_writer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8List srl = {0};
|
|
||||||
|
|
||||||
String8List string_table = {0};
|
|
||||||
U32 *string_table_size = push_array(scratch.arena, U32, 1);
|
|
||||||
*string_table_size = sizeof(*string_table_size);
|
|
||||||
str8_list_push(scratch.arena, &string_table, str8_struct(string_table_size));
|
|
||||||
|
|
||||||
//
|
|
||||||
// assing section numbers
|
|
||||||
//
|
|
||||||
U64 obj_sections_count;
|
|
||||||
COFF_ObjSection **obj_sections;
|
|
||||||
{
|
|
||||||
obj_sections_count = obj_writer->sect_count;
|
|
||||||
obj_sections = push_array(scratch.arena, COFF_ObjSection *, obj_writer->sect_count);
|
|
||||||
U64 sect_idx = 0;
|
|
||||||
for (COFF_ObjSectionNode *sect_n = obj_writer->sect_first; sect_n != 0; sect_n = sect_n->next, sect_idx += 1) {
|
|
||||||
COFF_ObjSection *sect = §_n->v;
|
|
||||||
sect->section_number = sect_idx+1;
|
|
||||||
obj_sections[sect_idx] = sect;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AssertAlways(obj_sections_count <= max_U16);
|
|
||||||
|
|
||||||
//
|
|
||||||
// serialize symbol table
|
|
||||||
//
|
|
||||||
String8List symbol_table = {0};
|
|
||||||
{
|
|
||||||
{
|
|
||||||
U64 symbol_idx = 0;
|
|
||||||
for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) {
|
|
||||||
COFF_ObjSymbol *s = &symbol_n->v;
|
|
||||||
|
|
||||||
// assign symbol index
|
|
||||||
s->idx = symbol_idx++;
|
|
||||||
symbol_idx += s->aux_symbols.node_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 symbol_idx = 0;
|
|
||||||
for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) {
|
|
||||||
COFF_ObjSymbol *s = &symbol_n->v;
|
|
||||||
|
|
||||||
COFF_Symbol16 *d = push_array(scratch.arena, COFF_Symbol16, 1);
|
|
||||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d));
|
|
||||||
|
|
||||||
COFF_SymbolName name = {0};
|
|
||||||
// long name
|
|
||||||
if (s->name.size > sizeof(name.short_name)) {
|
|
||||||
U64 string_table_offset = string_table.total_size;
|
|
||||||
str8_list_push(scratch.arena, &string_table, s->name);
|
|
||||||
str8_list_push(scratch.arena, &string_table, str8_lit("\0"));
|
|
||||||
|
|
||||||
name.long_name.zeroes = 0;
|
|
||||||
name.long_name.string_table_offset = safe_cast_u32(string_table_offset);
|
|
||||||
}
|
|
||||||
// short name
|
|
||||||
else {
|
|
||||||
MemoryCopyStr8(name.short_name, s->name);
|
|
||||||
MemoryZeroTyped(name.short_name + s->name.size, sizeof(name.short_name) - s->name.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// symbol header
|
|
||||||
AssertAlways(s->aux_symbols.node_count <= max_U8);
|
|
||||||
d->name = name;
|
|
||||||
d->value = s->value;
|
|
||||||
switch (s->loc.type) {
|
|
||||||
case COFF_SymbolLocation_Null: break;
|
|
||||||
case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break;
|
|
||||||
case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break;
|
|
||||||
case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break;
|
|
||||||
case COFF_SymbolLocation_Common: d->section_number = COFF_Symbol_UndefinedSection; break;
|
|
||||||
}
|
|
||||||
d->type = s->type;
|
|
||||||
d->storage_class = s->storage_class;
|
|
||||||
d->aux_symbol_count = 0;
|
|
||||||
|
|
||||||
U64 start_symbol_idx = symbol_idx;
|
|
||||||
if (s->storage_class == COFF_SymStorageClass_WeakExternal) {
|
|
||||||
if (s->aux_symbols.node_count > 0) {
|
|
||||||
COFF_ObjSymbolWeak *s_weak = (COFF_ObjSymbolWeak *)s->aux_symbols.first->string.str;
|
|
||||||
COFF_SymbolWeakExt *d_weak = push_array(scratch.arena, COFF_SymbolWeakExt, 1);
|
|
||||||
d_weak->tag_index = s_weak->tag ? s_weak->tag->idx : max_U32;
|
|
||||||
d_weak->characteristics = s_weak->characteristics;
|
|
||||||
|
|
||||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_weak));
|
|
||||||
symbol_idx += 1;
|
|
||||||
}
|
|
||||||
} else if (s->storage_class == COFF_SymStorageClass_Static) {
|
|
||||||
if (s->aux_symbols.node_count > 0) {
|
|
||||||
Assert(s->loc.type == COFF_SymbolLocation_Section);
|
|
||||||
COFF_ObjSection *sect = s->loc.u.section;
|
|
||||||
|
|
||||||
COFF_ObjSymbolSecDef *s_sd = (COFF_ObjSymbolSecDef *)s->aux_symbols.first->string.str;
|
|
||||||
COFF_SymbolSecDef *d_sd = push_array(scratch.arena, COFF_SymbolSecDef, 1);
|
|
||||||
|
|
||||||
d_sd->length = safe_cast_u32(sect->data.total_size);
|
|
||||||
d_sd->number_of_relocations = (U16)sect->reloc_count;
|
|
||||||
d_sd->check_sum = 0;
|
|
||||||
d_sd->number_lo = s_sd->selection == COFF_ComdatSelect_Associative ? safe_cast_u16(s_sd->associate->section_number) : 0;
|
|
||||||
d_sd->selection = s_sd->selection;
|
|
||||||
|
|
||||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_sd));
|
|
||||||
symbol_idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
U8 processed_aux_symbol_count = (U8)(symbol_idx - start_symbol_idx);
|
|
||||||
|
|
||||||
for (U64 aux_idx = processed_aux_symbol_count; aux_idx < s->aux_symbols.node_count; aux_idx += 1) {
|
|
||||||
COFF_Symbol16 *a = push_array(scratch.arena, COFF_Symbol16, 1);
|
|
||||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
d->aux_symbol_count = (U8)s->aux_symbols.node_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// file header
|
|
||||||
//
|
|
||||||
COFF_FileHeader *file_header = push_array(scratch.arena, COFF_FileHeader, 1);
|
|
||||||
file_header->machine = obj_writer->machine;
|
|
||||||
file_header->section_count = obj_sections_count;
|
|
||||||
file_header->time_stamp = obj_writer->time_stamp;
|
|
||||||
file_header->symbol_table_foff = 0;
|
|
||||||
file_header->symbol_count = safe_cast_u32(symbol_table.node_count);
|
|
||||||
file_header->optional_header_size = 0;
|
|
||||||
file_header->flags = 0;
|
|
||||||
str8_list_push(scratch.arena, &srl, str8_struct(file_header));
|
|
||||||
|
|
||||||
//
|
|
||||||
// section table
|
|
||||||
//
|
|
||||||
|
|
||||||
COFF_SectionHeader *sectab = push_array(scratch.arena, COFF_SectionHeader, obj_sections_count);
|
|
||||||
str8_list_push(scratch.arena, &srl, str8_array(sectab, obj_sections_count));
|
|
||||||
{
|
|
||||||
for (U64 sect_idx = 0; sect_idx < obj_sections_count; sect_idx += 1) {
|
|
||||||
COFF_ObjSection *s = obj_sections[sect_idx];
|
|
||||||
COFF_SectionHeader *d = §ab[sect_idx];
|
|
||||||
|
|
||||||
// section name
|
|
||||||
String8 sect_name = s->name;
|
|
||||||
if (sect_name.size > sizeof(d->name)) {
|
|
||||||
U64 sect_name_off = string_table.total_size;
|
|
||||||
str8_list_push(scratch.arena, &string_table, push_cstr(scratch.arena, sect_name));
|
|
||||||
|
|
||||||
sect_name = push_str8f(scratch.arena, "/%u", sect_name_off);
|
|
||||||
AssertAlways(sect_name.size <= sizeof(d->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// alloc zero nodes
|
|
||||||
for (String8Node *data_n = s->data.first; data_n != 0; data_n = data_n->next) {
|
|
||||||
if (data_n->string.str == 0 && data_n->string.size > 0) {
|
|
||||||
data_n->string = str8(push_array(scratch.arena, U8, data_n->string.size), data_n->string.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// section data
|
|
||||||
U64 data_foff = 0;
|
|
||||||
U64 data_size = 0;
|
|
||||||
if (s->data.total_size > 0) {
|
|
||||||
data_foff = srl.total_size;
|
|
||||||
data_size = s->data.total_size;
|
|
||||||
str8_list_concat_in_place(&srl, &s->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// section relocs
|
|
||||||
U64 relocs_foff = 0;
|
|
||||||
if (s->reloc_count) {
|
|
||||||
AssertAlways(s->reloc_count <= max_U16);
|
|
||||||
COFF_Reloc *relocs = push_array(scratch.arena, COFF_Reloc, s->reloc_count);
|
|
||||||
U64 reloc_idx = 0;
|
|
||||||
for (COFF_ObjRelocNode *reloc_n = s->reloc_first; reloc_n != 0; reloc_n = reloc_n->next, reloc_idx += 1) {
|
|
||||||
COFF_ObjReloc *rs = &reloc_n->v;
|
|
||||||
COFF_Reloc *rd = &relocs[reloc_idx];
|
|
||||||
rd->apply_off = rs->apply_off;
|
|
||||||
rd->isymbol = rs->symbol->idx;
|
|
||||||
rd->type = rs->type;
|
|
||||||
}
|
|
||||||
relocs_foff = srl.total_size;
|
|
||||||
str8_list_push(scratch.arena, &srl, str8_array(relocs, s->reloc_count));
|
|
||||||
}
|
|
||||||
|
|
||||||
// section header
|
|
||||||
MemoryCopyStr8(d->name, sect_name);
|
|
||||||
MemoryZeroTyped(d->name + sect_name.size, sizeof(d->name) - sect_name.size);
|
|
||||||
d->vsize = 0;
|
|
||||||
d->voff = 0;
|
|
||||||
d->fsize = data_size;
|
|
||||||
d->foff = data_foff;
|
|
||||||
d->relocs_foff = relocs_foff;
|
|
||||||
d->lines_foff = 0;
|
|
||||||
d->reloc_count = safe_cast_u32(s->reloc_count);
|
|
||||||
d->line_count = 0;
|
|
||||||
d->flags = s->flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// symbol table
|
|
||||||
//
|
|
||||||
if (symbol_table.total_size || string_table.total_size > sizeof(*string_table_size)) {
|
|
||||||
file_header->symbol_table_foff = srl.total_size;
|
|
||||||
str8_list_concat_in_place(&srl, &symbol_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// string table
|
|
||||||
//
|
|
||||||
if (string_table.total_size) {
|
|
||||||
*string_table_size = safe_cast_u32(string_table.total_size);
|
|
||||||
str8_list_concat_in_place(&srl, &string_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// join
|
|
||||||
//
|
|
||||||
String8 obj = str8_list_join(arena, &srl, 0);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSection *
|
|
||||||
coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
|
|
||||||
{
|
|
||||||
COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
|
|
||||||
SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
|
|
||||||
obj_writer->sect_count += 1;
|
|
||||||
|
|
||||||
COFF_ObjSection *sect = §_n->v;
|
|
||||||
sect->name = name;
|
|
||||||
sect->flags = flags;
|
|
||||||
|
|
||||||
if (data.size) {
|
|
||||||
str8_list_push(obj_writer->arena, §->data, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sect;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1);
|
|
||||||
SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n);
|
|
||||||
obj_writer->symbol_count += 1;
|
|
||||||
|
|
||||||
COFF_ObjSymbol *s = &n->v;
|
|
||||||
s->name = name;
|
|
||||||
s->value = value;
|
|
||||||
s->loc = loc;
|
|
||||||
s->type = type;
|
|
||||||
s->storage_class = storage_class;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
|
|
||||||
{
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Section;
|
|
||||||
loc.u.section = section;
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_External);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
|
|
||||||
{
|
|
||||||
COFF_SymbolType type = { .u.msb = COFF_SymDType_Func };
|
|
||||||
COFF_SymbolLocation loc = { .type = COFF_SymbolLocation_Section, .u.section = section };
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_External);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section)
|
|
||||||
{
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Section;
|
|
||||||
loc.u.section = section;
|
|
||||||
|
|
||||||
COFF_SymbolType symtype = {0};
|
|
||||||
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, loc, symtype, COFF_SymStorageClass_Static);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection)
|
|
||||||
{
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, section->name, 0, section);
|
|
||||||
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
|
|
||||||
sd->selection = selection;
|
|
||||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate)
|
|
||||||
{
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, head->name, 0, head);
|
|
||||||
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
|
|
||||||
sd->selection = COFF_ComdatSelect_Associative;
|
|
||||||
sd->associate = associate;
|
|
||||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag)
|
|
||||||
{
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
COFF_SymbolType symtype = {0};
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, COFF_Symbol_UndefinedSection, loc, symtype, COFF_SymStorageClass_WeakExternal);
|
|
||||||
|
|
||||||
COFF_ObjSymbolWeak *weak_ext = push_array(obj_writer->arena, COFF_ObjSymbolWeak, 1);
|
|
||||||
weak_ext->tag = tag;
|
|
||||||
weak_ext->characteristics = characteristics;
|
|
||||||
|
|
||||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(weak_ext));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class)
|
|
||||||
{
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Abs;
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, storage_class);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name)
|
|
||||||
{
|
|
||||||
COFF_SymbolType type = {0};
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Undef;
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name)
|
|
||||||
{
|
|
||||||
COFF_SymbolType type = {0};
|
|
||||||
type.u.msb = COFF_SymDType_Func;
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Undef;
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value)
|
|
||||||
{
|
|
||||||
COFF_SymbolType type = {0};
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Undef;
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_Section);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect)
|
|
||||||
{
|
|
||||||
COFF_SymbolType type = {0};
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Section;
|
|
||||||
loc.u.section = sect;
|
|
||||||
|
|
||||||
// strip align flags
|
|
||||||
COFF_SectionFlags expected_flags = sect->flags & ~(COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift);
|
|
||||||
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, expected_flags, loc, type, COFF_SymStorageClass_Section);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol *
|
|
||||||
coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size)
|
|
||||||
{
|
|
||||||
COFF_SymbolType type = {0};
|
|
||||||
COFF_SymbolLocation loc = {0};
|
|
||||||
loc.type = COFF_SymbolLocation_Common;
|
|
||||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, size, loc, type, COFF_SymStorageClass_External);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol)
|
|
||||||
{
|
|
||||||
AssertAlways(weak_symbol->storage_class == COFF_SymStorageClass_WeakExternal);
|
|
||||||
COFF_ObjSymbolWeak *w = (COFF_ObjSymbolWeak *)weak_symbol->aux_symbols.first->string.str;
|
|
||||||
w->tag = 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 type)
|
|
||||||
{
|
|
||||||
COFF_ObjRelocNode *reloc_n = push_array(obj_writer->arena, COFF_ObjRelocNode, 1);
|
|
||||||
SLLQueuePush(sect->reloc_first, sect->reloc_last, reloc_n);
|
|
||||||
sect->reloc_count += 1;
|
|
||||||
|
|
||||||
COFF_ObjReloc *reloc = &reloc_n->v;
|
|
||||||
reloc->apply_off = apply_off;
|
|
||||||
reloc->symbol = symbol;
|
|
||||||
reloc->type = type;
|
|
||||||
|
|
||||||
return reloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjReloc *
|
|
||||||
coff_obj_writer_section_push_reloc_addr32(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_Addr32; break;
|
|
||||||
default: { NotImplemented; } break;
|
|
||||||
}
|
|
||||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjReloc *
|
|
||||||
coff_obj_writer_section_push_reloc_addr(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_Addr64; break;
|
|
||||||
default: { NotImplemented; } break;
|
|
||||||
}
|
|
||||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ObjReloc *
|
|
||||||
coff_obj_writer_section_push_reloc_voff(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_Addr32Nb; break;
|
|
||||||
default: { NotImplemented; } break;
|
|
||||||
}
|
|
||||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive)
|
|
||||||
{
|
|
||||||
if (obj_writer->drectve_sect == 0) {
|
|
||||||
local_persist const U8 bom_sig[] = { ' ', ' ', ' ' };
|
|
||||||
obj_writer->drectve_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".drectve"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove|COFF_SectionFlag_Align1Bytes, str8_array_fixed(bom_sig));
|
|
||||||
}
|
|
||||||
String8List *data = &obj_writer->drectve_sect->data;
|
|
||||||
str8_list_push(obj_writer->arena, data, directive);
|
|
||||||
str8_list_pushf(obj_writer->arena, data, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
internal int
|
|
||||||
coff_obj_section_is_before(void *raw_a, void *raw_b)
|
|
||||||
{
|
|
||||||
COFF_ObjSection **a = raw_a;
|
|
||||||
COFF_ObjSection **b = raw_b;
|
|
||||||
return (*a)->section_number < (*b)->section_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
#ifndef COFF_OBJ_WRITER_H
|
|
||||||
#define COFF_OBJ_WRITER_H
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
COFF_SymbolLocation_Null,
|
|
||||||
COFF_SymbolLocation_Section,
|
|
||||||
COFF_SymbolLocation_Abs,
|
|
||||||
COFF_SymbolLocation_Undef,
|
|
||||||
COFF_SymbolLocation_Common,
|
|
||||||
} COFF_SymbolLocationType;
|
|
||||||
|
|
||||||
typedef struct COFF_SymbolLocation
|
|
||||||
{
|
|
||||||
COFF_SymbolLocationType type;
|
|
||||||
union {
|
|
||||||
struct COFF_ObjSection *section;
|
|
||||||
} u;
|
|
||||||
} COFF_SymbolLocation;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjSymbolWeak
|
|
||||||
{
|
|
||||||
struct COFF_ObjSymbol *tag;
|
|
||||||
COFF_WeakExtType characteristics;
|
|
||||||
} COFF_ObjSymbolWeak;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjSymbolSecDef
|
|
||||||
{
|
|
||||||
COFF_ComdatSelectType selection;
|
|
||||||
struct COFF_ObjSection *associate;
|
|
||||||
} COFF_ObjSymbolSecDef;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjSymbol
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
U32 value;
|
|
||||||
COFF_SymbolLocation loc;
|
|
||||||
COFF_SymbolType type;
|
|
||||||
COFF_SymStorageClass storage_class;
|
|
||||||
String8List aux_symbols;
|
|
||||||
U32 idx;
|
|
||||||
} COFF_ObjSymbol;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjSymbolNode
|
|
||||||
{
|
|
||||||
struct COFF_ObjSymbolNode *next;
|
|
||||||
COFF_ObjSymbol v;
|
|
||||||
} COFF_ObjSymbolNode;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjReloc
|
|
||||||
{
|
|
||||||
U32 apply_off;
|
|
||||||
COFF_ObjSymbol *symbol;
|
|
||||||
COFF_RelocType type;
|
|
||||||
} COFF_ObjReloc;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjRelocNode
|
|
||||||
{
|
|
||||||
struct COFF_ObjRelocNode *next;
|
|
||||||
COFF_ObjReloc v;
|
|
||||||
} COFF_ObjRelocNode;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjSection
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8List data;
|
|
||||||
COFF_SectionFlags flags;
|
|
||||||
|
|
||||||
U64 reloc_count;
|
|
||||||
COFF_ObjRelocNode *reloc_first;
|
|
||||||
COFF_ObjRelocNode *reloc_last;
|
|
||||||
|
|
||||||
U32 section_number;
|
|
||||||
} COFF_ObjSection;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjSectionNode
|
|
||||||
{
|
|
||||||
struct COFF_ObjSectionNode *next;
|
|
||||||
COFF_ObjSection v;
|
|
||||||
} COFF_ObjSectionNode;
|
|
||||||
|
|
||||||
typedef struct COFF_ObjWriter
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
COFF_TimeStamp time_stamp;
|
|
||||||
COFF_MachineType machine;
|
|
||||||
U64 symbol_count;
|
|
||||||
COFF_ObjSymbolNode *symbol_first;
|
|
||||||
COFF_ObjSymbolNode *symbol_last;
|
|
||||||
U64 sect_count;
|
|
||||||
COFF_ObjSectionNode *sect_first;
|
|
||||||
COFF_ObjSectionNode *sect_last;
|
|
||||||
COFF_ObjSection *drectve_sect;
|
|
||||||
} COFF_ObjWriter;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal COFF_ObjWriter * coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
|
|
||||||
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
|
|
||||||
internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer);
|
|
||||||
|
|
||||||
internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
|
|
||||||
|
|
||||||
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
|
|
||||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size);
|
|
||||||
|
|
||||||
internal 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_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
|
||||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
|
||||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
|
||||||
|
|
||||||
internal void coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive);
|
|
||||||
|
|
||||||
#endif // COFF_OBJ_WRITER_H
|
|
||||||
|
|
||||||
@@ -1,991 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_is_big_obj(String8 raw_coff)
|
|
||||||
{
|
|
||||||
B32 is_big_obj = 0;
|
|
||||||
if (raw_coff.size >= sizeof(COFF_BigObjHeader)) {
|
|
||||||
COFF_BigObjHeader *file_header32 = (COFF_BigObjHeader*)(raw_coff.str);
|
|
||||||
is_big_obj = file_header32->sig1 == COFF_MachineType_Unknown &&
|
|
||||||
file_header32->sig2 == max_U16 &&
|
|
||||||
file_header32->version >= 2 &&
|
|
||||||
MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0;
|
|
||||||
}
|
|
||||||
return is_big_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_is_obj(String8 raw_coff)
|
|
||||||
{
|
|
||||||
B32 is_obj = 0;
|
|
||||||
|
|
||||||
if (raw_coff.size >= sizeof(COFF_FileHeader)) {
|
|
||||||
COFF_FileHeader *header = (COFF_FileHeader*)(raw_coff.str);
|
|
||||||
|
|
||||||
// validate machine
|
|
||||||
B32 is_machine_type_valid = 0;
|
|
||||||
switch (header->machine) {
|
|
||||||
case COFF_MachineType_Unknown:
|
|
||||||
case COFF_MachineType_X86: case COFF_MachineType_X64:
|
|
||||||
case COFF_MachineType_Am33: case COFF_MachineType_Arm:
|
|
||||||
case COFF_MachineType_Arm64: case COFF_MachineType_ArmNt:
|
|
||||||
case COFF_MachineType_Ebc: case COFF_MachineType_Ia64:
|
|
||||||
case COFF_MachineType_M32R: case COFF_MachineType_Mips16:
|
|
||||||
case COFF_MachineType_MipsFpu:case COFF_MachineType_MipsFpu16:
|
|
||||||
case COFF_MachineType_PowerPc:case COFF_MachineType_PowerPcFp:
|
|
||||||
case COFF_MachineType_R4000: case COFF_MachineType_RiscV32:
|
|
||||||
case COFF_MachineType_RiscV64:case COFF_MachineType_RiscV128:
|
|
||||||
case COFF_MachineType_Sh3: case COFF_MachineType_Sh3Dsp:
|
|
||||||
case COFF_MachineType_Sh4: case COFF_MachineType_Sh5:
|
|
||||||
case COFF_MachineType_Thumb: case COFF_MachineType_WceMipsV2:
|
|
||||||
{
|
|
||||||
is_machine_type_valid = 1;
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_machine_type_valid) {
|
|
||||||
// validate section count
|
|
||||||
U64 section_count = header->section_count;
|
|
||||||
U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader);
|
|
||||||
if (raw_coff.size >= section_hdr_opl_off) {
|
|
||||||
|
|
||||||
COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(raw_coff.str + sizeof(*header));
|
|
||||||
COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count;
|
|
||||||
|
|
||||||
// validate section ranges
|
|
||||||
B32 is_sect_range_valid = 1;
|
|
||||||
for (COFF_SectionHeader *sec_hdr = section_hdrs;
|
|
||||||
sec_hdr < section_hdr_opl;
|
|
||||||
sec_hdr += 1) {
|
|
||||||
if (!(sec_hdr->flags & COFF_SectionFlag_CntUninitializedData)) {
|
|
||||||
U64 min = sec_hdr->foff;
|
|
||||||
U64 max = min + sec_hdr->fsize;
|
|
||||||
if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= raw_coff.size)) {
|
|
||||||
is_sect_range_valid = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_sect_range_valid) {
|
|
||||||
// validate symbol table
|
|
||||||
U64 symbol_table_off = header->symbol_table_foff;
|
|
||||||
U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count;
|
|
||||||
U64 symbol_table_opl_off = symbol_table_off + symbol_table_size;
|
|
||||||
|
|
||||||
// don't validate symbol table when there is none
|
|
||||||
if (symbol_table_off == 0 && symbol_table_size == 0) {
|
|
||||||
symbol_table_off = section_hdr_opl_off;
|
|
||||||
symbol_table_opl_off = section_hdr_opl_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_obj = (section_hdr_opl_off <= symbol_table_off &&
|
|
||||||
symbol_table_off <= symbol_table_opl_off &&
|
|
||||||
symbol_table_opl_off <= raw_coff.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_FileHeaderInfo
|
|
||||||
coff_file_header_info_from_data(String8 raw_coff)
|
|
||||||
{
|
|
||||||
COFF_FileHeaderInfo info = {0};
|
|
||||||
if (coff_is_big_obj(raw_coff)) {
|
|
||||||
COFF_BigObjHeader *header32 = (COFF_BigObjHeader*)raw_coff.str;
|
|
||||||
info.is_big_obj = 1;
|
|
||||||
info.machine = header32->machine;
|
|
||||||
info.section_count_no_null = header32->section_count;
|
|
||||||
info.symbol_count = header32->symbol_count;
|
|
||||||
info.symbol_size = sizeof(COFF_Symbol32);
|
|
||||||
info.header_range = rng_1u64(0, sizeof(COFF_BigObjHeader));
|
|
||||||
info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header32->section_count);
|
|
||||||
info.symbol_table_range = rng_1u64(header32->symbol_table_foff, header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count);
|
|
||||||
info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size);
|
|
||||||
} else if (coff_is_obj(raw_coff)) {
|
|
||||||
COFF_FileHeader *header16 = (COFF_FileHeader*)raw_coff.str;
|
|
||||||
info.is_big_obj = 0;
|
|
||||||
info.machine = header16->machine;
|
|
||||||
info.section_count_no_null = header16->section_count;
|
|
||||||
info.symbol_count = header16->symbol_count;
|
|
||||||
info.symbol_size = sizeof(COFF_Symbol16);
|
|
||||||
info.header_range = rng_1u64(0, sizeof(COFF_FileHeader));
|
|
||||||
info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header16->section_count);
|
|
||||||
info.symbol_table_range = rng_1u64(header16->symbol_table_foff, header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count);
|
|
||||||
info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size);
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_SectionHeader **
|
|
||||||
coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range)
|
|
||||||
{
|
|
||||||
U64 section_count = dim_1u64(section_table_range) / sizeof(COFF_SectionHeader);
|
|
||||||
COFF_SectionHeader **section_table = push_array_no_zero(arena, COFF_SectionHeader *, section_count+1);
|
|
||||||
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
|
|
||||||
for (U64 i = 0; i < section_count; ++i) {
|
|
||||||
section_table[i+1] = str8_deserial_get_raw_ptr(data, section_table_range.min + i*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
|
|
||||||
}
|
|
||||||
return section_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ParsedSymbol
|
|
||||||
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
|
|
||||||
{
|
|
||||||
COFF_ParsedSymbol result = {0};
|
|
||||||
result.name = coff_read_symbol_name(string_table, &sym32->name);
|
|
||||||
result.value = sym32->value;
|
|
||||||
result.section_number = sym32->section_number;
|
|
||||||
result.type = sym32->type;
|
|
||||||
result.storage_class = sym32->storage_class;
|
|
||||||
result.aux_symbol_count = sym32->aux_symbol_count;
|
|
||||||
result.raw_symbol = sym32;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ParsedSymbol
|
|
||||||
coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
|
|
||||||
{
|
|
||||||
COFF_ParsedSymbol result = {0};
|
|
||||||
result.name = coff_read_symbol_name(string_table, &sym16->name);
|
|
||||||
result.value = sym16->value;
|
|
||||||
if (sym16->section_number == COFF_Symbol_DebugSection16) {
|
|
||||||
result.section_number = COFF_Symbol_DebugSection32;
|
|
||||||
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
|
|
||||||
result.section_number = COFF_Symbol_AbsSection32;
|
|
||||||
} else {
|
|
||||||
result.section_number = (U32)sym16->section_number;
|
|
||||||
}
|
|
||||||
result.type = sym16->type;
|
|
||||||
result.storage_class = sym16->storage_class;
|
|
||||||
result.aux_symbol_count = sym16->aux_symbol_count;
|
|
||||||
result.raw_symbol = sym16;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ParsedSymbol
|
|
||||||
coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx)
|
|
||||||
{
|
|
||||||
COFF_ParsedSymbol symbol;
|
|
||||||
if (header.is_big_obj) {
|
|
||||||
symbol = coff_parse_symbol32(string_table, (COFF_Symbol32 *)symbol_table.str + symbol_idx);
|
|
||||||
} else {
|
|
||||||
symbol = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + symbol_idx);
|
|
||||||
}
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_Symbol32Array
|
|
||||||
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
|
|
||||||
{
|
|
||||||
COFF_Symbol32Array result = {0};
|
|
||||||
result.count = symbol_count;
|
|
||||||
result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8);
|
|
||||||
|
|
||||||
Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count);
|
|
||||||
String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range);
|
|
||||||
COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str;
|
|
||||||
|
|
||||||
for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) {
|
|
||||||
COFF_Symbol16 *sym16 = &sym16_arr[isymbol];
|
|
||||||
COFF_Symbol32 *sym32 = &result.v[isymbol];
|
|
||||||
|
|
||||||
sym32->name = sym16->name;
|
|
||||||
sym32->value = sym16->value;
|
|
||||||
if (sym16->section_number == COFF_Symbol_DebugSection16) {
|
|
||||||
sym32->section_number = COFF_Symbol_DebugSection32;
|
|
||||||
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
|
|
||||||
sym32->section_number = COFF_Symbol_AbsSection32;
|
|
||||||
} else {
|
|
||||||
sym32->section_number = (U32)sym16->section_number;
|
|
||||||
}
|
|
||||||
sym32->type.v = sym16->type.v;
|
|
||||||
sym32->storage_class = sym16->storage_class;
|
|
||||||
sym32->aux_symbol_count = sym16->aux_symbol_count;
|
|
||||||
|
|
||||||
// copy aux symbols
|
|
||||||
for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) {
|
|
||||||
COFF_Symbol16 *aux16 = sym16_arr + iaux;
|
|
||||||
COFF_Symbol32 *aux32 = result.v + iaux;
|
|
||||||
|
|
||||||
// 32bit COFF uses 16bit aux symbols
|
|
||||||
MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16));
|
|
||||||
MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16));
|
|
||||||
}
|
|
||||||
|
|
||||||
// take into account aux symbols
|
|
||||||
isymbol += sym32->aux_symbol_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_Symbol32Array
|
|
||||||
coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count)
|
|
||||||
{
|
|
||||||
COFF_Symbol32Array result;
|
|
||||||
result.count = symbol_count;
|
|
||||||
result.v = (COFF_Symbol32 *)(data.str + symbol_array_off);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_Symbol32Array
|
|
||||||
coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size)
|
|
||||||
{
|
|
||||||
COFF_Symbol32Array result = {0};
|
|
||||||
switch (symbol_size) {
|
|
||||||
case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_array_off, symbol_count); break;
|
|
||||||
case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_array_off, symbol_count); break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_Symbol16Node *
|
|
||||||
coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol)
|
|
||||||
{
|
|
||||||
COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1);
|
|
||||||
node->next = 0;
|
|
||||||
node->data = symbol;
|
|
||||||
SLLQueuePush(list->first, list->last, node);
|
|
||||||
list->count += 1;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_SymbolValueInterpType
|
|
||||||
coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class)
|
|
||||||
{
|
|
||||||
if (storage_class == COFF_SymStorageClass_Section && section_number == COFF_Symbol_UndefinedSection) {
|
|
||||||
return COFF_SymbolValueInterp_Undefined;
|
|
||||||
}
|
|
||||||
if (storage_class == COFF_SymStorageClass_External && value == 0 && section_number == COFF_Symbol_UndefinedSection) {
|
|
||||||
return COFF_SymbolValueInterp_Undefined;
|
|
||||||
}
|
|
||||||
if (storage_class == COFF_SymStorageClass_External && value != 0 && section_number == COFF_Symbol_UndefinedSection) {
|
|
||||||
return COFF_SymbolValueInterp_Common;
|
|
||||||
}
|
|
||||||
if (section_number == COFF_Symbol_AbsSection32) {
|
|
||||||
return COFF_SymbolValueInterp_Abs;
|
|
||||||
}
|
|
||||||
if (section_number == COFF_Symbol_DebugSection32) {
|
|
||||||
return COFF_SymbolValueInterp_Debug;
|
|
||||||
}
|
|
||||||
if (storage_class == COFF_SymStorageClass_WeakExternal) {
|
|
||||||
return COFF_SymbolValueInterp_Weak;
|
|
||||||
}
|
|
||||||
return COFF_SymbolValueInterp_Regular;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_SymbolValueInterpType
|
|
||||||
coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol)
|
|
||||||
{
|
|
||||||
return coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol)
|
|
||||||
{
|
|
||||||
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
|
|
||||||
return interp == COFF_SymbolValueInterp_Undefined && symbol.storage_class == COFF_SymStorageClass_External;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out)
|
|
||||||
{
|
|
||||||
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Regular);
|
|
||||||
Assert(symbol.aux_symbol_count > 0);
|
|
||||||
|
|
||||||
if (is_big_obj) {
|
|
||||||
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
|
|
||||||
if (selection_out) *selection_out = sd->selection;
|
|
||||||
if (length_out) *length_out = sd->length;
|
|
||||||
if (check_sum_out) *check_sum_out = sd->check_sum;
|
|
||||||
if (number_out) *number_out = Compose32Bit(sd->number_hi, sd->number_lo);
|
|
||||||
} else {
|
|
||||||
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
|
|
||||||
if (selection_out) *selection_out = sd->selection;
|
|
||||||
if (length_out) *length_out = sd->length;
|
|
||||||
if (check_sum_out) *check_sum_out = sd->check_sum;
|
|
||||||
if (number_out) *number_out = sd->number_lo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_SymbolWeakExt *
|
|
||||||
coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj)
|
|
||||||
{
|
|
||||||
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Weak);
|
|
||||||
Assert(symbol.aux_symbol_count > 0);
|
|
||||||
|
|
||||||
void *tag;
|
|
||||||
if (is_big_obj) {
|
|
||||||
tag = (COFF_SymbolWeakExt *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
|
|
||||||
} else {
|
|
||||||
tag = (COFF_SymbolWeakExt *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_RelocNode *
|
|
||||||
coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc)
|
|
||||||
{
|
|
||||||
COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1);
|
|
||||||
node->data = reloc;
|
|
||||||
SLLQueuePush(list->first, list->last, node);
|
|
||||||
++list->count;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_RelocInfo
|
|
||||||
coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header)
|
|
||||||
{
|
|
||||||
COFF_RelocInfo result = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl && header->reloc_count == max_U16) {
|
|
||||||
COFF_Reloc counter;
|
|
||||||
U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter);
|
|
||||||
if (read_size == sizeof(counter) && counter.apply_off > 0) {
|
|
||||||
result.array_off = header->relocs_foff + sizeof(COFF_Reloc);
|
|
||||||
result.count = counter.apply_off - 1; // exclude counter entry
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.array_off = header->relocs_foff;
|
|
||||||
result.count = header->reloc_count;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_resource_string_from_str16(Arena *arena, String16 string)
|
|
||||||
{
|
|
||||||
AssertAlways(string.size <= max_U16);
|
|
||||||
U16 size16 = (U16)string.size;
|
|
||||||
|
|
||||||
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
|
|
||||||
MemoryCopy(buffer + 0, &size16, sizeof(size16));
|
|
||||||
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
|
|
||||||
|
|
||||||
return str8_array(buffer, size16 + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_resource_string_from_str8(Arena *arena, String8 string)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String16 string16 = str16_from_8(scratch.arena, string);
|
|
||||||
String8 result = coff_resource_string_from_str16(arena, string16);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_resource_number_from_u16(Arena *arena, U16 number)
|
|
||||||
{
|
|
||||||
U16 *buffer = push_array_no_zero(arena, U16, 2);
|
|
||||||
buffer[0] = max_U16;
|
|
||||||
buffer[1] = number;
|
|
||||||
return str8_array(buffer, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ResourceID
|
|
||||||
coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16)
|
|
||||||
{
|
|
||||||
COFF_ResourceID id = {0};
|
|
||||||
id.type = id_16->type;
|
|
||||||
switch (id_16->type) {
|
|
||||||
case COFF_ResourceIDType_Null: break;
|
|
||||||
case COFF_ResourceIDType_Number: {
|
|
||||||
id.u.number = id_16->u.number;
|
|
||||||
} break;
|
|
||||||
case COFF_ResourceIDType_String: {
|
|
||||||
id.u.string = str8_from_16(arena, id_16->u.string);
|
|
||||||
} break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_read_resource_id_utf16(String8 raw_res, U64 off, COFF_ResourceID16 *id_out)
|
|
||||||
{
|
|
||||||
U64 cursor = off;
|
|
||||||
|
|
||||||
U16 flag = 0;
|
|
||||||
str8_deserial_read_struct(raw_res, cursor, &flag);
|
|
||||||
|
|
||||||
if (flag == max_U16) {
|
|
||||||
id_out->type = COFF_ResourceIDType_Number;
|
|
||||||
cursor += sizeof(flag);
|
|
||||||
cursor += str8_deserial_read_struct(raw_res, cursor, &id_out->u.number);
|
|
||||||
} else {
|
|
||||||
id_out->type = COFF_ResourceIDType_String;
|
|
||||||
cursor += str8_deserial_read_windows_utf16_string16(raw_res, cursor, &id_out->u.string);
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 read_size = cursor - off;
|
|
||||||
read_size = AlignPow2(read_size, COFF_ResourceAlign);
|
|
||||||
return read_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out)
|
|
||||||
{
|
|
||||||
String8 raw_header = str8_skip(raw_res, off);
|
|
||||||
U64 header_cursor = 0;
|
|
||||||
|
|
||||||
// prefix
|
|
||||||
COFF_ResourceHeaderPrefix prefix = {0};
|
|
||||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
|
|
||||||
|
|
||||||
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
|
|
||||||
raw_header = str8_prefix(raw_header, prefix.header_size);
|
|
||||||
|
|
||||||
// header
|
|
||||||
COFF_ResourceID16 type_16 = {0};
|
|
||||||
COFF_ResourceID16 name_16 = {0};
|
|
||||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
|
|
||||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
|
|
||||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
|
|
||||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
|
|
||||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
|
|
||||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
|
|
||||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
|
|
||||||
Assert(prefix.header_size == header_cursor);
|
|
||||||
|
|
||||||
// convert utf-16 resource ids to utf-8
|
|
||||||
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
|
|
||||||
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
|
|
||||||
|
|
||||||
// read data
|
|
||||||
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
|
|
||||||
Assert(prefix.data_size == data_read_size);
|
|
||||||
|
|
||||||
// compute read size
|
|
||||||
U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_ResourceAlign);
|
|
||||||
return read_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ParsedResourceList
|
|
||||||
coff_resource_list_from_data(Arena *arena, String8 data)
|
|
||||||
{
|
|
||||||
COFF_ParsedResourceList list = {0};
|
|
||||||
U64 cursor;
|
|
||||||
for (cursor = 0 ; cursor < data.size; ) {
|
|
||||||
COFF_ParsedResourceNode *node = push_array(arena, COFF_ParsedResourceNode, 1);
|
|
||||||
cursor += coff_read_resource(arena, data, cursor, &node->data);
|
|
||||||
SLLQueuePush(list.first, list.last, node);
|
|
||||||
++list.count;
|
|
||||||
}
|
|
||||||
Assert(cursor == data.size);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_write_resource_id(Arena *arena, COFF_ResourceID id)
|
|
||||||
{
|
|
||||||
String8 result = str8_zero();
|
|
||||||
switch (id.type) {
|
|
||||||
case COFF_ResourceIDType_Null: break;
|
|
||||||
case COFF_ResourceIDType_Number: {
|
|
||||||
result = coff_resource_number_from_u16(arena, id.u.number);
|
|
||||||
} break;
|
|
||||||
case COFF_ResourceIDType_String: {
|
|
||||||
result = coff_resource_string_from_str8(arena, id.u.string);
|
|
||||||
} break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_write_resource(Arena *arena,
|
|
||||||
COFF_ResourceID type,
|
|
||||||
COFF_ResourceID name,
|
|
||||||
U32 data_version,
|
|
||||||
COFF_ResourceMemoryFlags memory_flags,
|
|
||||||
U16 language_id,
|
|
||||||
U32 version,
|
|
||||||
U32 characteristics,
|
|
||||||
String8 data)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8List list = {0};
|
|
||||||
|
|
||||||
COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
|
|
||||||
String8 packed_type = coff_write_resource_id(scratch.arena, type);
|
|
||||||
String8 packed_name = coff_write_resource_id(scratch.arena, name);
|
|
||||||
|
|
||||||
// prefix + header
|
|
||||||
str8_list_push(scratch.arena, &list, str8_struct(prefix));
|
|
||||||
str8_list_push(scratch.arena, &list, packed_type);
|
|
||||||
str8_list_push(scratch.arena, &list, packed_name);
|
|
||||||
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
|
|
||||||
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
|
|
||||||
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
|
|
||||||
str8_list_push(scratch.arena, &list, str8_struct(&version));
|
|
||||||
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
|
|
||||||
|
|
||||||
prefix->data_size = safe_cast_u32(data.size);
|
|
||||||
prefix->header_size = safe_cast_u32(list.total_size);
|
|
||||||
|
|
||||||
// data
|
|
||||||
str8_list_push(scratch.arena, &list, data);
|
|
||||||
|
|
||||||
// magic
|
|
||||||
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
|
|
||||||
|
|
||||||
// align
|
|
||||||
U64 align_size = AlignPow2(list.total_size, COFF_ResourceAlign) - list.total_size;
|
|
||||||
U8 *align = push_array(scratch.arena, U8, align_size);
|
|
||||||
str8_list_push(scratch.arena, &list, str8(align, align_size));
|
|
||||||
|
|
||||||
// join
|
|
||||||
String8 res = str8_list_join(arena, &list, 0);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal int
|
|
||||||
coff_resource_id_compar(void *raw_a, void *raw_b)
|
|
||||||
{
|
|
||||||
int cmp;
|
|
||||||
COFF_ResourceID *a = raw_a;
|
|
||||||
COFF_ResourceID *b = raw_b;
|
|
||||||
if (a->type == b->type) {
|
|
||||||
switch (a->type) {
|
|
||||||
default:
|
|
||||||
case COFF_ResourceIDType_Null: cmp = 0; break;
|
|
||||||
case COFF_ResourceIDType_Number: cmp = MemoryCompare(&a->u.number, &b->u.number, sizeof(a->u.number)); break;
|
|
||||||
case COFF_ResourceIDType_String: cmp = strncmp((char *)a->u.string.str, (char *)b->u.string.str, Min(a->u.string.size, b->u.string.size)); break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cmp = a->type < b->type ? -1 : a->type > b->type ? +1 : 0;
|
|
||||||
}
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_is_import(String8 raw_archive_member)
|
|
||||||
{
|
|
||||||
B32 is_import = 0;
|
|
||||||
if (raw_archive_member.size >= sizeof(U16)*2) {
|
|
||||||
U16 *sig1 = (U16*)raw_archive_member.str;
|
|
||||||
U16 *sig2 = sig1 + 1;
|
|
||||||
is_import = *sig1 == COFF_MachineType_Unknown && *sig2 == 0xffff;
|
|
||||||
}
|
|
||||||
return is_import;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_DataType
|
|
||||||
coff_data_type_from_data(String8 raw_archive_member)
|
|
||||||
{
|
|
||||||
B32 is_big_obj = coff_is_big_obj(raw_archive_member);
|
|
||||||
if (is_big_obj) {
|
|
||||||
return COFF_DataType_BigObj;
|
|
||||||
}
|
|
||||||
B32 is_import = coff_is_import(raw_archive_member);
|
|
||||||
if (is_import) {
|
|
||||||
return COFF_DataType_Import;
|
|
||||||
}
|
|
||||||
return COFF_DataType_Obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_is_regular_archive(String8 raw_archive)
|
|
||||||
{
|
|
||||||
B32 is_archive = 0;
|
|
||||||
U8 sig[sizeof(g_coff_archive_sig)];
|
|
||||||
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
|
|
||||||
is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0;
|
|
||||||
}
|
|
||||||
return is_archive;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_is_thin_archive(String8 raw_archive)
|
|
||||||
{
|
|
||||||
B32 is_archive = 0;
|
|
||||||
U8 sig[sizeof(g_coff_thin_archive_sig)];
|
|
||||||
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
|
|
||||||
is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0;
|
|
||||||
}
|
|
||||||
return is_archive;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveType
|
|
||||||
coff_archive_type_from_data(String8 raw_archive)
|
|
||||||
{
|
|
||||||
if (coff_is_regular_archive(raw_archive)) {
|
|
||||||
return COFF_Archive_Regular;
|
|
||||||
} else if (coff_is_thin_archive(raw_archive)) {
|
|
||||||
return COFF_Archive_Thin;
|
|
||||||
}
|
|
||||||
return COFF_Archive_Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out)
|
|
||||||
{
|
|
||||||
COFF_ArchiveMemberHeader *header = str8_deserial_get_raw_ptr(raw_archive, offset, sizeof(*header));
|
|
||||||
if (header) {
|
|
||||||
String8 name = str8_skip_chop_whitespace(str8_cstring_capped(header->name, header->name + sizeof(header->name) ));
|
|
||||||
String8 date = str8_skip_chop_whitespace(str8_cstring_capped(header->date, header->date + sizeof(header->date) ));
|
|
||||||
String8 user_id = str8_skip_chop_whitespace(str8_cstring_capped(header->user_id, header->user_id + sizeof(header->user_id) ));
|
|
||||||
String8 group_id = str8_skip_chop_whitespace(str8_cstring_capped(header->group_id, header->group_id + sizeof(header->group_id)));
|
|
||||||
String8 mode = str8_skip_chop_whitespace(str8_cstring_capped(header->mode, header->mode + sizeof(header->mode) ));
|
|
||||||
String8 size = str8_skip_chop_whitespace(str8_cstring_capped(header->size, header->size + sizeof(header->size) ));
|
|
||||||
String8 end = str8_cstring_capped(header->end, header->end + sizeof(header->end));
|
|
||||||
|
|
||||||
U32 data_size = u32_from_str8(size, 10);
|
|
||||||
U64 data_off = offset + sizeof(COFF_ArchiveMemberHeader);
|
|
||||||
|
|
||||||
header_out->name = name;
|
|
||||||
header_out->time_stamp = u32_from_str8(date, 10);
|
|
||||||
header_out->user_id = u32_from_str8(user_id, 10);
|
|
||||||
header_out->group_id = u32_from_str8(group_id, 10);
|
|
||||||
header_out->mode = mode;
|
|
||||||
header_out->is_end_correct = str8_match_lit("`\n", end, 0);
|
|
||||||
header_out->data_range = rng_1u64(data_off, data_off + data_size);
|
|
||||||
|
|
||||||
return sizeof(*header);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveFirstMember
|
|
||||||
coff_parse_first_archive_member(COFF_ArchiveMember *member)
|
|
||||||
{
|
|
||||||
Assert(str8_match_lit("/", member->header.name, 0));
|
|
||||||
|
|
||||||
U64 cursor = 0;
|
|
||||||
|
|
||||||
U32 symbol_count = 0;
|
|
||||||
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
|
|
||||||
|
|
||||||
symbol_count = from_be_u32(symbol_count);
|
|
||||||
|
|
||||||
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32));
|
|
||||||
cursor += dim_1u64(member_offsets_range);
|
|
||||||
|
|
||||||
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
|
|
||||||
cursor += dim_1u64(string_table_range);
|
|
||||||
|
|
||||||
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
|
|
||||||
U32 *member_offsets = (U32 *)raw_member_offsets.str;
|
|
||||||
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
|
|
||||||
|
|
||||||
COFF_ArchiveFirstMember result = {0};
|
|
||||||
result.symbol_count = symbol_count;
|
|
||||||
result.member_offset_count = member_offset_count;
|
|
||||||
result.member_offsets = member_offsets;
|
|
||||||
result.string_table = str8_substr(member->data, string_table_range);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveSecondMember
|
|
||||||
coff_parse_second_archive_member(COFF_ArchiveMember *member)
|
|
||||||
{
|
|
||||||
COFF_ArchiveSecondMember result = {0};
|
|
||||||
|
|
||||||
if (str8_match_lit("/", member->header.name, 0)) {
|
|
||||||
U64 cursor = 0;
|
|
||||||
|
|
||||||
U32 member_count = 0;
|
|
||||||
cursor += str8_deserial_read_struct(member->data, cursor, &member_count);
|
|
||||||
|
|
||||||
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32));
|
|
||||||
cursor += dim_1u64(member_offsets_range);
|
|
||||||
|
|
||||||
U32 symbol_count = 0;
|
|
||||||
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
|
|
||||||
|
|
||||||
Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16));
|
|
||||||
cursor += dim_1u64(symbol_indices_range);
|
|
||||||
|
|
||||||
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
|
|
||||||
|
|
||||||
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
|
|
||||||
String8 raw_indices = str8_substr(member->data, symbol_indices_range);
|
|
||||||
|
|
||||||
U32 *member_offsets = (U32 *)raw_member_offsets.str;
|
|
||||||
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
|
|
||||||
|
|
||||||
U16 *symbol_indices = (U16 *)raw_indices.str;
|
|
||||||
U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]);
|
|
||||||
|
|
||||||
result.member_count = member_count;
|
|
||||||
result.symbol_count = symbol_count;
|
|
||||||
result.member_offsets = member_offsets;
|
|
||||||
result.member_offset_count = member_offset_count;
|
|
||||||
result.symbol_indices = symbol_indices;
|
|
||||||
result.symbol_index_count = symbol_index_count;
|
|
||||||
result.string_table = str8_substr(member->data, string_table_range);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_decode_raw_member_name(String8 long_names, String8 name)
|
|
||||||
{
|
|
||||||
String8 result = name;
|
|
||||||
if (name.size > 0 && name.str[0] == '/') {
|
|
||||||
String8 offset_str = str8(name.str + 1, name.size - 1);
|
|
||||||
U64 offset = u64_from_str8(offset_str, 10);
|
|
||||||
if (offset < long_names.size) {
|
|
||||||
U8 *ptr = long_names.str + offset;
|
|
||||||
U8 *opl = long_names.str + long_names.size;
|
|
||||||
for (; ptr < opl; ++ptr) {
|
|
||||||
if (*ptr == '\0' || *ptr == '\n') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = str8_range(long_names.str + offset, ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_decode_member_name(String8 long_names, String8 name)
|
|
||||||
{
|
|
||||||
String8 member_name = coff_decode_raw_member_name(long_names, name);
|
|
||||||
String8 slash = str8_lit("/");
|
|
||||||
if (str8_ends_with(member_name, slash, 0)) {
|
|
||||||
member_name = str8_chop(member_name, slash.size);
|
|
||||||
}
|
|
||||||
return member_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out)
|
|
||||||
{
|
|
||||||
COFF_ImportHeader *header = str8_deserial_get_raw_ptr(raw_archive_member, offset, sizeof(*header));
|
|
||||||
if (header) {
|
|
||||||
Rng1U64 data_range = rng_1u64(offset + sizeof(*header), offset + sizeof(*header) + header->data_size);
|
|
||||||
String8 raw_data = str8_substr(raw_archive_member, data_range);
|
|
||||||
U64 data_cursor = 0;
|
|
||||||
|
|
||||||
header_out->version = header->version;
|
|
||||||
header_out->machine = header->machine;
|
|
||||||
header_out->time_stamp = header->time_stamp;
|
|
||||||
header_out->data_size = header->data_size;
|
|
||||||
header_out->hint_or_ordinal = header->hint_or_ordinal;
|
|
||||||
header_out->type = COFF_ImportHeader_ExtractType(header->flags);
|
|
||||||
header_out->import_by = COFF_ImportHeader_ExtractImportBy(header->flags);
|
|
||||||
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->func_name);
|
|
||||||
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->dll_name);
|
|
||||||
|
|
||||||
Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size);
|
|
||||||
U64 read_size = sizeof(*header) + header->data_size;
|
|
||||||
return read_size;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveMember
|
|
||||||
coff_archive_member_from_offset(String8 raw_archive, U64 offset)
|
|
||||||
{
|
|
||||||
COFF_ArchiveMember member = {0};
|
|
||||||
coff_regular_archive_member_iter_next(raw_archive, &offset, &member);
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveMember
|
|
||||||
coff_archive_member_from_data(String8 raw_archive_member)
|
|
||||||
{
|
|
||||||
return coff_archive_member_from_offset(raw_archive_member, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ParsedArchiveImportHeader
|
|
||||||
coff_archive_import_from_data(String8 raw_archive_member)
|
|
||||||
{
|
|
||||||
COFF_ParsedArchiveImportHeader header = {0};
|
|
||||||
coff_parse_import(raw_archive_member, 0, &header);
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_regular_archive_member_iter_init(String8 raw_archive)
|
|
||||||
{
|
|
||||||
U64 cursor = raw_archive.size;
|
|
||||||
if (coff_is_regular_archive(raw_archive)) {
|
|
||||||
cursor = sizeof(g_coff_archive_sig);
|
|
||||||
}
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
|
|
||||||
{
|
|
||||||
B32 is_parsed = 0;
|
|
||||||
|
|
||||||
member_out->header.is_end_correct = 0;
|
|
||||||
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
|
|
||||||
|
|
||||||
if (member_out->header.is_end_correct) {
|
|
||||||
member_out->offset = *offset;
|
|
||||||
member_out->data = str8_substr(raw_archive, member_out->header.data_range);
|
|
||||||
|
|
||||||
U64 read_size = AlignPow2(header_size + dim_1u64(member_out->header.data_range), COFF_Archive_MemberAlign);
|
|
||||||
*offset += read_size;
|
|
||||||
|
|
||||||
is_parsed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_thin_archive_member_iter_init(String8 raw_archive)
|
|
||||||
{
|
|
||||||
U64 cursor = raw_archive.size;
|
|
||||||
if (coff_is_thin_archive(raw_archive)) {
|
|
||||||
cursor = sizeof(g_coff_thin_archive_sig);
|
|
||||||
}
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
|
|
||||||
{
|
|
||||||
B32 is_parsed = 0;
|
|
||||||
|
|
||||||
member_out->header.is_end_correct = 0;
|
|
||||||
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
|
|
||||||
|
|
||||||
if (member_out->header.is_end_correct) {
|
|
||||||
Rng1U64 data_in_archive_range = {0};
|
|
||||||
if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) {
|
|
||||||
data_in_archive_range = member_out->header.data_range;
|
|
||||||
}
|
|
||||||
|
|
||||||
member_out->offset = *offset;
|
|
||||||
member_out->data = str8_substr(raw_archive, data_in_archive_range);
|
|
||||||
|
|
||||||
U64 read_size = AlignPow2(header_size + dim_1u64(data_in_archive_range), COFF_Archive_MemberAlign);
|
|
||||||
*offset += read_size;
|
|
||||||
|
|
||||||
is_parsed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node)
|
|
||||||
{
|
|
||||||
SLLQueuePush(list->first, list->last, node);
|
|
||||||
list->count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveParse
|
|
||||||
coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list)
|
|
||||||
{
|
|
||||||
String8 error = str8_zero();
|
|
||||||
B32 has_second_header = 0;
|
|
||||||
B32 has_long_names = 0;
|
|
||||||
COFF_ArchiveMember first_header = {0};
|
|
||||||
COFF_ArchiveMember second_header = {0};
|
|
||||||
COFF_ArchiveMember long_names_member = {0};
|
|
||||||
|
|
||||||
COFF_ArchiveMemberNode *ptr = member_list.first;
|
|
||||||
|
|
||||||
if (ptr) {
|
|
||||||
if (str8_match_lit("/", ptr->data.header.name, 0)) {
|
|
||||||
if (ptr->data.header.is_end_correct) {
|
|
||||||
first_header = ptr->data;
|
|
||||||
ptr = ptr->next;
|
|
||||||
} else {
|
|
||||||
error = str8_lit("first header doesn't have correct end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error = str8_lit("missing first header");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!error.size && ptr) {
|
|
||||||
if (str8_match_lit("/", ptr->data.header.name, 0)) {
|
|
||||||
if (ptr->data.header.is_end_correct) {
|
|
||||||
second_header = ptr->data;
|
|
||||||
ptr = ptr->next;
|
|
||||||
has_second_header = 1;
|
|
||||||
} else {
|
|
||||||
error = str8_lit("second header doesn't have correct end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!error.size && ptr) {
|
|
||||||
if (str8_match_lit("//", ptr->data.header.name, 0)) {
|
|
||||||
if (ptr->data.header.is_end_correct) {
|
|
||||||
long_names_member = ptr->data;
|
|
||||||
ptr = ptr->next;
|
|
||||||
has_long_names;
|
|
||||||
} else {
|
|
||||||
error = str8_lit("long names header doesn't have correct end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
COFF_ArchiveParse parse = {0};
|
|
||||||
parse.has_second_header = has_second_header;
|
|
||||||
parse.has_long_names = has_long_names;
|
|
||||||
parse.first_member = coff_parse_first_archive_member(&first_header);
|
|
||||||
parse.second_member = coff_parse_second_archive_member(&second_header);
|
|
||||||
parse.long_names = long_names_member.data;
|
|
||||||
parse.error = error;
|
|
||||||
|
|
||||||
return parse;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveParse
|
|
||||||
coff_regular_archive_parse_from_data(String8 raw_archive)
|
|
||||||
{
|
|
||||||
COFF_ArchiveMemberList list = {0};
|
|
||||||
COFF_ArchiveMemberNode node_arr[3] = {0};
|
|
||||||
U64 cursor = coff_regular_archive_member_iter_init(raw_archive);
|
|
||||||
for (U64 i = 0; i < ArrayCount(node_arr); ++i) {
|
|
||||||
COFF_ArchiveMemberNode *node = &node_arr[i];
|
|
||||||
if (!coff_regular_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
coff_archive_member_list_push_node(&list, node);
|
|
||||||
}
|
|
||||||
return coff_archive_parse_from_member_list(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveParse
|
|
||||||
coff_thin_archive_parse_from_data(String8 raw_archive)
|
|
||||||
{
|
|
||||||
COFF_ArchiveMemberList list = {0};
|
|
||||||
COFF_ArchiveMemberNode node_arr[3] = {0};
|
|
||||||
U64 cursor = coff_thin_archive_member_iter_init(raw_archive);
|
|
||||||
for (U64 i = 0; i < ArrayCount(node_arr); i += 1) {
|
|
||||||
COFF_ArchiveMemberNode *node = &node_arr[i];
|
|
||||||
if (!coff_thin_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
coff_archive_member_list_push_node(&list, node);
|
|
||||||
}
|
|
||||||
return coff_archive_parse_from_member_list(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ArchiveParse
|
|
||||||
coff_archive_parse_from_data(String8 raw_archive)
|
|
||||||
{
|
|
||||||
COFF_ArchiveType type = coff_archive_type_from_data(raw_archive);
|
|
||||||
switch (type) {
|
|
||||||
case COFF_Archive_Null: break;
|
|
||||||
case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive);
|
|
||||||
case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive);
|
|
||||||
}
|
|
||||||
COFF_ArchiveParse null_parse = {0};
|
|
||||||
return null_parse;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,329 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef COFF_PARSE_H
|
|
||||||
#define COFF_PARSE_H
|
|
||||||
|
|
||||||
typedef struct COFF_FileHeaderInfo
|
|
||||||
{
|
|
||||||
B32 is_big_obj;
|
|
||||||
COFF_MachineType machine;
|
|
||||||
U64 header_size;
|
|
||||||
U64 section_count_no_null;
|
|
||||||
U64 symbol_size;
|
|
||||||
U64 symbol_count;
|
|
||||||
Rng1U64 header_range;
|
|
||||||
Rng1U64 section_table_range;
|
|
||||||
Rng1U64 symbol_table_range;
|
|
||||||
Rng1U64 string_table_range;
|
|
||||||
} COFF_FileHeaderInfo;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct COFF_SectionHeaderArray
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_SectionHeader *v;
|
|
||||||
} COFF_SectionHeaderArray;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct COFF_Symbol16Node
|
|
||||||
{
|
|
||||||
struct COFF_Symbol16Node *next;
|
|
||||||
COFF_Symbol16 data;
|
|
||||||
} COFF_Symbol16Node;
|
|
||||||
|
|
||||||
typedef struct COFF_Symbol16List
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_Symbol16Node *first;
|
|
||||||
COFF_Symbol16Node *last;
|
|
||||||
} COFF_Symbol16List;
|
|
||||||
|
|
||||||
typedef struct COFF_Symbol32Array
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_Symbol32 *v;
|
|
||||||
} COFF_Symbol32Array;
|
|
||||||
|
|
||||||
typedef struct COFF_ParsedSymbol
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
U64 value;
|
|
||||||
U32 section_number;
|
|
||||||
COFF_SymbolType type;
|
|
||||||
COFF_SymStorageClass storage_class;
|
|
||||||
U8 aux_symbol_count;
|
|
||||||
void *raw_symbol;
|
|
||||||
} COFF_ParsedSymbol;
|
|
||||||
|
|
||||||
typedef U32 COFF_SymbolValueInterpType;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
COFF_SymbolValueInterp_Regular, // symbol has section and offset.
|
|
||||||
COFF_SymbolValueInterp_Weak, // symbol is overridable.
|
|
||||||
COFF_SymbolValueInterp_Undefined, // symbol doesn't have a reference section.
|
|
||||||
COFF_SymbolValueInterp_Common, // symbol has no section but still has size.
|
|
||||||
COFF_SymbolValueInterp_Abs, // symbol has an absolute (non-relocatable) value and is not an address.
|
|
||||||
COFF_SymbolValueInterp_Debug // symbol is used to provide general type of debugging information.
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct COFF_RelocNode
|
|
||||||
{
|
|
||||||
struct COFF_RelocNode *next;
|
|
||||||
COFF_Reloc data;
|
|
||||||
} COFF_RelocNode;
|
|
||||||
|
|
||||||
typedef struct COFF_RelocList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_RelocNode *first;
|
|
||||||
COFF_RelocNode *last;
|
|
||||||
} COFF_RelocList;
|
|
||||||
|
|
||||||
typedef struct COFF_RelocArray
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_Reloc *v;
|
|
||||||
} COFF_RelocArray;
|
|
||||||
|
|
||||||
typedef struct COFF_RelocInfo
|
|
||||||
{
|
|
||||||
U64 array_off;
|
|
||||||
U64 count;
|
|
||||||
} COFF_RelocInfo;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef U32 COFF_ResourceIDType;
|
|
||||||
enum COFF_ResourceIDTypeEnum
|
|
||||||
{
|
|
||||||
COFF_ResourceIDType_Null,
|
|
||||||
COFF_ResourceIDType_Number,
|
|
||||||
COFF_ResourceIDType_String,
|
|
||||||
COFF_ResourceIDType_Count
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct COFF_ResourceID16
|
|
||||||
{
|
|
||||||
COFF_ResourceIDType type;
|
|
||||||
union {
|
|
||||||
U16 number;
|
|
||||||
String16 string;
|
|
||||||
} u;
|
|
||||||
} COFF_ResourceID16;
|
|
||||||
|
|
||||||
typedef struct COFF_ResourceID
|
|
||||||
{
|
|
||||||
COFF_ResourceIDType type;
|
|
||||||
union {
|
|
||||||
U16 number;
|
|
||||||
String8 string;
|
|
||||||
} u;
|
|
||||||
} COFF_ResourceID;
|
|
||||||
|
|
||||||
typedef struct COFF_ParsedResource
|
|
||||||
{
|
|
||||||
COFF_ResourceID type;
|
|
||||||
COFF_ResourceID name;
|
|
||||||
U32 data_version;
|
|
||||||
COFF_ResourceMemoryFlags memory_flags;
|
|
||||||
U16 language_id;
|
|
||||||
U32 version;
|
|
||||||
U32 characteristics;
|
|
||||||
String8 data;
|
|
||||||
} COFF_ParsedResource;
|
|
||||||
|
|
||||||
typedef struct COFF_ParsedResourceNode
|
|
||||||
{
|
|
||||||
struct COFF_ParsedResourceNode *next;
|
|
||||||
COFF_ParsedResource data;
|
|
||||||
} COFF_ParsedResourceNode;
|
|
||||||
|
|
||||||
typedef struct COFF_ParsedResourceList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_ParsedResourceNode *first;
|
|
||||||
COFF_ParsedResourceNode *last;
|
|
||||||
} COFF_ParsedResourceList;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
COFF_DataType_Null,
|
|
||||||
COFF_DataType_Obj,
|
|
||||||
COFF_DataType_BigObj,
|
|
||||||
COFF_DataType_Import
|
|
||||||
} COFF_DataType;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
COFF_Archive_Null,
|
|
||||||
COFF_Archive_Regular,
|
|
||||||
COFF_Archive_Thin
|
|
||||||
} COFF_ArchiveType;
|
|
||||||
|
|
||||||
typedef struct COFF_ParsedArchiveMemberHeader
|
|
||||||
{
|
|
||||||
String8 name; // padded to 16 bytes with spaces
|
|
||||||
COFF_TimeStamp time_stamp;
|
|
||||||
U32 user_id; // unix artifact that does not have meaning on windows
|
|
||||||
U32 group_id; // unix artifact that does not have meaning on windows
|
|
||||||
String8 mode; // octal representation the members file mode
|
|
||||||
B32 is_end_correct; // set to true if found correct signature after header
|
|
||||||
Rng1U64 data_range;
|
|
||||||
} COFF_ParsedArchiveMemberHeader;
|
|
||||||
|
|
||||||
typedef struct COFF_ParsedArchiveImportHeader
|
|
||||||
{
|
|
||||||
B32 is_sig_correct;
|
|
||||||
U16 version;
|
|
||||||
COFF_MachineType machine;
|
|
||||||
COFF_TimeStamp time_stamp;
|
|
||||||
U32 data_size;
|
|
||||||
U16 hint_or_ordinal;
|
|
||||||
COFF_ImportType type;
|
|
||||||
COFF_ImportByType import_by;
|
|
||||||
String8 func_name;
|
|
||||||
String8 dll_name;
|
|
||||||
} COFF_ParsedArchiveImportHeader;
|
|
||||||
|
|
||||||
typedef struct COFF_ArchiveMember
|
|
||||||
{
|
|
||||||
COFF_ParsedArchiveMemberHeader header;
|
|
||||||
U64 offset;
|
|
||||||
String8 data;
|
|
||||||
} COFF_ArchiveMember;
|
|
||||||
|
|
||||||
typedef struct COFF_ArchiveFirstMember
|
|
||||||
{
|
|
||||||
U32 symbol_count;
|
|
||||||
U64 member_offset_count;
|
|
||||||
U32 *member_offsets;
|
|
||||||
String8 string_table;
|
|
||||||
} COFF_ArchiveFirstMember;
|
|
||||||
|
|
||||||
typedef struct COFF_ArchiveSecondMember
|
|
||||||
{
|
|
||||||
U32 member_count;
|
|
||||||
U32 symbol_count;
|
|
||||||
U64 member_offset_count;
|
|
||||||
U32 *member_offsets;
|
|
||||||
U64 symbol_index_count;
|
|
||||||
U16 *symbol_indices;
|
|
||||||
String8 string_table;
|
|
||||||
} COFF_ArchiveSecondMember;
|
|
||||||
|
|
||||||
typedef struct COFF_ArchiveMemberNode
|
|
||||||
{
|
|
||||||
struct COFF_ArchiveMemberNode *next;
|
|
||||||
COFF_ArchiveMember data;
|
|
||||||
} COFF_ArchiveMemberNode;
|
|
||||||
|
|
||||||
typedef struct COFF_ArchiveMemberList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_ArchiveMemberNode *first;
|
|
||||||
COFF_ArchiveMemberNode *last;
|
|
||||||
} COFF_ArchiveMemberList;
|
|
||||||
|
|
||||||
typedef struct COFF_ArchiveParse
|
|
||||||
{
|
|
||||||
B32 has_second_header;
|
|
||||||
B32 has_long_names;
|
|
||||||
COFF_ArchiveFirstMember first_member;
|
|
||||||
COFF_ArchiveSecondMember second_member;
|
|
||||||
String8 long_names;
|
|
||||||
String8 error;
|
|
||||||
} COFF_ArchiveParse;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Obj Header
|
|
||||||
|
|
||||||
internal B32 coff_is_big_obj(String8 raw_coff);
|
|
||||||
internal B32 coff_is_obj (String8 raw_coff);
|
|
||||||
internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Section
|
|
||||||
|
|
||||||
internal COFF_SectionHeader ** coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Symbol
|
|
||||||
|
|
||||||
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
|
|
||||||
internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16);
|
|
||||||
internal COFF_ParsedSymbol coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
|
|
||||||
|
|
||||||
internal COFF_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 (Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size);
|
|
||||||
|
|
||||||
internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol);
|
|
||||||
|
|
||||||
internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class);
|
|
||||||
internal COFF_SymbolValueInterpType coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol);
|
|
||||||
internal B32 coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol);
|
|
||||||
|
|
||||||
internal void coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out);
|
|
||||||
internal COFF_SymbolWeakExt * coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Reloc
|
|
||||||
|
|
||||||
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Resource
|
|
||||||
|
|
||||||
internal String8 coff_resource_string_from_str16 (Arena *arena, String16 string);
|
|
||||||
internal String8 coff_resource_string_from_str8 (Arena *arena, String8 string);
|
|
||||||
internal String8 coff_resource_number_from_u16 (Arena *arena, U16 number);
|
|
||||||
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16);
|
|
||||||
|
|
||||||
internal U64 coff_read_resource_id_utf16 (String8 raw_res, U64 off, COFF_ResourceID16 *id_out);
|
|
||||||
internal U64 coff_read_resource (Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out);
|
|
||||||
internal COFF_ParsedResourceList coff_resource_list_from_data(Arena *arena, String8 data);
|
|
||||||
|
|
||||||
internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
|
|
||||||
internal String8 coff_write_resource (Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
|
|
||||||
|
|
||||||
internal int coff_resource_id_compar(void *raw_a, void *raw_b); // COFF_ResourceID
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Archive
|
|
||||||
|
|
||||||
internal B32 coff_is_import (String8 raw_archive_member);
|
|
||||||
internal COFF_DataType coff_data_type_from_data (String8 raw_archive_member);
|
|
||||||
internal B32 coff_is_regular_archive (String8 raw_archive);
|
|
||||||
internal B32 coff_is_thin_archive (String8 raw_archive);
|
|
||||||
internal COFF_ArchiveType coff_archive_type_from_data(String8 raw_archive);
|
|
||||||
|
|
||||||
internal U64 coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out);
|
|
||||||
internal COFF_ArchiveFirstMember coff_parse_first_archive_member (COFF_ArchiveMember *member);
|
|
||||||
internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member);
|
|
||||||
internal String8 coff_decode_raw_member_name (String8 long_names, String8 name);
|
|
||||||
internal String8 coff_decode_member_name (String8 long_names, String8 name);
|
|
||||||
internal U64 coff_parse_import (String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out);
|
|
||||||
|
|
||||||
internal COFF_ArchiveMember coff_archive_member_from_offset(String8 raw_archive, U64 offset);
|
|
||||||
internal COFF_ArchiveMember coff_archive_member_from_data (String8 raw_archive_member);
|
|
||||||
internal COFF_ParsedArchiveImportHeader coff_archive_import_from_data (String8 raw_archive_member);
|
|
||||||
|
|
||||||
internal U64 coff_regular_archive_member_iter_init(String8 raw_archive);
|
|
||||||
internal B32 coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
|
|
||||||
|
|
||||||
internal U64 coff_thin_archive_member_iter_init(String8 raw_archive);
|
|
||||||
internal B32 coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
|
|
||||||
|
|
||||||
internal COFF_ArchiveParse coff_regular_archive_parse_from_member_list(COFF_ArchiveMemberList list);
|
|
||||||
internal COFF_ArchiveParse coff_thin_archive_parse_from_data (String8 raw_archive);
|
|
||||||
internal COFF_ArchiveParse coff_regular_archive_parse_from_data (String8 raw_archive);
|
|
||||||
internal COFF_ArchiveParse coff_archive_parse_from_data (String8 raw_archive);
|
|
||||||
|
|
||||||
#endif // COFF_PARSE_H
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal CFG_KeyMap *
|
|
||||||
cfg_key_map_from_cfg(Arena *arena)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
CFG_KeyMap *key_map = push_array(arena, CFG_KeyMap, 1);
|
|
||||||
{
|
|
||||||
key_map->name_slots_count = 4096;
|
|
||||||
key_map->name_slots = push_array(arena, CFG_KeyMapSlot, key_map->name_slots_count);
|
|
||||||
key_map->binding_slots_count = 4096;
|
|
||||||
key_map->binding_slots = push_array(arena, CFG_KeyMapSlot, key_map->binding_slots_count);
|
|
||||||
|
|
||||||
//- rjf: gather & parse all explicitly stored keybinding sets
|
|
||||||
CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings"));
|
|
||||||
for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
CFG_Node *keybindings_root = n->v;
|
|
||||||
for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next)
|
|
||||||
{
|
|
||||||
String8 name = {0};
|
|
||||||
CFG_Binding binding = {0};
|
|
||||||
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
|
|
||||||
{
|
|
||||||
if(0){}
|
|
||||||
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
|
|
||||||
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
|
|
||||||
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OS_Key key = OS_Key_Null;
|
|
||||||
for EachEnumVal(OS_Key, k)
|
|
||||||
{
|
|
||||||
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
|
|
||||||
{
|
|
||||||
key = k;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(key != OS_Key_Null)
|
|
||||||
{
|
|
||||||
binding.key = key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = child->string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(name.size != 0)
|
|
||||||
{
|
|
||||||
U64 name_hash = d_hash_from_string(name);
|
|
||||||
U64 binding_hash = d_hash_from_string(str8_struct(&binding));
|
|
||||||
U64 name_slot_idx = name_hash%key_map->name_slots_count;
|
|
||||||
U64 binding_slot_idx = binding_hash%key_map->binding_slots_count;
|
|
||||||
CFG_KeyMapNode *n = push_array(arena, CFG_KeyMapNode, 1);
|
|
||||||
n->cfg_id = keybinding->id;
|
|
||||||
n->name = push_str8_copy(arena, name);
|
|
||||||
n->binding = binding;
|
|
||||||
SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next);
|
|
||||||
SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
return key_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_KeyMapNodePtrList
|
|
||||||
cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string)
|
|
||||||
{
|
|
||||||
CFG_KeyMapNodePtrList list = {0};
|
|
||||||
{
|
|
||||||
U64 hash = d_hash_from_string(string);
|
|
||||||
U64 slot_idx = hash%key_map->name_slots_count;
|
|
||||||
for(CFG_KeyMapNode *n = key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->name, string, 0))
|
|
||||||
{
|
|
||||||
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
|
|
||||||
ptr->v = n;
|
|
||||||
SLLQueuePush(list.first, list.last, ptr);
|
|
||||||
list.count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_KeyMapNodePtrList
|
|
||||||
cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding)
|
|
||||||
{
|
|
||||||
CFG_KeyMapNodePtrList list = {0};
|
|
||||||
{
|
|
||||||
U64 hash = d_hash_from_string(str8_struct(&binding));
|
|
||||||
U64 slot_idx = hash%key_map->binding_slots_count;
|
|
||||||
for(CFG_KeyMapNode *n = key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next)
|
|
||||||
{
|
|
||||||
if(MemoryMatchStruct(&binding, &n->binding))
|
|
||||||
{
|
|
||||||
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
|
|
||||||
ptr->v = n;
|
|
||||||
SLLQueuePush(list.first, list.last, ptr);
|
|
||||||
list.count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CONFIG_BINDINGS_H
|
|
||||||
#define CONFIG_BINDINGS_H
|
|
||||||
|
|
||||||
typedef struct CFG_Binding CFG_Binding;
|
|
||||||
struct CFG_Binding
|
|
||||||
{
|
|
||||||
OS_Key key;
|
|
||||||
OS_Modifiers modifiers;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
|
|
||||||
struct CFG_KeyMapNode
|
|
||||||
{
|
|
||||||
CFG_KeyMapNode *name_hash_next;
|
|
||||||
CFG_KeyMapNode *binding_hash_next;
|
|
||||||
CFG_ID cfg_id;
|
|
||||||
String8 name;
|
|
||||||
CFG_Binding binding;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_KeyMapNodePtr CFG_KeyMapNodePtr;
|
|
||||||
struct CFG_KeyMapNodePtr
|
|
||||||
{
|
|
||||||
CFG_KeyMapNodePtr *next;
|
|
||||||
CFG_KeyMapNode *v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_KeyMapNodePtrList CFG_KeyMapNodePtrList;
|
|
||||||
struct CFG_KeyMapNodePtrList
|
|
||||||
{
|
|
||||||
CFG_KeyMapNodePtr *first;
|
|
||||||
CFG_KeyMapNodePtr *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_KeyMapSlot CFG_KeyMapSlot;
|
|
||||||
struct CFG_KeyMapSlot
|
|
||||||
{
|
|
||||||
CFG_KeyMapNode *first;
|
|
||||||
CFG_KeyMapNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_KeyMap CFG_KeyMap;
|
|
||||||
struct CFG_KeyMap
|
|
||||||
{
|
|
||||||
U64 name_slots_count;
|
|
||||||
CFG_KeyMapSlot *name_slots;
|
|
||||||
U64 binding_slots_count;
|
|
||||||
CFG_KeyMapSlot *binding_slots;
|
|
||||||
};
|
|
||||||
|
|
||||||
internal CFG_KeyMap *cfg_key_map_from_cfg(Arena *arena);
|
|
||||||
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string);
|
|
||||||
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding);
|
|
||||||
|
|
||||||
#endif // CONFIG_BINDINGS_H
|
|
||||||
@@ -1,896 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: ID Functions
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id)
|
|
||||||
{
|
|
||||||
CFG_IDNode *n = push_array(arena, CFG_IDNode, 1);
|
|
||||||
SLLQueuePush(list->first, list->last, n);
|
|
||||||
list->count += 1;
|
|
||||||
n->v = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_IDList
|
|
||||||
cfg_id_list_copy(Arena *arena, CFG_IDList *src)
|
|
||||||
{
|
|
||||||
CFG_IDList dst = {0};
|
|
||||||
for EachNode(n, CFG_IDNode, src->first)
|
|
||||||
{
|
|
||||||
cfg_id_list_push(arena, &dst, n->v);
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Node Pointer Data Structure Functions
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
|
|
||||||
{
|
|
||||||
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
|
|
||||||
DLLPushBack(list->first, list->last, n);
|
|
||||||
list->count += 1;
|
|
||||||
n->v = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
|
|
||||||
{
|
|
||||||
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
|
|
||||||
DLLPushFront(list->first, list->last, n);
|
|
||||||
list->count += 1;
|
|
||||||
n->v = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_NodePtrArray
|
|
||||||
cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list)
|
|
||||||
{
|
|
||||||
CFG_NodePtrArray array = {0};
|
|
||||||
array.count = list->count;
|
|
||||||
array.v = push_array_no_zero(arena, CFG_Node *, array.count);
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, CFG_NodePtrNode, list->first)
|
|
||||||
{
|
|
||||||
array.v[idx] = n->v;
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Schema Data Structure Functions
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema)
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(name);
|
|
||||||
U64 slot_idx = hash%table->slots_count;
|
|
||||||
CFG_SchemaNode *node = 0;
|
|
||||||
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->name, name, 0))
|
|
||||||
{
|
|
||||||
node = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(node == 0)
|
|
||||||
{
|
|
||||||
node = push_array(arena, CFG_SchemaNode, 1);
|
|
||||||
node->name = str8_copy(arena, name);
|
|
||||||
node->schema = schema;
|
|
||||||
SLLStackPush(table->slots[slot_idx], node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal MD_Node *
|
|
||||||
cfg_schema_from_name(CFG_SchemaTable *table, String8 name)
|
|
||||||
{
|
|
||||||
MD_Node *result = &md_nil_node;
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(name);
|
|
||||||
U64 slot_idx = hash%table->slots_count;
|
|
||||||
CFG_SchemaNode *node = 0;
|
|
||||||
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->name, name, 0))
|
|
||||||
{
|
|
||||||
result = n->schema;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal MD_NodePtrList
|
|
||||||
cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name)
|
|
||||||
{
|
|
||||||
MD_NodePtrList result = {0};
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List tasks = {0};
|
|
||||||
String8Node seed_task = {0, name};
|
|
||||||
str8_list_push_node(&tasks, &seed_task);
|
|
||||||
for EachNode(task, String8Node, tasks.first)
|
|
||||||
{
|
|
||||||
MD_Node *schema = cfg_schema_from_name(table, task->string);
|
|
||||||
if(!md_node_is_nil(schema))
|
|
||||||
{
|
|
||||||
md_node_ptr_list_push_front(arena, &result, schema);
|
|
||||||
for MD_EachNode(tag, schema->first_tag)
|
|
||||||
{
|
|
||||||
if(str8_match(tag->string, str8_lit("inherit"), 0))
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &tasks, tag->first->string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Config Reading Functions
|
|
||||||
|
|
||||||
//- rjf: context selection
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_ctx_select(CFG_Ctx *ctx)
|
|
||||||
{
|
|
||||||
cfg_ctx = ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: tree navigations
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
cfg_change_gen(void)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
if(cfg_ctx != 0)
|
|
||||||
{
|
|
||||||
result = cfg_ctx->change_gen;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_root(void)
|
|
||||||
{
|
|
||||||
CFG_Node *result = &cfg_nil_node;
|
|
||||||
if(cfg_ctx != 0)
|
|
||||||
{
|
|
||||||
result = cfg_ctx->root;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_from_id(CFG_ID id)
|
|
||||||
{
|
|
||||||
CFG_Node *result = &cfg_nil_node;
|
|
||||||
if(id != 0 &&
|
|
||||||
id == cfg_ctx->last_accessed_id &&
|
|
||||||
id == cfg_ctx->last_accessed->id)
|
|
||||||
{
|
|
||||||
result = cfg_ctx->last_accessed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(str8_struct(&id));
|
|
||||||
U64 slot_idx = hash%cfg_ctx->id_slots_count;
|
|
||||||
for(CFG_NodePtrNode *n = cfg_ctx->id_slots[slot_idx].first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(n->v->id == id)
|
|
||||||
{
|
|
||||||
result = n->v;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cfg_ctx->last_accessed_id = id;
|
|
||||||
cfg_ctx->last_accessed = result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_child_from_string(CFG_Node *parent, String8 string)
|
|
||||||
{
|
|
||||||
CFG_Node *child = &cfg_nil_node;
|
|
||||||
if(string.size != 0)
|
|
||||||
{
|
|
||||||
for(CFG_Node *c = parent->first; c != &cfg_nil_node; c = c->next)
|
|
||||||
{
|
|
||||||
if(str8_match(c->string, string, 0))
|
|
||||||
{
|
|
||||||
child = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string)
|
|
||||||
{
|
|
||||||
CFG_Node *result = cfg_node_child_from_string(parent, string);
|
|
||||||
if(result == &cfg_nil_node)
|
|
||||||
{
|
|
||||||
result = parent;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_NodePtrList
|
|
||||||
cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string)
|
|
||||||
{
|
|
||||||
CFG_NodePtrList result = {0};
|
|
||||||
for(CFG_Node *child = parent->first; child != &cfg_nil_node; child = child->next)
|
|
||||||
{
|
|
||||||
if(str8_match(child->string, string, 0))
|
|
||||||
{
|
|
||||||
cfg_node_ptr_list_push(arena, &result, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_NodePtrList
|
|
||||||
cfg_node_top_level_list_from_string(Arena *arena, String8 string)
|
|
||||||
{
|
|
||||||
CFG_NodePtrList result = {0};
|
|
||||||
for(CFG_Node *bucket = cfg_ctx->root->first; bucket != &cfg_nil_node; bucket = bucket->next)
|
|
||||||
{
|
|
||||||
for(CFG_Node *tln = bucket->first; tln != &cfg_nil_node; tln = tln->next)
|
|
||||||
{
|
|
||||||
if(str8_match(tln->string, string, 0))
|
|
||||||
{
|
|
||||||
cfg_node_ptr_list_push(arena, &result, tln);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_NodeRec
|
|
||||||
cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node)
|
|
||||||
{
|
|
||||||
CFG_NodeRec rec = {&cfg_nil_node};
|
|
||||||
if(node->first != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
rec.next = node->first;
|
|
||||||
rec.push_count = 1;
|
|
||||||
}
|
|
||||||
else for(CFG_Node *p = node; p != root; p = p->parent, rec.pop_count += 1)
|
|
||||||
{
|
|
||||||
if(p->next != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
rec.next = p->next;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: serialization
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List strings = {0};
|
|
||||||
{
|
|
||||||
typedef struct NestTask NestTask;
|
|
||||||
struct NestTask
|
|
||||||
{
|
|
||||||
NestTask *next;
|
|
||||||
CFG_Node *cfg;
|
|
||||||
MD_Node *schema;
|
|
||||||
B32 is_simple;
|
|
||||||
};
|
|
||||||
NestTask *top_nest_task = 0;
|
|
||||||
CFG_NodeRec rec = {0};
|
|
||||||
for(CFG_Node *c = root; c != &cfg_nil_node; c = rec.next)
|
|
||||||
{
|
|
||||||
// rjf: look up parent's schemas
|
|
||||||
MD_NodePtrList schemas = {0};
|
|
||||||
if(top_nest_task != 0)
|
|
||||||
{
|
|
||||||
CFG_Node *parent = top_nest_task->cfg;
|
|
||||||
schemas = cfg_schemas_from_name(scratch.arena, schema_table, parent->string);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: look up child schema
|
|
||||||
MD_Node *c_schema = &md_nil_node;
|
|
||||||
for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next)
|
|
||||||
{
|
|
||||||
c_schema = md_child_from_string(n->v, c->string, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push name of this node
|
|
||||||
if(c->string.size != 0 || c->first == &cfg_nil_node)
|
|
||||||
{
|
|
||||||
// rjf: extract the textualized form for this string (we may need to escape / relativize)
|
|
||||||
String8 c_serialized_string = c->string;
|
|
||||||
{
|
|
||||||
MD_Node *c_schema = &md_nil_node;
|
|
||||||
if(top_nest_task != 0)
|
|
||||||
{
|
|
||||||
c_schema = top_nest_task->schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: paths -> relativize
|
|
||||||
if(!md_node_has_tag(c_schema->first, str8_lit("no_relativize"), 0))
|
|
||||||
{
|
|
||||||
if(str8_match(c_schema->first->string, str8_lit("path"), 0))
|
|
||||||
{
|
|
||||||
String8 path_absolute = c->string;
|
|
||||||
String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path);
|
|
||||||
c_serialized_string = path_relative;
|
|
||||||
}
|
|
||||||
else if(str8_match(c_schema->first->string, str8_lit("path_pt"), 0))
|
|
||||||
{
|
|
||||||
String8 value = c->string;
|
|
||||||
String8TxtPtPair parts = str8_txt_pt_pair_from_string(value);
|
|
||||||
String8 path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, parts.string, root_path);
|
|
||||||
c_serialized_string = push_str8f(arena, "%S:%I64d:%I64d", path_relative, parts.pt.line, parts.pt.column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: all strings -> escape
|
|
||||||
c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: generate all strings for this node's string
|
|
||||||
String8List c_name_strings = {0};
|
|
||||||
{
|
|
||||||
B32 name_can_be_pushed_standalone = 0;
|
|
||||||
{
|
|
||||||
Temp temp = temp_begin(scratch.arena);
|
|
||||||
MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string);
|
|
||||||
name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier|
|
|
||||||
MD_TokenFlag_Numeric|
|
|
||||||
MD_TokenFlag_StringLiteral|
|
|
||||||
MD_TokenFlag_Symbol));
|
|
||||||
temp_end(temp);
|
|
||||||
}
|
|
||||||
if(name_can_be_pushed_standalone)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
|
|
||||||
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
|
|
||||||
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: if we're in a simple nesting task, then just break children by space
|
|
||||||
if(top_nest_task != 0 && top_nest_task->is_simple)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &strings, str8_lit(" "));
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: join c's strings with main string list
|
|
||||||
str8_list_concat_in_place(&strings, &c_name_strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: grab next recursion
|
|
||||||
rec = cfg_node_rec__depth_first(root, c);
|
|
||||||
|
|
||||||
// rjf: push a new nesting task before descending to children
|
|
||||||
if(c->first != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
B32 is_simple_children_list = 1;
|
|
||||||
for(CFG_Node *child = c->first; child != &cfg_nil_node; child = child->next)
|
|
||||||
{
|
|
||||||
if(child->first != &cfg_nil_node && child != c->last)
|
|
||||||
{
|
|
||||||
is_simple_children_list = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestTask *task = push_array(scratch.arena, NestTask, 1);
|
|
||||||
task->cfg = c;
|
|
||||||
task->schema = c_schema;
|
|
||||||
task->is_simple = is_simple_children_list;
|
|
||||||
SLLStackPush(top_nest_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: tree navigations -> encode hierarchy
|
|
||||||
if(rec.push_count > 0)
|
|
||||||
{
|
|
||||||
if(top_nest_task->is_simple && c->string.size != 0)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &strings, str8_lit(":"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(c->string.size != 0)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &strings, str8_lit(":\n"));
|
|
||||||
}
|
|
||||||
str8_list_push(scratch.arena, &strings, str8_lit("{"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task))
|
|
||||||
{
|
|
||||||
if(top_nest_task->is_simple)
|
|
||||||
{
|
|
||||||
if(top_nest_task->cfg->string.size == 0)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &strings, str8_lit(" }"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &strings, str8_lit("\n}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!top_nest_task || top_nest_task->is_simple == 0)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &strings, str8_lit("\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String8 result_unindented = str8_list_join(scratch.arena, &strings, 0);
|
|
||||||
String8 result = indented_from_string(arena, result_unindented);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Config Writing Functions
|
|
||||||
|
|
||||||
//- rjf: state creation / destroying
|
|
||||||
|
|
||||||
internal CFG_State *
|
|
||||||
cfg_state_alloc(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
CFG_State *state = push_array(arena, CFG_State, 1);
|
|
||||||
state->arena = arena;
|
|
||||||
state->ctx.id_slots_count = 4096;
|
|
||||||
state->ctx.id_slots = push_array(arena, CFG_NodePtrSlot, state->ctx.id_slots_count);
|
|
||||||
state->ctx.root = cfg_node_alloc(state);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_state_release(CFG_State *state)
|
|
||||||
{
|
|
||||||
arena_release(state->arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: state -> ctx
|
|
||||||
|
|
||||||
internal CFG_Ctx *
|
|
||||||
cfg_state_ctx(CFG_State *state)
|
|
||||||
{
|
|
||||||
CFG_Ctx *ctx = &state->ctx;
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: string allocations
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
cfg_string_bucket_num_from_size(U64 size)
|
|
||||||
{
|
|
||||||
U64 bucket_num = 0;
|
|
||||||
if(size > 0)
|
|
||||||
{
|
|
||||||
for EachElement(idx, cfg_string_bucket_chunk_sizes)
|
|
||||||
{
|
|
||||||
if(size <= cfg_string_bucket_chunk_sizes[idx])
|
|
||||||
{
|
|
||||||
bucket_num = idx+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bucket_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cfg_string_alloc(CFG_State *state, String8 string)
|
|
||||||
{
|
|
||||||
//- rjf: allocate node
|
|
||||||
CFG_StringChunkNode *node = 0;
|
|
||||||
{
|
|
||||||
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
|
|
||||||
if(bucket_num == ArrayCount(cfg_string_bucket_chunk_sizes))
|
|
||||||
{
|
|
||||||
CFG_StringChunkNode *best_node = 0;
|
|
||||||
CFG_StringChunkNode *best_node_prev = 0;
|
|
||||||
U64 best_node_size = max_U64;
|
|
||||||
{
|
|
||||||
for(CFG_StringChunkNode *n = state->free_string_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next))
|
|
||||||
{
|
|
||||||
if(n->size >= string.size && n->size < best_node_size)
|
|
||||||
{
|
|
||||||
best_node = n;
|
|
||||||
best_node_prev = prev;
|
|
||||||
best_node_size = n->size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(best_node != 0)
|
|
||||||
{
|
|
||||||
node = best_node;
|
|
||||||
if(best_node_prev)
|
|
||||||
{
|
|
||||||
best_node_prev->next = best_node->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state->free_string_chunks[bucket_num-1] = best_node->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
U64 chunk_size = u64_up_to_pow2(string.size);
|
|
||||||
node = (CFG_StringChunkNode *)push_array(state->arena, U8, chunk_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(bucket_num != 0)
|
|
||||||
{
|
|
||||||
node = state->free_string_chunks[bucket_num-1];
|
|
||||||
if(node != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(state->free_string_chunks[bucket_num-1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = (CFG_StringChunkNode *)push_array(state->arena, U8, cfg_string_bucket_chunk_sizes[bucket_num-1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: fill node
|
|
||||||
String8 result = {0};
|
|
||||||
if(node != 0)
|
|
||||||
{
|
|
||||||
result.str = (U8 *)node;
|
|
||||||
result.size = string.size;
|
|
||||||
MemoryCopy(result.str, string.str, result.size);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_string_release(CFG_State *state, String8 string)
|
|
||||||
{
|
|
||||||
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
|
|
||||||
if(1 <= bucket_num && bucket_num <= ArrayCount(cfg_string_bucket_chunk_sizes))
|
|
||||||
{
|
|
||||||
U64 bucket_idx = bucket_num-1;
|
|
||||||
CFG_StringChunkNode *node = (CFG_StringChunkNode *)string.str;
|
|
||||||
SLLStackPush(state->free_string_chunks[bucket_idx], node);
|
|
||||||
node->size = u64_up_to_pow2(string.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: tree building
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_alloc(CFG_State *state)
|
|
||||||
{
|
|
||||||
state->ctx.change_gen += 1;
|
|
||||||
|
|
||||||
// rjf: allocate
|
|
||||||
CFG_Node *result = state->free;
|
|
||||||
{
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
SLLStackPop(state->free);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = push_array_no_zero(state->arena, CFG_Node, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: generate ID & fill
|
|
||||||
state->id_gen += 1;
|
|
||||||
MemoryZeroStruct(result);
|
|
||||||
result->first = result->last = result->next = result->prev = result->parent = &cfg_nil_node;
|
|
||||||
result->id = state->id_gen;
|
|
||||||
|
|
||||||
// rjf: store to ID -> cfg map
|
|
||||||
{
|
|
||||||
CFG_NodePtrNode *cfg_id_node = state->free_id_node;
|
|
||||||
if(cfg_id_node != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(state->free_id_node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cfg_id_node = push_array(state->arena, CFG_NodePtrNode, 1);
|
|
||||||
}
|
|
||||||
U64 hash = u64_hash_from_str8(str8_struct(&result->id));
|
|
||||||
U64 slot_idx = hash%state->ctx.id_slots_count;
|
|
||||||
DLLPushBack(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, cfg_id_node);
|
|
||||||
cfg_id_node->v = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_release(CFG_State *state, CFG_Node *node)
|
|
||||||
{
|
|
||||||
state->ctx.change_gen += 1;
|
|
||||||
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
// rjf: unhook from context
|
|
||||||
cfg_node_unhook(state, node->parent, node);
|
|
||||||
|
|
||||||
// rjf: gather root & all descendants
|
|
||||||
CFG_NodePtrList nodes = {0};
|
|
||||||
for(CFG_Node *c = node; c != &cfg_nil_node; c = cfg_node_rec__depth_first(node, c).next)
|
|
||||||
{
|
|
||||||
cfg_node_ptr_list_push(scratch.arena, &nodes, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: release all nodes
|
|
||||||
for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
CFG_Node *c = n->v;
|
|
||||||
cfg_string_release(state, c->string);
|
|
||||||
SLLStackPush(state->free, c);
|
|
||||||
c->first = c->last = c->prev = c->parent = 0;
|
|
||||||
c->id = 0;
|
|
||||||
c->string = str8_zero();
|
|
||||||
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
|
|
||||||
U64 slot_idx = hash%state->ctx.id_slots_count;
|
|
||||||
for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(n->v == c)
|
|
||||||
{
|
|
||||||
DLLRemove(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, n);
|
|
||||||
SLLStackPush(state->free_id_node, n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_release_all_children(CFG_State *state, CFG_Node *node)
|
|
||||||
{
|
|
||||||
for(CFG_Node *child = node->first, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
|
|
||||||
{
|
|
||||||
next = child->next;
|
|
||||||
cfg_node_release(state, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string)
|
|
||||||
{
|
|
||||||
CFG_Node *node = cfg_node_alloc(state);
|
|
||||||
cfg_node_insert_child(state, parent, parent->last, node);
|
|
||||||
cfg_node_equip_string(state, node, string);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
CFG_Node *result = cfg_node_new(state, parent, string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
string = push_str8_copy(scratch.arena, string);
|
|
||||||
for(CFG_Node *child = parent->first->next, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
|
|
||||||
{
|
|
||||||
next = child->next;
|
|
||||||
cfg_node_release(state, child);
|
|
||||||
}
|
|
||||||
if(parent->first == &cfg_nil_node)
|
|
||||||
{
|
|
||||||
cfg_node_new(state, parent, str8_zero());
|
|
||||||
}
|
|
||||||
CFG_Node *child = parent->first;
|
|
||||||
cfg_node_equip_string(state, child, string);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
CFG_Node *result = cfg_node_new_replace(state, parent, string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root)
|
|
||||||
{
|
|
||||||
CFG_NodeRec rec = {0};
|
|
||||||
CFG_Node *dst_root = &cfg_nil_node;
|
|
||||||
CFG_Node *dst_parent = &cfg_nil_node;
|
|
||||||
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
|
|
||||||
{
|
|
||||||
CFG_Node *dst = cfg_node_new(state, dst_parent, src->string);
|
|
||||||
if(dst_root == &cfg_nil_node)
|
|
||||||
{
|
|
||||||
dst_root = dst;
|
|
||||||
}
|
|
||||||
rec = cfg_node_rec__depth_first(src_root, src);
|
|
||||||
if(rec.push_count > 0)
|
|
||||||
{
|
|
||||||
dst_parent = dst;
|
|
||||||
}
|
|
||||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
|
||||||
{
|
|
||||||
dst_parent = dst_parent->parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dst_root;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string)
|
|
||||||
{
|
|
||||||
cfg_string_release(state, node->string);
|
|
||||||
node->string = cfg_string_alloc(state, string);
|
|
||||||
state->ctx.change_gen += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
cfg_node_equip_string(state, node, string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child)
|
|
||||||
{
|
|
||||||
if(parent != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
if(new_child->parent != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
cfg_node_unhook(state, new_child->parent, new_child);
|
|
||||||
}
|
|
||||||
DLLInsert_NPZ(&cfg_nil_node, parent->first, parent->last, prev_child, new_child, next, prev);
|
|
||||||
new_child->parent = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child)
|
|
||||||
{
|
|
||||||
if(child != &cfg_nil_node && parent == child->parent && parent != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
DLLRemove_NPZ(&cfg_nil_node, parent->first, parent->last, child, next, prev);
|
|
||||||
child->parent = &cfg_nil_node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string)
|
|
||||||
{
|
|
||||||
CFG_Node *node = cfg_node_child_from_string(parent, string);
|
|
||||||
if(node == &cfg_nil_node)
|
|
||||||
{
|
|
||||||
node = cfg_node_new(state, parent, string);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: deserialization
|
|
||||||
|
|
||||||
internal CFG_NodePtrList
|
|
||||||
cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string)
|
|
||||||
{
|
|
||||||
CFG_NodePtrList result = {0};
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
//- rjf: parse the string as metadesk
|
|
||||||
MD_Node *root = md_tree_from_string(scratch.arena, string);
|
|
||||||
|
|
||||||
//- rjf: iterate the top-level metadesk trees, generate new cfg trees for each
|
|
||||||
for MD_EachNode(tln, root->first)
|
|
||||||
{
|
|
||||||
CFG_Node *dst_root_n = &cfg_nil_node;
|
|
||||||
CFG_Node *dst_active_parent_n = &cfg_nil_node;
|
|
||||||
MD_NodeRec rec = {0};
|
|
||||||
for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next)
|
|
||||||
{
|
|
||||||
// rjf: lookup schema for this string
|
|
||||||
MD_Node *schema = &md_nil_node;
|
|
||||||
{
|
|
||||||
MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, schema_table, dst_active_parent_n->parent->string);
|
|
||||||
for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next)
|
|
||||||
{
|
|
||||||
schema = md_child_from_string(n->v, dst_active_parent_n->string, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: extract & transform metadesk node's string (it is raw textual data, so we need to
|
|
||||||
// go escaped -> raw, and derelativize paths)
|
|
||||||
String8 dst_n_string = {0};
|
|
||||||
{
|
|
||||||
String8 src_n_string = src_n->string;
|
|
||||||
String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string);
|
|
||||||
if(!md_node_has_tag(schema->first, str8_lit("no_relativize"), 0))
|
|
||||||
{
|
|
||||||
if(str8_match(schema->first->string, str8_lit("path"), 0))
|
|
||||||
{
|
|
||||||
src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path);
|
|
||||||
}
|
|
||||||
else if(str8_match(schema->first->string, str8_lit("path_pt"), 0))
|
|
||||||
{
|
|
||||||
String8TxtPtPair parts = str8_txt_pt_pair_from_string(src_n_string__raw);
|
|
||||||
src_n_string__raw = push_str8f(scratch.arena, "%S:%I64d:%I64d", path_absolute_dst_from_relative_dst_src(scratch.arena, parts.string, root_path), parts.pt.line, parts.pt.column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dst_n_string = src_n_string__raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: allocate, fill, & insert new cfg for this metadesk node
|
|
||||||
CFG_Node *dst_n = cfg_node_alloc(state);
|
|
||||||
cfg_node_equip_string(state, dst_n, dst_n_string);
|
|
||||||
if(dst_active_parent_n != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
cfg_node_insert_child(state, dst_active_parent_n, dst_active_parent_n->last, dst_n);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: recurse
|
|
||||||
rec = md_node_rec_depth_first_pre(src_n, tln);
|
|
||||||
if(dst_active_parent_n == &cfg_nil_node)
|
|
||||||
{
|
|
||||||
dst_root_n = dst_n;
|
|
||||||
}
|
|
||||||
if(rec.push_count > 0)
|
|
||||||
{
|
|
||||||
dst_active_parent_n = dst_n;
|
|
||||||
}
|
|
||||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
|
||||||
{
|
|
||||||
dst_active_parent_n = dst_active_parent_n->parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cfg_node_ptr_list_push(arena, &result, dst_root_n);
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CONFIG_CORE_H
|
|
||||||
#define CONFIG_CORE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: IDs
|
|
||||||
|
|
||||||
typedef U64 CFG_ID;
|
|
||||||
|
|
||||||
typedef struct CFG_IDNode CFG_IDNode;
|
|
||||||
struct CFG_IDNode
|
|
||||||
{
|
|
||||||
CFG_IDNode *next;
|
|
||||||
CFG_ID v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_IDList CFG_IDList;
|
|
||||||
struct CFG_IDList
|
|
||||||
{
|
|
||||||
CFG_IDNode *first;
|
|
||||||
CFG_IDNode *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Tree Types
|
|
||||||
|
|
||||||
typedef struct CFG_Node CFG_Node;
|
|
||||||
struct CFG_Node
|
|
||||||
{
|
|
||||||
CFG_Node *first;
|
|
||||||
CFG_Node *last;
|
|
||||||
CFG_Node *next;
|
|
||||||
CFG_Node *prev;
|
|
||||||
CFG_Node *parent;
|
|
||||||
CFG_ID id;
|
|
||||||
String8 string;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_NodePtrNode CFG_NodePtrNode;
|
|
||||||
struct CFG_NodePtrNode
|
|
||||||
{
|
|
||||||
CFG_NodePtrNode *next;
|
|
||||||
CFG_NodePtrNode *prev;
|
|
||||||
CFG_Node *v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_NodePtrSlot CFG_NodePtrSlot;
|
|
||||||
struct CFG_NodePtrSlot
|
|
||||||
{
|
|
||||||
CFG_NodePtrNode *first;
|
|
||||||
CFG_NodePtrNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_NodePtrList CFG_NodePtrList;
|
|
||||||
struct CFG_NodePtrList
|
|
||||||
{
|
|
||||||
CFG_NodePtrNode *first;
|
|
||||||
CFG_NodePtrNode *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_NodePtrArray CFG_NodePtrArray;
|
|
||||||
struct CFG_NodePtrArray
|
|
||||||
{
|
|
||||||
CFG_Node **v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_NodeRec CFG_NodeRec;
|
|
||||||
struct CFG_NodeRec
|
|
||||||
{
|
|
||||||
CFG_Node *next;
|
|
||||||
S32 push_count;
|
|
||||||
S32 pop_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: String Allocator
|
|
||||||
|
|
||||||
read_only global U64 cfg_string_bucket_chunk_sizes[] =
|
|
||||||
{
|
|
||||||
16,
|
|
||||||
64,
|
|
||||||
256,
|
|
||||||
1024,
|
|
||||||
4096,
|
|
||||||
16384,
|
|
||||||
65536,
|
|
||||||
0xffffffffffffffffull,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_StringChunkNode CFG_StringChunkNode;
|
|
||||||
struct CFG_StringChunkNode
|
|
||||||
{
|
|
||||||
CFG_StringChunkNode *next;
|
|
||||||
U64 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Config State Bundles
|
|
||||||
|
|
||||||
typedef struct CFG_Ctx CFG_Ctx;
|
|
||||||
struct CFG_Ctx
|
|
||||||
{
|
|
||||||
CFG_Node *root;
|
|
||||||
U64 id_slots_count;
|
|
||||||
CFG_NodePtrSlot *id_slots;
|
|
||||||
U64 change_gen;
|
|
||||||
CFG_ID last_accessed_id;
|
|
||||||
CFG_Node *last_accessed;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_State CFG_State;
|
|
||||||
struct CFG_State
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
CFG_Node *free;
|
|
||||||
CFG_NodePtrNode *free_id_node;
|
|
||||||
CFG_StringChunkNode *free_string_chunks[ArrayCount(cfg_string_bucket_chunk_sizes)];
|
|
||||||
U64 id_gen;
|
|
||||||
CFG_Ctx ctx;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Schema Table
|
|
||||||
|
|
||||||
typedef struct CFG_SchemaNode CFG_SchemaNode;
|
|
||||||
struct CFG_SchemaNode
|
|
||||||
{
|
|
||||||
CFG_SchemaNode *next;
|
|
||||||
String8 name;
|
|
||||||
MD_Node *schema;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_SchemaTable CFG_SchemaTable;
|
|
||||||
struct CFG_SchemaTable
|
|
||||||
{
|
|
||||||
CFG_SchemaNode **slots;
|
|
||||||
U64 slots_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
read_only global CFG_Node cfg_nil_node =
|
|
||||||
{
|
|
||||||
&cfg_nil_node,
|
|
||||||
&cfg_nil_node,
|
|
||||||
&cfg_nil_node,
|
|
||||||
&cfg_nil_node,
|
|
||||||
&cfg_nil_node,
|
|
||||||
};
|
|
||||||
|
|
||||||
thread_static CFG_Ctx *cfg_ctx = 0;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: ID Functions
|
|
||||||
|
|
||||||
internal void cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id);
|
|
||||||
internal CFG_IDList cfg_id_list_copy(Arena *arena, CFG_IDList *src);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Node Pointer Data Structure Functions
|
|
||||||
|
|
||||||
internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
|
|
||||||
internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
|
|
||||||
#define cfg_node_ptr_list_first(list) ((list)->count ? (list)->first->v : &cfg_nil_node)
|
|
||||||
#define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node)
|
|
||||||
internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Schema Data Structure Functions
|
|
||||||
|
|
||||||
internal void cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema);
|
|
||||||
internal MD_Node *cfg_schema_from_name(CFG_SchemaTable *table, String8 name);
|
|
||||||
internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Config Reading Functions
|
|
||||||
|
|
||||||
//- rjf: context selection
|
|
||||||
internal void cfg_ctx_select(CFG_Ctx *ctx);
|
|
||||||
|
|
||||||
//- rjf: tree navigations
|
|
||||||
internal U64 cfg_change_gen(void);
|
|
||||||
internal CFG_Node *cfg_node_root(void);
|
|
||||||
internal CFG_Node *cfg_node_from_id(CFG_ID id);
|
|
||||||
internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string);
|
|
||||||
internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string);
|
|
||||||
internal CFG_NodePtrList cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string);
|
|
||||||
internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, String8 string);
|
|
||||||
internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node);
|
|
||||||
|
|
||||||
//- rjf: serialization
|
|
||||||
internal String8 cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Config Writing Functions
|
|
||||||
|
|
||||||
//- rjf: state creation / destroying
|
|
||||||
internal CFG_State *cfg_state_alloc(void);
|
|
||||||
internal void cfg_state_release(CFG_State *state);
|
|
||||||
|
|
||||||
//- rjf: state -> ctx
|
|
||||||
internal CFG_Ctx *cfg_state_ctx(CFG_State *state);
|
|
||||||
|
|
||||||
//- rjf: string allocations
|
|
||||||
internal U64 cfg_string_bucket_num_from_size(U64 size);
|
|
||||||
internal String8 cfg_string_alloc(CFG_State *state, String8 string);
|
|
||||||
internal void cfg_string_release(CFG_State *state, String8 string);
|
|
||||||
|
|
||||||
//- rjf: tree building
|
|
||||||
internal CFG_Node *cfg_node_alloc(CFG_State *state);
|
|
||||||
internal void cfg_node_release(CFG_State *state, CFG_Node *node);
|
|
||||||
internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node);
|
|
||||||
internal CFG_Node *cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string);
|
|
||||||
internal CFG_Node *cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...);
|
|
||||||
internal CFG_Node *cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string);
|
|
||||||
internal CFG_Node *cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...);
|
|
||||||
internal CFG_Node *cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root);
|
|
||||||
internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string);
|
|
||||||
internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...);
|
|
||||||
internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child);
|
|
||||||
internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child);
|
|
||||||
internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string);
|
|
||||||
|
|
||||||
//- rjf: deserialization
|
|
||||||
internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string);
|
|
||||||
|
|
||||||
#endif // CONFIG_CORE_H
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#include "config_core.c"
|
|
||||||
#include "config_panels.c"
|
|
||||||
#if defined(OS_GFX_H)
|
|
||||||
# include "config_bindings.c"
|
|
||||||
#endif
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CONFIG_INC_H
|
|
||||||
#define CONFIG_INC_H
|
|
||||||
|
|
||||||
#include "config_core.h"
|
|
||||||
#include "config_panels.h"
|
|
||||||
#if defined(OS_GFX_H)
|
|
||||||
# include "config_bindings.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // CONFIG_INC_H
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal CFG_Node *
|
|
||||||
cfg_window_from_cfg(CFG_Node *cfg)
|
|
||||||
{
|
|
||||||
CFG_Node *result = &cfg_nil_node;
|
|
||||||
for(CFG_Node *c = cfg; c != &cfg_nil_node; c = c->parent)
|
|
||||||
{
|
|
||||||
if(c->parent->parent == cfg_node_root() && str8_match(c->string, str8_lit("window"), 0))
|
|
||||||
{
|
|
||||||
result = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_PanelTree
|
|
||||||
cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
CFG_Node *wcfg = cfg_window_from_cfg(cfg_root);
|
|
||||||
CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels"));
|
|
||||||
CFG_PanelNode *dst_root = &cfg_nil_panel_node;
|
|
||||||
CFG_PanelNode *dst_focused = &cfg_nil_panel_node;
|
|
||||||
{
|
|
||||||
Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y;
|
|
||||||
CFG_NodeRec rec = {0};
|
|
||||||
CFG_PanelNode *dst_active_parent = &cfg_nil_panel_node;
|
|
||||||
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
|
|
||||||
{
|
|
||||||
// rjf: build a panel node
|
|
||||||
CFG_PanelNode *dst = push_array(arena, CFG_PanelNode, 1);
|
|
||||||
MemoryCopyStruct(dst, &cfg_nil_panel_node);
|
|
||||||
dst->parent = dst_active_parent;
|
|
||||||
if(dst_active_parent != &cfg_nil_panel_node)
|
|
||||||
{
|
|
||||||
DLLPushBack_NPZ(&cfg_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev);
|
|
||||||
dst_active_parent->child_count += 1;
|
|
||||||
}
|
|
||||||
if(dst_root == &cfg_nil_panel_node)
|
|
||||||
{
|
|
||||||
dst_root = dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: extract cfg info
|
|
||||||
B32 panel_has_children = 0;
|
|
||||||
dst->cfg = src;
|
|
||||||
dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string));
|
|
||||||
dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min);
|
|
||||||
dst->split_axis = active_split_axis;
|
|
||||||
for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next)
|
|
||||||
{
|
|
||||||
MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string);
|
|
||||||
if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric)
|
|
||||||
{
|
|
||||||
panel_has_children = 1;
|
|
||||||
}
|
|
||||||
else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0))
|
|
||||||
{
|
|
||||||
// NOTE(rjf): skip - this is a panel option.
|
|
||||||
}
|
|
||||||
else if(str8_match(src_child->string, str8_lit("selected"), 0))
|
|
||||||
{
|
|
||||||
dst_focused = dst;
|
|
||||||
}
|
|
||||||
else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier)
|
|
||||||
{
|
|
||||||
cfg_node_ptr_list_push(arena, &dst->tabs, src_child);
|
|
||||||
if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
dst->selected_tab = src_child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: recurse
|
|
||||||
rec = cfg_node_rec__depth_first(src_root, src);
|
|
||||||
if(!panel_has_children)
|
|
||||||
{
|
|
||||||
MemoryZeroStruct(&rec);
|
|
||||||
rec.next = &cfg_nil_node;
|
|
||||||
for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1)
|
|
||||||
{
|
|
||||||
if(p->next != &cfg_nil_node)
|
|
||||||
{
|
|
||||||
rec.next = p->next;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(rec.push_count > 0)
|
|
||||||
{
|
|
||||||
dst_active_parent = dst;
|
|
||||||
active_split_axis = axis2_flip(active_split_axis);
|
|
||||||
}
|
|
||||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
|
||||||
{
|
|
||||||
dst_active_parent = dst_active_parent->parent;
|
|
||||||
active_split_axis = axis2_flip(active_split_axis);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
CFG_PanelTree tree = {dst_root, dst_focused};
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_PanelNodeRec
|
|
||||||
cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off)
|
|
||||||
{
|
|
||||||
CFG_PanelNodeRec rec = {&cfg_nil_panel_node};
|
|
||||||
if(*MemberFromOffset(CFG_PanelNode **, panel, child_off) != &cfg_nil_panel_node)
|
|
||||||
{
|
|
||||||
rec.next = *MemberFromOffset(CFG_PanelNode **, panel, child_off);
|
|
||||||
rec.push_count += 1;
|
|
||||||
}
|
|
||||||
else for(CFG_PanelNode *p = panel; p != &cfg_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1)
|
|
||||||
{
|
|
||||||
if(*MemberFromOffset(CFG_PanelNode **, p, sib_off) != &cfg_nil_panel_node)
|
|
||||||
{
|
|
||||||
rec.next = *MemberFromOffset(CFG_PanelNode **, p, sib_off);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CFG_PanelNode *
|
|
||||||
cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg)
|
|
||||||
{
|
|
||||||
CFG_PanelNode *result = &cfg_nil_panel_node;
|
|
||||||
for(CFG_PanelNode *p = root;
|
|
||||||
p != &cfg_nil_panel_node;
|
|
||||||
p = cfg_panel_node_rec__depth_first_pre(root, p).next)
|
|
||||||
{
|
|
||||||
if(p->cfg == cfg)
|
|
||||||
{
|
|
||||||
result = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Rng2F32
|
|
||||||
cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel)
|
|
||||||
{
|
|
||||||
Rng2F32 rect = parent_rect;
|
|
||||||
if(parent != &cfg_nil_panel_node)
|
|
||||||
{
|
|
||||||
Vec2F32 parent_rect_size = dim_2f32(parent_rect);
|
|
||||||
Axis2 axis = parent->split_axis;
|
|
||||||
rect.p1.v[axis] = rect.p0.v[axis];
|
|
||||||
for(CFG_PanelNode *child = parent->first; child != &cfg_nil_panel_node; child = child->next)
|
|
||||||
{
|
|
||||||
rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent;
|
|
||||||
if(child == panel)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rect.p0.v[axis] = rect.p1.v[axis];
|
|
||||||
}
|
|
||||||
//rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis];
|
|
||||||
//rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)];
|
|
||||||
}
|
|
||||||
rect.x0 = round_f32(rect.x0);
|
|
||||||
rect.x1 = round_f32(rect.x1);
|
|
||||||
rect.y0 = round_f32(rect.y0);
|
|
||||||
rect.y1 = round_f32(rect.y1);
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Rng2F32
|
|
||||||
cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
// rjf: count ancestors
|
|
||||||
U64 ancestor_count = 0;
|
|
||||||
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
|
|
||||||
{
|
|
||||||
ancestor_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: gather ancestors
|
|
||||||
CFG_PanelNode **ancestors = push_array(scratch.arena, CFG_PanelNode *, ancestor_count);
|
|
||||||
{
|
|
||||||
U64 ancestor_idx = 0;
|
|
||||||
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
|
|
||||||
{
|
|
||||||
ancestors[ancestor_idx] = p;
|
|
||||||
ancestor_idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: go from highest ancestor => panel and calculate rect
|
|
||||||
Rng2F32 parent_rect = root_rect;
|
|
||||||
for(S64 ancestor_idx = (S64)ancestor_count-1;
|
|
||||||
0 <= ancestor_idx && ancestor_idx < ancestor_count;
|
|
||||||
ancestor_idx -= 1)
|
|
||||||
{
|
|
||||||
CFG_PanelNode *ancestor = ancestors[ancestor_idx];
|
|
||||||
CFG_PanelNode *parent = ancestor->parent;
|
|
||||||
if(parent != &cfg_nil_panel_node)
|
|
||||||
{
|
|
||||||
parent_rect = cfg_target_rect_from_panel_node_child(parent_rect, parent, ancestor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: calculate final rect
|
|
||||||
Rng2F32 rect = cfg_target_rect_from_panel_node_child(parent_rect, panel->parent, panel);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CONFIG_PANELS_H
|
|
||||||
#define CONFIG_PANELS_H
|
|
||||||
|
|
||||||
typedef struct CFG_PanelNode CFG_PanelNode;
|
|
||||||
struct CFG_PanelNode
|
|
||||||
{
|
|
||||||
// rjf: links data
|
|
||||||
CFG_PanelNode *first;
|
|
||||||
CFG_PanelNode *last;
|
|
||||||
CFG_PanelNode *next;
|
|
||||||
CFG_PanelNode *prev;
|
|
||||||
CFG_PanelNode *parent;
|
|
||||||
U64 child_count;
|
|
||||||
CFG_Node *cfg;
|
|
||||||
|
|
||||||
// rjf: split data
|
|
||||||
Axis2 split_axis;
|
|
||||||
F32 pct_of_parent;
|
|
||||||
|
|
||||||
// rjf: tab params
|
|
||||||
Side tab_side;
|
|
||||||
|
|
||||||
// rjf: which tabs are attached
|
|
||||||
CFG_NodePtrList tabs;
|
|
||||||
CFG_Node *selected_tab;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_PanelTree CFG_PanelTree;
|
|
||||||
struct CFG_PanelTree
|
|
||||||
{
|
|
||||||
CFG_PanelNode *root;
|
|
||||||
CFG_PanelNode *focused;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CFG_PanelNodeRec CFG_PanelNodeRec;
|
|
||||||
struct CFG_PanelNodeRec
|
|
||||||
{
|
|
||||||
CFG_PanelNode *next;
|
|
||||||
S32 push_count;
|
|
||||||
S32 pop_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
read_only global CFG_PanelNode cfg_nil_panel_node =
|
|
||||||
{
|
|
||||||
&cfg_nil_panel_node,
|
|
||||||
&cfg_nil_panel_node,
|
|
||||||
&cfg_nil_panel_node,
|
|
||||||
&cfg_nil_panel_node,
|
|
||||||
&cfg_nil_panel_node,
|
|
||||||
0,
|
|
||||||
&cfg_nil_node,
|
|
||||||
.selected_tab = &cfg_nil_node,
|
|
||||||
};
|
|
||||||
|
|
||||||
internal CFG_Node *cfg_window_from_cfg(CFG_Node *cfg);
|
|
||||||
internal CFG_PanelTree cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root);
|
|
||||||
internal CFG_PanelNodeRec cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off);
|
|
||||||
#define cfg_panel_node_rec__depth_first_pre(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, next), OffsetOf(CFG_PanelNode, first))
|
|
||||||
#define cfg_panel_node_rec__depth_first_pre_rev(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, prev), OffsetOf(CFG_PanelNode, last))
|
|
||||||
internal CFG_PanelNode *cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg);
|
|
||||||
internal Rng2F32 cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel);
|
|
||||||
internal Rng2F32 cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel);
|
|
||||||
|
|
||||||
#endif // CONFIG_PANELS_H
|
|
||||||
@@ -1,522 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#undef LAYER_COLOR
|
|
||||||
#define LAYER_COLOR 0x684123ff
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Helpers
|
|
||||||
|
|
||||||
internal C_ID
|
|
||||||
c_id_make(U64 u64_0, U64 u64_1)
|
|
||||||
{
|
|
||||||
C_ID id;
|
|
||||||
id.u128[0].u64[0] = u64_0;
|
|
||||||
id.u128[0].u64[1] = u64_1;
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
c_id_match(C_ID a, C_ID b)
|
|
||||||
{
|
|
||||||
B32 result = MemoryMatchStruct(&a, &b);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal C_Key
|
|
||||||
c_key_make(C_Root root, C_ID id)
|
|
||||||
{
|
|
||||||
C_Key key = {root, 0, id};
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
c_key_match(C_Key a, C_Key b)
|
|
||||||
{
|
|
||||||
return (MemoryMatchStruct(&a.root, &b.root) && c_id_match(a.id, b.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Main Layer Initialization
|
|
||||||
|
|
||||||
internal void
|
|
||||||
c_init(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
c_shared = push_array(arena, C_Shared, 1);
|
|
||||||
c_shared->arena = arena;
|
|
||||||
c_shared->blob_slots_count = 16384;
|
|
||||||
c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, os_get_system_info()->logical_processor_count);
|
|
||||||
c_shared->blob_slots = push_array(arena, C_BlobSlot, c_shared->blob_slots_count);
|
|
||||||
c_shared->blob_stripes = push_array(arena, C_Stripe, c_shared->blob_stripes_count);
|
|
||||||
c_shared->blob_stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->blob_stripes_count);
|
|
||||||
for(U64 idx = 0; idx < c_shared->blob_stripes_count; idx += 1)
|
|
||||||
{
|
|
||||||
C_Stripe *stripe = &c_shared->blob_stripes[idx];
|
|
||||||
stripe->arena = arena_alloc();
|
|
||||||
stripe->rw_mutex = rw_mutex_alloc();
|
|
||||||
stripe->cv = cond_var_alloc();
|
|
||||||
}
|
|
||||||
c_shared->key_slots_count = 4096;
|
|
||||||
c_shared->key_stripes_count = Min(c_shared->key_slots_count, os_get_system_info()->logical_processor_count);
|
|
||||||
c_shared->key_slots = push_array(arena, C_KeySlot, c_shared->key_slots_count);
|
|
||||||
c_shared->key_stripes = push_array(arena, C_Stripe, c_shared->key_stripes_count);
|
|
||||||
c_shared->key_stripes_free_nodes = push_array(arena, C_KeyNode *, c_shared->key_stripes_count);
|
|
||||||
for(U64 idx = 0; idx < c_shared->key_stripes_count; idx += 1)
|
|
||||||
{
|
|
||||||
C_Stripe *stripe = &c_shared->key_stripes[idx];
|
|
||||||
stripe->arena = arena_alloc();
|
|
||||||
stripe->rw_mutex = rw_mutex_alloc();
|
|
||||||
stripe->cv = cond_var_alloc();
|
|
||||||
}
|
|
||||||
c_shared->root_slots_count = 4096;
|
|
||||||
c_shared->root_stripes_count = Min(c_shared->root_slots_count, os_get_system_info()->logical_processor_count);
|
|
||||||
c_shared->root_slots = push_array(arena, C_RootSlot, c_shared->root_slots_count);
|
|
||||||
c_shared->root_stripes = push_array(arena, C_Stripe, c_shared->root_stripes_count);
|
|
||||||
c_shared->root_stripes_free_nodes = push_array(arena, C_RootNode *, c_shared->root_stripes_count);
|
|
||||||
for(U64 idx = 0; idx < c_shared->root_stripes_count; idx += 1)
|
|
||||||
{
|
|
||||||
C_Stripe *stripe = &c_shared->root_stripes[idx];
|
|
||||||
stripe->arena = arena_alloc();
|
|
||||||
stripe->rw_mutex = rw_mutex_alloc();
|
|
||||||
stripe->cv = cond_var_alloc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Root Allocation/Deallocation
|
|
||||||
|
|
||||||
internal C_Root
|
|
||||||
c_root_alloc(void)
|
|
||||||
{
|
|
||||||
C_Root root = {0};
|
|
||||||
root.u64[0] = ins_atomic_u64_inc_eval(&c_shared->root_id_gen);
|
|
||||||
U64 slot_idx = root.u64[0]%c_shared->root_slots_count;
|
|
||||||
U64 stripe_idx = slot_idx%c_shared->root_stripes_count;
|
|
||||||
C_RootSlot *slot = &c_shared->root_slots[slot_idx];
|
|
||||||
C_Stripe *stripe = &c_shared->root_stripes[stripe_idx];
|
|
||||||
MutexScopeW(stripe->rw_mutex)
|
|
||||||
{
|
|
||||||
C_RootNode *node = c_shared->root_stripes_free_nodes[stripe_idx];
|
|
||||||
if(node != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(c_shared->root_stripes_free_nodes[stripe_idx]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = push_array(stripe->arena, C_RootNode, 1);
|
|
||||||
}
|
|
||||||
DLLPushBack(slot->first, slot->last, node);
|
|
||||||
node->root = root;
|
|
||||||
node->arena = arena_alloc();
|
|
||||||
}
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
c_root_release(C_Root root)
|
|
||||||
{
|
|
||||||
//- rjf: unpack root
|
|
||||||
U64 slot_idx = root.u64[0]%c_shared->root_slots_count;
|
|
||||||
U64 stripe_idx = slot_idx%c_shared->root_stripes_count;
|
|
||||||
C_RootSlot *slot = &c_shared->root_slots[slot_idx];
|
|
||||||
C_Stripe *stripe = &c_shared->root_stripes[stripe_idx];
|
|
||||||
|
|
||||||
//- rjf: release root node, grab its arena / ID list
|
|
||||||
Arena *root_arena = 0;
|
|
||||||
C_RootIDChunkList root_ids = {0};
|
|
||||||
MutexScopeW(stripe->rw_mutex)
|
|
||||||
{
|
|
||||||
for(C_RootNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(MemoryMatchStruct(&root, &n->root))
|
|
||||||
{
|
|
||||||
DLLRemove(slot->first, slot->last, n);
|
|
||||||
root_arena = n->arena;
|
|
||||||
root_ids = n->ids;
|
|
||||||
SLLStackPush(c_shared->root_stripes_free_nodes[stripe_idx], n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: release all IDs
|
|
||||||
for(C_RootIDChunkNode *id_chunk_n = root_ids.first; id_chunk_n != 0; id_chunk_n = id_chunk_n->next)
|
|
||||||
{
|
|
||||||
for EachIndex(chunk_idx, id_chunk_n->count)
|
|
||||||
{
|
|
||||||
C_ID id = id_chunk_n->v[chunk_idx];
|
|
||||||
C_Key key = c_key_make(root, id);
|
|
||||||
c_close_key(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Submission
|
|
||||||
|
|
||||||
internal U128
|
|
||||||
c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
|
||||||
{
|
|
||||||
//- rjf: unpack key
|
|
||||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
|
||||||
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
|
|
||||||
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
|
|
||||||
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
|
|
||||||
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
|
|
||||||
|
|
||||||
//- rjf: hash data, unpack hash
|
|
||||||
U128 hash = u128_hash_from_str8(data);
|
|
||||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
|
||||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
|
||||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
|
||||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
|
||||||
|
|
||||||
//- rjf: commit to (hash -> data) cache
|
|
||||||
ProfScope("commit to (hash -> data) cache") RWMutexScope(stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
// rjf: find existing node
|
|
||||||
C_BlobNode *node = 0;
|
|
||||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(u128_match(n->hash, hash))
|
|
||||||
{
|
|
||||||
node = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: release duplicate data if node already exists
|
|
||||||
if(node != 0 && data_arena != 0 && *data_arena != 0)
|
|
||||||
{
|
|
||||||
arena_release(*data_arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: allocate node if needed
|
|
||||||
if(node == 0)
|
|
||||||
{
|
|
||||||
node = c_shared->blob_stripes_free_nodes[stripe_idx];
|
|
||||||
if(node)
|
|
||||||
{
|
|
||||||
SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = push_array_no_zero(stripe->arena, C_BlobNode, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(node);
|
|
||||||
node->hash = hash;
|
|
||||||
if(data_arena != 0)
|
|
||||||
{
|
|
||||||
node->arena = *data_arena;
|
|
||||||
}
|
|
||||||
node->data = data;
|
|
||||||
DLLPushBack(slot->first, slot->last, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: bump key ref count
|
|
||||||
node->key_ref_count += 1;
|
|
||||||
|
|
||||||
// rjf "steal" arena from caller
|
|
||||||
if(data_arena != 0)
|
|
||||||
{
|
|
||||||
*data_arena = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: commit to (key -> list(hash)) cache
|
|
||||||
U128 key_expired_hash = {0};
|
|
||||||
ProfScope("commit to (key -> list(hash)) cache") RWMutexScope(key_stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
// rjf: find existing key
|
|
||||||
C_KeyNode *key_node = 0;
|
|
||||||
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(c_key_match(n->key, key))
|
|
||||||
{
|
|
||||||
key_node = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: create key node if it doesn't exist
|
|
||||||
B32 key_is_new = 0;
|
|
||||||
if(!key_node)
|
|
||||||
{
|
|
||||||
key_is_new = 1;
|
|
||||||
key_node = c_shared->key_stripes_free_nodes[key_stripe_idx];
|
|
||||||
if(key_node)
|
|
||||||
{
|
|
||||||
SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
key_node = push_array_no_zero(key_stripe->arena, C_KeyNode, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(key_node);
|
|
||||||
key_node->key = key;
|
|
||||||
DLLPushBack(key_slot->first, key_slot->last, key_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push hash into key's history
|
|
||||||
if(key_node)
|
|
||||||
{
|
|
||||||
if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT)
|
|
||||||
{
|
|
||||||
key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)];
|
|
||||||
}
|
|
||||||
key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash;
|
|
||||||
key_node->hash_history_gen += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: key is new -> add this key to the associated root
|
|
||||||
if(key_is_new)
|
|
||||||
{
|
|
||||||
U64 root_hash = u64_hash_from_str8(str8_struct(&key.root));
|
|
||||||
U64 root_slot_idx = root_hash%c_shared->root_slots_count;
|
|
||||||
U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count;
|
|
||||||
C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx];
|
|
||||||
C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx];
|
|
||||||
RWMutexScope(root_stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(C_RootNode *n = root_slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(MemoryMatchStruct(&n->root, &key.root))
|
|
||||||
{
|
|
||||||
C_RootIDChunkNode *chunk = n->ids.last;
|
|
||||||
if(chunk == 0 || chunk->count >= chunk->cap)
|
|
||||||
{
|
|
||||||
chunk = push_array(n->arena, C_RootIDChunkNode, 1);
|
|
||||||
SLLQueuePush(n->ids.first, n->ids.last, chunk);
|
|
||||||
n->ids.chunk_count += 1;
|
|
||||||
chunk->cap = 1024;
|
|
||||||
chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap);
|
|
||||||
}
|
|
||||||
chunk->v[chunk->count] = key.id;
|
|
||||||
chunk->count += 1;
|
|
||||||
n->ids.total_count += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: decrement key ref count of expired hash
|
|
||||||
if(!u128_match(key_expired_hash, u128_zero())) ProfScope("decrement key ref count of expired hash")
|
|
||||||
{
|
|
||||||
U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->blob_slots_count;
|
|
||||||
U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->blob_stripes_count;
|
|
||||||
C_BlobSlot *old_hash_slot = &c_shared->blob_slots[old_hash_slot_idx];
|
|
||||||
C_Stripe *old_hash_stripe = &c_shared->blob_stripes[old_hash_stripe_idx];
|
|
||||||
RWMutexScope(old_hash_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(C_BlobNode *n = old_hash_slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(u128_match(n->hash, key_expired_hash))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_dec_eval(&n->key_ref_count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Key Closing
|
|
||||||
|
|
||||||
internal void
|
|
||||||
c_close_key(C_Key key)
|
|
||||||
{
|
|
||||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
|
||||||
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
|
|
||||||
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
|
|
||||||
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
|
|
||||||
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
|
|
||||||
RWMutexScope(key_stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(c_key_match(n->key, key))
|
|
||||||
{
|
|
||||||
for(U64 history_idx = 0;
|
|
||||||
history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen;
|
|
||||||
history_idx += 1)
|
|
||||||
{
|
|
||||||
U128 hash = n->hash_history[(n->hash_history_gen-1-history_idx) % ArrayCount(n->hash_history)];
|
|
||||||
U64 hash_slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
|
||||||
U64 hash_stripe_idx = hash_slot_idx%c_shared->blob_stripes_count;
|
|
||||||
C_BlobSlot *hash_slot = &c_shared->blob_slots[hash_slot_idx];
|
|
||||||
C_Stripe *hash_stripe = &c_shared->blob_stripes[hash_stripe_idx];
|
|
||||||
MutexScopeR(hash_stripe->rw_mutex)
|
|
||||||
{
|
|
||||||
for(C_BlobNode *n = hash_slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(u128_match(n->hash, hash))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_dec_eval(&n->key_ref_count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DLLRemove(key_slot->first, key_slot->last, n);
|
|
||||||
SLLStackPush(c_shared->key_stripes_free_nodes[key_stripe_idx], n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Downstream Accesses
|
|
||||||
|
|
||||||
internal void
|
|
||||||
c_hash_downstream_inc(U128 hash)
|
|
||||||
{
|
|
||||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
|
||||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
|
||||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
|
||||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
|
||||||
MutexScopeR(stripe->rw_mutex)
|
|
||||||
{
|
|
||||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(u128_match(hash, n->hash))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_inc_eval(&n->downstream_ref_count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
c_hash_downstream_dec(U128 hash)
|
|
||||||
{
|
|
||||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
|
||||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
|
||||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
|
||||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
|
||||||
MutexScopeR(stripe->rw_mutex)
|
|
||||||
{
|
|
||||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(u128_match(hash, n->hash))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_dec_eval(&n->downstream_ref_count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookup
|
|
||||||
|
|
||||||
internal U128
|
|
||||||
c_hash_from_key(C_Key key, U64 rewind_count)
|
|
||||||
{
|
|
||||||
U128 result = {0};
|
|
||||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
|
||||||
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
|
|
||||||
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
|
|
||||||
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
|
|
||||||
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
|
|
||||||
RWMutexScope(key_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(c_key_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count)
|
|
||||||
{
|
|
||||||
result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
c_data_from_hash(Access *access, U128 hash)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
String8 result = {0};
|
|
||||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
|
||||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
|
||||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
|
||||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
|
||||||
MutexScopeR(stripe->rw_mutex)
|
|
||||||
{
|
|
||||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(u128_match(n->hash, hash))
|
|
||||||
{
|
|
||||||
result = n->data;
|
|
||||||
access_touch(access, &n->access_pt, stripe->cv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ProfEnd();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
internal void
|
|
||||||
c_async_tick(void)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
|
|
||||||
//- rjf: garbage collect blobs
|
|
||||||
{
|
|
||||||
Rng1U64 range = lane_range(c_shared->blob_slots_count);
|
|
||||||
for EachInRange(slot_idx, range)
|
|
||||||
{
|
|
||||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
|
||||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
|
||||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
B32 slot_has_work = 0;
|
|
||||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(C_BlobNode *n = slot->first, *next = 0; n != 0; n = next)
|
|
||||||
{
|
|
||||||
next = n->next;
|
|
||||||
U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count);
|
|
||||||
U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count);
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = 5000000) && key_ref_count == 0 && downstream_ref_count == 0)
|
|
||||||
{
|
|
||||||
slot_has_work = 1;
|
|
||||||
if(!write_mode)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DLLRemove(slot->first, slot->last, n);
|
|
||||||
SLLStackPush(c_shared->blob_stripes_free_nodes[stripe_idx], n);
|
|
||||||
if(n->arena != 0)
|
|
||||||
{
|
|
||||||
arena_release(n->arena);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!slot_has_work)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CONTENT_H
|
|
||||||
#define CONTENT_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ NOTE(rjf): Hash Store Notes (2025/05/18)
|
|
||||||
//
|
|
||||||
// The hash store is a general-purpose data cache. It offers three layers of
|
|
||||||
// caching: (a) content (hash of data), (b) key (unique identity correllated
|
|
||||||
// with history of hashes), and (c) root (bucket for many keys, manually
|
|
||||||
// allocated / deallocated).
|
|
||||||
//
|
|
||||||
// (a) The "content" level of cache access is a simply hash(data) -> data
|
|
||||||
// mapping. This bypasses all identity/key/root mechanisms and provides a
|
|
||||||
// way to just talk about unique (and deduplicated) blobs of data.
|
|
||||||
//
|
|
||||||
// (b) The "key" level of cache access is used to encode a history of hashes
|
|
||||||
// for some unique "identity", where the "identity" is a concept managed
|
|
||||||
// by the user. One example of an identity would be a particular address
|
|
||||||
// range inside of some process to which the debugger is attached. Another
|
|
||||||
// might be a range inside of some file.
|
|
||||||
//
|
|
||||||
// (c) The "root" level is to provide a top-level allocation/deallocation
|
|
||||||
// mechanism for a large set of keys. It also provides an extra level of
|
|
||||||
// key uniqueness. For instance, each process to which the debugger is
|
|
||||||
// attached might have its own root, and each key might correspond to a
|
|
||||||
// particular address range within that process. This way, when the
|
|
||||||
// process ends, all of its keys can be easily destroyed using a single
|
|
||||||
// deallocation of the root.
|
|
||||||
//
|
|
||||||
// The way this might be generally used inside of the debugger would be that
|
|
||||||
// some evaluation - let's say it's some variable `x` - is mapped (via debug
|
|
||||||
// info) to some address range. If `x` is a `char[4096]`, then it might map
|
|
||||||
// to some address range [&x, &x + 4096). This, together with the process
|
|
||||||
// within which `x` is evaluated, forms both a `root` (for the process) and
|
|
||||||
// a `key` (for the address range). Some asynchronous memory streaming system
|
|
||||||
// can then, together with the root and key, read memory for that range, then
|
|
||||||
// submit that data to the hash store, correllating with the root and key
|
|
||||||
// combo.
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Key Types
|
|
||||||
|
|
||||||
typedef struct C_Root C_Root;
|
|
||||||
struct C_Root
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct C_ID C_ID;
|
|
||||||
struct C_ID
|
|
||||||
{
|
|
||||||
U128 u128[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct C_Key C_Key;
|
|
||||||
struct C_Key
|
|
||||||
{
|
|
||||||
C_Root root;
|
|
||||||
U64 _padding_;
|
|
||||||
C_ID id;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Stripe Type
|
|
||||||
|
|
||||||
typedef struct C_Stripe C_Stripe;
|
|
||||||
struct C_Stripe
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
RWMutex rw_mutex;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Root Cache Types
|
|
||||||
|
|
||||||
typedef struct C_RootIDChunkNode C_RootIDChunkNode;
|
|
||||||
struct C_RootIDChunkNode
|
|
||||||
{
|
|
||||||
C_RootIDChunkNode *next;
|
|
||||||
C_ID *v;
|
|
||||||
U64 count;
|
|
||||||
U64 cap;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct C_RootIDChunkList C_RootIDChunkList;
|
|
||||||
struct C_RootIDChunkList
|
|
||||||
{
|
|
||||||
C_RootIDChunkNode *first;
|
|
||||||
C_RootIDChunkNode *last;
|
|
||||||
U64 chunk_count;
|
|
||||||
U64 total_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct C_RootNode C_RootNode;
|
|
||||||
struct C_RootNode
|
|
||||||
{
|
|
||||||
C_RootNode *next;
|
|
||||||
C_RootNode *prev;
|
|
||||||
Arena *arena;
|
|
||||||
C_Root root;
|
|
||||||
C_RootIDChunkList ids;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct C_RootSlot C_RootSlot;
|
|
||||||
struct C_RootSlot
|
|
||||||
{
|
|
||||||
C_RootNode *first;
|
|
||||||
C_RootNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Key Cache Types
|
|
||||||
|
|
||||||
#define C_KEY_HASH_HISTORY_COUNT 64
|
|
||||||
#define C_KEY_HASH_HISTORY_STRONG_REF_COUNT 2
|
|
||||||
|
|
||||||
typedef struct C_KeyNode C_KeyNode;
|
|
||||||
struct C_KeyNode
|
|
||||||
{
|
|
||||||
C_KeyNode *next;
|
|
||||||
C_KeyNode *prev;
|
|
||||||
C_Key key;
|
|
||||||
U128 hash_history[C_KEY_HASH_HISTORY_COUNT];
|
|
||||||
U64 hash_history_gen;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct C_KeySlot C_KeySlot;
|
|
||||||
struct C_KeySlot
|
|
||||||
{
|
|
||||||
C_KeyNode *first;
|
|
||||||
C_KeyNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Content Blob Cache Types
|
|
||||||
|
|
||||||
typedef struct C_BlobNode C_BlobNode;
|
|
||||||
struct C_BlobNode
|
|
||||||
{
|
|
||||||
C_BlobNode *next;
|
|
||||||
C_BlobNode *prev;
|
|
||||||
U128 hash;
|
|
||||||
Arena *arena;
|
|
||||||
String8 data;
|
|
||||||
AccessPt access_pt;
|
|
||||||
U64 key_ref_count;
|
|
||||||
U64 downstream_ref_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct C_BlobSlot C_BlobSlot;
|
|
||||||
struct C_BlobSlot
|
|
||||||
{
|
|
||||||
C_BlobNode *first;
|
|
||||||
C_BlobNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Shared State
|
|
||||||
|
|
||||||
typedef struct C_Shared C_Shared;
|
|
||||||
struct C_Shared
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
|
|
||||||
// rjf: main data blob cache
|
|
||||||
U64 blob_slots_count;
|
|
||||||
U64 blob_stripes_count;
|
|
||||||
C_BlobSlot *blob_slots;
|
|
||||||
C_Stripe *blob_stripes;
|
|
||||||
C_BlobNode **blob_stripes_free_nodes;
|
|
||||||
|
|
||||||
// rjf: key cache
|
|
||||||
U64 key_slots_count;
|
|
||||||
U64 key_stripes_count;
|
|
||||||
C_KeySlot *key_slots;
|
|
||||||
C_Stripe *key_stripes;
|
|
||||||
C_KeyNode **key_stripes_free_nodes;
|
|
||||||
|
|
||||||
// rjf: root cache
|
|
||||||
U64 root_slots_count;
|
|
||||||
U64 root_stripes_count;
|
|
||||||
C_RootSlot *root_slots;
|
|
||||||
C_Stripe *root_stripes;
|
|
||||||
C_RootNode **root_stripes_free_nodes;
|
|
||||||
U64 root_id_gen;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
global C_Shared *c_shared = 0;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Helpers
|
|
||||||
|
|
||||||
internal C_ID c_id_make(U64 u64_0, U64 u64_1);
|
|
||||||
internal B32 c_id_match(C_ID a, C_ID b);
|
|
||||||
internal C_Key c_key_make(C_Root root, C_ID id);
|
|
||||||
internal B32 c_key_match(C_Key a, C_Key b);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Main Layer Initialization
|
|
||||||
|
|
||||||
internal void c_init(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Root Allocation/Deallocation
|
|
||||||
|
|
||||||
internal C_Root c_root_alloc(void);
|
|
||||||
internal void c_root_release(C_Root root);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Submission
|
|
||||||
|
|
||||||
internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Key Closing
|
|
||||||
|
|
||||||
internal void c_close_key(C_Key key);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Downstream Accesses
|
|
||||||
|
|
||||||
internal void c_hash_downstream_inc(U128 hash);
|
|
||||||
internal void c_hash_downstream_dec(U128 hash);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookups
|
|
||||||
|
|
||||||
internal U128 c_hash_from_key(C_Key key, U64 rewind_count);
|
|
||||||
internal String8 c_data_from_hash(Access *access, U128 hash);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
internal void c_async_tick(void);
|
|
||||||
|
|
||||||
#endif // CONTENT_H
|
|
||||||
+85
-192
@@ -1,192 +1,85 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Entity Kinds
|
//~ rjf: Tables
|
||||||
|
|
||||||
@table(name code_name display_string)
|
@table(name lower_name code default display_string)
|
||||||
CTRL_EntityKindTable:
|
CTRL_ExceptionCodeKindTable:
|
||||||
{
|
{
|
||||||
{Root root "Root" }
|
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
|
||||||
{Machine machine "Machine" }
|
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
|
||||||
{Process process "Process" }
|
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
|
||||||
{Thread thread "Thread" }
|
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
|
||||||
{Module module "Module" }
|
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
|
||||||
{EntryPoint entry_point "Entry Point" }
|
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
|
||||||
{DebugInfoPath debug_info_path "Debug Info Path" }
|
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
|
||||||
{PendingThreadName pending_thread_name "Pending Thread Name" }
|
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
|
||||||
{PendingThreadColor pending_thread_color "Pending Thread Color" }
|
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
|
||||||
{Breakpoint breakpoint "Breakpoint" }
|
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
|
||||||
{AddressRangeAnnotation address_range_annotation "Address Range Annotation" }
|
{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" }
|
||||||
@enum CTRL_EntityKind:
|
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
|
||||||
{
|
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
|
||||||
Null,
|
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
|
||||||
@expand(CTRL_EntityKindTable a) `$(a.name)`,
|
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
|
||||||
COUNT,
|
{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" }
|
||||||
@data(String8) ctrl_entity_kind_code_name_table:
|
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
|
||||||
{
|
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
|
||||||
`{0}`,
|
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
|
||||||
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.code_name)")`
|
{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" }
|
||||||
@data(String8) ctrl_entity_kind_display_string_table:
|
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
|
||||||
{
|
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
|
||||||
`{0}`,
|
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
|
||||||
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.display_name)")`
|
{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" }
|
||||||
//~ rjf: Exception Codes
|
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
|
||||||
|
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
|
||||||
@table(name lower_name code default display_string)
|
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
|
||||||
CTRL_ExceptionCodeKindTable:
|
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
||||||
{
|
}
|
||||||
{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" }
|
//~ rjf: Generators
|
||||||
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
|
|
||||||
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
|
@table_gen_enum CTRL_ExceptionCodeKind:
|
||||||
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
|
{
|
||||||
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
|
`CTRL_ExceptionCodeKind_Null,`;
|
||||||
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
|
@expand(CTRL_ExceptionCodeKindTable a) `CTRL_ExceptionCodeKind_$(a.name),`;
|
||||||
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
|
`CTRL_ExceptionCodeKind_COUNT`;
|
||||||
{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" }
|
@table_gen_data(type:U32, fallback:0)
|
||||||
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
|
ctrl_exception_code_kind_code_table:
|
||||||
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
|
{
|
||||||
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
|
`0,`;
|
||||||
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
|
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code),`;
|
||||||
{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" }
|
@table_gen_data(type:String8, fallback:`{0}`)
|
||||||
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
|
ctrl_exception_code_kind_display_string_table:
|
||||||
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
|
{
|
||||||
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
|
`{0},`;
|
||||||
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
|
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)"),`;
|
||||||
{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" }
|
@table_gen_data(type:String8, fallback:`{0}`)
|
||||||
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
|
ctrl_exception_code_kind_lowercase_code_string_table:
|
||||||
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
|
{
|
||||||
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
|
`{0},`;
|
||||||
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
|
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)"),`;
|
||||||
{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" }
|
@table_gen_data(type:B8, fallback:0)
|
||||||
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
|
ctrl_exception_code_kind_default_enable_table:
|
||||||
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
|
{
|
||||||
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
|
`0,`;
|
||||||
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default),`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 }
|
|
||||||
}
|
|
||||||
|
|||||||
+3406
-6739
File diff suppressed because it is too large
Load Diff
+602
-1031
File diff suppressed because it is too large
Load Diff
+4
-7
@@ -1,7 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#undef LAYER_COLOR
|
#include "ctrl_core.c"
|
||||||
#define LAYER_COLOR 0x969696ff
|
|
||||||
|
|
||||||
#include "ctrl_core.c"
|
|
||||||
|
|||||||
+77
-77
@@ -1,77 +1,77 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef CTRL_INC_H
|
#ifndef CTRL_INC_H
|
||||||
#define CTRL_INC_H
|
#define CTRL_INC_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
|
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
|
||||||
//
|
//
|
||||||
// This layer's purpose is to provide access to the asynchronously-running, low
|
// 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
|
// level parts of a debugger, running on the debugger client. This primarily
|
||||||
// consists of process control, using the Demon layer (the lower level
|
// consists of process control, using the Demon layer (the lower level
|
||||||
// abstraction layer for process control, across multiple OSes), but including
|
// abstraction layer for process control, across multiple OSes), but including
|
||||||
// higher-level concepts, like stepping, breakpoint resolution, conditional
|
// higher-level concepts, like stepping, breakpoint resolution, conditional
|
||||||
// breakpoint evaluation, and so on. Right now, this just includes process
|
// breakpoint evaluation, and so on. Right now, this just includes process
|
||||||
// control *local to the debugger client machine*. But in the future, this can
|
// control *local to the debugger client machine*. But in the future, this can
|
||||||
// also include communication to multiple target machines, all running their
|
// also include communication to multiple target machines, all running their
|
||||||
// own process controller, using the Demon layer.
|
// own process controller, using the Demon layer.
|
||||||
//
|
//
|
||||||
// This part of a debugger must run asynchronously to prevent blocking the UI -
|
// 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
|
// 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,
|
// debugger frontend is still usable for a variety of purposes. So, in short,
|
||||||
// the asynchronously-running "control thread", implemented by this layer, is
|
// the asynchronously-running "control thread", implemented by this layer, is
|
||||||
// tasked with communicating with a separately executing "user thread". This
|
// tasked with communicating with a separately executing "user thread". This
|
||||||
// communication happens in two directions - `user -> ctrl`, and the reverse,
|
// communication happens in two directions - `user -> ctrl`, and the reverse,
|
||||||
// `ctrl -> user`.
|
// `ctrl -> user`.
|
||||||
//
|
//
|
||||||
// In the case of `user -> ctrl` communication, this is done with a ring buffer
|
// 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
|
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
|
||||||
// include commands like: launching targets, attaching to targets, killing
|
// include commands like: launching targets, attaching to targets, killing
|
||||||
// targets, detaching from targets, stepping/running, or single stepping.
|
// targets, detaching from targets, stepping/running, or single stepping.
|
||||||
//
|
//
|
||||||
// In the case of `ctrl -> user` communication, this is done with a ring buffer
|
// 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
|
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
|
||||||
// include information about what happened during the execution of targets -
|
// include information about what happened during the execution of targets -
|
||||||
// including: process/module/thread creation, process/module/thread deletion,
|
// including: process/module/thread creation, process/module/thread deletion,
|
||||||
// debug strings, thread name events, memory allocation events, and stop events
|
// debug strings, thread name events, memory allocation events, and stop events
|
||||||
// (where stops can be caused by: user breakpoints, traps set for stepping,
|
// (where stops can be caused by: user breakpoints, traps set for stepping,
|
||||||
// exceptions, halts, or errors).
|
// exceptions, halts, or errors).
|
||||||
//
|
//
|
||||||
// The various stepping algorithms are implemented with two concepts: (a) the
|
// The various stepping algorithms are implemented with two concepts: (a) the
|
||||||
// "trap net", and (b) "spoofs".
|
// "trap net", and (b) "spoofs".
|
||||||
//
|
//
|
||||||
// A "trap net" is a term which refers to a set of addresses paired with a set
|
// 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
|
// of behavioral flags. Before targets run, trap instructions are written to
|
||||||
// these addresses. After targets stop, these addresses are reset to their
|
// these addresses. After targets stop, these addresses are reset to their
|
||||||
// original bytes. These trap instructions cause the debugger's targets to
|
// original bytes. These trap instructions cause the debugger's targets to
|
||||||
// stop executing, and based on which behavioral flags are associated with
|
// stop executing, and based on which behavioral flags are associated with
|
||||||
// the instruction causing the stop, the control thread may adjust parameters
|
// the instruction causing the stop, the control thread may adjust parameters
|
||||||
// used for running, then continue execution, or it will not resume target
|
// used for running, then continue execution, or it will not resume target
|
||||||
// execution, and will report stopped events. These behavioral flags can
|
// execution, and will report stopped events. These behavioral flags can
|
||||||
// include: single-stepping the stopped thread to execute the instruction at
|
// include: single-stepping the stopped thread to execute the instruction at
|
||||||
// the trap location, saving a stack pointer "check value" (where this check
|
// the trap location, saving a stack pointer "check value" (where this check
|
||||||
// value is compared against when making decisions about whether to continue
|
// 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
|
// 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
|
// 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,
|
// 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 `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,
|
// 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.
|
// 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
|
// 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
|
// returns from a particular sub-callstack. This is useful when implementing
|
||||||
// "step over" in functions that may be recursive. In short, unlike a trap,
|
// "step over" in functions that may be recursive. In short, unlike a trap,
|
||||||
// which writes a trap instruction (like `int3`) into an instruction stream,
|
// which writes a trap instruction (like `int3`) into an instruction stream,
|
||||||
// a spoof overwrites a *return address* on some thread's *stack*. This return
|
// 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
|
// 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
|
// 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,
|
// 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
|
// 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
|
// 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
|
// code execution. At that point, the debugger can move the thread back to
|
||||||
// the pre-spoof return address, and resume execution.
|
// the pre-spoof return address, and resume execution.
|
||||||
|
|
||||||
#include "ctrl_core.h"
|
#include "ctrl_core.h"
|
||||||
|
|
||||||
#endif // CTRL_INC_H
|
#endif //CTRL_INC_H
|
||||||
|
|||||||
@@ -1,208 +1,5 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
//- GENERATED CODE
|
//- 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
|
|
||||||
|
|
||||||
|
|||||||
+221
-79
@@ -1,79 +1,221 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
//- GENERATED CODE
|
//- GENERATED CODE
|
||||||
|
|
||||||
#ifndef CTRL_META_H
|
#ifndef CTRL_META_H
|
||||||
#define CTRL_META_H
|
#define CTRL_META_H
|
||||||
|
|
||||||
typedef enum CTRL_EntityKind
|
typedef enum CTRL_ExceptionCodeKind
|
||||||
{
|
{
|
||||||
CTRL_EntityKind_Null,
|
CTRL_ExceptionCodeKind_Null,
|
||||||
CTRL_EntityKind_Root,
|
CTRL_ExceptionCodeKind_Win32CtrlC,
|
||||||
CTRL_EntityKind_Machine,
|
CTRL_ExceptionCodeKind_Win32CtrlBreak,
|
||||||
CTRL_EntityKind_Process,
|
CTRL_ExceptionCodeKind_Win32WinRTOriginateError,
|
||||||
CTRL_EntityKind_Thread,
|
CTRL_ExceptionCodeKind_Win32WinRTTransformError,
|
||||||
CTRL_EntityKind_Module,
|
CTRL_ExceptionCodeKind_Win32RPCCallCancelled,
|
||||||
CTRL_EntityKind_EntryPoint,
|
CTRL_ExceptionCodeKind_Win32DatatypeMisalignment,
|
||||||
CTRL_EntityKind_DebugInfoPath,
|
CTRL_ExceptionCodeKind_Win32AccessViolation,
|
||||||
CTRL_EntityKind_PendingThreadName,
|
CTRL_ExceptionCodeKind_Win32InPageError,
|
||||||
CTRL_EntityKind_PendingThreadColor,
|
CTRL_ExceptionCodeKind_Win32InvalidHandle,
|
||||||
CTRL_EntityKind_Breakpoint,
|
CTRL_ExceptionCodeKind_Win32NotEnoughQuota,
|
||||||
CTRL_EntityKind_AddressRangeAnnotation,
|
CTRL_ExceptionCodeKind_Win32IllegalInstruction,
|
||||||
CTRL_EntityKind_COUNT,
|
CTRL_ExceptionCodeKind_Win32CannotContinueException,
|
||||||
} CTRL_EntityKind;
|
CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition,
|
||||||
|
CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded,
|
||||||
typedef enum CTRL_ExceptionCodeKind
|
CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand,
|
||||||
{
|
CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero,
|
||||||
CTRL_ExceptionCodeKind_Null,
|
CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult,
|
||||||
CTRL_ExceptionCodeKind_Win32CtrlC,
|
CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation,
|
||||||
CTRL_ExceptionCodeKind_Win32CtrlBreak,
|
CTRL_ExceptionCodeKind_Win32FloatingPointOverflow,
|
||||||
CTRL_ExceptionCodeKind_Win32WinRTOriginateError,
|
CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck,
|
||||||
CTRL_ExceptionCodeKind_Win32WinRTTransformError,
|
CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow,
|
||||||
CTRL_ExceptionCodeKind_Win32RPCCallCancelled,
|
CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero,
|
||||||
CTRL_ExceptionCodeKind_Win32DatatypeMisalignment,
|
CTRL_ExceptionCodeKind_Win32IntegerOverflow,
|
||||||
CTRL_ExceptionCodeKind_Win32AccessViolation,
|
CTRL_ExceptionCodeKind_Win32PrivilegedInstruction,
|
||||||
CTRL_ExceptionCodeKind_Win32InPageError,
|
CTRL_ExceptionCodeKind_Win32StackOverflow,
|
||||||
CTRL_ExceptionCodeKind_Win32InvalidHandle,
|
CTRL_ExceptionCodeKind_Win32UnableToLocateDLL,
|
||||||
CTRL_ExceptionCodeKind_Win32NotEnoughQuota,
|
CTRL_ExceptionCodeKind_Win32OrdinalNotFound,
|
||||||
CTRL_ExceptionCodeKind_Win32IllegalInstruction,
|
CTRL_ExceptionCodeKind_Win32EntryPointNotFound,
|
||||||
CTRL_ExceptionCodeKind_Win32CannotContinueException,
|
CTRL_ExceptionCodeKind_Win32DLLInitializationFailed,
|
||||||
CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition,
|
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults,
|
||||||
CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded,
|
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand,
|
CTRL_ExceptionCodeKind_Win32AssertionFailed,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero,
|
CTRL_ExceptionCodeKind_Win32ModuleNotFound,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult,
|
CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation,
|
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointOverflow,
|
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck,
|
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow,
|
CTRL_ExceptionCodeKind_COUNT
|
||||||
CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero,
|
} CTRL_ExceptionCodeKind;
|
||||||
CTRL_ExceptionCodeKind_Win32IntegerOverflow,
|
|
||||||
CTRL_ExceptionCodeKind_Win32PrivilegedInstruction,
|
U32 ctrl_exception_code_kind_code_table[] =
|
||||||
CTRL_ExceptionCodeKind_Win32StackOverflow,
|
{
|
||||||
CTRL_ExceptionCodeKind_Win32UnableToLocateDLL,
|
0,
|
||||||
CTRL_ExceptionCodeKind_Win32OrdinalNotFound,
|
0x40010005,
|
||||||
CTRL_ExceptionCodeKind_Win32EntryPointNotFound,
|
0x40010008,
|
||||||
CTRL_ExceptionCodeKind_Win32DLLInitializationFailed,
|
0x40080201,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults,
|
0x40080202,
|
||||||
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps,
|
0x0000071a,
|
||||||
CTRL_ExceptionCodeKind_Win32AssertionFailed,
|
0x80000002,
|
||||||
CTRL_ExceptionCodeKind_Win32ModuleNotFound,
|
0xc0000005,
|
||||||
CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
|
0xc0000006,
|
||||||
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
|
0xc0000008,
|
||||||
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
|
0xc0000017,
|
||||||
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
|
0xc000001d,
|
||||||
CTRL_ExceptionCodeKind_COUNT,
|
0xc0000025,
|
||||||
} CTRL_ExceptionCodeKind;
|
0xc0000026,
|
||||||
|
0xc000008c,
|
||||||
C_LINKAGE_BEGIN
|
0xc000008d,
|
||||||
extern String8 ctrl_entity_kind_code_name_table[12];
|
0xc000008e,
|
||||||
extern String8 ctrl_entity_kind_display_string_table[12];
|
0xc000008f,
|
||||||
extern U32 ctrl_exception_code_kind_code_table[38];
|
0xc0000090,
|
||||||
extern String8 ctrl_exception_code_kind_display_string_table[38];
|
0xc0000091,
|
||||||
extern String8 ctrl_exception_code_kind_lowercase_code_string_table[38];
|
0xc0000092,
|
||||||
extern B8 ctrl_exception_code_kind_default_enable_table[38];
|
0xc0000093,
|
||||||
|
0xc0000094,
|
||||||
C_LINKAGE_END
|
0xc0000095,
|
||||||
|
0xc0000096,
|
||||||
#endif // CTRL_META_H
|
0xc00000fd,
|
||||||
|
0xc0000135,
|
||||||
|
0xc0000138,
|
||||||
|
0xc0000139,
|
||||||
|
0xc0000142,
|
||||||
|
0xc00002b4,
|
||||||
|
0xc00002b5,
|
||||||
|
0xc0000420,
|
||||||
|
0xc06d007e,
|
||||||
|
0xc06d007f,
|
||||||
|
0xe073616e,
|
||||||
|
0xe0736171,
|
||||||
|
0x0000087a,
|
||||||
|
};
|
||||||
|
|
||||||
|
String8 ctrl_exception_code_kind_display_string_table[] =
|
||||||
|
{
|
||||||
|
{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[] =
|
||||||
|
{
|
||||||
|
{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[] =
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CTRL_META_H
|
||||||
|
|||||||
+540
@@ -0,0 +1,540 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Main Layer Initialization
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dasm_init(void)
|
||||||
|
{
|
||||||
|
Arena *arena = arena_alloc();
|
||||||
|
dasm_shared = push_array(arena, DASM_Shared, 1);
|
||||||
|
dasm_shared->arena = arena;
|
||||||
|
dasm_shared->entity_map.slots_count = 1024;
|
||||||
|
dasm_shared->entity_map.slots = push_array(arena, DASM_EntitySlot, dasm_shared->entity_map.slots_count);
|
||||||
|
dasm_shared->entity_map_stripes.count = 64;
|
||||||
|
dasm_shared->entity_map_stripes.v = push_array(arena, DASM_Stripe, dasm_shared->entity_map_stripes.count);
|
||||||
|
for(U64 idx = 0; idx < dasm_shared->entity_map_stripes.count; idx += 1)
|
||||||
|
{
|
||||||
|
dasm_shared->entity_map_stripes.v[idx].arena = arena_alloc();
|
||||||
|
dasm_shared->entity_map_stripes.v[idx].rw_mutex = os_rw_mutex_alloc();
|
||||||
|
dasm_shared->entity_map_stripes.v[idx].cv = os_condition_variable_alloc();
|
||||||
|
}
|
||||||
|
dasm_shared->u2d_ring_mutex = os_mutex_alloc();
|
||||||
|
dasm_shared->u2d_ring_cv = os_condition_variable_alloc();
|
||||||
|
dasm_shared->u2d_ring_size = KB(64);
|
||||||
|
dasm_shared->u2d_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2d_ring_size);
|
||||||
|
dasm_shared->decode_thread_count = Max(1, os_logical_core_count()-1);
|
||||||
|
dasm_shared->decode_threads = push_array(arena, OS_Handle, dasm_shared->decode_thread_count);
|
||||||
|
for(U64 idx = 0; idx < dasm_shared->decode_thread_count; idx += 1)
|
||||||
|
{
|
||||||
|
dasm_shared->decode_threads[idx] = os_launch_thread(dasm_decode_thread_entry_point, (void *)idx, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Basic Helpers
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
dasm_hash_from_string(String8 string)
|
||||||
|
{
|
||||||
|
U64 result = 5381;
|
||||||
|
for(U64 i = 0; i < string.size; i += 1)
|
||||||
|
{
|
||||||
|
result = ((result << 5) + result) + string.str[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Instruction Type Functions
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst)
|
||||||
|
{
|
||||||
|
DASM_InstChunkNode *node = list->last;
|
||||||
|
if(node == 0 || node->count >= node->cap)
|
||||||
|
{
|
||||||
|
node = push_array(arena, DASM_InstChunkNode, 1);
|
||||||
|
node->v = push_array_no_zero(arena, DASM_Inst, cap);
|
||||||
|
node->cap = cap;
|
||||||
|
SLLQueuePush(list->first, list->last, node);
|
||||||
|
list->node_count += 1;
|
||||||
|
}
|
||||||
|
MemoryCopyStruct(&node->v[node->count], inst);
|
||||||
|
node->count += 1;
|
||||||
|
list->inst_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DASM_InstArray
|
||||||
|
dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list)
|
||||||
|
{
|
||||||
|
DASM_InstArray array = {0};
|
||||||
|
array.count = list->inst_count;
|
||||||
|
array.v = push_array_no_zero(arena, DASM_Inst, array.count);
|
||||||
|
U64 idx = 0;
|
||||||
|
for(DASM_InstChunkNode *n = list->first; n != 0; n = n->next)
|
||||||
|
{
|
||||||
|
MemoryCopy(array.v+idx, n->v, sizeof(DASM_Inst)*n->count);
|
||||||
|
idx += n->count;
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off)
|
||||||
|
{
|
||||||
|
U64 result = 0;
|
||||||
|
for(U64 idx = 0; idx < array->count; idx += 1)
|
||||||
|
{
|
||||||
|
if(array->v[idx].off == off)
|
||||||
|
{
|
||||||
|
result = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx)
|
||||||
|
{
|
||||||
|
U64 off = 0;
|
||||||
|
if(idx < array->count)
|
||||||
|
{
|
||||||
|
off = array->v[idx].off;
|
||||||
|
}
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Disassembly Functions
|
||||||
|
|
||||||
|
#include "third_party/udis86/config.h"
|
||||||
|
#include "third_party/udis86/udis86.h"
|
||||||
|
#include "third_party/udis86/libudis86/decode.c"
|
||||||
|
#include "third_party/udis86/libudis86/itab.c"
|
||||||
|
#include "third_party/udis86/libudis86/syn-att.c"
|
||||||
|
#include "third_party/udis86/libudis86/syn-intel.c"
|
||||||
|
#include "third_party/udis86/libudis86/syn.c"
|
||||||
|
#include "third_party/udis86/libudis86/udis86.c"
|
||||||
|
|
||||||
|
internal DASM_InstChunkList
|
||||||
|
dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data)
|
||||||
|
{
|
||||||
|
DASM_InstChunkList inst_list = {0};
|
||||||
|
switch(arch)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
|
||||||
|
//- rjf: x86/x64 decoding
|
||||||
|
case Architecture_x64:
|
||||||
|
case Architecture_x86:
|
||||||
|
{
|
||||||
|
// rjf: grab context
|
||||||
|
struct ud udc;
|
||||||
|
ud_init(&udc);
|
||||||
|
ud_set_mode(&udc, bit_size_from_arch(arch));
|
||||||
|
ud_set_pc(&udc, addr);
|
||||||
|
ud_set_input_buffer(&udc, data.str, data.size);
|
||||||
|
ud_set_vendor(&udc, UD_VENDOR_ANY);
|
||||||
|
ud_set_syntax(&udc, UD_SYN_INTEL);
|
||||||
|
|
||||||
|
// rjf: disassemble
|
||||||
|
U64 byte_process_start_off = 0;
|
||||||
|
for(U64 off = 0; off < data.size;)
|
||||||
|
{
|
||||||
|
// rjf: disassemble one instruction
|
||||||
|
U64 size = ud_disassemble(&udc);
|
||||||
|
if(size == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: analyze
|
||||||
|
struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0);
|
||||||
|
U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0;
|
||||||
|
|
||||||
|
// rjf: push
|
||||||
|
String8 string = push_str8f(arena, "%s", udc.asm_buf);
|
||||||
|
DASM_Inst inst = {string, off, rel_voff};
|
||||||
|
dasm_inst_chunk_list_push(arena, &inst_list, 1024, &inst);
|
||||||
|
|
||||||
|
// rjf: increment
|
||||||
|
off += size;
|
||||||
|
if(bytes_processed_counter != 0 && (off-byte_process_start_off >= 1000))
|
||||||
|
{
|
||||||
|
ins_atomic_u64_add_eval(bytes_processed_counter, (off-byte_process_start_off));
|
||||||
|
byte_process_start_off = off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
return inst_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Cache Lookups
|
||||||
|
|
||||||
|
//- rjf: opening handles & correllation with module
|
||||||
|
|
||||||
|
internal DASM_Handle
|
||||||
|
dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range)
|
||||||
|
{
|
||||||
|
DASM_Handle result = {0};
|
||||||
|
if(machine != 0 && process.u64[0] != 0)
|
||||||
|
{
|
||||||
|
U64 hash = dasm_hash_from_string(str8_struct(&process));
|
||||||
|
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||||
|
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||||
|
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||||
|
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||||
|
OS_MutexScopeW(stripe->rw_mutex)
|
||||||
|
{
|
||||||
|
DASM_Entity *entity = 0;
|
||||||
|
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||||
|
{
|
||||||
|
if(e->machine_id == machine &&
|
||||||
|
ctrl_handle_match(e->process, process) &&
|
||||||
|
MemoryMatchStruct(&e->vaddr_range, &vaddr_range))
|
||||||
|
{
|
||||||
|
entity = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(entity == 0)
|
||||||
|
{
|
||||||
|
entity = push_array(stripe->arena, DASM_Entity, 1);
|
||||||
|
SLLQueuePush(slot->first, slot->last, entity);
|
||||||
|
entity->machine_id = machine;
|
||||||
|
entity->process = process;
|
||||||
|
entity->vaddr_range= vaddr_range;
|
||||||
|
entity->id = ins_atomic_u64_inc_eval(&dasm_shared->entity_id_gen);
|
||||||
|
entity->decode_inst_arena = arena_alloc__sized(MB(256), KB(64));
|
||||||
|
entity->decode_string_arena = arena_alloc__sized(GB(1), KB(64));
|
||||||
|
}
|
||||||
|
result.u64[0] = hash;
|
||||||
|
result.u64[1] = entity->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: asking for top-level info of a handle
|
||||||
|
|
||||||
|
internal DASM_BinaryInfo
|
||||||
|
dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle)
|
||||||
|
{
|
||||||
|
DASM_BinaryInfo info = {0};
|
||||||
|
{
|
||||||
|
U64 hash = handle.u64[0];
|
||||||
|
U64 id = handle.u64[1];
|
||||||
|
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||||
|
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||||
|
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||||
|
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||||
|
OS_MutexScopeR(stripe->rw_mutex)
|
||||||
|
{
|
||||||
|
DASM_Entity *entity = 0;
|
||||||
|
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||||
|
{
|
||||||
|
if(e->id == id)
|
||||||
|
{
|
||||||
|
entity = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(entity != 0)
|
||||||
|
{
|
||||||
|
info.machine_id = entity->machine_id;
|
||||||
|
info.process = entity->process;
|
||||||
|
info.vaddr_range = entity->vaddr_range;
|
||||||
|
info.bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed);
|
||||||
|
info.bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: asking for decoded instructions
|
||||||
|
|
||||||
|
internal DASM_InstArray
|
||||||
|
dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us)
|
||||||
|
{
|
||||||
|
DASM_InstArray result = {0};
|
||||||
|
if(handle.u64[0] != 0 || handle.u64[1] != 0)
|
||||||
|
{
|
||||||
|
U64 hash = handle.u64[0];
|
||||||
|
U64 id = handle.u64[1];
|
||||||
|
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||||
|
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||||
|
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||||
|
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||||
|
B32 sent = 0;
|
||||||
|
OS_MutexScopeR(stripe->rw_mutex) for(;;)
|
||||||
|
{
|
||||||
|
DASM_Entity *entity = 0;
|
||||||
|
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||||
|
{
|
||||||
|
if(e->id == id)
|
||||||
|
{
|
||||||
|
entity = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
U64 last_time_sent_us = 0;
|
||||||
|
if(entity != 0)
|
||||||
|
{
|
||||||
|
U64 bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed);
|
||||||
|
U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
|
||||||
|
last_time_sent_us = ins_atomic_u64_eval(&entity->last_time_sent_us);
|
||||||
|
if(bytes_processed == bytes_to_process && bytes_processed != 0)
|
||||||
|
{
|
||||||
|
result.count = entity->decode_inst_array.count;
|
||||||
|
result.v = push_array_no_zero(arena, DASM_Inst, result.count);
|
||||||
|
MemoryCopy(result.v, entity->decode_inst_array.v, sizeof(DASM_Inst)*result.count);
|
||||||
|
for(U64 idx = 0; idx < result.count; idx += 1)
|
||||||
|
{
|
||||||
|
result.v[idx].string = push_str8_copy(arena, result.v[idx].string);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!sent && entity != 0 && last_time_sent_us+10000 <= os_now_microseconds())
|
||||||
|
{
|
||||||
|
DASM_DecodeRequest req = {handle};
|
||||||
|
sent = dasm_u2d_enqueue_request(&req, endt_us);
|
||||||
|
ins_atomic_u64_eval_assign(&entity->last_time_sent_us, os_now_microseconds());
|
||||||
|
}
|
||||||
|
if(os_now_microseconds() >= endt_us)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Decode Threads
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us)
|
||||||
|
{
|
||||||
|
B32 result = 0;
|
||||||
|
OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;)
|
||||||
|
{
|
||||||
|
U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos);
|
||||||
|
U64 available_size = (dasm_shared->u2d_ring_size-unconsumed_size);
|
||||||
|
if(available_size >= sizeof(*req))
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
dasm_shared->u2d_ring_write_pos += ring_write_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_write_pos, req);
|
||||||
|
dasm_shared->u2d_ring_write_pos += 7;
|
||||||
|
dasm_shared->u2d_ring_write_pos -= dasm_shared->u2d_ring_write_pos%8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(os_now_microseconds() >= endt_us)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, endt_us);
|
||||||
|
}
|
||||||
|
if(result)
|
||||||
|
{
|
||||||
|
os_condition_variable_broadcast(dasm_shared->u2d_ring_cv);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DASM_DecodeRequest
|
||||||
|
dasm_u2d_dequeue_request(void)
|
||||||
|
{
|
||||||
|
DASM_DecodeRequest req = {0};
|
||||||
|
OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;)
|
||||||
|
{
|
||||||
|
U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos);
|
||||||
|
if(unconsumed_size >= sizeof(DASM_DecodeRequest))
|
||||||
|
{
|
||||||
|
dasm_shared->u2d_ring_read_pos += ring_read_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_read_pos, &req);
|
||||||
|
dasm_shared->u2d_ring_read_pos += 7;
|
||||||
|
dasm_shared->u2d_ring_read_pos -= dasm_shared->u2d_ring_read_pos%8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, max_U64);
|
||||||
|
}
|
||||||
|
os_condition_variable_broadcast(dasm_shared->u2d_ring_cv);
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dasm_decode_thread_entry_point(void *p)
|
||||||
|
{
|
||||||
|
TCTX tctx_;
|
||||||
|
tctx_init_and_equip(&tctx_);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(0, 0);
|
||||||
|
|
||||||
|
//- rjf: get next request & unpack
|
||||||
|
DASM_DecodeRequest req = dasm_u2d_dequeue_request();
|
||||||
|
DASM_Handle handle = req.handle;
|
||||||
|
U64 hash = handle.u64[0];
|
||||||
|
U64 id = handle.u64[1];
|
||||||
|
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||||
|
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||||
|
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||||
|
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||||
|
|
||||||
|
//- rjf: request -> ctrl info
|
||||||
|
B32 is_first_to_task = 0;
|
||||||
|
CTRL_MachineID ctrl_machine_id = 0;
|
||||||
|
CTRL_Handle ctrl_process = {0};
|
||||||
|
Rng1U64 vaddr_range = {0};
|
||||||
|
Architecture arch = Architecture_Null;
|
||||||
|
U64 *bytes_processed_counter = 0;
|
||||||
|
OS_MutexScopeR(stripe->rw_mutex)
|
||||||
|
{
|
||||||
|
DASM_Entity *entity = 0;
|
||||||
|
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||||
|
{
|
||||||
|
if(e->id == id)
|
||||||
|
{
|
||||||
|
entity = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(entity != 0)
|
||||||
|
{
|
||||||
|
U64 initial_working_count = ins_atomic_u32_eval_cond_assign(&entity->working_count, 1, 0);
|
||||||
|
if(initial_working_count == 0)
|
||||||
|
{
|
||||||
|
is_first_to_task = 1;
|
||||||
|
ctrl_machine_id = entity->machine_id;
|
||||||
|
ctrl_process = entity->process;
|
||||||
|
vaddr_range = entity->vaddr_range;
|
||||||
|
arch = ctrl_arch_from_handle(ctrl_machine_id, ctrl_process);
|
||||||
|
bytes_processed_counter = &entity->bytes_processed;
|
||||||
|
U64 bytes_to_process = dim_1u64(vaddr_range);
|
||||||
|
ins_atomic_u64_eval_assign(&entity->bytes_processed, 0);
|
||||||
|
ins_atomic_u64_eval_assign(&entity->bytes_to_process, bytes_to_process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: bad handle or machine id -> bad task
|
||||||
|
B32 good_task = (is_first_to_task && ctrl_process.u64[0] != 0 && ctrl_machine_id != 0 && arch != Architecture_Null && bytes_processed_counter != 0);
|
||||||
|
|
||||||
|
//- rjf: good task -> clear entity's info
|
||||||
|
if(good_task)
|
||||||
|
{
|
||||||
|
OS_MutexScopeW(stripe->rw_mutex)
|
||||||
|
{
|
||||||
|
DASM_Entity *entity = 0;
|
||||||
|
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||||
|
{
|
||||||
|
if(e->id == id)
|
||||||
|
{
|
||||||
|
entity = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(entity != 0)
|
||||||
|
{
|
||||||
|
arena_clear(entity->decode_inst_arena);
|
||||||
|
arena_clear(entity->decode_string_arena);
|
||||||
|
MemoryZeroStruct(&entity->decode_inst_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: good task -> read process memory & decode instructions - stop each
|
||||||
|
// 4k and write into cache, so users can read incremental results
|
||||||
|
if(good_task)
|
||||||
|
{
|
||||||
|
U64 chunk_size = KB(4);
|
||||||
|
for(U64 off = 0; vaddr_range.min+off < vaddr_range.max; off += chunk_size)
|
||||||
|
{
|
||||||
|
Rng1U64 chunk_vaddr_range = r1u64(vaddr_range.min+off, vaddr_range.min+off+chunk_size);
|
||||||
|
chunk_vaddr_range.min = ClampTop(chunk_vaddr_range.min, vaddr_range.max);
|
||||||
|
chunk_vaddr_range.max = ClampTop(chunk_vaddr_range.max, vaddr_range.max);
|
||||||
|
|
||||||
|
//- rjf: read next chunk & decode
|
||||||
|
String8 data = {0};
|
||||||
|
DASM_InstChunkList inst_list = {0};
|
||||||
|
if(good_task)
|
||||||
|
{
|
||||||
|
data.str = push_array_no_zero(scratch.arena, U8, dim_1u64(chunk_vaddr_range));
|
||||||
|
data.size = ctrl_process_read(ctrl_machine_id, ctrl_process, chunk_vaddr_range, data.str);
|
||||||
|
if(data.size != 0)
|
||||||
|
{
|
||||||
|
inst_list = dasm_inst_chunk_list_from_arch_addr_data(scratch.arena, bytes_processed_counter, arch, chunk_vaddr_range.min, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: write into cache
|
||||||
|
{
|
||||||
|
OS_MutexScopeW(stripe->rw_mutex)
|
||||||
|
{
|
||||||
|
DASM_Entity *entity = 0;
|
||||||
|
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||||
|
{
|
||||||
|
if(e->id == id)
|
||||||
|
{
|
||||||
|
entity = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(entity != 0)
|
||||||
|
{
|
||||||
|
DASM_Inst *new_chunk_base = push_array(entity->decode_inst_arena, DASM_Inst, inst_list.inst_count);
|
||||||
|
U64 off = 0;
|
||||||
|
for(DASM_InstChunkNode *node = inst_list.first; node != 0; node = node->next)
|
||||||
|
{
|
||||||
|
MemoryCopy(new_chunk_base+off, node->v, sizeof(DASM_Inst)*node->count);
|
||||||
|
off += node->count;
|
||||||
|
}
|
||||||
|
for(U64 idx = 0; idx < inst_list.inst_count; idx += 1)
|
||||||
|
{
|
||||||
|
new_chunk_base[idx].string = push_str8_copy(entity->decode_string_arena, new_chunk_base[idx].string);
|
||||||
|
}
|
||||||
|
entity->decode_inst_array.count += inst_list.inst_count;
|
||||||
|
if(entity->decode_inst_array.v == 0)
|
||||||
|
{
|
||||||
|
entity->decode_inst_array.v = new_chunk_base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os_condition_variable_broadcast(stripe->cv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: mark task as complete
|
||||||
|
if(good_task)
|
||||||
|
{
|
||||||
|
OS_MutexScopeR(stripe->rw_mutex)
|
||||||
|
{
|
||||||
|
DASM_Entity *entity = 0;
|
||||||
|
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||||
|
{
|
||||||
|
if(e->id == id)
|
||||||
|
{
|
||||||
|
entity = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(entity != 0)
|
||||||
|
{
|
||||||
|
U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
|
||||||
|
ins_atomic_u64_eval_assign(&entity->bytes_processed, bytes_to_process);
|
||||||
|
ins_atomic_u64_eval_assign(&entity->working_count, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
}
|
||||||
+206
@@ -0,0 +1,206 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef DASM_H
|
||||||
|
#define DASM_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Handle Type
|
||||||
|
|
||||||
|
typedef struct DASM_Handle DASM_Handle;
|
||||||
|
struct DASM_Handle
|
||||||
|
{
|
||||||
|
U64 u64[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Instruction Types
|
||||||
|
|
||||||
|
typedef struct DASM_Inst DASM_Inst;
|
||||||
|
struct DASM_Inst
|
||||||
|
{
|
||||||
|
String8 string;
|
||||||
|
U64 off;
|
||||||
|
U64 addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DASM_InstChunkNode DASM_InstChunkNode;
|
||||||
|
struct DASM_InstChunkNode
|
||||||
|
{
|
||||||
|
DASM_InstChunkNode *next;
|
||||||
|
DASM_Inst *v;
|
||||||
|
U64 cap;
|
||||||
|
U64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DASM_InstChunkList DASM_InstChunkList;
|
||||||
|
struct DASM_InstChunkList
|
||||||
|
{
|
||||||
|
DASM_InstChunkNode *first;
|
||||||
|
DASM_InstChunkNode *last;
|
||||||
|
U64 node_count;
|
||||||
|
U64 inst_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DASM_InstArray DASM_InstArray;
|
||||||
|
struct DASM_InstArray
|
||||||
|
{
|
||||||
|
DASM_Inst *v;
|
||||||
|
U64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Striped Access Types
|
||||||
|
|
||||||
|
typedef struct DASM_Stripe DASM_Stripe;
|
||||||
|
struct DASM_Stripe
|
||||||
|
{
|
||||||
|
Arena *arena;
|
||||||
|
OS_Handle cv;
|
||||||
|
OS_Handle rw_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DASM_StripeTable DASM_StripeTable;
|
||||||
|
struct DASM_StripeTable
|
||||||
|
{
|
||||||
|
U64 count;
|
||||||
|
DASM_Stripe *v;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Entity Cache Types
|
||||||
|
|
||||||
|
typedef struct DASM_Entity DASM_Entity;
|
||||||
|
struct DASM_Entity
|
||||||
|
{
|
||||||
|
DASM_Entity *next;
|
||||||
|
|
||||||
|
// rjf: key info
|
||||||
|
CTRL_MachineID machine_id;
|
||||||
|
CTRL_Handle process;
|
||||||
|
Rng1U64 vaddr_range;
|
||||||
|
U64 id;
|
||||||
|
|
||||||
|
// rjf: top-level info
|
||||||
|
U64 last_time_sent_us;
|
||||||
|
U64 working_count;
|
||||||
|
U64 bytes_processed;
|
||||||
|
U64 bytes_to_process;
|
||||||
|
|
||||||
|
// rjf: decoded instruction data
|
||||||
|
Arena *decode_inst_arena;
|
||||||
|
Arena *decode_string_arena;
|
||||||
|
DASM_InstArray decode_inst_array;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DASM_EntitySlot DASM_EntitySlot;
|
||||||
|
struct DASM_EntitySlot
|
||||||
|
{
|
||||||
|
DASM_Entity *first;
|
||||||
|
DASM_Entity *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DASM_EntityMap DASM_EntityMap;
|
||||||
|
struct DASM_EntityMap
|
||||||
|
{
|
||||||
|
U64 slots_count;
|
||||||
|
DASM_EntitySlot *slots;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Introspection Info Types
|
||||||
|
|
||||||
|
typedef struct DASM_BinaryInfo DASM_BinaryInfo;
|
||||||
|
struct DASM_BinaryInfo
|
||||||
|
{
|
||||||
|
CTRL_MachineID machine_id;
|
||||||
|
CTRL_Handle process;
|
||||||
|
Rng1U64 vaddr_range;
|
||||||
|
U64 bytes_processed;
|
||||||
|
U64 bytes_to_process;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Decode Request Types
|
||||||
|
|
||||||
|
typedef struct DASM_DecodeRequest DASM_DecodeRequest;
|
||||||
|
struct DASM_DecodeRequest
|
||||||
|
{
|
||||||
|
DASM_Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Shared State
|
||||||
|
|
||||||
|
typedef struct DASM_Shared DASM_Shared;
|
||||||
|
struct DASM_Shared
|
||||||
|
{
|
||||||
|
Arena *arena;
|
||||||
|
|
||||||
|
// rjf: entity table
|
||||||
|
DASM_EntityMap entity_map;
|
||||||
|
DASM_StripeTable entity_map_stripes;
|
||||||
|
U64 entity_id_gen;
|
||||||
|
|
||||||
|
// rjf: user -> decode ring
|
||||||
|
OS_Handle u2d_ring_mutex;
|
||||||
|
OS_Handle u2d_ring_cv;
|
||||||
|
U64 u2d_ring_size;
|
||||||
|
U8 *u2d_ring_base;
|
||||||
|
U64 u2d_ring_write_pos;
|
||||||
|
U64 u2d_ring_read_pos;
|
||||||
|
|
||||||
|
// rjf: decode threads
|
||||||
|
U64 decode_thread_count;
|
||||||
|
OS_Handle *decode_threads;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Globals
|
||||||
|
|
||||||
|
global DASM_Shared *dasm_shared = 0;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Main Layer Initialization
|
||||||
|
|
||||||
|
internal void dasm_init(void);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Basic Helpers
|
||||||
|
|
||||||
|
internal U64 dasm_hash_from_string(String8 string);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Instruction Type Functions
|
||||||
|
|
||||||
|
internal void dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst);
|
||||||
|
internal DASM_InstArray dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list);
|
||||||
|
internal U64 dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off);
|
||||||
|
internal U64 dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Disassembly Functions
|
||||||
|
|
||||||
|
internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Cache Lookups
|
||||||
|
|
||||||
|
//- rjf: opening handles & correllation with module
|
||||||
|
internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range);
|
||||||
|
|
||||||
|
//- rjf: asking for top-level info of a handle
|
||||||
|
internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle);
|
||||||
|
|
||||||
|
//- rjf: asking for decoded instructions
|
||||||
|
internal DASM_InstArray dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Decode Threads
|
||||||
|
|
||||||
|
internal B32 dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us);
|
||||||
|
internal DASM_DecodeRequest dasm_u2d_dequeue_request(void);
|
||||||
|
|
||||||
|
internal void dasm_decode_thread_entry_point(void *p);
|
||||||
|
|
||||||
|
#endif //DASM_H
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Built-In Command Tables
|
|
||||||
|
|
||||||
@table(name ui_vis ipc_docs_vis text_pt_vis text_rng_vis q_expr q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags ctx_filter)
|
|
||||||
// / | | | | | | \___ _________________________________/ | | | | | |
|
|
||||||
// / | | | | | | \ / | | | | | |
|
|
||||||
D_CmdTable: // | | | | | | | | | | | | | |
|
|
||||||
{
|
|
||||||
//- rjf: low-level target control operations
|
|
||||||
{LaunchAndRun 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" }
|
|
||||||
{LaunchAndStepInto 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" }
|
|
||||||
{Kill 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" }
|
|
||||||
{KillAll 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" }
|
|
||||||
{Detach 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" }
|
|
||||||
{Continue 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" }
|
|
||||||
{StepIntoInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" }
|
|
||||||
{StepOverInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" }
|
|
||||||
{StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
|
|
||||||
{StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
|
|
||||||
{StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" "" }
|
|
||||||
{Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
|
|
||||||
{SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
|
|
||||||
{SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
|
|
||||||
|
|
||||||
//- rjf: high-level composite target control operations
|
|
||||||
{RunToLine 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "$text_pt," }
|
|
||||||
{Run 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" }
|
|
||||||
{Restart 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" }
|
|
||||||
{StepInto 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" }
|
|
||||||
{StepOver 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" }
|
|
||||||
|
|
||||||
//- rjf: debug control context management operations
|
|
||||||
{FreezeThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" }
|
|
||||||
{ThawThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" }
|
|
||||||
{FreezeProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" }
|
|
||||||
{ThawProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" }
|
|
||||||
{FreezeMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" }
|
|
||||||
{ThawMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" }
|
|
||||||
{FreezeLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" }
|
|
||||||
{ThawLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" }
|
|
||||||
{FreezeEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" }
|
|
||||||
{ThawEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" }
|
|
||||||
|
|
||||||
//- rjf: entity decoration
|
|
||||||
{SetEntityColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
|
|
||||||
{SetEntityName 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
|
|
||||||
|
|
||||||
//- 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." "" "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum D_CmdKind:
|
|
||||||
{
|
|
||||||
Null,
|
|
||||||
@expand(D_CmdTable, a) `$(a.name)`,
|
|
||||||
COUNT,
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Developer Toggles
|
|
||||||
|
|
||||||
@table(name)
|
|
||||||
D_DevToggleTable:
|
|
||||||
{
|
|
||||||
{always_refresh}
|
|
||||||
{simulate_lag}
|
|
||||||
{draw_ui_text_pos}
|
|
||||||
{draw_ui_focus_debug}
|
|
||||||
{draw_ui_box_heatmap}
|
|
||||||
{eval_compiler_tooltips}
|
|
||||||
{eval_watch_key_tooltips}
|
|
||||||
{cmd_context_tooltips}
|
|
||||||
{updating_indicator}
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen
|
|
||||||
{
|
|
||||||
@expand(D_DevToggleTable a) `global B32 DEV_$(a.name) = 0;`
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen
|
|
||||||
{
|
|
||||||
`struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =`;
|
|
||||||
`{`;
|
|
||||||
@expand(D_DevToggleTable a) `{&DEV_$(a.name), str8_lit_comp("$(a.name)")},`
|
|
||||||
`};`;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,438 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DBG_ENGINE_CORE_H
|
|
||||||
#define DBG_ENGINE_CORE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Tick Input Types
|
|
||||||
|
|
||||||
typedef struct D_Target D_Target;
|
|
||||||
struct D_Target
|
|
||||||
{
|
|
||||||
String8 exe;
|
|
||||||
String8 args;
|
|
||||||
String8 working_directory;
|
|
||||||
String8 custom_entry_point_name;
|
|
||||||
String8 stdout_path;
|
|
||||||
String8 stderr_path;
|
|
||||||
String8 stdin_path;
|
|
||||||
B32 debug_subprocesses;
|
|
||||||
String8List env;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_TargetArray D_TargetArray;
|
|
||||||
struct D_TargetArray
|
|
||||||
{
|
|
||||||
D_Target *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef U32 D_BreakpointFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
D_BreakpointFlag_BreakOnWrite = (1<<0),
|
|
||||||
D_BreakpointFlag_BreakOnRead = (1<<1),
|
|
||||||
D_BreakpointFlag_BreakOnExecute = (1<<2),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_Breakpoint D_Breakpoint;
|
|
||||||
struct D_Breakpoint
|
|
||||||
{
|
|
||||||
D_BreakpointFlags flags;
|
|
||||||
U64 id;
|
|
||||||
String8 file_path;
|
|
||||||
TxtPt pt;
|
|
||||||
String8 vaddr_expr;
|
|
||||||
String8 condition;
|
|
||||||
U64 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_BreakpointArray D_BreakpointArray;
|
|
||||||
struct D_BreakpointArray
|
|
||||||
{
|
|
||||||
D_Breakpoint *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_PathMap D_PathMap;
|
|
||||||
struct D_PathMap
|
|
||||||
{
|
|
||||||
String8 src;
|
|
||||||
String8 dst;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_PathMapArray D_PathMapArray;
|
|
||||||
struct D_PathMapArray
|
|
||||||
{
|
|
||||||
D_PathMap *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Trap Nets
|
|
||||||
|
|
||||||
typedef struct D_TrapNet D_TrapNet;
|
|
||||||
struct D_TrapNet
|
|
||||||
{
|
|
||||||
CTRL_TrapList traps;
|
|
||||||
B32 good_line_info;
|
|
||||||
B32 good_read;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Tick Output Types
|
|
||||||
|
|
||||||
typedef enum D_EventKind
|
|
||||||
{
|
|
||||||
D_EventKind_Null,
|
|
||||||
D_EventKind_ModuleLoad,
|
|
||||||
D_EventKind_ProcessEnd,
|
|
||||||
D_EventKind_Stop,
|
|
||||||
D_EventKind_COUNT
|
|
||||||
}
|
|
||||||
D_EventKind;
|
|
||||||
|
|
||||||
typedef enum D_EventCause
|
|
||||||
{
|
|
||||||
D_EventCause_Null,
|
|
||||||
D_EventCause_UserBreakpoint,
|
|
||||||
D_EventCause_Halt,
|
|
||||||
D_EventCause_SoftHalt,
|
|
||||||
D_EventCause_COUNT
|
|
||||||
}
|
|
||||||
D_EventCause;
|
|
||||||
|
|
||||||
typedef struct D_Event D_Event;
|
|
||||||
struct D_Event
|
|
||||||
{
|
|
||||||
D_EventKind kind;
|
|
||||||
D_EventCause cause;
|
|
||||||
CTRL_Handle module;
|
|
||||||
CTRL_Handle thread;
|
|
||||||
U64 vaddr;
|
|
||||||
U64 code;
|
|
||||||
U64 id;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_EventNode D_EventNode;
|
|
||||||
struct D_EventNode
|
|
||||||
{
|
|
||||||
D_EventNode *next;
|
|
||||||
D_Event v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_EventList D_EventList;
|
|
||||||
struct D_EventList
|
|
||||||
{
|
|
||||||
D_EventNode *first;
|
|
||||||
D_EventNode *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Line Info Types
|
|
||||||
|
|
||||||
typedef struct D_Line D_Line;
|
|
||||||
struct D_Line
|
|
||||||
{
|
|
||||||
String8 file_path;
|
|
||||||
TxtPt pt;
|
|
||||||
Rng1U64 voff_range;
|
|
||||||
DI_Key dbgi_key;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_LineNode D_LineNode;
|
|
||||||
struct D_LineNode
|
|
||||||
{
|
|
||||||
D_LineNode *next;
|
|
||||||
D_Line v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_LineList D_LineList;
|
|
||||||
struct D_LineList
|
|
||||||
{
|
|
||||||
D_LineNode *first;
|
|
||||||
D_LineNode *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_LineListArray D_LineListArray;
|
|
||||||
struct D_LineListArray
|
|
||||||
{
|
|
||||||
D_LineList *v;
|
|
||||||
U64 count;
|
|
||||||
DI_KeyList dbgi_keys;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Debug Engine Control Communication Types
|
|
||||||
|
|
||||||
typedef enum D_RunKind
|
|
||||||
{
|
|
||||||
D_RunKind_Run,
|
|
||||||
D_RunKind_SingleStep,
|
|
||||||
D_RunKind_Step,
|
|
||||||
D_RunKind_COUNT
|
|
||||||
}
|
|
||||||
D_RunKind;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Generated Code
|
|
||||||
|
|
||||||
#include "dbg_engine/generated/dbg_engine.meta.h"
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Command Types
|
|
||||||
|
|
||||||
typedef struct D_CmdParams D_CmdParams;
|
|
||||||
struct D_CmdParams
|
|
||||||
{
|
|
||||||
CTRL_Handle machine;
|
|
||||||
CTRL_Handle process;
|
|
||||||
CTRL_Handle thread;
|
|
||||||
CTRL_Handle entity;
|
|
||||||
String8 string;
|
|
||||||
String8 file_path;
|
|
||||||
TxtPt cursor;
|
|
||||||
U64 vaddr;
|
|
||||||
B32 prefer_disasm;
|
|
||||||
U32 pid;
|
|
||||||
U32 rgba;
|
|
||||||
D_TargetArray targets;
|
|
||||||
U64 retry_idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_Cmd D_Cmd;
|
|
||||||
struct D_Cmd
|
|
||||||
{
|
|
||||||
D_CmdKind kind;
|
|
||||||
D_CmdParams params;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_CmdNode D_CmdNode;
|
|
||||||
struct D_CmdNode
|
|
||||||
{
|
|
||||||
D_CmdNode *next;
|
|
||||||
D_CmdNode *prev;
|
|
||||||
D_Cmd cmd;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_CmdList D_CmdList;
|
|
||||||
struct D_CmdList
|
|
||||||
{
|
|
||||||
D_CmdNode *first;
|
|
||||||
D_CmdNode *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Main State Caches
|
|
||||||
|
|
||||||
//- rjf: per-run tls-base-vaddr cache
|
|
||||||
|
|
||||||
typedef struct D_RunTLSBaseCacheNode D_RunTLSBaseCacheNode;
|
|
||||||
struct D_RunTLSBaseCacheNode
|
|
||||||
{
|
|
||||||
D_RunTLSBaseCacheNode *hash_next;
|
|
||||||
CTRL_Handle process;
|
|
||||||
U64 root_vaddr;
|
|
||||||
U64 rip_vaddr;
|
|
||||||
U64 tls_base_vaddr;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_RunTLSBaseCacheSlot D_RunTLSBaseCacheSlot;
|
|
||||||
struct D_RunTLSBaseCacheSlot
|
|
||||||
{
|
|
||||||
D_RunTLSBaseCacheNode *first;
|
|
||||||
D_RunTLSBaseCacheNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_RunTLSBaseCache D_RunTLSBaseCache;
|
|
||||||
struct D_RunTLSBaseCache
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
U64 slots_count;
|
|
||||||
D_RunTLSBaseCacheSlot *slots;
|
|
||||||
};
|
|
||||||
|
|
||||||
//- rjf: per-run locals cache
|
|
||||||
|
|
||||||
typedef struct D_RunLocalsCacheNode D_RunLocalsCacheNode;
|
|
||||||
struct D_RunLocalsCacheNode
|
|
||||||
{
|
|
||||||
D_RunLocalsCacheNode *hash_next;
|
|
||||||
DI_Key dbgi_key;
|
|
||||||
U64 voff;
|
|
||||||
E_String2NumMap *locals_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_RunLocalsCacheSlot D_RunLocalsCacheSlot;
|
|
||||||
struct D_RunLocalsCacheSlot
|
|
||||||
{
|
|
||||||
D_RunLocalsCacheNode *first;
|
|
||||||
D_RunLocalsCacheNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_RunLocalsCache D_RunLocalsCache;
|
|
||||||
struct D_RunLocalsCache
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
U64 table_size;
|
|
||||||
D_RunLocalsCacheSlot *table;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Main State Types
|
|
||||||
|
|
||||||
typedef struct D_State D_State;
|
|
||||||
struct D_State
|
|
||||||
{
|
|
||||||
// rjf: top-level state
|
|
||||||
Arena *arena;
|
|
||||||
U64 frame_index;
|
|
||||||
|
|
||||||
// rjf: commands
|
|
||||||
Arena *cmds_arena;
|
|
||||||
D_CmdList cmds;
|
|
||||||
|
|
||||||
// rjf: output log key
|
|
||||||
C_Key output_log_key;
|
|
||||||
|
|
||||||
// rjf: per-run caches
|
|
||||||
U64 tls_base_cache_reggen_idx;
|
|
||||||
U64 tls_base_cache_memgen_idx;
|
|
||||||
D_RunTLSBaseCache tls_base_caches[2];
|
|
||||||
U64 tls_base_cache_gen;
|
|
||||||
U64 locals_cache_reggen_idx;
|
|
||||||
D_RunLocalsCache locals_caches[2];
|
|
||||||
U64 locals_cache_gen;
|
|
||||||
U64 member_cache_reggen_idx;
|
|
||||||
D_RunLocalsCache member_caches[2];
|
|
||||||
U64 member_cache_gen;
|
|
||||||
|
|
||||||
// rjf: user -> ctrl driving state
|
|
||||||
Arena *ctrl_last_run_arena;
|
|
||||||
D_RunKind ctrl_last_run_kind;
|
|
||||||
U64 ctrl_last_run_frame_idx;
|
|
||||||
CTRL_Handle ctrl_last_run_thread_handle;
|
|
||||||
CTRL_RunFlags ctrl_last_run_flags;
|
|
||||||
CTRL_TrapList ctrl_last_run_traps;
|
|
||||||
D_BreakpointArray ctrl_last_run_extra_bps;
|
|
||||||
U128 ctrl_last_run_param_state_hash;
|
|
||||||
B32 ctrl_is_running;
|
|
||||||
B32 ctrl_thread_run_state;
|
|
||||||
B32 ctrl_soft_halt_issued;
|
|
||||||
Arena *ctrl_msg_arena;
|
|
||||||
CTRL_MsgList ctrl_msgs;
|
|
||||||
|
|
||||||
// rjf: ctrl -> user reading state
|
|
||||||
CTRL_EntityCtxRWStore *ctrl_entity_store;
|
|
||||||
Arena *ctrl_stop_arena;
|
|
||||||
CTRL_Event ctrl_last_stop_event;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
global D_State *d_state = 0;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Helpers
|
|
||||||
|
|
||||||
internal U64 d_hash_from_seed_string(U64 seed, String8 string);
|
|
||||||
internal U64 d_hash_from_string(String8 string);
|
|
||||||
internal U64 d_hash_from_seed_string__case_insensitive(U64 seed, String8 string);
|
|
||||||
internal U64 d_hash_from_string__case_insensitive(String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Breakpoints
|
|
||||||
|
|
||||||
internal D_BreakpointArray d_breakpoint_array_copy(Arena *arena, D_BreakpointArray *src);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Path Map Application
|
|
||||||
|
|
||||||
internal String8List d_possible_path_overrides_from_maps_path(Arena *arena, D_PathMapArray *path_maps, String8 file_path);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Debug Info Extraction Type Pure Functions
|
|
||||||
|
|
||||||
internal D_LineList d_line_list_copy(Arena *arena, D_LineList *list);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Command Type Functions
|
|
||||||
|
|
||||||
//- rjf: command parameters
|
|
||||||
internal D_CmdParams d_cmd_params_copy(Arena *arena, D_CmdParams *src);
|
|
||||||
|
|
||||||
//- rjf: command lists
|
|
||||||
internal void d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, D_CmdParams *params);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Stepping "Trap Net" Builders
|
|
||||||
|
|
||||||
internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread);
|
|
||||||
internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread);
|
|
||||||
internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Debug Info Lookups
|
|
||||||
|
|
||||||
//- rjf: voff -> line info
|
|
||||||
internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key dbgi_key, U64 voff);
|
|
||||||
|
|
||||||
//- rjf: file:line -> line info
|
|
||||||
// TODO(rjf): this depends on file path maps, needs to move
|
|
||||||
// TODO(rjf): need to clean this up & dedup
|
|
||||||
internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range);
|
|
||||||
internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range);
|
|
||||||
internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num);
|
|
||||||
internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Process/Thread/Module Info Lookups
|
|
||||||
|
|
||||||
internal U64 d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Target Controls
|
|
||||||
|
|
||||||
//- rjf: stopped info from the control thread
|
|
||||||
internal CTRL_Event d_ctrl_last_stop_event(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Main State Accessors/Mutators
|
|
||||||
|
|
||||||
//- rjf: frame data
|
|
||||||
internal U64 d_frame_index(void);
|
|
||||||
|
|
||||||
//- rjf: control state
|
|
||||||
internal D_RunKind d_ctrl_last_run_kind(void);
|
|
||||||
internal U64 d_ctrl_last_run_frame_idx(void);
|
|
||||||
internal B32 d_ctrl_targets_running(void);
|
|
||||||
|
|
||||||
//- rjf: active entity based queries
|
|
||||||
internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena);
|
|
||||||
|
|
||||||
//- rjf: per-run caches
|
|
||||||
internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread);
|
|
||||||
internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count);
|
|
||||||
internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr);
|
|
||||||
internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
|
|
||||||
internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
|
|
||||||
|
|
||||||
//- rjf: top-level command dispatch
|
|
||||||
internal void d_push_cmd(D_CmdKind kind, D_CmdParams *params);
|
|
||||||
#define d_cmd(kind, ...) d_push_cmd((kind), &(D_CmdParams){.thread = {0}, __VA_ARGS__})
|
|
||||||
|
|
||||||
//- rjf: command iteration
|
|
||||||
internal B32 d_next_cmd(D_Cmd **cmd);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Main Layer Top-Level Calls
|
|
||||||
|
|
||||||
internal void d_init(void);
|
|
||||||
internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]);
|
|
||||||
|
|
||||||
#endif // DBG_ENGINE_CORE_H
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#include "dbg_engine_core.c"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DBG_ENGINE_INC_H
|
|
||||||
#define DBG_ENGINE_INC_H
|
|
||||||
|
|
||||||
#include "dbg_engine_core.h"
|
|
||||||
|
|
||||||
#endif // DBG_ENGINE_INC_H
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
//- GENERATED CODE
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user