mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-12 23:31:38 -07:00
git normalize all files
This commit is contained in:
@@ -1,30 +1,30 @@
|
||||
name: builds
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build-windows-2022:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: build (vs 2022)
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
call build raddbg msvc debug || exit /b 1
|
||||
call build rdi_from_pdb msvc debug || exit /b 1
|
||||
call build rdi_from_dwarf msvc debug || exit /b 1
|
||||
call build rdi_dump msvc debug || exit /b 1
|
||||
call build raddbg clang debug || exit /b 1
|
||||
call build rdi_from_pdb clang debug || exit /b 1
|
||||
call build rdi_from_dwarf clang debug || exit /b 1
|
||||
call build rdi_dump clang debug || exit /b 1
|
||||
name: builds
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build-windows-2022:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: build (vs 2022)
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
call build raddbg msvc debug || exit /b 1
|
||||
call build rdi_from_pdb msvc debug || exit /b 1
|
||||
call build rdi_from_dwarf msvc debug || exit /b 1
|
||||
call build rdi_dump msvc debug || exit /b 1
|
||||
call build raddbg clang debug || exit /b 1
|
||||
call build rdi_from_pdb clang debug || exit /b 1
|
||||
call build rdi_from_dwarf clang debug || exit /b 1
|
||||
call build rdi_dump clang debug || exit /b 1
|
||||
|
||||
+3
-3
@@ -1,3 +1,3 @@
|
||||
/build/
|
||||
/local/
|
||||
*~
|
||||
/build/
|
||||
/local/
|
||||
*~
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
Copyright (c) 2024 Epic Games Tools
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Copyright (c) 2024 Epic Games Tools
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -1,327 +1,327 @@
|
||||
# The RAD Debugger Project
|
||||
|
||||
_**Note:** This README does not document usage instructions and tips for the
|
||||
debugger itself, and is intended as a technical overview of the project. The
|
||||
debugger's README, which includes usage instructions and tips, can be found
|
||||
packaged along with debugger releases, or within the `build` folder after a
|
||||
local copy has been built._
|
||||
|
||||
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
||||
plans to expand and port in the future. In the future we'll expand to also
|
||||
support native Linux debugging and DWARF debug info.
|
||||
|
||||
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
|
||||
with any information you can gather, like dump files (along with the build you
|
||||
used), instructions to reproduce, test executables, and so on.
|
||||
|
||||
You can download pre-built binaries for the debugger
|
||||
[here](https://github.com/EpicGames/raddebugger/releases).
|
||||
|
||||
The RAD Debugger project aims to simplify the debugger by simplifying and
|
||||
unifying the underlying debug info format. In that pursuit we've built the RAD
|
||||
Debug Info (RDI) format, which is what the debugger parses and uses. To work
|
||||
with existing toolchains, we convert PDB (and eventually PE/ELF files with
|
||||
embedded DWARF) into the RDI format on-demand.
|
||||
|
||||
The RDI format is currently specified in code, in the files within the
|
||||
`src/lib_rdi_format` folder. The other relevant folders for working with the
|
||||
format are:
|
||||
|
||||
- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info.
|
||||
- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase
|
||||
layer, or built as an executable with a command line interface frontend.
|
||||
- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter.
|
||||
- `rdi_dump`: Our RDI textual dumping utility.
|
||||
|
||||
## Development Setup Instructions
|
||||
|
||||
**Note: Currently, only x64 Windows development is supported.**
|
||||
|
||||
### 1. Installing the Required Tools (MSVC & Windows SDK)
|
||||
|
||||
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
|
||||
the Windows SDK and the MSVC compiler and linker.
|
||||
|
||||
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/).
|
||||
|
||||
### 2. Build Environment Setup
|
||||
|
||||
Building the codebase can be done in a terminal which is equipped with the
|
||||
ability to call either MSVC or Clang from command line.
|
||||
|
||||
This is generally done by calling `vcvarsall.bat x64`, which is included in the
|
||||
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
|
||||
you've installed the build tools, this command prompt may be easily located by
|
||||
searching for `Native` from the Windows Start Menu search.
|
||||
|
||||
You can ensure that the MSVC compiler is accessible from your command line by
|
||||
running:
|
||||
|
||||
```
|
||||
cl
|
||||
```
|
||||
|
||||
If everything is set up correctly, you should have output very similar to the
|
||||
following:
|
||||
|
||||
```
|
||||
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
|
||||
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
|
||||
usage: cl [ option... ] filename... [ /link linkoption... ]
|
||||
```
|
||||
|
||||
### 3. Building
|
||||
|
||||
Within this terminal, `cd` to the root directory of the codebase, and just run
|
||||
the `build.bat` script:
|
||||
|
||||
```
|
||||
build
|
||||
```
|
||||
|
||||
You should see the following output:
|
||||
|
||||
```
|
||||
[debug mode]
|
||||
[msvc compile]
|
||||
[default mode, assuming `raddbg` build]
|
||||
metagen_main.c
|
||||
searching C:\devel\raddebugger/src... 299 files found
|
||||
parsing metadesk... 12 metadesk files parsed
|
||||
gathering tables... 37 tables found
|
||||
generating layer code...
|
||||
raddbg.cpp
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
## Short-To-Medium-Term Roadmap
|
||||
|
||||
### The Initial Alpha Battle-Testing Phase
|
||||
|
||||
The first priority for the project is to ensure that the most crucial debugger
|
||||
components are functioning extremely reliably for local, x64, Windows
|
||||
debugging. This would include parts like debug info conversion, debug info
|
||||
loading, process control, stepping, evaluation (correct usage of both location
|
||||
info and type info), and a robust frontend which ensures the lower level parts
|
||||
are usable.
|
||||
|
||||
We feel that the debugger has already come a long way in all of these respects,
|
||||
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
|
||||
still issues. So, we feel that the top priority is eliminating these issues,
|
||||
such that the debugging experience is rock solid.
|
||||
|
||||
### Local x64 Linux Debugging Phase
|
||||
|
||||
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
|
||||
Linux debugging also.
|
||||
|
||||
The debugger has been written to abstract over the parts that need to differ on
|
||||
either Linux or Windows, and this is mainly going to be a task in building out
|
||||
different backends for those abstraction layers.
|
||||
|
||||
The major parts of this phase are:
|
||||
|
||||
- Porting the `src/demon` layer to implement the Demon local process control
|
||||
abstraction API.
|
||||
- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer.
|
||||
- Creating a DWARF-to-RDI converter (in the same way that we've built a
|
||||
PDB-to-RDI converter). A partial implementation of this is in
|
||||
`src/rdi_from_dwarf`.
|
||||
- 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).
|
||||
- Porting the `src/font_provider` layer to a Linux-compatible font
|
||||
rasterization backend, like FreeType (the backend used on Windows is
|
||||
DirectWrite).
|
||||
- Porting the `src/os` layers to Linux. This includes core operating system
|
||||
abstraction (virtual memory allocation, threading and synchronization
|
||||
primitives, and so on), and graphical operating system abstraction (windows,
|
||||
input events, and so on).
|
||||
|
||||
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
|
||||
available natively on Linux machines.
|
||||
|
||||
### And Beyond!
|
||||
|
||||
There are several directions we might take after these two major phases,
|
||||
like remote debugging, porting to different architectures, further improving
|
||||
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
|
||||
|
||||
- `data`: Small binary files which are used when building, either to embed
|
||||
within build artifacts, or to package with them.
|
||||
- `src`: All source code.
|
||||
|
||||
After setting up the codebase and building, the following directories will
|
||||
also exist:
|
||||
|
||||
- `build`: All build artifacts. Not checked in to version control.
|
||||
- `local`: Local files, used for local build configuration input files.
|
||||
|
||||
## Codebase Introduction
|
||||
|
||||
The codebase is organized into *layers*. Layers are separated either to isolate
|
||||
certain problems, and to allow inclusion into various builds without needing to
|
||||
pull everything in the codebase into a build. Layers correspond with folders
|
||||
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
|
||||
fairly flat.
|
||||
|
||||
Layers correspond roughly 1-to-1 with *namespaces*. The term "namespaces" in
|
||||
this context does not refer to specific namespace language features, but rather
|
||||
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
|
||||
namespaces are used such that the layer to which certain code belongs may be
|
||||
quickly understood by glancing at code. The namespaces are generally quite short
|
||||
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
|
||||
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
|
||||
capitalized. For functions and global variables, they are lowercase.
|
||||
|
||||
Layers depend on other layers, but circular dependencies would break the
|
||||
separability and isolation utility of layers (in effect, forming one big layer),
|
||||
so in other words, layers are arranged into a directed acyclic graph.
|
||||
|
||||
A few layers are built to be used completely independently from the rest of the
|
||||
codebase, as libraries in other codebases and projects. As such, these layers do
|
||||
not depend on any other layers in the codebase. The folders which contain these
|
||||
layers are prefixed with `lib_`, like `lib_rdi_format`.
|
||||
|
||||
A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||
on no other codebase layers.
|
||||
- `codeview` (`CV_`): Code for parsing and/or writing the CodeView format.
|
||||
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||
Format) file format.
|
||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||
asynchronous process control, stepping, and breakpoints for all attached
|
||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||
processes are halted. When attached processes are running, it is halted.
|
||||
Driven by a debugger frontend on another thread.
|
||||
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
|
||||
disassembly for a particular virtual address range in a process, and threads
|
||||
implemented in this layer decode and cache the disassembly for that range.
|
||||
- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info
|
||||
stored in the RDI format. Users ask for debug info for a particular path, and
|
||||
on separate threads, this layer loads the associated debug info file. If
|
||||
necessary, it will launch a separate conversion process to convert original
|
||||
debug info into the RDI format.
|
||||
- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process
|
||||
control. The abstraction is used to provide a common interface for process
|
||||
control on target platforms. Used to implement part of `ctrl`.
|
||||
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
|
||||
debugger "entity cache" (where "entities" include processes, threads, modules,
|
||||
breakpoints, source files, targets, and so on). Implements a command loop
|
||||
for driving process control, which is used to implement stepping commands and
|
||||
user breakpoints. Implements extractors and caches for various entity-related
|
||||
data, like full thread unwinds and local variable maps. Also implements core
|
||||
building blocks for evaluation and evaluation visualization.
|
||||
- `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
|
||||
purposes, using the underlying `render` abstraction layer. Provides high-level
|
||||
APIs for various draw commands, but takes care of batching them, and so on.
|
||||
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
|
||||
evaluation of variables, registers, and so on from debugger-attached processes
|
||||
and/or debug info. Broken into several phases mostly corresponding to
|
||||
traditional compiler phases - lexer, parser, type-checker, IR generation, and
|
||||
IR evaluation.
|
||||
- `font_cache` (`F_`): 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.
|
||||
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for memory visualization in the debugger.
|
||||
- `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.
|
||||
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
|
||||
programs to work with various features in the `raddbg` debugger. 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.
|
||||
- `lib_rdi_format` (`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.
|
||||
- `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.
|
||||
This layer cannot depend on any other layer in the codebase directly,
|
||||
including `base`, because it may be used to generate code for those layers. To
|
||||
still use `base` and `os` layer features in the `metagen` program, a separate,
|
||||
duplicate version of `base` and `os` are included in this layer. They are
|
||||
updated manually, as needed. This is to ensure the stability of the
|
||||
metaprogram.
|
||||
- `msf` (`MSF_`): Code for parsing and/or writing the MSF file format.
|
||||
- `mule` (no namespace): Test executables for battle testing debugger
|
||||
functionality.
|
||||
- `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.
|
||||
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||
networking operating system features under an abstract API, which is
|
||||
implemented per-target-operating-system.
|
||||
- `pdb` (`PDB_`): Code for parsing and/or writing the PDB file format.
|
||||
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
|
||||
file format.
|
||||
- `raddbg` (no namespace): The layer which ties everything together for the main
|
||||
graphical debugger. Not much "meat", just drives `df`, implements command line
|
||||
options, and so on.
|
||||
- `rdi_from_pdb` (`P2R_`): Our implementation of PDB-to-RDI conversion.
|
||||
- `rdi_from_dwarf` (`D2R_`): Our in-progress implementation of DWARF-to-RDI
|
||||
conversion.
|
||||
- `rdi_dump` (no namespace): A dumper utility program for dumping
|
||||
textualizations of RDI debug info files.
|
||||
- `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 or sample
|
||||
programs.
|
||||
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for memory visualization in the debugger.
|
||||
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
|
||||
reloaded, asynchronously parsed, and asynchronously mutated source code files.
|
||||
Used by the debugger to visualize source code files. Users ask for text lines,
|
||||
tokens, and metadata, and it is prepared on background threads.
|
||||
- `type_graph` (`TG_`): Code for analyzing and navigating type structures from
|
||||
RDI debug info files, with the additional capability of constructing
|
||||
synthetic types *not* found in debug info. Used in `eval` and for various
|
||||
visualization features.
|
||||
- `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.
|
||||
# The RAD Debugger Project
|
||||
|
||||
_**Note:** This README does not document usage instructions and tips for the
|
||||
debugger itself, and is intended as a technical overview of the project. The
|
||||
debugger's README, which includes usage instructions and tips, can be found
|
||||
packaged along with debugger releases, or within the `build` folder after a
|
||||
local copy has been built._
|
||||
|
||||
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
||||
plans to expand and port in the future. In the future we'll expand to also
|
||||
support native Linux debugging and DWARF debug info.
|
||||
|
||||
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
|
||||
with any information you can gather, like dump files (along with the build you
|
||||
used), instructions to reproduce, test executables, and so on.
|
||||
|
||||
You can download pre-built binaries for the debugger
|
||||
[here](https://github.com/EpicGames/raddebugger/releases).
|
||||
|
||||
The RAD Debugger project aims to simplify the debugger by simplifying and
|
||||
unifying the underlying debug info format. In that pursuit we've built the RAD
|
||||
Debug Info (RDI) format, which is what the debugger parses and uses. To work
|
||||
with existing toolchains, we convert PDB (and eventually PE/ELF files with
|
||||
embedded DWARF) into the RDI format on-demand.
|
||||
|
||||
The RDI format is currently specified in code, in the files within the
|
||||
`src/lib_rdi_format` folder. The other relevant folders for working with the
|
||||
format are:
|
||||
|
||||
- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info.
|
||||
- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase
|
||||
layer, or built as an executable with a command line interface frontend.
|
||||
- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter.
|
||||
- `rdi_dump`: Our RDI textual dumping utility.
|
||||
|
||||
## Development Setup Instructions
|
||||
|
||||
**Note: Currently, only x64 Windows development is supported.**
|
||||
|
||||
### 1. Installing the Required Tools (MSVC & Windows SDK)
|
||||
|
||||
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
|
||||
the Windows SDK and the MSVC compiler and linker.
|
||||
|
||||
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/).
|
||||
|
||||
### 2. Build Environment Setup
|
||||
|
||||
Building the codebase can be done in a terminal which is equipped with the
|
||||
ability to call either MSVC or Clang from command line.
|
||||
|
||||
This is generally done by calling `vcvarsall.bat x64`, which is included in the
|
||||
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
|
||||
you've installed the build tools, this command prompt may be easily located by
|
||||
searching for `Native` from the Windows Start Menu search.
|
||||
|
||||
You can ensure that the MSVC compiler is accessible from your command line by
|
||||
running:
|
||||
|
||||
```
|
||||
cl
|
||||
```
|
||||
|
||||
If everything is set up correctly, you should have output very similar to the
|
||||
following:
|
||||
|
||||
```
|
||||
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
|
||||
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
|
||||
usage: cl [ option... ] filename... [ /link linkoption... ]
|
||||
```
|
||||
|
||||
### 3. Building
|
||||
|
||||
Within this terminal, `cd` to the root directory of the codebase, and just run
|
||||
the `build.bat` script:
|
||||
|
||||
```
|
||||
build
|
||||
```
|
||||
|
||||
You should see the following output:
|
||||
|
||||
```
|
||||
[debug mode]
|
||||
[msvc compile]
|
||||
[default mode, assuming `raddbg` build]
|
||||
metagen_main.c
|
||||
searching C:\devel\raddebugger/src... 299 files found
|
||||
parsing metadesk... 12 metadesk files parsed
|
||||
gathering tables... 37 tables found
|
||||
generating layer code...
|
||||
raddbg.cpp
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
## Short-To-Medium-Term Roadmap
|
||||
|
||||
### The Initial Alpha Battle-Testing Phase
|
||||
|
||||
The first priority for the project is to ensure that the most crucial debugger
|
||||
components are functioning extremely reliably for local, x64, Windows
|
||||
debugging. This would include parts like debug info conversion, debug info
|
||||
loading, process control, stepping, evaluation (correct usage of both location
|
||||
info and type info), and a robust frontend which ensures the lower level parts
|
||||
are usable.
|
||||
|
||||
We feel that the debugger has already come a long way in all of these respects,
|
||||
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
|
||||
still issues. So, we feel that the top priority is eliminating these issues,
|
||||
such that the debugging experience is rock solid.
|
||||
|
||||
### Local x64 Linux Debugging Phase
|
||||
|
||||
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
|
||||
Linux debugging also.
|
||||
|
||||
The debugger has been written to abstract over the parts that need to differ on
|
||||
either Linux or Windows, and this is mainly going to be a task in building out
|
||||
different backends for those abstraction layers.
|
||||
|
||||
The major parts of this phase are:
|
||||
|
||||
- Porting the `src/demon` layer to implement the Demon local process control
|
||||
abstraction API.
|
||||
- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer.
|
||||
- Creating a DWARF-to-RDI converter (in the same way that we've built a
|
||||
PDB-to-RDI converter). A partial implementation of this is in
|
||||
`src/rdi_from_dwarf`.
|
||||
- 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).
|
||||
- Porting the `src/font_provider` layer to a Linux-compatible font
|
||||
rasterization backend, like FreeType (the backend used on Windows is
|
||||
DirectWrite).
|
||||
- Porting the `src/os` layers to Linux. This includes core operating system
|
||||
abstraction (virtual memory allocation, threading and synchronization
|
||||
primitives, and so on), and graphical operating system abstraction (windows,
|
||||
input events, and so on).
|
||||
|
||||
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
|
||||
available natively on Linux machines.
|
||||
|
||||
### And Beyond!
|
||||
|
||||
There are several directions we might take after these two major phases,
|
||||
like remote debugging, porting to different architectures, further improving
|
||||
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
|
||||
|
||||
- `data`: Small binary files which are used when building, either to embed
|
||||
within build artifacts, or to package with them.
|
||||
- `src`: All source code.
|
||||
|
||||
After setting up the codebase and building, the following directories will
|
||||
also exist:
|
||||
|
||||
- `build`: All build artifacts. Not checked in to version control.
|
||||
- `local`: Local files, used for local build configuration input files.
|
||||
|
||||
## Codebase Introduction
|
||||
|
||||
The codebase is organized into *layers*. Layers are separated either to isolate
|
||||
certain problems, and to allow inclusion into various builds without needing to
|
||||
pull everything in the codebase into a build. Layers correspond with folders
|
||||
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
|
||||
fairly flat.
|
||||
|
||||
Layers correspond roughly 1-to-1 with *namespaces*. The term "namespaces" in
|
||||
this context does not refer to specific namespace language features, but rather
|
||||
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
|
||||
namespaces are used such that the layer to which certain code belongs may be
|
||||
quickly understood by glancing at code. The namespaces are generally quite short
|
||||
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
|
||||
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
|
||||
capitalized. For functions and global variables, they are lowercase.
|
||||
|
||||
Layers depend on other layers, but circular dependencies would break the
|
||||
separability and isolation utility of layers (in effect, forming one big layer),
|
||||
so in other words, layers are arranged into a directed acyclic graph.
|
||||
|
||||
A few layers are built to be used completely independently from the rest of the
|
||||
codebase, as libraries in other codebases and projects. As such, these layers do
|
||||
not depend on any other layers in the codebase. The folders which contain these
|
||||
layers are prefixed with `lib_`, like `lib_rdi_format`.
|
||||
|
||||
A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||
on no other codebase layers.
|
||||
- `codeview` (`CV_`): Code for parsing and/or writing the CodeView format.
|
||||
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||
Format) file format.
|
||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||
asynchronous process control, stepping, and breakpoints for all attached
|
||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||
processes are halted. When attached processes are running, it is halted.
|
||||
Driven by a debugger frontend on another thread.
|
||||
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
|
||||
disassembly for a particular virtual address range in a process, and threads
|
||||
implemented in this layer decode and cache the disassembly for that range.
|
||||
- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info
|
||||
stored in the RDI format. Users ask for debug info for a particular path, and
|
||||
on separate threads, this layer loads the associated debug info file. If
|
||||
necessary, it will launch a separate conversion process to convert original
|
||||
debug info into the RDI format.
|
||||
- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process
|
||||
control. The abstraction is used to provide a common interface for process
|
||||
control on target platforms. Used to implement part of `ctrl`.
|
||||
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
|
||||
debugger "entity cache" (where "entities" include processes, threads, modules,
|
||||
breakpoints, source files, targets, and so on). Implements a command loop
|
||||
for driving process control, which is used to implement stepping commands and
|
||||
user breakpoints. Implements extractors and caches for various entity-related
|
||||
data, like full thread unwinds and local variable maps. Also implements core
|
||||
building blocks for evaluation and evaluation visualization.
|
||||
- `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
|
||||
purposes, using the underlying `render` abstraction layer. Provides high-level
|
||||
APIs for various draw commands, but takes care of batching them, and so on.
|
||||
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
|
||||
evaluation of variables, registers, and so on from debugger-attached processes
|
||||
and/or debug info. Broken into several phases mostly corresponding to
|
||||
traditional compiler phases - lexer, parser, type-checker, IR generation, and
|
||||
IR evaluation.
|
||||
- `font_cache` (`F_`): 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.
|
||||
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for memory visualization in the debugger.
|
||||
- `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.
|
||||
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
|
||||
programs to work with various features in the `raddbg` debugger. 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.
|
||||
- `lib_rdi_format` (`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.
|
||||
- `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.
|
||||
This layer cannot depend on any other layer in the codebase directly,
|
||||
including `base`, because it may be used to generate code for those layers. To
|
||||
still use `base` and `os` layer features in the `metagen` program, a separate,
|
||||
duplicate version of `base` and `os` are included in this layer. They are
|
||||
updated manually, as needed. This is to ensure the stability of the
|
||||
metaprogram.
|
||||
- `msf` (`MSF_`): Code for parsing and/or writing the MSF file format.
|
||||
- `mule` (no namespace): Test executables for battle testing debugger
|
||||
functionality.
|
||||
- `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.
|
||||
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||
networking operating system features under an abstract API, which is
|
||||
implemented per-target-operating-system.
|
||||
- `pdb` (`PDB_`): Code for parsing and/or writing the PDB file format.
|
||||
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
|
||||
file format.
|
||||
- `raddbg` (no namespace): The layer which ties everything together for the main
|
||||
graphical debugger. Not much "meat", just drives `df`, implements command line
|
||||
options, and so on.
|
||||
- `rdi_from_pdb` (`P2R_`): Our implementation of PDB-to-RDI conversion.
|
||||
- `rdi_from_dwarf` (`D2R_`): Our in-progress implementation of DWARF-to-RDI
|
||||
conversion.
|
||||
- `rdi_dump` (no namespace): A dumper utility program for dumping
|
||||
textualizations of RDI debug info files.
|
||||
- `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 or sample
|
||||
programs.
|
||||
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for memory visualization in the debugger.
|
||||
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
|
||||
reloaded, asynchronously parsed, and asynchronously mutated source code files.
|
||||
Used by the debugger to visualize source code files. Users ask for text lines,
|
||||
tokens, and metadata, and it is prepared on background threads.
|
||||
- `type_graph` (`TG_`): Code for analyzing and navigating type structures from
|
||||
RDI debug info files, with the additional capability of constructing
|
||||
synthetic types *not* found in debug info. Used in `eval` and for various
|
||||
visualization features.
|
||||
- `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.
|
||||
|
||||
+232
-232
@@ -1,232 +1,232 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64
|
||||
cmd_line_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;
|
||||
}
|
||||
|
||||
internal CmdLineOpt **
|
||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||
{
|
||||
CmdLineOpt **slot = 0;
|
||||
if(cmd_line->option_table_size != 0)
|
||||
{
|
||||
U64 hash = cmd_line_hash_from_string(string);
|
||||
U64 bucket = hash % cmd_line->option_table_size;
|
||||
slot = &cmd_line->option_table[bucket];
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string)
|
||||
{
|
||||
CmdLineOpt *result = 0;
|
||||
for(CmdLineOpt *var = *slot; var; var = var->hash_next)
|
||||
{
|
||||
if(str8_match(string, var->string, 0))
|
||||
{
|
||||
result = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, var);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values)
|
||||
{
|
||||
CmdLineOpt *var = 0;
|
||||
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
|
||||
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
|
||||
if(existing_var != 0)
|
||||
{
|
||||
var = existing_var;
|
||||
}
|
||||
else
|
||||
{
|
||||
var = push_array(arena, CmdLineOpt, 1);
|
||||
var->hash_next = *slot;
|
||||
var->hash = cmd_line_hash_from_string(string);
|
||||
var->string = push_str8_copy(arena, string);
|
||||
var->value_strings = values;
|
||||
StringJoin join = {0};
|
||||
join.pre = str8_lit("");
|
||||
join.sep = str8_lit(",");
|
||||
join.post = str8_lit("");
|
||||
var->value_string = str8_list_join(arena, &var->value_strings, &join);
|
||||
*slot = var;
|
||||
cmd_line_push_opt(&cmd_line->options, var);
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
internal CmdLine
|
||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
{
|
||||
CmdLine parsed = {0};
|
||||
parsed.exe_name = command_line.first->string;
|
||||
|
||||
// NOTE(rjf): Set up config option table.
|
||||
{
|
||||
parsed.option_table_size = 4096;
|
||||
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Parse command line.
|
||||
B32 after_passthrough_option = 0;
|
||||
B32 first_passthrough = 1;
|
||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
String8 option_name = node->string;
|
||||
|
||||
// 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
|
||||
// on the command line will be considered as input files.
|
||||
B32 is_option = 1;
|
||||
if(after_passthrough_option == 0)
|
||||
{
|
||||
if(str8_match(node->string, str8_lit("--"), 0))
|
||||
{
|
||||
after_passthrough_option = 1;
|
||||
is_option = 0;
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 2);
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
|
||||
// NOTE(rjf): This string is an option.
|
||||
if(is_option)
|
||||
{
|
||||
B32 has_arguments = 0;
|
||||
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||
if(arg_signifier_position < option_name.size)
|
||||
{
|
||||
has_arguments = 1;
|
||||
}
|
||||
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||
|
||||
String8List arguments = {0};
|
||||
|
||||
// NOTE(rjf): Parse arguments.
|
||||
if(has_arguments)
|
||||
{
|
||||
for(String8Node *n = node; n; n = n->next)
|
||||
{
|
||||
next = n->next;
|
||||
|
||||
String8 string = n->string;
|
||||
if(n == node)
|
||||
{
|
||||
string = arg_portion_this_string;
|
||||
}
|
||||
|
||||
U8 splits[] = { ',' };
|
||||
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||
{
|
||||
str8_list_push(arena, &arguments, sub_arg->string);
|
||||
}
|
||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||
(n != node || arg_portion_this_string.size != 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(rjf): Register config variable.
|
||||
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||
// handled by tool-specific code.
|
||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
||||
{
|
||||
str8_list_push(arena, &parsed.inputs, node->string);
|
||||
after_passthrough_option = 1;
|
||||
first_passthrough = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
internal String8List
|
||||
cmd_line_strings(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8List result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_strings;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cmd_line_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8 result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_string;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64
|
||||
cmd_line_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;
|
||||
}
|
||||
|
||||
internal CmdLineOpt **
|
||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||
{
|
||||
CmdLineOpt **slot = 0;
|
||||
if(cmd_line->option_table_size != 0)
|
||||
{
|
||||
U64 hash = cmd_line_hash_from_string(string);
|
||||
U64 bucket = hash % cmd_line->option_table_size;
|
||||
slot = &cmd_line->option_table[bucket];
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string)
|
||||
{
|
||||
CmdLineOpt *result = 0;
|
||||
for(CmdLineOpt *var = *slot; var; var = var->hash_next)
|
||||
{
|
||||
if(str8_match(string, var->string, 0))
|
||||
{
|
||||
result = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, var);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values)
|
||||
{
|
||||
CmdLineOpt *var = 0;
|
||||
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
|
||||
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
|
||||
if(existing_var != 0)
|
||||
{
|
||||
var = existing_var;
|
||||
}
|
||||
else
|
||||
{
|
||||
var = push_array(arena, CmdLineOpt, 1);
|
||||
var->hash_next = *slot;
|
||||
var->hash = cmd_line_hash_from_string(string);
|
||||
var->string = push_str8_copy(arena, string);
|
||||
var->value_strings = values;
|
||||
StringJoin join = {0};
|
||||
join.pre = str8_lit("");
|
||||
join.sep = str8_lit(",");
|
||||
join.post = str8_lit("");
|
||||
var->value_string = str8_list_join(arena, &var->value_strings, &join);
|
||||
*slot = var;
|
||||
cmd_line_push_opt(&cmd_line->options, var);
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
internal CmdLine
|
||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
{
|
||||
CmdLine parsed = {0};
|
||||
parsed.exe_name = command_line.first->string;
|
||||
|
||||
// NOTE(rjf): Set up config option table.
|
||||
{
|
||||
parsed.option_table_size = 4096;
|
||||
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Parse command line.
|
||||
B32 after_passthrough_option = 0;
|
||||
B32 first_passthrough = 1;
|
||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
String8 option_name = node->string;
|
||||
|
||||
// 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
|
||||
// on the command line will be considered as input files.
|
||||
B32 is_option = 1;
|
||||
if(after_passthrough_option == 0)
|
||||
{
|
||||
if(str8_match(node->string, str8_lit("--"), 0))
|
||||
{
|
||||
after_passthrough_option = 1;
|
||||
is_option = 0;
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 2);
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
|
||||
// NOTE(rjf): This string is an option.
|
||||
if(is_option)
|
||||
{
|
||||
B32 has_arguments = 0;
|
||||
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||
if(arg_signifier_position < option_name.size)
|
||||
{
|
||||
has_arguments = 1;
|
||||
}
|
||||
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||
|
||||
String8List arguments = {0};
|
||||
|
||||
// NOTE(rjf): Parse arguments.
|
||||
if(has_arguments)
|
||||
{
|
||||
for(String8Node *n = node; n; n = n->next)
|
||||
{
|
||||
next = n->next;
|
||||
|
||||
String8 string = n->string;
|
||||
if(n == node)
|
||||
{
|
||||
string = arg_portion_this_string;
|
||||
}
|
||||
|
||||
U8 splits[] = { ',' };
|
||||
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||
{
|
||||
str8_list_push(arena, &arguments, sub_arg->string);
|
||||
}
|
||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||
(n != node || arg_portion_this_string.size != 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(rjf): Register config variable.
|
||||
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||
// handled by tool-specific code.
|
||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
||||
{
|
||||
str8_list_push(arena, &parsed.inputs, node->string);
|
||||
after_passthrough_option = 1;
|
||||
first_passthrough = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
internal String8List
|
||||
cmd_line_strings(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8List result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_strings;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cmd_line_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8 result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_string;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_COMMAND_LINE_H
|
||||
#define BASE_COMMAND_LINE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsed Command Line Types
|
||||
|
||||
typedef struct CmdLineOpt CmdLineOpt;
|
||||
struct CmdLineOpt
|
||||
{
|
||||
CmdLineOpt *next;
|
||||
CmdLineOpt *hash_next;
|
||||
U64 hash;
|
||||
String8 string;
|
||||
String8List value_strings;
|
||||
String8 value_string;
|
||||
};
|
||||
|
||||
typedef struct CmdLineOptList CmdLineOptList;
|
||||
struct CmdLineOptList
|
||||
{
|
||||
U64 count;
|
||||
CmdLineOpt *first;
|
||||
CmdLineOpt *last;
|
||||
};
|
||||
|
||||
typedef struct CmdLine CmdLine;
|
||||
struct CmdLine
|
||||
{
|
||||
String8 exe_name;
|
||||
CmdLineOptList options;
|
||||
String8List inputs;
|
||||
U64 option_table_size;
|
||||
CmdLineOpt **option_table;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64 cmd_line_hash_from_string(String8 string);
|
||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||
internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values);
|
||||
internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments);
|
||||
internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name);
|
||||
internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name);
|
||||
internal String8 cmd_line_string(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
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_COMMAND_LINE_H
|
||||
#define BASE_COMMAND_LINE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsed Command Line Types
|
||||
|
||||
typedef struct CmdLineOpt CmdLineOpt;
|
||||
struct CmdLineOpt
|
||||
{
|
||||
CmdLineOpt *next;
|
||||
CmdLineOpt *hash_next;
|
||||
U64 hash;
|
||||
String8 string;
|
||||
String8List value_strings;
|
||||
String8 value_string;
|
||||
};
|
||||
|
||||
typedef struct CmdLineOptList CmdLineOptList;
|
||||
struct CmdLineOptList
|
||||
{
|
||||
U64 count;
|
||||
CmdLineOpt *first;
|
||||
CmdLineOpt *last;
|
||||
};
|
||||
|
||||
typedef struct CmdLine CmdLine;
|
||||
struct CmdLine
|
||||
{
|
||||
String8 exe_name;
|
||||
CmdLineOptList options;
|
||||
String8List inputs;
|
||||
U64 option_table_size;
|
||||
CmdLineOpt **option_table;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64 cmd_line_hash_from_string(String8 string);
|
||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||
internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values);
|
||||
internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments);
|
||||
internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name);
|
||||
internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name);
|
||||
internal String8 cmd_line_string(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
|
||||
|
||||
+247
-247
@@ -1,247 +1,247 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_CONTEXT_CRACKING_H
|
||||
#define BASE_CONTEXT_CRACKING_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Clang OS/Arch Cracking
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSVC OS/Arch Cracking
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
# define COMPILER_MSVC 1
|
||||
|
||||
# if _MSC_VER >= 1920
|
||||
# define COMPILER_MSVC_YEAR 2019
|
||||
# elif _MSC_VER >= 1910
|
||||
# define COMPILER_MSVC_YEAR 2017
|
||||
# elif _MSC_VER >= 1900
|
||||
# define COMPILER_MSVC_YEAR 2015
|
||||
# elif _MSC_VER >= 1800
|
||||
# define COMPILER_MSVC_YEAR 2013
|
||||
# elif _MSC_VER >= 1700
|
||||
# define COMPILER_MSVC_YEAR 2012
|
||||
# elif _MSC_VER >= 1600
|
||||
# define COMPILER_MSVC_YEAR 2010
|
||||
# elif _MSC_VER >= 1500
|
||||
# define COMPILER_MSVC_YEAR 2008
|
||||
# elif _MSC_VER >= 1400
|
||||
# define COMPILER_MSVC_YEAR 2005
|
||||
# else
|
||||
# define COMPILER_MSVC_YEAR 0
|
||||
# endif
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(_M_IX86)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(_M_ARM64)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(_M_ARM)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: GCC OS/Arch Cracking
|
||||
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
|
||||
# define COMPILER_GCC 1
|
||||
|
||||
# if defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error Compiler not supported.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arch Cracking
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
# define ARCH_64BIT 1
|
||||
#elif defined(ARCH_X86)
|
||||
# define ARCH_32BIT 1
|
||||
#endif
|
||||
|
||||
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
||||
# define ARCH_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# error Endianness of this architecture not understood by context cracker.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Language Cracking
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CPP 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Option Cracking
|
||||
|
||||
#if !defined(BUILD_DEBUG)
|
||||
# define BUILD_DEBUG 1
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
||||
#endif
|
||||
|
||||
#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 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 0
|
||||
#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/EpicGames/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
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_CONTEXT_CRACKING_H
|
||||
#define BASE_CONTEXT_CRACKING_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Clang OS/Arch Cracking
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSVC OS/Arch Cracking
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
# define COMPILER_MSVC 1
|
||||
|
||||
# if _MSC_VER >= 1920
|
||||
# define COMPILER_MSVC_YEAR 2019
|
||||
# elif _MSC_VER >= 1910
|
||||
# define COMPILER_MSVC_YEAR 2017
|
||||
# elif _MSC_VER >= 1900
|
||||
# define COMPILER_MSVC_YEAR 2015
|
||||
# elif _MSC_VER >= 1800
|
||||
# define COMPILER_MSVC_YEAR 2013
|
||||
# elif _MSC_VER >= 1700
|
||||
# define COMPILER_MSVC_YEAR 2012
|
||||
# elif _MSC_VER >= 1600
|
||||
# define COMPILER_MSVC_YEAR 2010
|
||||
# elif _MSC_VER >= 1500
|
||||
# define COMPILER_MSVC_YEAR 2008
|
||||
# elif _MSC_VER >= 1400
|
||||
# define COMPILER_MSVC_YEAR 2005
|
||||
# else
|
||||
# define COMPILER_MSVC_YEAR 0
|
||||
# endif
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(_M_IX86)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(_M_ARM64)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(_M_ARM)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: GCC OS/Arch Cracking
|
||||
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
|
||||
# define COMPILER_GCC 1
|
||||
|
||||
# if defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error Compiler not supported.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arch Cracking
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
# define ARCH_64BIT 1
|
||||
#elif defined(ARCH_X86)
|
||||
# define ARCH_32BIT 1
|
||||
#endif
|
||||
|
||||
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
||||
# define ARCH_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# error Endianness of this architecture not understood by context cracker.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Language Cracking
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CPP 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Option Cracking
|
||||
|
||||
#if !defined(BUILD_DEBUG)
|
||||
# define BUILD_DEBUG 1
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
||||
#endif
|
||||
|
||||
#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 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 0
|
||||
#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/EpicGames/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
|
||||
|
||||
+562
-562
File diff suppressed because it is too large
Load Diff
+10
-10
@@ -1,10 +1,10 @@
|
||||
// Copyright (c) 2024 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(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count);
|
||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||
|
||||
#endif // BASE_ENTRY_POINT_H
|
||||
// Copyright (c) 2024 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(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count);
|
||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||
|
||||
#endif // BASE_ENTRY_POINT_H
|
||||
|
||||
+19
-19
@@ -1,19 +1,19 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#undef RADDBG_LAYER_COLOR
|
||||
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||
|
||||
#include "base_core.c"
|
||||
#include "base_profile.c"
|
||||
#include "base_arena.c"
|
||||
#include "base_math.c"
|
||||
#include "base_strings.c"
|
||||
#include "base_thread_context.c"
|
||||
#include "base_command_line.c"
|
||||
#include "base_markup.c"
|
||||
#include "base_log.c"
|
||||
#include "base_entry_point.c"
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#undef RADDBG_LAYER_COLOR
|
||||
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||
|
||||
#include "base_core.c"
|
||||
#include "base_profile.c"
|
||||
#include "base_arena.c"
|
||||
#include "base_math.c"
|
||||
#include "base_strings.c"
|
||||
#include "base_thread_context.c"
|
||||
#include "base_command_line.c"
|
||||
#include "base_markup.c"
|
||||
#include "base_log.c"
|
||||
#include "base_entry_point.c"
|
||||
|
||||
+23
-23
@@ -1,23 +1,23 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_INC_H
|
||||
#define BASE_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#include "base_context_cracking.h"
|
||||
|
||||
#include "base_core.h"
|
||||
#include "base_profile.h"
|
||||
#include "base_arena.h"
|
||||
#include "base_math.h"
|
||||
#include "base_strings.h"
|
||||
#include "base_thread_context.h"
|
||||
#include "base_command_line.h"
|
||||
#include "base_markup.h"
|
||||
#include "base_log.h"
|
||||
#include "base_entry_point.h"
|
||||
|
||||
#endif // BASE_INC_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_INC_H
|
||||
#define BASE_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#include "base_context_cracking.h"
|
||||
|
||||
#include "base_core.h"
|
||||
#include "base_profile.h"
|
||||
#include "base_arena.h"
|
||||
#include "base_math.h"
|
||||
#include "base_strings.h"
|
||||
#include "base_thread_context.h"
|
||||
#include "base_command_line.h"
|
||||
#include "base_markup.h"
|
||||
#include "base_log.h"
|
||||
#include "base_entry_point.h"
|
||||
|
||||
#endif // BASE_INC_H
|
||||
|
||||
+103
-103
@@ -1,103 +1,103 @@
|
||||
// Copyright (c) 2024 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;
|
||||
}
|
||||
// Copyright (c) 2024 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;
|
||||
}
|
||||
|
||||
+21
-21
@@ -1,21 +1,21 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
set_thread_name(String8 string)
|
||||
{
|
||||
ProfThreadName("%.*s", str8_varg(string));
|
||||
os_set_thread_name(string);
|
||||
}
|
||||
|
||||
internal void
|
||||
set_thread_namef(char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
set_thread_name(string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
set_thread_name(String8 string)
|
||||
{
|
||||
ProfThreadName("%.*s", str8_varg(string));
|
||||
os_set_thread_name(string);
|
||||
}
|
||||
|
||||
internal void
|
||||
set_thread_namef(char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
set_thread_name(string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_MARKUP_H
|
||||
#define BASE_MARKUP_H
|
||||
|
||||
internal void set_thread_name(String8 string);
|
||||
internal void set_thread_namef(char *fmt, ...);
|
||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__))
|
||||
#define ThreadName(str) (set_thread_name(str))
|
||||
|
||||
#endif // BASE_MARKUP_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_MARKUP_H
|
||||
#define BASE_MARKUP_H
|
||||
|
||||
internal void set_thread_name(String8 string);
|
||||
internal void set_thread_namef(char *fmt, ...);
|
||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__))
|
||||
#define ThreadName(str) (set_thread_name(str))
|
||||
|
||||
#endif // BASE_MARKUP_H
|
||||
|
||||
+616
-616
File diff suppressed because it is too large
Load Diff
+649
-649
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
+74
-74
@@ -1,74 +1,74 @@
|
||||
// Copyright (c) 2024 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(MARKUP_LAYER_COLOR)
|
||||
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# 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())
|
||||
|
||||
#endif // BASE_PROFILE_H
|
||||
// Copyright (c) 2024 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(MARKUP_LAYER_COLOR)
|
||||
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# 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())
|
||||
|
||||
#endif // BASE_PROFILE_H
|
||||
|
||||
+381
-381
@@ -1,381 +1,381 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_STRINGS_H
|
||||
#define BASE_STRINGS_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||
#include "third_party/stb/stb_sprintf.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Types
|
||||
|
||||
typedef struct String8 String8;
|
||||
struct String8
|
||||
{
|
||||
U8 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String16 String16;
|
||||
struct String16
|
||||
{
|
||||
U16 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String32 String32;
|
||||
struct String32
|
||||
{
|
||||
U32 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List & Array Types
|
||||
|
||||
typedef struct String8Node String8Node;
|
||||
struct String8Node
|
||||
{
|
||||
String8Node *next;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct String8MetaNode String8MetaNode;
|
||||
struct String8MetaNode
|
||||
{
|
||||
String8MetaNode *next;
|
||||
String8Node *node;
|
||||
};
|
||||
|
||||
typedef struct String8List String8List;
|
||||
struct String8List
|
||||
{
|
||||
String8Node *first;
|
||||
String8Node *last;
|
||||
U64 node_count;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
typedef struct String8Array String8Array;
|
||||
struct String8Array
|
||||
{
|
||||
String8 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching, Splitting, & Joining Types
|
||||
|
||||
typedef U32 StringMatchFlags;
|
||||
enum
|
||||
{
|
||||
StringMatchFlag_CaseInsensitive = (1 << 0),
|
||||
StringMatchFlag_RightSideSloppy = (1 << 1),
|
||||
StringMatchFlag_SlashInsensitive = (1 << 2),
|
||||
};
|
||||
|
||||
typedef U32 StringSplitFlags;
|
||||
enum
|
||||
{
|
||||
StringSplitFlag_KeepEmpties = (1 << 0),
|
||||
};
|
||||
|
||||
typedef enum PathStyle
|
||||
{
|
||||
PathStyle_Relative,
|
||||
PathStyle_WindowsAbsolute,
|
||||
PathStyle_UnixAbsolute,
|
||||
|
||||
#if OS_WINDOWS
|
||||
PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute
|
||||
#elif OS_LINUX
|
||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||
#else
|
||||
# error "absolute path style is undefined for this OS"
|
||||
#endif
|
||||
}
|
||||
PathStyle;
|
||||
|
||||
typedef struct StringJoin StringJoin;
|
||||
struct StringJoin
|
||||
{
|
||||
String8 pre;
|
||||
String8 sep;
|
||||
String8 post;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Pair Types
|
||||
|
||||
typedef struct String8TxtPtPair String8TxtPtPair;
|
||||
struct String8TxtPtPair
|
||||
{
|
||||
String8 string;
|
||||
TxtPt pt;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF Decoding Types
|
||||
|
||||
typedef struct UnicodeDecode UnicodeDecode;
|
||||
struct UnicodeDecode
|
||||
{
|
||||
U32 inc;
|
||||
U32 codepoint;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching Types
|
||||
|
||||
typedef struct FuzzyMatchRangeNode FuzzyMatchRangeNode;
|
||||
struct FuzzyMatchRangeNode
|
||||
{
|
||||
FuzzyMatchRangeNode *next;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct FuzzyMatchRangeList FuzzyMatchRangeList;
|
||||
struct FuzzyMatchRangeList
|
||||
{
|
||||
FuzzyMatchRangeNode *first;
|
||||
FuzzyMatchRangeNode *last;
|
||||
U64 count;
|
||||
U64 needle_part_count;
|
||||
U64 total_dim;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Character Classification & Conversion Functions
|
||||
|
||||
internal B32 char_is_space(U8 c);
|
||||
internal B32 char_is_upper(U8 c);
|
||||
internal B32 char_is_lower(U8 c);
|
||||
internal B32 char_is_alpha(U8 c);
|
||||
internal B32 char_is_slash(U8 c);
|
||||
internal B32 char_is_digit(U8 c, U32 base);
|
||||
internal U8 char_to_lower(U8 c);
|
||||
internal U8 char_to_upper(U8 c);
|
||||
internal U8 char_to_correct_slash(U8 c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String Measurement
|
||||
|
||||
internal U64 cstring8_length(U8 *c);
|
||||
internal U64 cstring16_length(U16 *c);
|
||||
internal U64 cstring32_length(U32 *c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Constructors
|
||||
|
||||
#define str8_lit(S) str8((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_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
||||
#define str8_array_fixed(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_range(U8 *first, U8 *one_past_last);
|
||||
internal String8 str8_zero(void);
|
||||
internal String16 str16(U16 *str, U64 size);
|
||||
internal String16 str16_range(U16 *first, U16 *one_past_last);
|
||||
internal String16 str16_zero(void);
|
||||
internal String32 str32(U32 *str, U64 size);
|
||||
internal String32 str32_range(U32 *first, U32 *one_past_last);
|
||||
internal String32 str32_zero(void);
|
||||
internal String8 str8_cstring(char *c);
|
||||
internal String16 str16_cstring(U16 *c);
|
||||
internal String32 str32_cstring(U32 *c);
|
||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Stylization
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Slicing
|
||||
|
||||
internal String8 str8_substr(String8 str, Rng1U64 range);
|
||||
internal String8 str8_prefix(String8 str, U64 size);
|
||||
internal String8 str8_skip(String8 str, U64 amt);
|
||||
internal String8 str8_postfix(String8 str, U64 size);
|
||||
internal String8 str8_chop(String8 str, U64 amt);
|
||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Formatting & Copying
|
||||
|
||||
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);
|
||||
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Integer Conversions
|
||||
|
||||
//- rjf: string -> integer
|
||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||
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: integer -> string
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||
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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Float Conversions
|
||||
|
||||
internal F64 f64_from_str8(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List Construction Functions
|
||||
|
||||
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);
|
||||
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 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);
|
||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Splitting & Joining
|
||||
|
||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||
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);
|
||||
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf; String Arrays
|
||||
|
||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Path Helpers
|
||||
|
||||
internal String8 str8_chop_last_slash(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);
|
||||
|
||||
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);
|
||||
internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style);
|
||||
|
||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||
|
||||
internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unicode String Conversions
|
||||
|
||||
internal String8 str8_from_16(Arena *arena, String16 in);
|
||||
internal String16 str16_from_8(Arena *arena, String8 in);
|
||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
internal String8 string_from_dimension(Dimension dimension);
|
||||
internal String8 string_from_side(Side side);
|
||||
internal String8 string_from_operating_system(OperatingSystem os);
|
||||
internal String8 string_from_architecture(Architecture arch);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Types -> String
|
||||
|
||||
internal String8 string_from_week_day(WeekDay week_day);
|
||||
internal String8 string_from_month(Month month);
|
||||
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 Text Indentation
|
||||
|
||||
internal String8 indented_from_string(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Wrapping
|
||||
|
||||
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <-> Color
|
||||
|
||||
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
||||
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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);
|
||||
#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)))
|
||||
|
||||
#endif // BASE_STRINGS_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_STRINGS_H
|
||||
#define BASE_STRINGS_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||
#include "third_party/stb/stb_sprintf.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Types
|
||||
|
||||
typedef struct String8 String8;
|
||||
struct String8
|
||||
{
|
||||
U8 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String16 String16;
|
||||
struct String16
|
||||
{
|
||||
U16 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String32 String32;
|
||||
struct String32
|
||||
{
|
||||
U32 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List & Array Types
|
||||
|
||||
typedef struct String8Node String8Node;
|
||||
struct String8Node
|
||||
{
|
||||
String8Node *next;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct String8MetaNode String8MetaNode;
|
||||
struct String8MetaNode
|
||||
{
|
||||
String8MetaNode *next;
|
||||
String8Node *node;
|
||||
};
|
||||
|
||||
typedef struct String8List String8List;
|
||||
struct String8List
|
||||
{
|
||||
String8Node *first;
|
||||
String8Node *last;
|
||||
U64 node_count;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
typedef struct String8Array String8Array;
|
||||
struct String8Array
|
||||
{
|
||||
String8 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching, Splitting, & Joining Types
|
||||
|
||||
typedef U32 StringMatchFlags;
|
||||
enum
|
||||
{
|
||||
StringMatchFlag_CaseInsensitive = (1 << 0),
|
||||
StringMatchFlag_RightSideSloppy = (1 << 1),
|
||||
StringMatchFlag_SlashInsensitive = (1 << 2),
|
||||
};
|
||||
|
||||
typedef U32 StringSplitFlags;
|
||||
enum
|
||||
{
|
||||
StringSplitFlag_KeepEmpties = (1 << 0),
|
||||
};
|
||||
|
||||
typedef enum PathStyle
|
||||
{
|
||||
PathStyle_Relative,
|
||||
PathStyle_WindowsAbsolute,
|
||||
PathStyle_UnixAbsolute,
|
||||
|
||||
#if OS_WINDOWS
|
||||
PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute
|
||||
#elif OS_LINUX
|
||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||
#else
|
||||
# error "absolute path style is undefined for this OS"
|
||||
#endif
|
||||
}
|
||||
PathStyle;
|
||||
|
||||
typedef struct StringJoin StringJoin;
|
||||
struct StringJoin
|
||||
{
|
||||
String8 pre;
|
||||
String8 sep;
|
||||
String8 post;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Pair Types
|
||||
|
||||
typedef struct String8TxtPtPair String8TxtPtPair;
|
||||
struct String8TxtPtPair
|
||||
{
|
||||
String8 string;
|
||||
TxtPt pt;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF Decoding Types
|
||||
|
||||
typedef struct UnicodeDecode UnicodeDecode;
|
||||
struct UnicodeDecode
|
||||
{
|
||||
U32 inc;
|
||||
U32 codepoint;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching Types
|
||||
|
||||
typedef struct FuzzyMatchRangeNode FuzzyMatchRangeNode;
|
||||
struct FuzzyMatchRangeNode
|
||||
{
|
||||
FuzzyMatchRangeNode *next;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct FuzzyMatchRangeList FuzzyMatchRangeList;
|
||||
struct FuzzyMatchRangeList
|
||||
{
|
||||
FuzzyMatchRangeNode *first;
|
||||
FuzzyMatchRangeNode *last;
|
||||
U64 count;
|
||||
U64 needle_part_count;
|
||||
U64 total_dim;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Character Classification & Conversion Functions
|
||||
|
||||
internal B32 char_is_space(U8 c);
|
||||
internal B32 char_is_upper(U8 c);
|
||||
internal B32 char_is_lower(U8 c);
|
||||
internal B32 char_is_alpha(U8 c);
|
||||
internal B32 char_is_slash(U8 c);
|
||||
internal B32 char_is_digit(U8 c, U32 base);
|
||||
internal U8 char_to_lower(U8 c);
|
||||
internal U8 char_to_upper(U8 c);
|
||||
internal U8 char_to_correct_slash(U8 c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String Measurement
|
||||
|
||||
internal U64 cstring8_length(U8 *c);
|
||||
internal U64 cstring16_length(U16 *c);
|
||||
internal U64 cstring32_length(U32 *c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Constructors
|
||||
|
||||
#define str8_lit(S) str8((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_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
||||
#define str8_array_fixed(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_range(U8 *first, U8 *one_past_last);
|
||||
internal String8 str8_zero(void);
|
||||
internal String16 str16(U16 *str, U64 size);
|
||||
internal String16 str16_range(U16 *first, U16 *one_past_last);
|
||||
internal String16 str16_zero(void);
|
||||
internal String32 str32(U32 *str, U64 size);
|
||||
internal String32 str32_range(U32 *first, U32 *one_past_last);
|
||||
internal String32 str32_zero(void);
|
||||
internal String8 str8_cstring(char *c);
|
||||
internal String16 str16_cstring(U16 *c);
|
||||
internal String32 str32_cstring(U32 *c);
|
||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Stylization
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Slicing
|
||||
|
||||
internal String8 str8_substr(String8 str, Rng1U64 range);
|
||||
internal String8 str8_prefix(String8 str, U64 size);
|
||||
internal String8 str8_skip(String8 str, U64 amt);
|
||||
internal String8 str8_postfix(String8 str, U64 size);
|
||||
internal String8 str8_chop(String8 str, U64 amt);
|
||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Formatting & Copying
|
||||
|
||||
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);
|
||||
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Integer Conversions
|
||||
|
||||
//- rjf: string -> integer
|
||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||
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: integer -> string
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||
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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Float Conversions
|
||||
|
||||
internal F64 f64_from_str8(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List Construction Functions
|
||||
|
||||
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);
|
||||
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 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);
|
||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Splitting & Joining
|
||||
|
||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||
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);
|
||||
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf; String Arrays
|
||||
|
||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Path Helpers
|
||||
|
||||
internal String8 str8_chop_last_slash(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);
|
||||
|
||||
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);
|
||||
internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style);
|
||||
|
||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||
|
||||
internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unicode String Conversions
|
||||
|
||||
internal String8 str8_from_16(Arena *arena, String16 in);
|
||||
internal String16 str16_from_8(Arena *arena, String8 in);
|
||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
internal String8 string_from_dimension(Dimension dimension);
|
||||
internal String8 string_from_side(Side side);
|
||||
internal String8 string_from_operating_system(OperatingSystem os);
|
||||
internal String8 string_from_architecture(Architecture arch);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Types -> String
|
||||
|
||||
internal String8 string_from_week_day(WeekDay week_day);
|
||||
internal String8 string_from_month(Month month);
|
||||
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 Text Indentation
|
||||
|
||||
internal String8 indented_from_string(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Wrapping
|
||||
|
||||
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <-> Color
|
||||
|
||||
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
||||
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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);
|
||||
#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)))
|
||||
|
||||
#endif // BASE_STRINGS_H
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||
#endif
|
||||
|
||||
internal void
|
||||
tctx_init_and_equip(TCTX *tctx){
|
||||
MemoryZeroStruct(tctx);
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
*arena_ptr = arena_alloc();
|
||||
}
|
||||
tctx_thread_local = tctx;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_release(void)
|
||||
{
|
||||
for(U64 i = 0; i < ArrayCount(tctx_thread_local->arenas); i += 1)
|
||||
{
|
||||
arena_release(tctx_thread_local->arenas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal TCTX*
|
||||
tctx_get_equipped(void){
|
||||
return(tctx_thread_local);
|
||||
}
|
||||
|
||||
internal Arena*
|
||||
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
|
||||
Arena *result = 0;
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
Arena **conflict_ptr = conflicts;
|
||||
B32 has_conflict = 0;
|
||||
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||
if (*arena_ptr == *conflict_ptr){
|
||||
has_conflict = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_conflict){
|
||||
result = *arena_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_set_thread_name(String8 string){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
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_get_equipped();
|
||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
tctx->file_name = file_name;
|
||||
tctx->line_number = line_number;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
*file_name = tctx->file_name;
|
||||
*line_number = tctx->line_number;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||
#endif
|
||||
|
||||
internal void
|
||||
tctx_init_and_equip(TCTX *tctx){
|
||||
MemoryZeroStruct(tctx);
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
*arena_ptr = arena_alloc();
|
||||
}
|
||||
tctx_thread_local = tctx;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_release(void)
|
||||
{
|
||||
for(U64 i = 0; i < ArrayCount(tctx_thread_local->arenas); i += 1)
|
||||
{
|
||||
arena_release(tctx_thread_local->arenas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal TCTX*
|
||||
tctx_get_equipped(void){
|
||||
return(tctx_thread_local);
|
||||
}
|
||||
|
||||
internal Arena*
|
||||
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
|
||||
Arena *result = 0;
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
Arena **conflict_ptr = conflicts;
|
||||
B32 has_conflict = 0;
|
||||
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||
if (*arena_ptr == *conflict_ptr){
|
||||
has_conflict = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_conflict){
|
||||
result = *arena_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_set_thread_name(String8 string){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
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_get_equipped();
|
||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
tctx->file_name = file_name;
|
||||
tctx->line_number = line_number;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
*file_name = tctx->file_name;
|
||||
*line_number = tctx->line_number;
|
||||
}
|
||||
|
||||
+622
-622
File diff suppressed because it is too large
Load Diff
+2330
-2330
File diff suppressed because it is too large
Load Diff
@@ -1,82 +1,82 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CODEVIEW_STRINGIZE_H
|
||||
#define CODEVIEW_STRINGIZE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Stringize Helper Types
|
||||
|
||||
typedef struct CV_StringizeSymParams{
|
||||
CV_Arch arch;
|
||||
} CV_StringizeSymParams;
|
||||
|
||||
typedef struct CV_StringizeLeafParams{
|
||||
U32 dummy;
|
||||
} CV_StringizeLeafParams;
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Common Stringize Functions
|
||||
|
||||
internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num);
|
||||
|
||||
internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out,
|
||||
CV_LvarAddrRange *range);
|
||||
internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap);
|
||||
internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out,
|
||||
void *first, void *opl);
|
||||
|
||||
internal String8 cv_string_from_basic_type(CV_BasicType basic_type);
|
||||
internal String8 cv_string_from_c13_sub_section_kind(CV_C13SubSectionKind kind);
|
||||
internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg);
|
||||
internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind);
|
||||
internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode);
|
||||
internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind);
|
||||
internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Flags Stringize Functions
|
||||
|
||||
internal void cv_stringize_modifier_flags(Arena *arena, String8List *out,
|
||||
U32 indent, CV_ModifierFlags flags);
|
||||
|
||||
internal void cv_stringize_type_props(Arena *arena, String8List *out,
|
||||
U32 indent, CV_TypeProps props);
|
||||
|
||||
internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out,
|
||||
U32 indent, CV_PointerAttribs attribs);
|
||||
|
||||
internal void cv_stringize_local_flags(Arena *arena, String8List *out,
|
||||
U32 indent, CV_LocalFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Sym Stringize Functions
|
||||
|
||||
internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym);
|
||||
|
||||
internal void cv_stringize_sym_range(Arena *arena, String8List *out,
|
||||
CV_RecRange *range, String8 data,
|
||||
CV_StringizeSymParams *p);
|
||||
internal void cv_stringize_sym_array(Arena *arena, String8List *out,
|
||||
CV_RecRangeArray *ranges, String8 data,
|
||||
CV_StringizeSymParams *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Leaf Stringize Functions
|
||||
|
||||
internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf);
|
||||
|
||||
internal void cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
CV_RecRange *range, CV_TypeId itype, String8 data,
|
||||
CV_StringizeLeafParams *p);
|
||||
internal void cv_stringize_leaf_array(Arena *arena, String8List *out,
|
||||
CV_RecRangeArray *ranges, CV_TypeId itype_first,
|
||||
String8 data,
|
||||
CV_StringizeLeafParams *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView C13 Stringize Functions
|
||||
|
||||
internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13);
|
||||
|
||||
#endif // CODEVIEW_STRINGIZE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CODEVIEW_STRINGIZE_H
|
||||
#define CODEVIEW_STRINGIZE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Stringize Helper Types
|
||||
|
||||
typedef struct CV_StringizeSymParams{
|
||||
CV_Arch arch;
|
||||
} CV_StringizeSymParams;
|
||||
|
||||
typedef struct CV_StringizeLeafParams{
|
||||
U32 dummy;
|
||||
} CV_StringizeLeafParams;
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Common Stringize Functions
|
||||
|
||||
internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num);
|
||||
|
||||
internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out,
|
||||
CV_LvarAddrRange *range);
|
||||
internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap);
|
||||
internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out,
|
||||
void *first, void *opl);
|
||||
|
||||
internal String8 cv_string_from_basic_type(CV_BasicType basic_type);
|
||||
internal String8 cv_string_from_c13_sub_section_kind(CV_C13SubSectionKind kind);
|
||||
internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg);
|
||||
internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind);
|
||||
internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode);
|
||||
internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind);
|
||||
internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Flags Stringize Functions
|
||||
|
||||
internal void cv_stringize_modifier_flags(Arena *arena, String8List *out,
|
||||
U32 indent, CV_ModifierFlags flags);
|
||||
|
||||
internal void cv_stringize_type_props(Arena *arena, String8List *out,
|
||||
U32 indent, CV_TypeProps props);
|
||||
|
||||
internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out,
|
||||
U32 indent, CV_PointerAttribs attribs);
|
||||
|
||||
internal void cv_stringize_local_flags(Arena *arena, String8List *out,
|
||||
U32 indent, CV_LocalFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Sym Stringize Functions
|
||||
|
||||
internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym);
|
||||
|
||||
internal void cv_stringize_sym_range(Arena *arena, String8List *out,
|
||||
CV_RecRange *range, String8 data,
|
||||
CV_StringizeSymParams *p);
|
||||
internal void cv_stringize_sym_array(Arena *arena, String8List *out,
|
||||
CV_RecRangeArray *ranges, String8 data,
|
||||
CV_StringizeSymParams *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Leaf Stringize Functions
|
||||
|
||||
internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf);
|
||||
|
||||
internal void cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
CV_RecRange *range, CV_TypeId itype, String8 data,
|
||||
CV_StringizeLeafParams *p);
|
||||
internal void cv_stringize_leaf_array(Arena *arena, String8List *out,
|
||||
CV_RecRangeArray *ranges, CV_TypeId itype_first,
|
||||
String8 data,
|
||||
CV_StringizeLeafParams *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView C13 Stringize Functions
|
||||
|
||||
internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13);
|
||||
|
||||
#endif // CODEVIEW_STRINGIZE_H
|
||||
|
||||
+81
-81
@@ -1,81 +1,81 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tables
|
||||
|
||||
@table(name lower_name code default display_string)
|
||||
CTRL_ExceptionCodeKindTable:
|
||||
{
|
||||
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
|
||||
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
|
||||
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
|
||||
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
|
||||
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
|
||||
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
|
||||
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
|
||||
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
|
||||
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
|
||||
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
|
||||
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
|
||||
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
|
||||
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
|
||||
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
|
||||
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
|
||||
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
|
||||
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
|
||||
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
|
||||
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
|
||||
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
|
||||
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
|
||||
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
|
||||
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
|
||||
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
|
||||
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
|
||||
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
|
||||
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
|
||||
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
|
||||
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
|
||||
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
|
||||
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
|
||||
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
|
||||
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
|
||||
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
|
||||
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
|
||||
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
|
||||
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@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)`;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tables
|
||||
|
||||
@table(name lower_name code default display_string)
|
||||
CTRL_ExceptionCodeKindTable:
|
||||
{
|
||||
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
|
||||
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
|
||||
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
|
||||
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
|
||||
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
|
||||
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
|
||||
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
|
||||
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
|
||||
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
|
||||
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
|
||||
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
|
||||
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
|
||||
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
|
||||
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
|
||||
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
|
||||
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
|
||||
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
|
||||
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
|
||||
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
|
||||
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
|
||||
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
|
||||
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
|
||||
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
|
||||
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
|
||||
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
|
||||
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
|
||||
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
|
||||
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
|
||||
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
|
||||
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
|
||||
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
|
||||
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
|
||||
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
|
||||
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
|
||||
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
|
||||
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
|
||||
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@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)`;
|
||||
}
|
||||
|
||||
+844
-844
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "ctrl_core.c"
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "ctrl_core.c"
|
||||
|
||||
+77
-77
@@ -1,77 +1,77 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CTRL_INC_H
|
||||
#define CTRL_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
|
||||
//
|
||||
// This layer's purpose is to provide access to the asynchronously-running, low
|
||||
// level parts of a debugger, running on the debugger client. This primarily
|
||||
// consists of process control, using the Demon layer (the lower level
|
||||
// abstraction layer for process control, across multiple OSes), but including
|
||||
// higher-level concepts, like stepping, breakpoint resolution, conditional
|
||||
// breakpoint evaluation, and so on. Right now, this just includes process
|
||||
// control *local to the debugger client machine*. But in the future, this can
|
||||
// also include communication to multiple target machines, all running their
|
||||
// own process controller, using the Demon layer.
|
||||
//
|
||||
// This part of a debugger must run asynchronously to prevent blocking the UI -
|
||||
// ideally our debugger is designed such that, if targets are running, the
|
||||
// debugger frontend is still usable for a variety of purposes. So, in short,
|
||||
// the asynchronously-running "control thread", implemented by this layer, is
|
||||
// tasked with communicating with a separately executing "user thread". This
|
||||
// communication happens in two directions - `user -> ctrl`, and the reverse,
|
||||
// `ctrl -> user`.
|
||||
//
|
||||
// In the case of `user -> ctrl` communication, this is done with a ring buffer
|
||||
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
|
||||
// include commands like: launching targets, attaching to targets, killing
|
||||
// targets, detaching from targets, stepping/running, or single stepping.
|
||||
//
|
||||
// In the case of `ctrl -> user` communication, this is done with a ring buffer
|
||||
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
|
||||
// include information about what happened during the execution of targets -
|
||||
// including: process/module/thread creation, process/module/thread deletion,
|
||||
// debug strings, thread name events, memory allocation events, and stop events
|
||||
// (where stops can be caused by: user breakpoints, traps set for stepping,
|
||||
// exceptions, halts, or errors).
|
||||
//
|
||||
// The various stepping algorithms are implemented with two concepts: (a) the
|
||||
// "trap net", and (b) "spoofs".
|
||||
//
|
||||
// A "trap net" is a term which refers to a set of addresses paired with a set
|
||||
// of behavioral flags. Before targets run, trap instructions are written to
|
||||
// these addresses. After targets stop, these addresses are reset to their
|
||||
// original bytes. These trap instructions cause the debugger's targets to
|
||||
// stop executing, and based on which behavioral flags are associated with
|
||||
// the instruction causing the stop, the control thread may adjust parameters
|
||||
// used for running, then continue execution, or it will not resume target
|
||||
// execution, and will report stopped events. These behavioral flags can
|
||||
// include: single-stepping the stopped thread to execute the instruction at
|
||||
// the trap location, saving a stack pointer "check value" (where this check
|
||||
// value is compared against when making decisions about whether to continue
|
||||
// running or not), and so on. It's complicated to unpack why exactly these
|
||||
// behaviors are useful, but the TL;DR of it is that they are used for a
|
||||
// variety of stepping behaviors. For example, when doing a "step into" step,
|
||||
// a `call` instruction can have a trap set at it, and will be marked with
|
||||
// a "single-step-after" trap flag, as well as the "end stepping" trap flag,
|
||||
// such that the step operation will complete after the `call` has executed.
|
||||
//
|
||||
// A "spoof" is a feature the control layer uses to detect when some thread
|
||||
// returns from a particular sub-callstack. This is useful when implementing
|
||||
// "step over" in functions that may be recursive. In short, unlike a trap,
|
||||
// which writes a trap instruction (like `int3`) into an instruction stream,
|
||||
// a spoof overwrites a *return address* on some thread's *stack*. This return
|
||||
// address is not a valid address for executing code -- it is simply a value
|
||||
// that the debugger can recognize, such that it is notified when the thread
|
||||
// returns from some level in a callstack. When the thread exits some function,
|
||||
// it will return to the "spoofed" address, and it will immediately hit an
|
||||
// exception, because the spoofed address will not be a valid address for
|
||||
// code execution. At that point, the debugger can move the thread back to
|
||||
// the pre-spoof return address, and resume execution.
|
||||
|
||||
#include "ctrl_core.h"
|
||||
|
||||
#endif // CTRL_INC_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CTRL_INC_H
|
||||
#define CTRL_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
|
||||
//
|
||||
// This layer's purpose is to provide access to the asynchronously-running, low
|
||||
// level parts of a debugger, running on the debugger client. This primarily
|
||||
// consists of process control, using the Demon layer (the lower level
|
||||
// abstraction layer for process control, across multiple OSes), but including
|
||||
// higher-level concepts, like stepping, breakpoint resolution, conditional
|
||||
// breakpoint evaluation, and so on. Right now, this just includes process
|
||||
// control *local to the debugger client machine*. But in the future, this can
|
||||
// also include communication to multiple target machines, all running their
|
||||
// own process controller, using the Demon layer.
|
||||
//
|
||||
// This part of a debugger must run asynchronously to prevent blocking the UI -
|
||||
// ideally our debugger is designed such that, if targets are running, the
|
||||
// debugger frontend is still usable for a variety of purposes. So, in short,
|
||||
// the asynchronously-running "control thread", implemented by this layer, is
|
||||
// tasked with communicating with a separately executing "user thread". This
|
||||
// communication happens in two directions - `user -> ctrl`, and the reverse,
|
||||
// `ctrl -> user`.
|
||||
//
|
||||
// In the case of `user -> ctrl` communication, this is done with a ring buffer
|
||||
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
|
||||
// include commands like: launching targets, attaching to targets, killing
|
||||
// targets, detaching from targets, stepping/running, or single stepping.
|
||||
//
|
||||
// In the case of `ctrl -> user` communication, this is done with a ring buffer
|
||||
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
|
||||
// include information about what happened during the execution of targets -
|
||||
// including: process/module/thread creation, process/module/thread deletion,
|
||||
// debug strings, thread name events, memory allocation events, and stop events
|
||||
// (where stops can be caused by: user breakpoints, traps set for stepping,
|
||||
// exceptions, halts, or errors).
|
||||
//
|
||||
// The various stepping algorithms are implemented with two concepts: (a) the
|
||||
// "trap net", and (b) "spoofs".
|
||||
//
|
||||
// A "trap net" is a term which refers to a set of addresses paired with a set
|
||||
// of behavioral flags. Before targets run, trap instructions are written to
|
||||
// these addresses. After targets stop, these addresses are reset to their
|
||||
// original bytes. These trap instructions cause the debugger's targets to
|
||||
// stop executing, and based on which behavioral flags are associated with
|
||||
// the instruction causing the stop, the control thread may adjust parameters
|
||||
// used for running, then continue execution, or it will not resume target
|
||||
// execution, and will report stopped events. These behavioral flags can
|
||||
// include: single-stepping the stopped thread to execute the instruction at
|
||||
// the trap location, saving a stack pointer "check value" (where this check
|
||||
// value is compared against when making decisions about whether to continue
|
||||
// running or not), and so on. It's complicated to unpack why exactly these
|
||||
// behaviors are useful, but the TL;DR of it is that they are used for a
|
||||
// variety of stepping behaviors. For example, when doing a "step into" step,
|
||||
// a `call` instruction can have a trap set at it, and will be marked with
|
||||
// a "single-step-after" trap flag, as well as the "end stepping" trap flag,
|
||||
// such that the step operation will complete after the `call` has executed.
|
||||
//
|
||||
// A "spoof" is a feature the control layer uses to detect when some thread
|
||||
// returns from a particular sub-callstack. This is useful when implementing
|
||||
// "step over" in functions that may be recursive. In short, unlike a trap,
|
||||
// which writes a trap instruction (like `int3`) into an instruction stream,
|
||||
// a spoof overwrites a *return address* on some thread's *stack*. This return
|
||||
// address is not a valid address for executing code -- it is simply a value
|
||||
// that the debugger can recognize, such that it is notified when the thread
|
||||
// returns from some level in a callstack. When the thread exits some function,
|
||||
// it will return to the "spoofed" address, and it will immediately hit an
|
||||
// exception, because the spoofed address will not be a valid address for
|
||||
// code execution. At that point, the debugger can move the thread back to
|
||||
// the pre-spoof return address, and resume execution.
|
||||
|
||||
#include "ctrl_core.h"
|
||||
|
||||
#endif // CTRL_INC_H
|
||||
|
||||
+255
-255
@@ -1,255 +1,255 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DI_H
|
||||
#define DI_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Key Type
|
||||
|
||||
typedef struct DI_Key DI_Key;
|
||||
struct DI_Key
|
||||
{
|
||||
String8 path;
|
||||
U64 min_timestamp;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyNode DI_KeyNode;
|
||||
struct DI_KeyNode
|
||||
{
|
||||
DI_KeyNode *next;
|
||||
DI_Key v;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyList DI_KeyList;
|
||||
struct DI_KeyList
|
||||
{
|
||||
DI_KeyNode *first;
|
||||
DI_KeyNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyArray DI_KeyArray;
|
||||
struct DI_KeyArray
|
||||
{
|
||||
DI_Key *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Types
|
||||
|
||||
typedef enum DI_EventKind
|
||||
{
|
||||
DI_EventKind_Null,
|
||||
DI_EventKind_ConversionStarted,
|
||||
DI_EventKind_ConversionEnded,
|
||||
DI_EventKind_ConversionFailureUnsupportedFormat,
|
||||
DI_EventKind_COUNT
|
||||
}
|
||||
DI_EventKind;
|
||||
|
||||
typedef struct DI_Event DI_Event;
|
||||
struct DI_Event
|
||||
{
|
||||
DI_EventKind kind;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct DI_EventNode DI_EventNode;
|
||||
struct DI_EventNode
|
||||
{
|
||||
DI_EventNode *next;
|
||||
DI_Event v;
|
||||
};
|
||||
|
||||
typedef struct DI_EventList DI_EventList;
|
||||
struct DI_EventList
|
||||
{
|
||||
DI_EventNode *first;
|
||||
DI_EventNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct DI_StringChunkNode DI_StringChunkNode;
|
||||
struct DI_StringChunkNode
|
||||
{
|
||||
DI_StringChunkNode *next;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct DI_Node DI_Node;
|
||||
struct DI_Node
|
||||
{
|
||||
// rjf: links
|
||||
DI_Node *next;
|
||||
DI_Node *prev;
|
||||
|
||||
// rjf: metadata
|
||||
U64 ref_count;
|
||||
U64 touch_count;
|
||||
U64 is_working;
|
||||
U64 last_time_requested_us;
|
||||
|
||||
// rjf: key
|
||||
DI_Key key;
|
||||
|
||||
// rjf: file handles
|
||||
OS_Handle file;
|
||||
OS_Handle file_map;
|
||||
void *file_base;
|
||||
FileProperties file_props;
|
||||
|
||||
// rjf: parse artifacts
|
||||
Arena *arena;
|
||||
RDI_Parsed rdi;
|
||||
B32 parse_done;
|
||||
};
|
||||
|
||||
typedef struct DI_Slot DI_Slot;
|
||||
struct DI_Slot
|
||||
{
|
||||
DI_Node *first;
|
||||
DI_Node *last;
|
||||
};
|
||||
|
||||
typedef struct DI_Stripe DI_Stripe;
|
||||
struct DI_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Node *free_node;
|
||||
DI_StringChunkNode *free_string_chunks[8];
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct DI_Touch DI_Touch;
|
||||
struct DI_Touch
|
||||
{
|
||||
DI_Touch *next;
|
||||
DI_Node *node;
|
||||
};
|
||||
|
||||
typedef struct DI_Scope DI_Scope;
|
||||
struct DI_Scope
|
||||
{
|
||||
DI_Scope *next;
|
||||
DI_Touch *first_touch;
|
||||
DI_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct DI_TCTX DI_TCTX;
|
||||
struct DI_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Scope *free_scope;
|
||||
DI_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
typedef struct DI_Shared DI_Shared;
|
||||
struct DI_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: node cache
|
||||
U64 slots_count;
|
||||
DI_Slot *slots;
|
||||
U64 stripes_count;
|
||||
DI_Stripe *stripes;
|
||||
|
||||
// rjf: user -> parse ring
|
||||
OS_Handle u2p_ring_mutex;
|
||||
OS_Handle u2p_ring_cv;
|
||||
U64 u2p_ring_size;
|
||||
U8 *u2p_ring_base;
|
||||
U64 u2p_ring_write_pos;
|
||||
U64 u2p_ring_read_pos;
|
||||
|
||||
// rjf: parse -> user event ring
|
||||
OS_Handle p2u_ring_mutex;
|
||||
OS_Handle p2u_ring_cv;
|
||||
U64 p2u_ring_size;
|
||||
U8 *p2u_ring_base;
|
||||
U64 p2u_ring_write_pos;
|
||||
U64 p2u_ring_read_pos;
|
||||
|
||||
// rjf: threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DI_Shared *di_shared = 0;
|
||||
thread_static DI_TCTX *di_tctx = 0;
|
||||
global RDI_Parsed di_rdi_parsed_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_key(DI_Key *k);
|
||||
internal DI_Key di_key_zero(void);
|
||||
internal B32 di_key_match(DI_Key *a, DI_Key *b);
|
||||
internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
|
||||
internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src);
|
||||
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key);
|
||||
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void di_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal DI_Scope *di_scope_open(void);
|
||||
internal void di_scope_close(DI_Scope *scope);
|
||||
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Slot Functions
|
||||
|
||||
internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Stripe Functions
|
||||
|
||||
internal U64 di_string_bucket_idx_from_string_size(U64 size);
|
||||
internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Opening/Closing
|
||||
|
||||
internal void di_open(DI_Key *key);
|
||||
internal void di_close(DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
|
||||
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
|
||||
internal void di_p2u_push_event(DI_Event *event);
|
||||
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||
|
||||
internal void di_parse_thread__entry_point(void *p);
|
||||
|
||||
#endif // DI_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DI_H
|
||||
#define DI_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Key Type
|
||||
|
||||
typedef struct DI_Key DI_Key;
|
||||
struct DI_Key
|
||||
{
|
||||
String8 path;
|
||||
U64 min_timestamp;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyNode DI_KeyNode;
|
||||
struct DI_KeyNode
|
||||
{
|
||||
DI_KeyNode *next;
|
||||
DI_Key v;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyList DI_KeyList;
|
||||
struct DI_KeyList
|
||||
{
|
||||
DI_KeyNode *first;
|
||||
DI_KeyNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyArray DI_KeyArray;
|
||||
struct DI_KeyArray
|
||||
{
|
||||
DI_Key *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Types
|
||||
|
||||
typedef enum DI_EventKind
|
||||
{
|
||||
DI_EventKind_Null,
|
||||
DI_EventKind_ConversionStarted,
|
||||
DI_EventKind_ConversionEnded,
|
||||
DI_EventKind_ConversionFailureUnsupportedFormat,
|
||||
DI_EventKind_COUNT
|
||||
}
|
||||
DI_EventKind;
|
||||
|
||||
typedef struct DI_Event DI_Event;
|
||||
struct DI_Event
|
||||
{
|
||||
DI_EventKind kind;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct DI_EventNode DI_EventNode;
|
||||
struct DI_EventNode
|
||||
{
|
||||
DI_EventNode *next;
|
||||
DI_Event v;
|
||||
};
|
||||
|
||||
typedef struct DI_EventList DI_EventList;
|
||||
struct DI_EventList
|
||||
{
|
||||
DI_EventNode *first;
|
||||
DI_EventNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct DI_StringChunkNode DI_StringChunkNode;
|
||||
struct DI_StringChunkNode
|
||||
{
|
||||
DI_StringChunkNode *next;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct DI_Node DI_Node;
|
||||
struct DI_Node
|
||||
{
|
||||
// rjf: links
|
||||
DI_Node *next;
|
||||
DI_Node *prev;
|
||||
|
||||
// rjf: metadata
|
||||
U64 ref_count;
|
||||
U64 touch_count;
|
||||
U64 is_working;
|
||||
U64 last_time_requested_us;
|
||||
|
||||
// rjf: key
|
||||
DI_Key key;
|
||||
|
||||
// rjf: file handles
|
||||
OS_Handle file;
|
||||
OS_Handle file_map;
|
||||
void *file_base;
|
||||
FileProperties file_props;
|
||||
|
||||
// rjf: parse artifacts
|
||||
Arena *arena;
|
||||
RDI_Parsed rdi;
|
||||
B32 parse_done;
|
||||
};
|
||||
|
||||
typedef struct DI_Slot DI_Slot;
|
||||
struct DI_Slot
|
||||
{
|
||||
DI_Node *first;
|
||||
DI_Node *last;
|
||||
};
|
||||
|
||||
typedef struct DI_Stripe DI_Stripe;
|
||||
struct DI_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Node *free_node;
|
||||
DI_StringChunkNode *free_string_chunks[8];
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct DI_Touch DI_Touch;
|
||||
struct DI_Touch
|
||||
{
|
||||
DI_Touch *next;
|
||||
DI_Node *node;
|
||||
};
|
||||
|
||||
typedef struct DI_Scope DI_Scope;
|
||||
struct DI_Scope
|
||||
{
|
||||
DI_Scope *next;
|
||||
DI_Touch *first_touch;
|
||||
DI_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct DI_TCTX DI_TCTX;
|
||||
struct DI_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Scope *free_scope;
|
||||
DI_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
typedef struct DI_Shared DI_Shared;
|
||||
struct DI_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: node cache
|
||||
U64 slots_count;
|
||||
DI_Slot *slots;
|
||||
U64 stripes_count;
|
||||
DI_Stripe *stripes;
|
||||
|
||||
// rjf: user -> parse ring
|
||||
OS_Handle u2p_ring_mutex;
|
||||
OS_Handle u2p_ring_cv;
|
||||
U64 u2p_ring_size;
|
||||
U8 *u2p_ring_base;
|
||||
U64 u2p_ring_write_pos;
|
||||
U64 u2p_ring_read_pos;
|
||||
|
||||
// rjf: parse -> user event ring
|
||||
OS_Handle p2u_ring_mutex;
|
||||
OS_Handle p2u_ring_cv;
|
||||
U64 p2u_ring_size;
|
||||
U8 *p2u_ring_base;
|
||||
U64 p2u_ring_write_pos;
|
||||
U64 p2u_ring_read_pos;
|
||||
|
||||
// rjf: threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DI_Shared *di_shared = 0;
|
||||
thread_static DI_TCTX *di_tctx = 0;
|
||||
global RDI_Parsed di_rdi_parsed_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_key(DI_Key *k);
|
||||
internal DI_Key di_key_zero(void);
|
||||
internal B32 di_key_match(DI_Key *a, DI_Key *b);
|
||||
internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
|
||||
internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src);
|
||||
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key);
|
||||
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void di_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal DI_Scope *di_scope_open(void);
|
||||
internal void di_scope_close(DI_Scope *scope);
|
||||
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Slot Functions
|
||||
|
||||
internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Stripe Functions
|
||||
|
||||
internal U64 di_string_bucket_idx_from_string_size(U64 size);
|
||||
internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Opening/Closing
|
||||
|
||||
internal void di_open(DI_Key *key);
|
||||
internal void di_close(DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
|
||||
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
|
||||
internal void di_p2u_push_event(DI_Event *event);
|
||||
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||
|
||||
internal void di_parse_thread__entry_point(void *p);
|
||||
|
||||
#endif // DI_H
|
||||
|
||||
+158
-158
@@ -1,158 +1,158 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/demon.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
|
||||
|
||||
//- rjf: handles
|
||||
|
||||
internal DMN_Handle
|
||||
dmn_handle_zero(void)
|
||||
{
|
||||
DMN_Handle h = {0};
|
||||
return h;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_handle_match(DMN_Handle a, DMN_Handle b)
|
||||
{
|
||||
return a.u32[0] == b.u32[0] && a.u32[1] == b.u32[1];
|
||||
}
|
||||
|
||||
//- rjf: trap chunk lists
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap)
|
||||
{
|
||||
DMN_TrapChunkNode *node = list->last;
|
||||
if(node == 0 || node->count >= node->cap)
|
||||
{
|
||||
node = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
node->cap = cap;
|
||||
node->v = push_array_no_zero(arena, DMN_Trap, node->cap);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->node_count += 1;
|
||||
}
|
||||
MemoryCopyStruct(&node->v[node->count], trap);
|
||||
node->count += 1;
|
||||
list->trap_count += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
if(dst->last == 0)
|
||||
{
|
||||
MemoryCopyStruct(dst, to_push);
|
||||
}
|
||||
else if(to_push->first != 0)
|
||||
{
|
||||
dst->last->next = to_push->first;
|
||||
dst->last = to_push->last;
|
||||
dst->node_count += to_push->node_count;
|
||||
dst->trap_count += to_push->trap_count;
|
||||
}
|
||||
MemoryZeroStruct(to_push);
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
for(DMN_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
|
||||
{
|
||||
DMN_TrapChunkNode *dst_n = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
dst_n->v = src_n->v;
|
||||
dst_n->cap = src_n->cap;
|
||||
dst_n->count = src_n->count;
|
||||
SLLQueuePush(dst->first, dst->last, dst_n);
|
||||
dst->node_count += 1;
|
||||
dst->trap_count += dst_n->count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: handle lists
|
||||
|
||||
internal void
|
||||
dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle)
|
||||
{
|
||||
DMN_HandleNode *node = push_array(arena, DMN_HandleNode, 1);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
node->v = handle;
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list)
|
||||
{
|
||||
DMN_HandleArray array = {0};
|
||||
array.count = list->count;
|
||||
array.handles = push_array_no_zero(arena, DMN_Handle, array.count);
|
||||
U64 idx = 0;
|
||||
for(DMN_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
array.handles[idx] = n->v;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src)
|
||||
{
|
||||
DMN_HandleArray dst = {0};
|
||||
dst.count = src->count;
|
||||
dst.handles = push_array_no_zero(arena, DMN_Handle, dst.count);
|
||||
MemoryCopy(dst.handles, src->handles, sizeof(DMN_Handle)*dst.count);
|
||||
return dst;
|
||||
}
|
||||
|
||||
//- rjf: event list building
|
||||
|
||||
internal DMN_Event *
|
||||
dmn_event_list_push(Arena *arena, DMN_EventList *list)
|
||||
{
|
||||
DMN_EventNode *n = push_array(arena, DMN_EventNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
DMN_Event *result = &n->v;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
|
||||
|
||||
internal U64
|
||||
dmn_rip_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rip_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_rsp_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rsp_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/demon.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
|
||||
|
||||
//- rjf: handles
|
||||
|
||||
internal DMN_Handle
|
||||
dmn_handle_zero(void)
|
||||
{
|
||||
DMN_Handle h = {0};
|
||||
return h;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_handle_match(DMN_Handle a, DMN_Handle b)
|
||||
{
|
||||
return a.u32[0] == b.u32[0] && a.u32[1] == b.u32[1];
|
||||
}
|
||||
|
||||
//- rjf: trap chunk lists
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap)
|
||||
{
|
||||
DMN_TrapChunkNode *node = list->last;
|
||||
if(node == 0 || node->count >= node->cap)
|
||||
{
|
||||
node = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
node->cap = cap;
|
||||
node->v = push_array_no_zero(arena, DMN_Trap, node->cap);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->node_count += 1;
|
||||
}
|
||||
MemoryCopyStruct(&node->v[node->count], trap);
|
||||
node->count += 1;
|
||||
list->trap_count += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
if(dst->last == 0)
|
||||
{
|
||||
MemoryCopyStruct(dst, to_push);
|
||||
}
|
||||
else if(to_push->first != 0)
|
||||
{
|
||||
dst->last->next = to_push->first;
|
||||
dst->last = to_push->last;
|
||||
dst->node_count += to_push->node_count;
|
||||
dst->trap_count += to_push->trap_count;
|
||||
}
|
||||
MemoryZeroStruct(to_push);
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
for(DMN_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
|
||||
{
|
||||
DMN_TrapChunkNode *dst_n = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
dst_n->v = src_n->v;
|
||||
dst_n->cap = src_n->cap;
|
||||
dst_n->count = src_n->count;
|
||||
SLLQueuePush(dst->first, dst->last, dst_n);
|
||||
dst->node_count += 1;
|
||||
dst->trap_count += dst_n->count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: handle lists
|
||||
|
||||
internal void
|
||||
dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle)
|
||||
{
|
||||
DMN_HandleNode *node = push_array(arena, DMN_HandleNode, 1);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
node->v = handle;
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list)
|
||||
{
|
||||
DMN_HandleArray array = {0};
|
||||
array.count = list->count;
|
||||
array.handles = push_array_no_zero(arena, DMN_Handle, array.count);
|
||||
U64 idx = 0;
|
||||
for(DMN_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
array.handles[idx] = n->v;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src)
|
||||
{
|
||||
DMN_HandleArray dst = {0};
|
||||
dst.count = src->count;
|
||||
dst.handles = push_array_no_zero(arena, DMN_Handle, dst.count);
|
||||
MemoryCopy(dst.handles, src->handles, sizeof(DMN_Handle)*dst.count);
|
||||
return dst;
|
||||
}
|
||||
|
||||
//- rjf: event list building
|
||||
|
||||
internal DMN_Event *
|
||||
dmn_event_list_push(Arena *arena, DMN_EventList *list)
|
||||
{
|
||||
DMN_EventNode *n = push_array(arena, DMN_EventNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
DMN_Event *result = &n->v;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
|
||||
|
||||
internal U64
|
||||
dmn_rip_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rip_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_rsp_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rsp_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
+90
-90
@@ -1,90 +1,90 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Kind Tables
|
||||
|
||||
@table(name)
|
||||
DMN_EventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Error}
|
||||
{HandshakeComplete}
|
||||
{CreateProcess}
|
||||
{ExitProcess}
|
||||
{CreateThread}
|
||||
{ExitThread}
|
||||
{LoadModule}
|
||||
{UnloadModule}
|
||||
{Breakpoint}
|
||||
{Trap}
|
||||
{SingleStep}
|
||||
{Exception}
|
||||
{Halt}
|
||||
{Memory}
|
||||
{DebugString}
|
||||
{SetThreadName}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ErrorKindTable:
|
||||
{
|
||||
{Null}
|
||||
{NotAttached}
|
||||
{UnexpectedFailure}
|
||||
{InvalidHandle}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_MemoryEventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Commit}
|
||||
{Reserve}
|
||||
{Decommit}
|
||||
{Release}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ExceptionKindTable:
|
||||
{
|
||||
{Null}
|
||||
{MemoryRead}
|
||||
{MemoryWrite}
|
||||
{MemoryExecute}
|
||||
{CppThrow}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@enum DMN_EventKind:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_event_kind_string_table:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
@enum DMN_ErrorKind:
|
||||
{
|
||||
@expand(DMN_ErrorKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_MemoryEventKind:
|
||||
{
|
||||
@expand(DMN_MemoryEventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_ExceptionKind:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_exception_kind_string_table:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Kind Tables
|
||||
|
||||
@table(name)
|
||||
DMN_EventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Error}
|
||||
{HandshakeComplete}
|
||||
{CreateProcess}
|
||||
{ExitProcess}
|
||||
{CreateThread}
|
||||
{ExitThread}
|
||||
{LoadModule}
|
||||
{UnloadModule}
|
||||
{Breakpoint}
|
||||
{Trap}
|
||||
{SingleStep}
|
||||
{Exception}
|
||||
{Halt}
|
||||
{Memory}
|
||||
{DebugString}
|
||||
{SetThreadName}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ErrorKindTable:
|
||||
{
|
||||
{Null}
|
||||
{NotAttached}
|
||||
{UnexpectedFailure}
|
||||
{InvalidHandle}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_MemoryEventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Commit}
|
||||
{Reserve}
|
||||
{Decommit}
|
||||
{Release}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ExceptionKindTable:
|
||||
{
|
||||
{Null}
|
||||
{MemoryRead}
|
||||
{MemoryWrite}
|
||||
{MemoryExecute}
|
||||
{CppThrow}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@enum DMN_EventKind:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_event_kind_string_table:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
@enum DMN_ErrorKind:
|
||||
{
|
||||
@expand(DMN_ErrorKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_MemoryEventKind:
|
||||
{
|
||||
@expand(DMN_MemoryEventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_ExceptionKind:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_exception_kind_string_table:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
+222
-222
@@ -1,222 +1,222 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_OS_LINUX_H
|
||||
#define DEMON_OS_LINUX_H
|
||||
|
||||
// TODO(allen): Potential Upgrades:
|
||||
//
|
||||
// memory fd upgrade - Right now for each process we hold open a file
|
||||
// descriptor for the process's memory (/proc/%d/mem) for the entire lifetime
|
||||
// of the process; it could be opened and closed with some kind of LRU cache
|
||||
// to put a finite cap on the number of handles the demon holds
|
||||
//
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Get The Linux Includes
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Types
|
||||
|
||||
//- entities
|
||||
|
||||
// Demon Linux Entity Extensions
|
||||
// Process: ext_u64 set to memory file descriptor
|
||||
// Thread : ext_u64 cast to DEMON_LNX_ThreadExt
|
||||
// Module : ext_u64 set to U64 (address of name)
|
||||
|
||||
struct DEMON_LNX_ThreadExt{
|
||||
B32 expecting_dummy_sigstop;
|
||||
};
|
||||
StaticAssert(sizeof(DEMON_LNX_ThreadExt) <= sizeof(Member(DEMON_Entity, ext_u64)), check_demon_lnx_thread_ext);
|
||||
|
||||
//- helpers
|
||||
|
||||
struct DEMON_LNX_AttachNode{
|
||||
DEMON_LNX_AttachNode *next;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ProcessAux{
|
||||
B32 filled;
|
||||
U64 phnum;
|
||||
U64 phent;
|
||||
U64 phdr;
|
||||
U64 execfn;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_PhdrInfo{
|
||||
Rng1U64 range;
|
||||
U64 dynamic;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ModuleNode{
|
||||
DEMON_LNX_ModuleNode *next;
|
||||
U64 vaddr;
|
||||
U64 size;
|
||||
U64 name;
|
||||
U64 already_known;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_EntityNode{
|
||||
DEMON_LNX_EntityNode *next;
|
||||
DEMON_Entity *entity;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Register Layouts
|
||||
|
||||
// these are defined in <sys/user.h> but only for one architecture at a time
|
||||
// (and we can't really trick it into giving us both in any obvious way)
|
||||
// we define them here so that we have them all "at once"
|
||||
|
||||
struct DEMON_LNX_UserRegsX64{
|
||||
U64 r15;
|
||||
U64 r14;
|
||||
U64 r13;
|
||||
U64 r12;
|
||||
U64 rbp;
|
||||
U64 rbx;
|
||||
U64 r11;
|
||||
U64 r10;
|
||||
U64 r9;
|
||||
U64 r8;
|
||||
U64 rax;
|
||||
U64 rcx;
|
||||
U64 rdx;
|
||||
U64 rsi;
|
||||
U64 rdi;
|
||||
U64 orig_rax;
|
||||
U64 rip;
|
||||
U64 cs;
|
||||
U64 rflags;
|
||||
U64 rsp;
|
||||
U64 ss;
|
||||
U64 fsbase;
|
||||
U64 gsbase;
|
||||
U64 ds;
|
||||
U64 es;
|
||||
U64 fs;
|
||||
U64 gs;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX64{
|
||||
DEMON_LNX_UserRegsX64 regs;
|
||||
S32 u_fpvalid, _pad0;
|
||||
SYMS_XSaveLegacy i387;
|
||||
U64 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
U64 signal;
|
||||
S32 reserved, _pad1;
|
||||
U64 u_ar0, u_fpstate;
|
||||
U64 magic;
|
||||
U8 u_comm[32];
|
||||
U64 u_debugreg[8];
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserRegsX86{
|
||||
U32 ebx;
|
||||
U32 ecx;
|
||||
U32 edx;
|
||||
U32 esi;
|
||||
U32 edi;
|
||||
U32 ebp;
|
||||
U32 eax;
|
||||
U32 ds;
|
||||
U32 es;
|
||||
U32 fs;
|
||||
U32 gs;
|
||||
U32 orig_eax;
|
||||
U32 eip;
|
||||
U32 cs;
|
||||
U32 eflags;
|
||||
U32 sp;
|
||||
U32 ss;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX86{
|
||||
DEMON_LNX_UserRegsX86 regs;
|
||||
S32 u_fpvalid;
|
||||
SYMS_FSave i387;
|
||||
U32 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
S32 signal, reserved;
|
||||
U32 u_ar0, u_fpstate;
|
||||
U32 magic;
|
||||
U8 u_comm[32];
|
||||
U32 u_debugreg[8];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_PermFlags_Read = (1 << 0),
|
||||
DEMON_LNX_PermFlags_Write = (1 << 1),
|
||||
DEMON_LNX_PermFlags_Exec = (1 << 2),
|
||||
DEMON_LNX_PermFlags_Private = (1 << 3)
|
||||
};
|
||||
typedef int DEMON_LNX_PermFlags;
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_MapsEntryType_Null,
|
||||
DEMON_LNX_MapsEntryType_Path,
|
||||
DEMON_LNX_MapsEntryType_Heap,
|
||||
DEMON_LNX_MapsEntryType_Stack,
|
||||
DEMON_LNX_MapsEntryType_VDSO,
|
||||
};
|
||||
typedef int DEMON_LNX_MapsEntryType;
|
||||
|
||||
struct DEMON_LNX_MapsEntry
|
||||
{
|
||||
U64 address_lo;
|
||||
U64 address_hi;
|
||||
DEMON_LNX_PermFlags perms;
|
||||
U64 offset;
|
||||
U32 dev_major;
|
||||
U32 dev_minor;
|
||||
U64 inode;
|
||||
String8 pathname;
|
||||
DEMON_LNX_MapsEntryType type;
|
||||
pid_t stack_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DEMON_LNX_ThreadExt* demon_lnx_thread_ext(DEMON_Entity *entity);
|
||||
|
||||
internal B32 demon_lnx_attach_pid(Arena *arena, pid_t pid, DEMON_LNX_AttachNode **new_node);
|
||||
|
||||
internal String8 demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid);
|
||||
internal int demon_lnx_open_memory_fd_for_pid(pid_t pid);
|
||||
|
||||
internal Architecture demon_lnx_arch_from_pid(pid_t pid);
|
||||
internal DEMON_LNX_ProcessAux demon_lnx_aux_from_pid(pid_t pid, Architecture arch);
|
||||
internal DEMON_LNX_PhdrInfo demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit,
|
||||
U64 phvaddr, U64 phstride, U64 phcount);
|
||||
internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process);
|
||||
|
||||
internal U64 demon_lnx_read_memory(int memory_fd, void *dst, U64 src, U64 size);
|
||||
internal B32 demon_lnx_write_memory(int memory_fd, U64 dst, void *src, U64 size);
|
||||
internal String8 demon_lnx_read_memory_str(Arena *arena, int memory_fd, U64 address);
|
||||
|
||||
internal void demon_lnx_regs_x64_from_usr_regs_x64(SYMS_RegX64 *dst, DEMON_LNX_UserRegsX64 *src);
|
||||
internal void demon_lnx_usr_regs_x64_from_regs_x64(DEMON_LNX_UserRegsX64 *dst, SYMS_RegX64 *src);
|
||||
|
||||
internal String8 demon_lnx_read_int_string(int fd);
|
||||
internal B32 demon_lnx_read_expect(int fd, char expect);
|
||||
internal int demon_lnx_read_whitespace(int fd);
|
||||
internal String8 demon_lnx_read_string(Arena *arena, int fd);
|
||||
|
||||
internal int demon_lnx_open_maps(pid_t pid);
|
||||
internal B32 demon_lnx_next_map(Arena *arena, int maps, DEMON_LNX_MapsEntry *entry_out);
|
||||
|
||||
#endif //DEMON_OS_LINUX_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_OS_LINUX_H
|
||||
#define DEMON_OS_LINUX_H
|
||||
|
||||
// TODO(allen): Potential Upgrades:
|
||||
//
|
||||
// memory fd upgrade - Right now for each process we hold open a file
|
||||
// descriptor for the process's memory (/proc/%d/mem) for the entire lifetime
|
||||
// of the process; it could be opened and closed with some kind of LRU cache
|
||||
// to put a finite cap on the number of handles the demon holds
|
||||
//
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Get The Linux Includes
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Types
|
||||
|
||||
//- entities
|
||||
|
||||
// Demon Linux Entity Extensions
|
||||
// Process: ext_u64 set to memory file descriptor
|
||||
// Thread : ext_u64 cast to DEMON_LNX_ThreadExt
|
||||
// Module : ext_u64 set to U64 (address of name)
|
||||
|
||||
struct DEMON_LNX_ThreadExt{
|
||||
B32 expecting_dummy_sigstop;
|
||||
};
|
||||
StaticAssert(sizeof(DEMON_LNX_ThreadExt) <= sizeof(Member(DEMON_Entity, ext_u64)), check_demon_lnx_thread_ext);
|
||||
|
||||
//- helpers
|
||||
|
||||
struct DEMON_LNX_AttachNode{
|
||||
DEMON_LNX_AttachNode *next;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ProcessAux{
|
||||
B32 filled;
|
||||
U64 phnum;
|
||||
U64 phent;
|
||||
U64 phdr;
|
||||
U64 execfn;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_PhdrInfo{
|
||||
Rng1U64 range;
|
||||
U64 dynamic;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ModuleNode{
|
||||
DEMON_LNX_ModuleNode *next;
|
||||
U64 vaddr;
|
||||
U64 size;
|
||||
U64 name;
|
||||
U64 already_known;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_EntityNode{
|
||||
DEMON_LNX_EntityNode *next;
|
||||
DEMON_Entity *entity;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Register Layouts
|
||||
|
||||
// these are defined in <sys/user.h> but only for one architecture at a time
|
||||
// (and we can't really trick it into giving us both in any obvious way)
|
||||
// we define them here so that we have them all "at once"
|
||||
|
||||
struct DEMON_LNX_UserRegsX64{
|
||||
U64 r15;
|
||||
U64 r14;
|
||||
U64 r13;
|
||||
U64 r12;
|
||||
U64 rbp;
|
||||
U64 rbx;
|
||||
U64 r11;
|
||||
U64 r10;
|
||||
U64 r9;
|
||||
U64 r8;
|
||||
U64 rax;
|
||||
U64 rcx;
|
||||
U64 rdx;
|
||||
U64 rsi;
|
||||
U64 rdi;
|
||||
U64 orig_rax;
|
||||
U64 rip;
|
||||
U64 cs;
|
||||
U64 rflags;
|
||||
U64 rsp;
|
||||
U64 ss;
|
||||
U64 fsbase;
|
||||
U64 gsbase;
|
||||
U64 ds;
|
||||
U64 es;
|
||||
U64 fs;
|
||||
U64 gs;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX64{
|
||||
DEMON_LNX_UserRegsX64 regs;
|
||||
S32 u_fpvalid, _pad0;
|
||||
SYMS_XSaveLegacy i387;
|
||||
U64 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
U64 signal;
|
||||
S32 reserved, _pad1;
|
||||
U64 u_ar0, u_fpstate;
|
||||
U64 magic;
|
||||
U8 u_comm[32];
|
||||
U64 u_debugreg[8];
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserRegsX86{
|
||||
U32 ebx;
|
||||
U32 ecx;
|
||||
U32 edx;
|
||||
U32 esi;
|
||||
U32 edi;
|
||||
U32 ebp;
|
||||
U32 eax;
|
||||
U32 ds;
|
||||
U32 es;
|
||||
U32 fs;
|
||||
U32 gs;
|
||||
U32 orig_eax;
|
||||
U32 eip;
|
||||
U32 cs;
|
||||
U32 eflags;
|
||||
U32 sp;
|
||||
U32 ss;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX86{
|
||||
DEMON_LNX_UserRegsX86 regs;
|
||||
S32 u_fpvalid;
|
||||
SYMS_FSave i387;
|
||||
U32 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
S32 signal, reserved;
|
||||
U32 u_ar0, u_fpstate;
|
||||
U32 magic;
|
||||
U8 u_comm[32];
|
||||
U32 u_debugreg[8];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_PermFlags_Read = (1 << 0),
|
||||
DEMON_LNX_PermFlags_Write = (1 << 1),
|
||||
DEMON_LNX_PermFlags_Exec = (1 << 2),
|
||||
DEMON_LNX_PermFlags_Private = (1 << 3)
|
||||
};
|
||||
typedef int DEMON_LNX_PermFlags;
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_MapsEntryType_Null,
|
||||
DEMON_LNX_MapsEntryType_Path,
|
||||
DEMON_LNX_MapsEntryType_Heap,
|
||||
DEMON_LNX_MapsEntryType_Stack,
|
||||
DEMON_LNX_MapsEntryType_VDSO,
|
||||
};
|
||||
typedef int DEMON_LNX_MapsEntryType;
|
||||
|
||||
struct DEMON_LNX_MapsEntry
|
||||
{
|
||||
U64 address_lo;
|
||||
U64 address_hi;
|
||||
DEMON_LNX_PermFlags perms;
|
||||
U64 offset;
|
||||
U32 dev_major;
|
||||
U32 dev_minor;
|
||||
U64 inode;
|
||||
String8 pathname;
|
||||
DEMON_LNX_MapsEntryType type;
|
||||
pid_t stack_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DEMON_LNX_ThreadExt* demon_lnx_thread_ext(DEMON_Entity *entity);
|
||||
|
||||
internal B32 demon_lnx_attach_pid(Arena *arena, pid_t pid, DEMON_LNX_AttachNode **new_node);
|
||||
|
||||
internal String8 demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid);
|
||||
internal int demon_lnx_open_memory_fd_for_pid(pid_t pid);
|
||||
|
||||
internal Architecture demon_lnx_arch_from_pid(pid_t pid);
|
||||
internal DEMON_LNX_ProcessAux demon_lnx_aux_from_pid(pid_t pid, Architecture arch);
|
||||
internal DEMON_LNX_PhdrInfo demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit,
|
||||
U64 phvaddr, U64 phstride, U64 phcount);
|
||||
internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process);
|
||||
|
||||
internal U64 demon_lnx_read_memory(int memory_fd, void *dst, U64 src, U64 size);
|
||||
internal B32 demon_lnx_write_memory(int memory_fd, U64 dst, void *src, U64 size);
|
||||
internal String8 demon_lnx_read_memory_str(Arena *arena, int memory_fd, U64 address);
|
||||
|
||||
internal void demon_lnx_regs_x64_from_usr_regs_x64(SYMS_RegX64 *dst, DEMON_LNX_UserRegsX64 *src);
|
||||
internal void demon_lnx_usr_regs_x64_from_regs_x64(DEMON_LNX_UserRegsX64 *dst, SYMS_RegX64 *src);
|
||||
|
||||
internal String8 demon_lnx_read_int_string(int fd);
|
||||
internal B32 demon_lnx_read_expect(int fd, char expect);
|
||||
internal int demon_lnx_read_whitespace(int fd);
|
||||
internal String8 demon_lnx_read_string(Arena *arena, int fd);
|
||||
|
||||
internal int demon_lnx_open_maps(pid_t pid);
|
||||
internal B32 demon_lnx_next_map(Arena *arena, int maps, DEMON_LNX_MapsEntry *entry_out);
|
||||
|
||||
#endif //DEMON_OS_LINUX_H
|
||||
|
||||
+286
-286
@@ -1,286 +1,286 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_WIN32_H
|
||||
#define DEMON_CORE_WIN32_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Windows Includes
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Exception Codes
|
||||
|
||||
#define DMN_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DMN_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DMN_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DMN_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DMN_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DMN_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DMN_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DMN_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DMN_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DMN_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DMN_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DMN_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DMN_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DMN_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DMN_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DMN_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DMN_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DMN_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DMN_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DMN_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DMN_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DMN_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DMN_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DMN_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DMN_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DMN_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DMN_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DMN_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DMN_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DMN_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DMN_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DMN_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DMN_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DMN_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DMN_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
#define DMN_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u
|
||||
#define DMN_w32_EXCEPTION_CLRDBG_NOTIFICATION 0x04242420u
|
||||
#define DMN_w32_EXCEPTION_CLR 0xE0434352u
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Register Codes
|
||||
|
||||
#define DMN_W32_CTX_X86 0x00010000
|
||||
#define DMN_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags
|
||||
#define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15
|
||||
#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 // segds, seges, segfs, and seggs
|
||||
#define DMN_W32_CTX_INTEL_FLOATS 0x0008 // xmm0-xmm15
|
||||
#define DMN_W32_CTX_INTEL_DEBUG 0x0010 // dr0-dr3 and dr6-dr7
|
||||
#define DMN_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DMN_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DMN_W32_CTX_X86_ALL (DMN_W32_CTX_X86 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_DEBUG | \
|
||||
DMN_W32_CTX_INTEL_EXTENDED)
|
||||
#define DMN_W32_CTX_X64_ALL (DMN_W32_CTX_X64 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_FLOATS | \
|
||||
DMN_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Entity State
|
||||
|
||||
typedef enum DMN_W32_EntityKind
|
||||
{
|
||||
DMN_W32_EntityKind_Null,
|
||||
DMN_W32_EntityKind_Root,
|
||||
DMN_W32_EntityKind_Process,
|
||||
DMN_W32_EntityKind_Thread,
|
||||
DMN_W32_EntityKind_Module,
|
||||
DMN_W32_EntityKind_COUNT
|
||||
}
|
||||
DMN_W32_EntityKind;
|
||||
|
||||
typedef struct DMN_W32_Entity DMN_W32_Entity;
|
||||
struct DMN_W32_Entity
|
||||
{
|
||||
DMN_W32_Entity *first;
|
||||
DMN_W32_Entity *last;
|
||||
DMN_W32_Entity *next;
|
||||
DMN_W32_Entity *prev;
|
||||
DMN_W32_Entity *parent;
|
||||
DMN_W32_EntityKind kind;
|
||||
U32 gen;
|
||||
U64 id;
|
||||
HANDLE handle;
|
||||
Architecture arch;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
U64 injection_address;
|
||||
B32 did_first_bp;
|
||||
}
|
||||
proc;
|
||||
struct
|
||||
{
|
||||
U64 thread_local_base;
|
||||
U64 last_name_hash;
|
||||
U64 name_gather_time_us;
|
||||
}
|
||||
thread;
|
||||
struct
|
||||
{
|
||||
Rng1U64 vaddr_range;
|
||||
U64 address_of_name_pointer;
|
||||
B32 is_main;
|
||||
B32 name_is_unicode;
|
||||
}
|
||||
module;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityNode DMN_W32_EntityNode;
|
||||
struct DMN_W32_EntityNode
|
||||
{
|
||||
DMN_W32_EntityNode *next;
|
||||
DMN_W32_Entity *v;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashNode DMN_W32_EntityIDHashNode;
|
||||
struct DMN_W32_EntityIDHashNode
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *next;
|
||||
DMN_W32_EntityIDHashNode *prev;
|
||||
U64 id;
|
||||
DMN_W32_Entity *entity;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashSlot DMN_W32_EntityIDHashSlot;
|
||||
struct DMN_W32_EntityIDHashSlot
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *first;
|
||||
DMN_W32_EntityIDHashNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Injection Types
|
||||
|
||||
typedef struct DMN_W32_InjectedBreak DMN_W32_InjectedBreak;
|
||||
struct DMN_W32_InjectedBreak
|
||||
{
|
||||
U64 code;
|
||||
U64 user_data;
|
||||
};
|
||||
|
||||
#define DMN_W32_INJECTED_CODE_SIZE 32
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Image Info Types
|
||||
|
||||
typedef struct DMN_W32_ImageInfo DMN_W32_ImageInfo;
|
||||
struct DMN_W32_ImageInfo
|
||||
{
|
||||
Architecture arch;
|
||||
U32 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Dynamically-Loaded Win32 Function Types
|
||||
|
||||
typedef HRESULT DMN_W32_GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct DMN_W32_Shared DMN_W32_Shared;
|
||||
struct DMN_W32_Shared
|
||||
{
|
||||
// rjf: top-level info
|
||||
Arena *arena;
|
||||
String8List env_strings;
|
||||
|
||||
// rjf: access locking mechanism
|
||||
OS_Handle access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: run/mem/reg gens
|
||||
U64 run_gen;
|
||||
U64 mem_gen;
|
||||
U64 reg_gen;
|
||||
|
||||
// rjf: detaching info
|
||||
Arena *detach_arena;
|
||||
DMN_HandleList detach_processes;
|
||||
|
||||
// rjf: entity state
|
||||
Arena *entities_arena;
|
||||
DMN_W32_Entity *entities_base;
|
||||
DMN_W32_Entity *entities_first_free;
|
||||
U64 entities_count;
|
||||
DMN_W32_EntityIDHashSlot *entities_id_hash_slots;
|
||||
U64 entities_id_hash_slots_count;
|
||||
DMN_W32_EntityIDHashNode *entities_id_hash_node_free;
|
||||
|
||||
// rjf: launch state
|
||||
B32 new_process_pending;
|
||||
|
||||
// rjf: run results
|
||||
B32 resume_needed;
|
||||
U32 resume_pid;
|
||||
U32 resume_tid;
|
||||
B32 exception_not_handled;
|
||||
|
||||
// rjf: halting info
|
||||
DMN_Handle halter_process;
|
||||
U32 halter_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DMN_W32_Shared *dmn_w32_shared = 0;
|
||||
global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil};
|
||||
global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0;
|
||||
thread_static B32 dmn_w32_ctrl_thread = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 dmn_w32_hash_from_string(String8 string);
|
||||
internal U64 dmn_w32_hash_from_id(U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Helpers
|
||||
|
||||
//- rjf: entity <-> handle
|
||||
internal DMN_Handle dmn_w32_handle_from_entity(DMN_W32_Entity *entity);
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_handle(DMN_Handle handle);
|
||||
|
||||
//- rjf: entity allocation/deallocation
|
||||
internal DMN_W32_Entity *dmn_w32_entity_alloc(DMN_W32_Entity *parent, DMN_W32_EntityKind kind, U64 id);
|
||||
internal void dmn_w32_entity_release(DMN_W32_Entity *entity);
|
||||
|
||||
//- rjf: kind*id -> entity
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Module Info Extraction
|
||||
|
||||
internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32-Level Process/Thread Reads/Writes
|
||||
|
||||
//- rjf: processes
|
||||
internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src);
|
||||
internal String8 dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
|
||||
internal String16 dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
|
||||
#define dmn_w32_process_read_struct(process, vaddr, ptr) dmn_w32_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
#define dmn_w32_process_write_struct(process, vaddr, ptr) dmn_w32_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr);
|
||||
|
||||
//- rjf: threads
|
||||
internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave);
|
||||
internal U16 dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw);
|
||||
internal B32 dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
|
||||
//- rjf: remote thread injection
|
||||
internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address);
|
||||
|
||||
#endif // DEMON_CORE_WIN32_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_WIN32_H
|
||||
#define DEMON_CORE_WIN32_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Windows Includes
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Exception Codes
|
||||
|
||||
#define DMN_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DMN_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DMN_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DMN_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DMN_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DMN_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DMN_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DMN_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DMN_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DMN_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DMN_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DMN_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DMN_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DMN_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DMN_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DMN_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DMN_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DMN_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DMN_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DMN_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DMN_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DMN_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DMN_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DMN_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DMN_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DMN_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DMN_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DMN_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DMN_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DMN_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DMN_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DMN_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DMN_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DMN_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DMN_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
#define DMN_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u
|
||||
#define DMN_w32_EXCEPTION_CLRDBG_NOTIFICATION 0x04242420u
|
||||
#define DMN_w32_EXCEPTION_CLR 0xE0434352u
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Register Codes
|
||||
|
||||
#define DMN_W32_CTX_X86 0x00010000
|
||||
#define DMN_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags
|
||||
#define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15
|
||||
#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 // segds, seges, segfs, and seggs
|
||||
#define DMN_W32_CTX_INTEL_FLOATS 0x0008 // xmm0-xmm15
|
||||
#define DMN_W32_CTX_INTEL_DEBUG 0x0010 // dr0-dr3 and dr6-dr7
|
||||
#define DMN_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DMN_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DMN_W32_CTX_X86_ALL (DMN_W32_CTX_X86 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_DEBUG | \
|
||||
DMN_W32_CTX_INTEL_EXTENDED)
|
||||
#define DMN_W32_CTX_X64_ALL (DMN_W32_CTX_X64 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_FLOATS | \
|
||||
DMN_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Entity State
|
||||
|
||||
typedef enum DMN_W32_EntityKind
|
||||
{
|
||||
DMN_W32_EntityKind_Null,
|
||||
DMN_W32_EntityKind_Root,
|
||||
DMN_W32_EntityKind_Process,
|
||||
DMN_W32_EntityKind_Thread,
|
||||
DMN_W32_EntityKind_Module,
|
||||
DMN_W32_EntityKind_COUNT
|
||||
}
|
||||
DMN_W32_EntityKind;
|
||||
|
||||
typedef struct DMN_W32_Entity DMN_W32_Entity;
|
||||
struct DMN_W32_Entity
|
||||
{
|
||||
DMN_W32_Entity *first;
|
||||
DMN_W32_Entity *last;
|
||||
DMN_W32_Entity *next;
|
||||
DMN_W32_Entity *prev;
|
||||
DMN_W32_Entity *parent;
|
||||
DMN_W32_EntityKind kind;
|
||||
U32 gen;
|
||||
U64 id;
|
||||
HANDLE handle;
|
||||
Architecture arch;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
U64 injection_address;
|
||||
B32 did_first_bp;
|
||||
}
|
||||
proc;
|
||||
struct
|
||||
{
|
||||
U64 thread_local_base;
|
||||
U64 last_name_hash;
|
||||
U64 name_gather_time_us;
|
||||
}
|
||||
thread;
|
||||
struct
|
||||
{
|
||||
Rng1U64 vaddr_range;
|
||||
U64 address_of_name_pointer;
|
||||
B32 is_main;
|
||||
B32 name_is_unicode;
|
||||
}
|
||||
module;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityNode DMN_W32_EntityNode;
|
||||
struct DMN_W32_EntityNode
|
||||
{
|
||||
DMN_W32_EntityNode *next;
|
||||
DMN_W32_Entity *v;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashNode DMN_W32_EntityIDHashNode;
|
||||
struct DMN_W32_EntityIDHashNode
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *next;
|
||||
DMN_W32_EntityIDHashNode *prev;
|
||||
U64 id;
|
||||
DMN_W32_Entity *entity;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashSlot DMN_W32_EntityIDHashSlot;
|
||||
struct DMN_W32_EntityIDHashSlot
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *first;
|
||||
DMN_W32_EntityIDHashNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Injection Types
|
||||
|
||||
typedef struct DMN_W32_InjectedBreak DMN_W32_InjectedBreak;
|
||||
struct DMN_W32_InjectedBreak
|
||||
{
|
||||
U64 code;
|
||||
U64 user_data;
|
||||
};
|
||||
|
||||
#define DMN_W32_INJECTED_CODE_SIZE 32
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Image Info Types
|
||||
|
||||
typedef struct DMN_W32_ImageInfo DMN_W32_ImageInfo;
|
||||
struct DMN_W32_ImageInfo
|
||||
{
|
||||
Architecture arch;
|
||||
U32 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Dynamically-Loaded Win32 Function Types
|
||||
|
||||
typedef HRESULT DMN_W32_GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct DMN_W32_Shared DMN_W32_Shared;
|
||||
struct DMN_W32_Shared
|
||||
{
|
||||
// rjf: top-level info
|
||||
Arena *arena;
|
||||
String8List env_strings;
|
||||
|
||||
// rjf: access locking mechanism
|
||||
OS_Handle access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: run/mem/reg gens
|
||||
U64 run_gen;
|
||||
U64 mem_gen;
|
||||
U64 reg_gen;
|
||||
|
||||
// rjf: detaching info
|
||||
Arena *detach_arena;
|
||||
DMN_HandleList detach_processes;
|
||||
|
||||
// rjf: entity state
|
||||
Arena *entities_arena;
|
||||
DMN_W32_Entity *entities_base;
|
||||
DMN_W32_Entity *entities_first_free;
|
||||
U64 entities_count;
|
||||
DMN_W32_EntityIDHashSlot *entities_id_hash_slots;
|
||||
U64 entities_id_hash_slots_count;
|
||||
DMN_W32_EntityIDHashNode *entities_id_hash_node_free;
|
||||
|
||||
// rjf: launch state
|
||||
B32 new_process_pending;
|
||||
|
||||
// rjf: run results
|
||||
B32 resume_needed;
|
||||
U32 resume_pid;
|
||||
U32 resume_tid;
|
||||
B32 exception_not_handled;
|
||||
|
||||
// rjf: halting info
|
||||
DMN_Handle halter_process;
|
||||
U32 halter_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DMN_W32_Shared *dmn_w32_shared = 0;
|
||||
global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil};
|
||||
global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0;
|
||||
thread_static B32 dmn_w32_ctrl_thread = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 dmn_w32_hash_from_string(String8 string);
|
||||
internal U64 dmn_w32_hash_from_id(U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Helpers
|
||||
|
||||
//- rjf: entity <-> handle
|
||||
internal DMN_Handle dmn_w32_handle_from_entity(DMN_W32_Entity *entity);
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_handle(DMN_Handle handle);
|
||||
|
||||
//- rjf: entity allocation/deallocation
|
||||
internal DMN_W32_Entity *dmn_w32_entity_alloc(DMN_W32_Entity *parent, DMN_W32_EntityKind kind, U64 id);
|
||||
internal void dmn_w32_entity_release(DMN_W32_Entity *entity);
|
||||
|
||||
//- rjf: kind*id -> entity
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Module Info Extraction
|
||||
|
||||
internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32-Level Process/Thread Reads/Writes
|
||||
|
||||
//- rjf: processes
|
||||
internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src);
|
||||
internal String8 dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
|
||||
internal String16 dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
|
||||
#define dmn_w32_process_read_struct(process, vaddr, ptr) dmn_w32_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
#define dmn_w32_process_write_struct(process, vaddr, ptr) dmn_w32_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr);
|
||||
|
||||
//- rjf: threads
|
||||
internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave);
|
||||
internal U16 dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw);
|
||||
internal B32 dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
|
||||
//- rjf: remote thread injection
|
||||
internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address);
|
||||
|
||||
#endif // DEMON_CORE_WIN32_H
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "df/core/df_core.c"
|
||||
#include "df/gfx/df_gfx.c"
|
||||
#include "df/gfx/df_views.c"
|
||||
#include "df/gfx/df_view_rules.c"
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "df/core/df_core.c"
|
||||
#include "df/gfx/df_gfx.c"
|
||||
#include "df/gfx/df_views.c"
|
||||
#include "df/gfx/df_view_rules.c"
|
||||
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEBUG_FRONTEND_INC_H
|
||||
#define DEBUG_FRONTEND_INC_H
|
||||
|
||||
#include "df/core/df_core.h"
|
||||
#include "df/gfx/df_gfx.h"
|
||||
#include "df/gfx/df_views.h"
|
||||
#include "df/gfx/df_view_rules.h"
|
||||
|
||||
#endif // DEBUG_FRONTEND_INC_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEBUG_FRONTEND_INC_H
|
||||
#define DEBUG_FRONTEND_INC_H
|
||||
|
||||
#include "df/core/df_core.h"
|
||||
#include "df/gfx/df_gfx.h"
|
||||
#include "df/gfx/df_views.h"
|
||||
#include "df/gfx/df_view_rules.h"
|
||||
|
||||
#endif // DEBUG_FRONTEND_INC_H
|
||||
|
||||
+1119
-1119
File diff suppressed because it is too large
Load Diff
+729
-729
File diff suppressed because it is too large
Load Diff
+144
-144
@@ -1,144 +1,144 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DF_VIEW_RULES_H
|
||||
#define DF_VIEW_RULES_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "rgba"
|
||||
|
||||
typedef struct DF_VR_RGBAState DF_VR_RGBAState;
|
||||
struct DF_VR_RGBAState
|
||||
{
|
||||
Vec4F32 hsva;
|
||||
U64 memgen_idx;
|
||||
};
|
||||
|
||||
internal Vec4F32 df_vr_rgba_from_eval(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_Entity *process);
|
||||
internal void df_vr_eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "text"
|
||||
|
||||
typedef struct DF_TxtTopologyInfo DF_TxtTopologyInfo;
|
||||
struct DF_TxtTopologyInfo
|
||||
{
|
||||
TXT_LangKind lang;
|
||||
U64 size_cap;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_TextState DF_VR_TextState;
|
||||
struct DF_VR_TextState
|
||||
{
|
||||
B32 initialized;
|
||||
TxtPt cursor;
|
||||
TxtPt mark;
|
||||
S64 preferred_column;
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
internal DF_TxtTopologyInfo df_vr_txt_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "disasm"
|
||||
|
||||
typedef struct DF_DisasmTopologyInfo DF_DisasmTopologyInfo;
|
||||
struct DF_DisasmTopologyInfo
|
||||
{
|
||||
Architecture arch;
|
||||
U64 size_cap;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_DisasmState DF_VR_DisasmState;
|
||||
struct DF_VR_DisasmState
|
||||
{
|
||||
B32 initialized;
|
||||
TxtPt cursor;
|
||||
TxtPt mark;
|
||||
S64 preferred_column;
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
internal DF_DisasmTopologyInfo df_vr_disasm_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "bitmap"
|
||||
|
||||
typedef struct DF_BitmapTopologyInfo DF_BitmapTopologyInfo;
|
||||
struct DF_BitmapTopologyInfo
|
||||
{
|
||||
U64 width;
|
||||
U64 height;
|
||||
R_Tex2DFormat fmt;
|
||||
};
|
||||
|
||||
typedef struct DF_BitmapViewState DF_BitmapViewState;
|
||||
struct DF_BitmapViewState
|
||||
{
|
||||
Vec2F32 view_center_pos;
|
||||
F32 zoom;
|
||||
DF_BitmapTopologyInfo top;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_BitmapState DF_VR_BitmapState;
|
||||
struct DF_VR_BitmapState
|
||||
{
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_BitmapBoxDrawData DF_VR_BitmapBoxDrawData;
|
||||
struct DF_VR_BitmapBoxDrawData
|
||||
{
|
||||
Rng2F32 src;
|
||||
R_Handle texture;
|
||||
F32 loaded_t;
|
||||
B32 hovered;
|
||||
Vec2S32 mouse_px;
|
||||
F32 ui_per_bmp_px;
|
||||
};
|
||||
|
||||
internal Vec2F32 df_bitmap_view_state__screen_from_canvas_pos(DF_BitmapViewState *bvs, Rng2F32 rect, Vec2F32 cvs);
|
||||
internal Rng2F32 df_bitmap_view_state__screen_from_canvas_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 cvs);
|
||||
internal Vec2F32 df_bitmap_view_state__canvas_from_screen_pos(DF_BitmapViewState *bvs, Rng2F32 rect, Vec2F32 scr);
|
||||
internal Rng2F32 df_bitmap_view_state__canvas_from_screen_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 scr);
|
||||
internal DF_BitmapTopologyInfo df_vr_bitmap_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "geo"
|
||||
|
||||
typedef struct DF_GeoTopologyInfo DF_GeoTopologyInfo;
|
||||
struct DF_GeoTopologyInfo
|
||||
{
|
||||
U64 index_count;
|
||||
Rng1U64 vertices_vaddr_range;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_GeoState DF_VR_GeoState;
|
||||
struct DF_VR_GeoState
|
||||
{
|
||||
B32 initialized;
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
F32 pitch;
|
||||
F32 pitch_target;
|
||||
F32 yaw;
|
||||
F32 yaw_target;
|
||||
F32 zoom;
|
||||
F32 zoom_target;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_GeoBoxDrawData DF_VR_GeoBoxDrawData;
|
||||
struct DF_VR_GeoBoxDrawData
|
||||
{
|
||||
DF_ExpandKey key;
|
||||
R_Handle vertex_buffer;
|
||||
R_Handle index_buffer;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
internal DF_GeoTopologyInfo df_vr_geo_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
#endif // DF_VIEW_RULES_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DF_VIEW_RULES_H
|
||||
#define DF_VIEW_RULES_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "rgba"
|
||||
|
||||
typedef struct DF_VR_RGBAState DF_VR_RGBAState;
|
||||
struct DF_VR_RGBAState
|
||||
{
|
||||
Vec4F32 hsva;
|
||||
U64 memgen_idx;
|
||||
};
|
||||
|
||||
internal Vec4F32 df_vr_rgba_from_eval(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_Entity *process);
|
||||
internal void df_vr_eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "text"
|
||||
|
||||
typedef struct DF_TxtTopologyInfo DF_TxtTopologyInfo;
|
||||
struct DF_TxtTopologyInfo
|
||||
{
|
||||
TXT_LangKind lang;
|
||||
U64 size_cap;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_TextState DF_VR_TextState;
|
||||
struct DF_VR_TextState
|
||||
{
|
||||
B32 initialized;
|
||||
TxtPt cursor;
|
||||
TxtPt mark;
|
||||
S64 preferred_column;
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
internal DF_TxtTopologyInfo df_vr_txt_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "disasm"
|
||||
|
||||
typedef struct DF_DisasmTopologyInfo DF_DisasmTopologyInfo;
|
||||
struct DF_DisasmTopologyInfo
|
||||
{
|
||||
Architecture arch;
|
||||
U64 size_cap;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_DisasmState DF_VR_DisasmState;
|
||||
struct DF_VR_DisasmState
|
||||
{
|
||||
B32 initialized;
|
||||
TxtPt cursor;
|
||||
TxtPt mark;
|
||||
S64 preferred_column;
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
internal DF_DisasmTopologyInfo df_vr_disasm_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "bitmap"
|
||||
|
||||
typedef struct DF_BitmapTopologyInfo DF_BitmapTopologyInfo;
|
||||
struct DF_BitmapTopologyInfo
|
||||
{
|
||||
U64 width;
|
||||
U64 height;
|
||||
R_Tex2DFormat fmt;
|
||||
};
|
||||
|
||||
typedef struct DF_BitmapViewState DF_BitmapViewState;
|
||||
struct DF_BitmapViewState
|
||||
{
|
||||
Vec2F32 view_center_pos;
|
||||
F32 zoom;
|
||||
DF_BitmapTopologyInfo top;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_BitmapState DF_VR_BitmapState;
|
||||
struct DF_VR_BitmapState
|
||||
{
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_BitmapBoxDrawData DF_VR_BitmapBoxDrawData;
|
||||
struct DF_VR_BitmapBoxDrawData
|
||||
{
|
||||
Rng2F32 src;
|
||||
R_Handle texture;
|
||||
F32 loaded_t;
|
||||
B32 hovered;
|
||||
Vec2S32 mouse_px;
|
||||
F32 ui_per_bmp_px;
|
||||
};
|
||||
|
||||
internal Vec2F32 df_bitmap_view_state__screen_from_canvas_pos(DF_BitmapViewState *bvs, Rng2F32 rect, Vec2F32 cvs);
|
||||
internal Rng2F32 df_bitmap_view_state__screen_from_canvas_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 cvs);
|
||||
internal Vec2F32 df_bitmap_view_state__canvas_from_screen_pos(DF_BitmapViewState *bvs, Rng2F32 rect, Vec2F32 scr);
|
||||
internal Rng2F32 df_bitmap_view_state__canvas_from_screen_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 scr);
|
||||
internal DF_BitmapTopologyInfo df_vr_bitmap_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: "geo"
|
||||
|
||||
typedef struct DF_GeoTopologyInfo DF_GeoTopologyInfo;
|
||||
struct DF_GeoTopologyInfo
|
||||
{
|
||||
U64 index_count;
|
||||
Rng1U64 vertices_vaddr_range;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_GeoState DF_VR_GeoState;
|
||||
struct DF_VR_GeoState
|
||||
{
|
||||
B32 initialized;
|
||||
U64 last_open_frame_idx;
|
||||
F32 loaded_t;
|
||||
F32 pitch;
|
||||
F32 pitch_target;
|
||||
F32 yaw;
|
||||
F32 yaw_target;
|
||||
F32 zoom;
|
||||
F32 zoom_target;
|
||||
};
|
||||
|
||||
typedef struct DF_VR_GeoBoxDrawData DF_VR_GeoBoxDrawData;
|
||||
struct DF_VR_GeoBoxDrawData
|
||||
{
|
||||
DF_ExpandKey key;
|
||||
R_Handle vertex_buffer;
|
||||
R_Handle index_buffer;
|
||||
F32 loaded_t;
|
||||
};
|
||||
|
||||
internal DF_GeoTopologyInfo df_vr_geo_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||
|
||||
#endif // DF_VIEW_RULES_H
|
||||
|
||||
+191
-191
@@ -1,191 +1,191 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Fancy String Types
|
||||
|
||||
typedef struct D_FancyString D_FancyString;
|
||||
struct D_FancyString
|
||||
{
|
||||
F_Tag font;
|
||||
String8 string;
|
||||
Vec4F32 color;
|
||||
F32 size;
|
||||
F32 underline_thickness;
|
||||
F32 strikethrough_thickness;
|
||||
};
|
||||
|
||||
typedef struct D_FancyStringNode D_FancyStringNode;
|
||||
struct D_FancyStringNode
|
||||
{
|
||||
D_FancyStringNode *next;
|
||||
D_FancyString v;
|
||||
};
|
||||
|
||||
typedef struct D_FancyStringList D_FancyStringList;
|
||||
struct D_FancyStringList
|
||||
{
|
||||
D_FancyStringNode *first;
|
||||
D_FancyStringNode *last;
|
||||
U64 node_count;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
typedef struct D_FancyRun D_FancyRun;
|
||||
struct D_FancyRun
|
||||
{
|
||||
F_Run run;
|
||||
Vec4F32 color;
|
||||
F32 underline_thickness;
|
||||
F32 strikethrough_thickness;
|
||||
};
|
||||
|
||||
typedef struct D_FancyRunNode D_FancyRunNode;
|
||||
struct D_FancyRunNode
|
||||
{
|
||||
D_FancyRunNode *next;
|
||||
D_FancyRun v;
|
||||
};
|
||||
|
||||
typedef struct D_FancyRunList D_FancyRunList;
|
||||
struct D_FancyRunList
|
||||
{
|
||||
D_FancyRunNode *first;
|
||||
D_FancyRunNode *last;
|
||||
U64 node_count;
|
||||
Vec2F32 dim;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/draw.meta.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Draw Bucket Types
|
||||
|
||||
typedef struct D_Bucket D_Bucket;
|
||||
struct D_Bucket
|
||||
{
|
||||
R_PassList passes;
|
||||
U64 stack_gen;
|
||||
U64 last_cmd_stack_gen;
|
||||
D_BucketStackDecls;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context
|
||||
|
||||
typedef struct D_BucketSelectionNode D_BucketSelectionNode;
|
||||
struct D_BucketSelectionNode
|
||||
{
|
||||
D_BucketSelectionNode *next;
|
||||
D_Bucket *bucket;
|
||||
};
|
||||
|
||||
typedef struct D_ThreadCtx D_ThreadCtx;
|
||||
struct D_ThreadCtx
|
||||
{
|
||||
Arena *arena;
|
||||
U64 arena_frame_start_pos;
|
||||
D_BucketSelectionNode *top_bucket;
|
||||
D_BucketSelectionNode *free_bucket_selection;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static D_ThreadCtx *d_thread_ctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 d_hash_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Fancy String Type Functions
|
||||
|
||||
internal void d_fancy_string_list_push(Arena *arena, D_FancyStringList *list, D_FancyString *str);
|
||||
internal void d_fancy_string_list_concat_in_place(D_FancyStringList *dst, D_FancyStringList *to_push);
|
||||
internal String8 d_string_from_fancy_string_list(Arena *arena, D_FancyStringList *list);
|
||||
internal D_FancyRunList d_fancy_run_list_from_fancy_string_list(Arena *arena, F32 tab_size_px, F_RasterFlags flags, D_FancyStringList *strs);
|
||||
internal D_FancyRunList d_fancy_run_list_copy(Arena *arena, D_FancyRunList *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level API
|
||||
//
|
||||
// (Frame boundaries & bucket submission)
|
||||
|
||||
internal void d_begin_frame(void);
|
||||
internal void d_submit_bucket(OS_Handle os_window, R_Handle r_window, D_Bucket *bucket);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bucket Construction & Selection API
|
||||
//
|
||||
// (Bucket: Handle to sequence of many render passes, constructed by this layer)
|
||||
|
||||
internal D_Bucket *d_bucket_make(void);
|
||||
internal void d_push_bucket(D_Bucket *bucket);
|
||||
internal void d_pop_bucket(void);
|
||||
internal D_Bucket *d_top_bucket(void);
|
||||
#define D_BucketScope(b) DeferLoop(d_push_bucket(b), d_pop_bucket())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bucket Stacks
|
||||
//
|
||||
// (Pushing/popping implicit draw parameters)
|
||||
|
||||
internal R_Tex2DSampleKind d_push_tex2d_sample_kind(R_Tex2DSampleKind v);
|
||||
internal Mat3x3F32 d_push_xform2d(Mat3x3F32 v);
|
||||
internal Rng2F32 d_push_clip(Rng2F32 v);
|
||||
internal F32 d_push_transparency(F32 v);
|
||||
internal R_Tex2DSampleKind d_pop_tex2d_sample_kind(void);
|
||||
internal Mat3x3F32 d_pop_xform2d(void);
|
||||
internal Rng2F32 d_pop_clip(void);
|
||||
internal F32 d_pop_transparency(void);
|
||||
internal R_Tex2DSampleKind d_top_tex2d_sample_kind(void);
|
||||
internal Mat3x3F32 d_top_xform2d(void);
|
||||
internal Rng2F32 d_top_clip(void);
|
||||
internal F32 d_top_transparency(void);
|
||||
|
||||
#define D_Tex2DSampleKindScope(v) DeferLoop(d_push_tex2d_sample_kind(v), d_pop_tex2d_sample_kind())
|
||||
#define D_XForm2DScope(v) DeferLoop(d_push_xform2d(v), d_pop_xform2d())
|
||||
#define D_ClipScope(v) DeferLoop(d_push_clip(v), d_pop_clip())
|
||||
#define D_TransparencyScope(v) DeferLoop(d_push_transparency(v), d_pop_transparency())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Core Draw Calls
|
||||
//
|
||||
// (Apply to the calling thread's currently selected bucket)
|
||||
|
||||
//- rjf: rectangles
|
||||
internal inline R_Rect2DInst *d_rect(Rng2F32 dst, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness);
|
||||
|
||||
//- rjf: images
|
||||
internal inline R_Rect2DInst *d_img(Rng2F32 dst, Rng2F32 src, R_Handle texture, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness);
|
||||
|
||||
//- rjf: blurs
|
||||
internal R_PassParams_Blur *d_blur(Rng2F32 rect, F32 blur_size, F32 corner_radius);
|
||||
|
||||
//- rjf: 3d rendering pass params
|
||||
internal R_PassParams_Geo3D *d_geo3d_begin(Rng2F32 viewport, Mat4x4F32 view, Mat4x4F32 projection);
|
||||
|
||||
//- rjf: meshes
|
||||
internal R_Mesh3DInst *d_mesh(R_Handle mesh_vertices, R_Handle mesh_indices, R_GeoTopologyKind mesh_geo_topology, R_GeoVertexFlags mesh_geo_vertex_flags, R_Handle albedo_tex, Mat4x4F32 inst_xform);
|
||||
|
||||
//- rjf: collating one pre-prepped bucket into parent bucket
|
||||
internal void d_sub_bucket(D_Bucket *bucket);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Draw Call Helpers
|
||||
|
||||
//- rjf: text
|
||||
internal void d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run trailer_run);
|
||||
internal void d_truncated_fancy_run_fuzzy_matches(Vec2F32 p, D_FancyRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color);
|
||||
internal void d_text_run(Vec2F32 p, Vec4F32 color, F_Run run);
|
||||
internal void d_text(F_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, F_RasterFlags flags, Vec2F32 p, Vec4F32 color, String8 string);
|
||||
|
||||
#endif // DRAW_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Fancy String Types
|
||||
|
||||
typedef struct D_FancyString D_FancyString;
|
||||
struct D_FancyString
|
||||
{
|
||||
F_Tag font;
|
||||
String8 string;
|
||||
Vec4F32 color;
|
||||
F32 size;
|
||||
F32 underline_thickness;
|
||||
F32 strikethrough_thickness;
|
||||
};
|
||||
|
||||
typedef struct D_FancyStringNode D_FancyStringNode;
|
||||
struct D_FancyStringNode
|
||||
{
|
||||
D_FancyStringNode *next;
|
||||
D_FancyString v;
|
||||
};
|
||||
|
||||
typedef struct D_FancyStringList D_FancyStringList;
|
||||
struct D_FancyStringList
|
||||
{
|
||||
D_FancyStringNode *first;
|
||||
D_FancyStringNode *last;
|
||||
U64 node_count;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
typedef struct D_FancyRun D_FancyRun;
|
||||
struct D_FancyRun
|
||||
{
|
||||
F_Run run;
|
||||
Vec4F32 color;
|
||||
F32 underline_thickness;
|
||||
F32 strikethrough_thickness;
|
||||
};
|
||||
|
||||
typedef struct D_FancyRunNode D_FancyRunNode;
|
||||
struct D_FancyRunNode
|
||||
{
|
||||
D_FancyRunNode *next;
|
||||
D_FancyRun v;
|
||||
};
|
||||
|
||||
typedef struct D_FancyRunList D_FancyRunList;
|
||||
struct D_FancyRunList
|
||||
{
|
||||
D_FancyRunNode *first;
|
||||
D_FancyRunNode *last;
|
||||
U64 node_count;
|
||||
Vec2F32 dim;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/draw.meta.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Draw Bucket Types
|
||||
|
||||
typedef struct D_Bucket D_Bucket;
|
||||
struct D_Bucket
|
||||
{
|
||||
R_PassList passes;
|
||||
U64 stack_gen;
|
||||
U64 last_cmd_stack_gen;
|
||||
D_BucketStackDecls;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context
|
||||
|
||||
typedef struct D_BucketSelectionNode D_BucketSelectionNode;
|
||||
struct D_BucketSelectionNode
|
||||
{
|
||||
D_BucketSelectionNode *next;
|
||||
D_Bucket *bucket;
|
||||
};
|
||||
|
||||
typedef struct D_ThreadCtx D_ThreadCtx;
|
||||
struct D_ThreadCtx
|
||||
{
|
||||
Arena *arena;
|
||||
U64 arena_frame_start_pos;
|
||||
D_BucketSelectionNode *top_bucket;
|
||||
D_BucketSelectionNode *free_bucket_selection;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static D_ThreadCtx *d_thread_ctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 d_hash_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Fancy String Type Functions
|
||||
|
||||
internal void d_fancy_string_list_push(Arena *arena, D_FancyStringList *list, D_FancyString *str);
|
||||
internal void d_fancy_string_list_concat_in_place(D_FancyStringList *dst, D_FancyStringList *to_push);
|
||||
internal String8 d_string_from_fancy_string_list(Arena *arena, D_FancyStringList *list);
|
||||
internal D_FancyRunList d_fancy_run_list_from_fancy_string_list(Arena *arena, F32 tab_size_px, F_RasterFlags flags, D_FancyStringList *strs);
|
||||
internal D_FancyRunList d_fancy_run_list_copy(Arena *arena, D_FancyRunList *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level API
|
||||
//
|
||||
// (Frame boundaries & bucket submission)
|
||||
|
||||
internal void d_begin_frame(void);
|
||||
internal void d_submit_bucket(OS_Handle os_window, R_Handle r_window, D_Bucket *bucket);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bucket Construction & Selection API
|
||||
//
|
||||
// (Bucket: Handle to sequence of many render passes, constructed by this layer)
|
||||
|
||||
internal D_Bucket *d_bucket_make(void);
|
||||
internal void d_push_bucket(D_Bucket *bucket);
|
||||
internal void d_pop_bucket(void);
|
||||
internal D_Bucket *d_top_bucket(void);
|
||||
#define D_BucketScope(b) DeferLoop(d_push_bucket(b), d_pop_bucket())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bucket Stacks
|
||||
//
|
||||
// (Pushing/popping implicit draw parameters)
|
||||
|
||||
internal R_Tex2DSampleKind d_push_tex2d_sample_kind(R_Tex2DSampleKind v);
|
||||
internal Mat3x3F32 d_push_xform2d(Mat3x3F32 v);
|
||||
internal Rng2F32 d_push_clip(Rng2F32 v);
|
||||
internal F32 d_push_transparency(F32 v);
|
||||
internal R_Tex2DSampleKind d_pop_tex2d_sample_kind(void);
|
||||
internal Mat3x3F32 d_pop_xform2d(void);
|
||||
internal Rng2F32 d_pop_clip(void);
|
||||
internal F32 d_pop_transparency(void);
|
||||
internal R_Tex2DSampleKind d_top_tex2d_sample_kind(void);
|
||||
internal Mat3x3F32 d_top_xform2d(void);
|
||||
internal Rng2F32 d_top_clip(void);
|
||||
internal F32 d_top_transparency(void);
|
||||
|
||||
#define D_Tex2DSampleKindScope(v) DeferLoop(d_push_tex2d_sample_kind(v), d_pop_tex2d_sample_kind())
|
||||
#define D_XForm2DScope(v) DeferLoop(d_push_xform2d(v), d_pop_xform2d())
|
||||
#define D_ClipScope(v) DeferLoop(d_push_clip(v), d_pop_clip())
|
||||
#define D_TransparencyScope(v) DeferLoop(d_push_transparency(v), d_pop_transparency())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Core Draw Calls
|
||||
//
|
||||
// (Apply to the calling thread's currently selected bucket)
|
||||
|
||||
//- rjf: rectangles
|
||||
internal inline R_Rect2DInst *d_rect(Rng2F32 dst, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness);
|
||||
|
||||
//- rjf: images
|
||||
internal inline R_Rect2DInst *d_img(Rng2F32 dst, Rng2F32 src, R_Handle texture, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness);
|
||||
|
||||
//- rjf: blurs
|
||||
internal R_PassParams_Blur *d_blur(Rng2F32 rect, F32 blur_size, F32 corner_radius);
|
||||
|
||||
//- rjf: 3d rendering pass params
|
||||
internal R_PassParams_Geo3D *d_geo3d_begin(Rng2F32 viewport, Mat4x4F32 view, Mat4x4F32 projection);
|
||||
|
||||
//- rjf: meshes
|
||||
internal R_Mesh3DInst *d_mesh(R_Handle mesh_vertices, R_Handle mesh_indices, R_GeoTopologyKind mesh_geo_topology, R_GeoVertexFlags mesh_geo_vertex_flags, R_Handle albedo_tex, Mat4x4F32 inst_xform);
|
||||
|
||||
//- rjf: collating one pre-prepped bucket into parent bucket
|
||||
internal void d_sub_bucket(D_Bucket *bucket);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Draw Call Helpers
|
||||
|
||||
//- rjf: text
|
||||
internal void d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run trailer_run);
|
||||
internal void d_truncated_fancy_run_fuzzy_matches(Vec2F32 p, D_FancyRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color);
|
||||
internal void d_text_run(Vec2F32 p, Vec4F32 color, F_Run run);
|
||||
internal void d_text(F_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, F_RasterFlags flags, Vec2F32 p, Vec4F32 color, String8 string);
|
||||
|
||||
#endif // DRAW_H
|
||||
|
||||
+58
-58
@@ -1,58 +1,58 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
@table(name, name_lower, type, default_init)
|
||||
D_StackTable:
|
||||
{
|
||||
{Tex2DSampleKind tex2d_sample_kind R_Tex2DSampleKind `R_Tex2DSampleKind_Nearest` }
|
||||
{XForm2D xform2d Mat3x3F32 `{1, 0, 0, 0, 1, 0, 0, 0, 1}` }
|
||||
{Clip clip Rng2F32 `{0}` }
|
||||
{Transparency transparency F32 `0` }
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
@expand(D_StackTable a) `typedef struct D_$(a.name)Node D_$(a.name)Node; struct D_$(a.name)Node {D_$(a.name)Node *next; $(a.type) v;};`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#define D_BucketStackDecls struct{\\`;
|
||||
@expand(D_StackTable a) `D_$(a.name)Node *top_$(a.name_lower);\\`;
|
||||
`}`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
@expand(D_StackTable a) `read_only global D_$(a.name)Node d_nil_$(a.name_lower) = {0, $(a.default_init)};`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#define D_BucketStackInits(b) do{\\`;
|
||||
@expand(D_StackTable a) `(b)->top_$(a.name_lower) = &d_nil_$(a.name_lower);\\`;
|
||||
`}while(0)`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#if 0`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v);`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_pop_$(a.name_lower)(void);`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_top_$(a.name_lower)(void);`;
|
||||
`#endif`;
|
||||
}
|
||||
|
||||
@gen @c_file
|
||||
{
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v) {D_StackPushImpl($(a.name), $(a.name_lower), $(a.type), v);}`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_pop_$(a.name_lower)(void) {D_StackPopImpl($(a.name), $(a.name_lower), $(a.type));}`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_top_$(a.name_lower)(void) {D_StackTopImpl($(a.name), $(a.name_lower), $(a.type));}`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#if 0`;
|
||||
@expand(D_StackTable a) `#define D_$(a.name)Scope(v) $(=>35) DeferLoop(d_push_$(a.name_lower)(v), d_pop_$(a.name_lower)())`;
|
||||
`#endif`;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
@table(name, name_lower, type, default_init)
|
||||
D_StackTable:
|
||||
{
|
||||
{Tex2DSampleKind tex2d_sample_kind R_Tex2DSampleKind `R_Tex2DSampleKind_Nearest` }
|
||||
{XForm2D xform2d Mat3x3F32 `{1, 0, 0, 0, 1, 0, 0, 0, 1}` }
|
||||
{Clip clip Rng2F32 `{0}` }
|
||||
{Transparency transparency F32 `0` }
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
@expand(D_StackTable a) `typedef struct D_$(a.name)Node D_$(a.name)Node; struct D_$(a.name)Node {D_$(a.name)Node *next; $(a.type) v;};`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#define D_BucketStackDecls struct{\\`;
|
||||
@expand(D_StackTable a) `D_$(a.name)Node *top_$(a.name_lower);\\`;
|
||||
`}`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
@expand(D_StackTable a) `read_only global D_$(a.name)Node d_nil_$(a.name_lower) = {0, $(a.default_init)};`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#define D_BucketStackInits(b) do{\\`;
|
||||
@expand(D_StackTable a) `(b)->top_$(a.name_lower) = &d_nil_$(a.name_lower);\\`;
|
||||
`}while(0)`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#if 0`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v);`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_pop_$(a.name_lower)(void);`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_top_$(a.name_lower)(void);`;
|
||||
`#endif`;
|
||||
}
|
||||
|
||||
@gen @c_file
|
||||
{
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v) {D_StackPushImpl($(a.name), $(a.name_lower), $(a.type), v);}`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_pop_$(a.name_lower)(void) {D_StackPopImpl($(a.name), $(a.name_lower), $(a.type));}`;
|
||||
@expand(D_StackTable a) `internal $(a.type) $(=>35) d_top_$(a.name_lower)(void) {D_StackTopImpl($(a.name), $(a.name_lower), $(a.type));}`;
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`#if 0`;
|
||||
@expand(D_StackTable a) `#define D_$(a.name)Scope(v) $(=>35) DeferLoop(d_push_$(a.name_lower)(v), d_pop_$(a.name_lower)())`;
|
||||
`#endif`;
|
||||
}
|
||||
|
||||
+106
-106
@@ -1,106 +1,106 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
@table(name num_children op_string)
|
||||
// num_children - # of children packed after this node kind
|
||||
// op_string - string for quick display of the operator
|
||||
EVAL_ExprKindTable:
|
||||
{
|
||||
{ Nil 0 "" }
|
||||
|
||||
{ ArrayIndex 2 "[]" }
|
||||
{ MemberAccess 2 "." }
|
||||
{ Deref 1 "*" }
|
||||
{ Address 1 "&" }
|
||||
|
||||
{ Cast 2 "cast" }
|
||||
{ Sizeof 1 "sizeof" }
|
||||
|
||||
{ Neg 1 "-" }
|
||||
{ LogNot 1 "!" }
|
||||
{ BitNot 1 "~" }
|
||||
{ Mul 2 "*" }
|
||||
{ Div 2 "/" }
|
||||
{ Mod 2 "%" }
|
||||
{ Add 2 "+" }
|
||||
{ Sub 2 "-" }
|
||||
{ LShift 2 "<<" }
|
||||
{ RShift 2 ">>" }
|
||||
{ Less 2 "<" }
|
||||
{ LsEq 2 "<=" }
|
||||
{ Grtr 2 ">" }
|
||||
{ GrEq 2 ">=" }
|
||||
{ EqEq 2 "==" }
|
||||
{ NtEq 2 "!=" }
|
||||
|
||||
{ BitAnd 2 "&" }
|
||||
{ BitXor 2 "^" }
|
||||
{ BitOr 2 "|" }
|
||||
{ LogAnd 2 "&&" }
|
||||
{ LogOr 2 "||" }
|
||||
|
||||
{ Ternary 3 "? " }
|
||||
|
||||
{ LeafBytecode 0 "bytecode" }
|
||||
{ LeafMember 0 "member" }
|
||||
{ LeafU64 0 "U64" }
|
||||
{ LeafF64 0 "F64" }
|
||||
{ LeafF32 0 "F32" }
|
||||
|
||||
{ TypeIdent 0 "type_ident" }
|
||||
{ Ptr 1 "ptr" }
|
||||
{ Array 2 "array" }
|
||||
{ Func 1 "function" }
|
||||
|
||||
{ Define 2 "=" }
|
||||
{ LeafIdent 0 "leaf_ident" }
|
||||
}
|
||||
|
||||
@table(name display_string)
|
||||
EVAL_ResultCodeTable:
|
||||
{
|
||||
{ Good "" }
|
||||
{ DivideByZero "Cannot divide by zero." }
|
||||
{ BadOp "Invalid operation." }
|
||||
{ BadOpTypes "Invalid operation types." }
|
||||
{ BadMemRead "Failed memory read." }
|
||||
{ BadRegRead "Failed register read." }
|
||||
{ BadFrameBase "Invalid frame base address." }
|
||||
{ BadModuleBase "Invalid module base address." }
|
||||
{ BadTLSBase "Invalid thread-local storage base address." }
|
||||
{ InsufficientStackSpace "Insufficient evaluation machine stack space." }
|
||||
{ MalformedBytecode "Malformed bytecode." }
|
||||
}
|
||||
|
||||
@enum(U32) EVAL_ExprKind:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@enum EVAL_ResultCode:
|
||||
{
|
||||
@expand(EVAL_ResultCodeTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@data(U8) eval_expr_kind_child_counts:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `$(a.num_children)`
|
||||
}
|
||||
|
||||
@data(String8)
|
||||
eval_expr_kind_strings:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
@data(String8) eval_result_code_display_strings:
|
||||
{
|
||||
@expand(EVAL_ResultCodeTable a) `str8_lit_comp("$(a.display_string)")`
|
||||
}
|
||||
|
||||
@data(String8) eval_expr_op_strings:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.op_string)")`
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
@table(name num_children op_string)
|
||||
// num_children - # of children packed after this node kind
|
||||
// op_string - string for quick display of the operator
|
||||
EVAL_ExprKindTable:
|
||||
{
|
||||
{ Nil 0 "" }
|
||||
|
||||
{ ArrayIndex 2 "[]" }
|
||||
{ MemberAccess 2 "." }
|
||||
{ Deref 1 "*" }
|
||||
{ Address 1 "&" }
|
||||
|
||||
{ Cast 2 "cast" }
|
||||
{ Sizeof 1 "sizeof" }
|
||||
|
||||
{ Neg 1 "-" }
|
||||
{ LogNot 1 "!" }
|
||||
{ BitNot 1 "~" }
|
||||
{ Mul 2 "*" }
|
||||
{ Div 2 "/" }
|
||||
{ Mod 2 "%" }
|
||||
{ Add 2 "+" }
|
||||
{ Sub 2 "-" }
|
||||
{ LShift 2 "<<" }
|
||||
{ RShift 2 ">>" }
|
||||
{ Less 2 "<" }
|
||||
{ LsEq 2 "<=" }
|
||||
{ Grtr 2 ">" }
|
||||
{ GrEq 2 ">=" }
|
||||
{ EqEq 2 "==" }
|
||||
{ NtEq 2 "!=" }
|
||||
|
||||
{ BitAnd 2 "&" }
|
||||
{ BitXor 2 "^" }
|
||||
{ BitOr 2 "|" }
|
||||
{ LogAnd 2 "&&" }
|
||||
{ LogOr 2 "||" }
|
||||
|
||||
{ Ternary 3 "? " }
|
||||
|
||||
{ LeafBytecode 0 "bytecode" }
|
||||
{ LeafMember 0 "member" }
|
||||
{ LeafU64 0 "U64" }
|
||||
{ LeafF64 0 "F64" }
|
||||
{ LeafF32 0 "F32" }
|
||||
|
||||
{ TypeIdent 0 "type_ident" }
|
||||
{ Ptr 1 "ptr" }
|
||||
{ Array 2 "array" }
|
||||
{ Func 1 "function" }
|
||||
|
||||
{ Define 2 "=" }
|
||||
{ LeafIdent 0 "leaf_ident" }
|
||||
}
|
||||
|
||||
@table(name display_string)
|
||||
EVAL_ResultCodeTable:
|
||||
{
|
||||
{ Good "" }
|
||||
{ DivideByZero "Cannot divide by zero." }
|
||||
{ BadOp "Invalid operation." }
|
||||
{ BadOpTypes "Invalid operation types." }
|
||||
{ BadMemRead "Failed memory read." }
|
||||
{ BadRegRead "Failed register read." }
|
||||
{ BadFrameBase "Invalid frame base address." }
|
||||
{ BadModuleBase "Invalid module base address." }
|
||||
{ BadTLSBase "Invalid thread-local storage base address." }
|
||||
{ InsufficientStackSpace "Insufficient evaluation machine stack space." }
|
||||
{ MalformedBytecode "Malformed bytecode." }
|
||||
}
|
||||
|
||||
@enum(U32) EVAL_ExprKind:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@enum EVAL_ResultCode:
|
||||
{
|
||||
@expand(EVAL_ResultCodeTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@data(U8) eval_expr_kind_child_counts:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `$(a.num_children)`
|
||||
}
|
||||
|
||||
@data(String8)
|
||||
eval_expr_kind_strings:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
@data(String8) eval_result_code_display_strings:
|
||||
{
|
||||
@expand(EVAL_ResultCodeTable a) `str8_lit_comp("$(a.display_string)")`
|
||||
}
|
||||
|
||||
@data(String8) eval_expr_op_strings:
|
||||
{
|
||||
@expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.op_string)")`
|
||||
}
|
||||
|
||||
+1641
-1641
File diff suppressed because it is too large
Load Diff
+82
-82
@@ -1,82 +1,82 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_COMPILER_H
|
||||
#define EVAL_COMPILER_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Bytecode Helpers
|
||||
|
||||
internal String8 eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list);
|
||||
|
||||
internal void eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RDI_EvalOp op, U64 p);
|
||||
internal void eval_oplist_push_uconst(Arena *arena, EVAL_OpList *list, U64 x);
|
||||
internal void eval_oplist_push_sconst(Arena *arena, EVAL_OpList *list, S64 x);
|
||||
|
||||
internal void eval_oplist_push_bytecode(Arena *arena, EVAL_OpList *list, String8 bytecode);
|
||||
|
||||
internal void eval_oplist_concat_in_place(EVAL_OpList *left_dst, EVAL_OpList *right_destroyed);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Expression Info Functions
|
||||
|
||||
internal RDI_EvalOp eval_opcode_from_expr_kind(EVAL_ExprKind kind);
|
||||
internal B32 eval_expr_kind_is_comparison(EVAL_ExprKind kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Expression Constructors
|
||||
|
||||
internal EVAL_Expr* eval_expr(Arena *arena, EVAL_ExprKind kind, void *location, EVAL_Expr *c0, EVAL_Expr *c1, EVAL_Expr *c2);
|
||||
internal EVAL_Expr* eval_expr_u64(Arena *arena, void *location, U64 u64);
|
||||
internal EVAL_Expr* eval_expr_f64(Arena *arena, void *location, F64 f64);
|
||||
internal EVAL_Expr* eval_expr_f32(Arena *arena, void *location, F32 f32);
|
||||
internal EVAL_Expr* eval_expr_child_and_u64(Arena *arena, EVAL_ExprKind kind, void *location, EVAL_Expr *child, U64 u64);
|
||||
internal EVAL_Expr* eval_expr_leaf_member(Arena *arena, void *location, String8 name);
|
||||
internal EVAL_Expr* eval_expr_leaf_ident(Arena *arena, void *location, String8 name);
|
||||
internal EVAL_Expr* eval_expr_leaf_bytecode(Arena *arena, void *location, TG_Key type_key, String8 bytecode, EVAL_EvalMode mode);
|
||||
internal EVAL_Expr* eval_expr_leaf_op_list(Arena *arena, void *location, TG_Key type_key, EVAL_OpList *ops, EVAL_EvalMode mode);
|
||||
internal EVAL_Expr* eval_expr_leaf_type(Arena *arena, void *location, TG_Key type_key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Type Information Transformers
|
||||
|
||||
internal RDI_EvalTypeGroup eval_type_group_from_kind(TG_Kind kind);
|
||||
|
||||
internal TG_Key eval_type_unwrap_enum(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key);
|
||||
internal TG_Key eval_type_promote(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key);
|
||||
internal TG_Key eval_type_coerce(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r);
|
||||
|
||||
internal B32 eval_type_match(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r);
|
||||
|
||||
internal B32 eval_kind_is_integer(TG_Kind kind);
|
||||
internal B32 eval_kind_is_signed(TG_Kind kind);
|
||||
internal B32 eval_kind_is_basic_or_enum(TG_Kind kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL IR-Tree Constructors
|
||||
|
||||
internal EVAL_IRTree* eval_irtree_const_u(Arena *arena, U64 v);
|
||||
internal EVAL_IRTree* eval_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, EVAL_IRTree *c);
|
||||
internal EVAL_IRTree* eval_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, EVAL_IRTree *l, EVAL_IRTree *r);
|
||||
internal EVAL_IRTree* eval_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r);
|
||||
internal EVAL_IRTree* eval_irtree_conditional(Arena *arena, EVAL_IRTree *c, EVAL_IRTree *l, EVAL_IRTree *r);
|
||||
internal EVAL_IRTree* eval_irtree_bytecode_no_copy(Arena *arena, String8 bytecode);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL IR-Tree High Level Helpers
|
||||
|
||||
internal EVAL_IRTree* eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key);
|
||||
internal EVAL_IRTree* eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RDI_EvalTypeGroup out, RDI_EvalTypeGroup in);
|
||||
internal EVAL_IRTree* eval_irtree_trunc(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key);
|
||||
internal EVAL_IRTree* eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key out, TG_Key in);
|
||||
internal EVAL_IRTree* eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_EvalMode from_mode, EVAL_IRTree *tree, TG_Key type_key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Compiler Phases
|
||||
|
||||
internal void eval_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, EVAL_String2ExprMap *map, EVAL_Expr *expr, EVAL_ErrorList *eout);
|
||||
internal TG_Key eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_Expr *expr, EVAL_ErrorList *eout);
|
||||
internal EVAL_IRTreeAndType eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_String2ExprMap *leaf_ident_expr_map, EVAL_Expr *expr, EVAL_ErrorList *eout);
|
||||
internal void eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out);
|
||||
|
||||
#endif //EVAL_COMPILER_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_COMPILER_H
|
||||
#define EVAL_COMPILER_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Bytecode Helpers
|
||||
|
||||
internal String8 eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list);
|
||||
|
||||
internal void eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RDI_EvalOp op, U64 p);
|
||||
internal void eval_oplist_push_uconst(Arena *arena, EVAL_OpList *list, U64 x);
|
||||
internal void eval_oplist_push_sconst(Arena *arena, EVAL_OpList *list, S64 x);
|
||||
|
||||
internal void eval_oplist_push_bytecode(Arena *arena, EVAL_OpList *list, String8 bytecode);
|
||||
|
||||
internal void eval_oplist_concat_in_place(EVAL_OpList *left_dst, EVAL_OpList *right_destroyed);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Expression Info Functions
|
||||
|
||||
internal RDI_EvalOp eval_opcode_from_expr_kind(EVAL_ExprKind kind);
|
||||
internal B32 eval_expr_kind_is_comparison(EVAL_ExprKind kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Expression Constructors
|
||||
|
||||
internal EVAL_Expr* eval_expr(Arena *arena, EVAL_ExprKind kind, void *location, EVAL_Expr *c0, EVAL_Expr *c1, EVAL_Expr *c2);
|
||||
internal EVAL_Expr* eval_expr_u64(Arena *arena, void *location, U64 u64);
|
||||
internal EVAL_Expr* eval_expr_f64(Arena *arena, void *location, F64 f64);
|
||||
internal EVAL_Expr* eval_expr_f32(Arena *arena, void *location, F32 f32);
|
||||
internal EVAL_Expr* eval_expr_child_and_u64(Arena *arena, EVAL_ExprKind kind, void *location, EVAL_Expr *child, U64 u64);
|
||||
internal EVAL_Expr* eval_expr_leaf_member(Arena *arena, void *location, String8 name);
|
||||
internal EVAL_Expr* eval_expr_leaf_ident(Arena *arena, void *location, String8 name);
|
||||
internal EVAL_Expr* eval_expr_leaf_bytecode(Arena *arena, void *location, TG_Key type_key, String8 bytecode, EVAL_EvalMode mode);
|
||||
internal EVAL_Expr* eval_expr_leaf_op_list(Arena *arena, void *location, TG_Key type_key, EVAL_OpList *ops, EVAL_EvalMode mode);
|
||||
internal EVAL_Expr* eval_expr_leaf_type(Arena *arena, void *location, TG_Key type_key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Type Information Transformers
|
||||
|
||||
internal RDI_EvalTypeGroup eval_type_group_from_kind(TG_Kind kind);
|
||||
|
||||
internal TG_Key eval_type_unwrap_enum(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key);
|
||||
internal TG_Key eval_type_promote(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key);
|
||||
internal TG_Key eval_type_coerce(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r);
|
||||
|
||||
internal B32 eval_type_match(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r);
|
||||
|
||||
internal B32 eval_kind_is_integer(TG_Kind kind);
|
||||
internal B32 eval_kind_is_signed(TG_Kind kind);
|
||||
internal B32 eval_kind_is_basic_or_enum(TG_Kind kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL IR-Tree Constructors
|
||||
|
||||
internal EVAL_IRTree* eval_irtree_const_u(Arena *arena, U64 v);
|
||||
internal EVAL_IRTree* eval_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, EVAL_IRTree *c);
|
||||
internal EVAL_IRTree* eval_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, EVAL_IRTree *l, EVAL_IRTree *r);
|
||||
internal EVAL_IRTree* eval_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r);
|
||||
internal EVAL_IRTree* eval_irtree_conditional(Arena *arena, EVAL_IRTree *c, EVAL_IRTree *l, EVAL_IRTree *r);
|
||||
internal EVAL_IRTree* eval_irtree_bytecode_no_copy(Arena *arena, String8 bytecode);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL IR-Tree High Level Helpers
|
||||
|
||||
internal EVAL_IRTree* eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key);
|
||||
internal EVAL_IRTree* eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RDI_EvalTypeGroup out, RDI_EvalTypeGroup in);
|
||||
internal EVAL_IRTree* eval_irtree_trunc(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key);
|
||||
internal EVAL_IRTree* eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key out, TG_Key in);
|
||||
internal EVAL_IRTree* eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_EvalMode from_mode, EVAL_IRTree *tree, TG_Key type_key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: EVAL Compiler Phases
|
||||
|
||||
internal void eval_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, EVAL_String2ExprMap *map, EVAL_Expr *expr, EVAL_ErrorList *eout);
|
||||
internal TG_Key eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_Expr *expr, EVAL_ErrorList *eout);
|
||||
internal EVAL_IRTreeAndType eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_String2ExprMap *leaf_ident_expr_map, EVAL_Expr *expr, EVAL_ErrorList *eout);
|
||||
internal void eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out);
|
||||
|
||||
#endif //EVAL_COMPILER_H
|
||||
|
||||
+254
-254
@@ -1,254 +1,254 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/eval.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
internal U64
|
||||
eval_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: Error List Building Functions
|
||||
|
||||
internal void
|
||||
eval_error(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, String8 text){
|
||||
EVAL_Error *error = push_array_no_zero(arena, EVAL_Error, 1);
|
||||
SLLQueuePush(list->first, list->last, error);
|
||||
list->count += 1;
|
||||
list->max_kind = Max(kind, list->max_kind);
|
||||
error->kind = kind;
|
||||
error->location = location;
|
||||
error->text = text;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_errorf(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, char *fmt, ...){
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 text = push_str8fv(arena, fmt, args);
|
||||
va_end(args);
|
||||
eval_error(arena, list, kind, location, text);
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_error_list_concat_in_place(EVAL_ErrorList *dst, EVAL_ErrorList *to_push){
|
||||
if (dst->last != 0){
|
||||
if (to_push->last != 0){
|
||||
dst->last->next = to_push->first;
|
||||
dst->last = to_push->last;
|
||||
dst->count += to_push->count;
|
||||
}
|
||||
}
|
||||
else{
|
||||
*dst = *to_push;
|
||||
}
|
||||
MemoryZeroStruct(to_push);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
//- rjf: string -> num
|
||||
|
||||
internal EVAL_String2NumMap
|
||||
eval_string2num_map_make(Arena *arena, U64 slot_count)
|
||||
{
|
||||
EVAL_String2NumMap map = {0};
|
||||
map.slots_count = slot_count;
|
||||
map.slots = push_array(arena, EVAL_String2NumMapSlot, map.slots_count);
|
||||
return map;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2num_map_insert(Arena *arena, EVAL_String2NumMap *map, String8 string, U64 num)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2NumMapNode *existing_node = 0;
|
||||
for(EVAL_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0) && node->num == num)
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node == 0)
|
||||
{
|
||||
EVAL_String2NumMapNode *node = push_array(arena, EVAL_String2NumMapNode, 1);
|
||||
SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next);
|
||||
SLLQueuePush_N(map->first, map->last, node, order_next);
|
||||
node->string = push_str8_copy(arena, string);
|
||||
node->num = num;
|
||||
map->node_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
internal U64
|
||||
eval_num_from_string(EVAL_String2NumMap *map, String8 string)
|
||||
{
|
||||
U64 num = 0;
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2NumMapNode *existing_node = 0;
|
||||
for(EVAL_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0))
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node != 0)
|
||||
{
|
||||
num = existing_node->num;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
internal EVAL_String2NumMapNodeArray
|
||||
eval_string2num_map_node_array_from_map(Arena *arena, EVAL_String2NumMap *map)
|
||||
{
|
||||
EVAL_String2NumMapNodeArray result = {0};
|
||||
result.count = map->node_count;
|
||||
result.v = push_array(arena, EVAL_String2NumMapNode *, result.count);
|
||||
U64 idx = 0;
|
||||
for(EVAL_String2NumMapNode *n = map->first; n != 0; n = n->order_next, idx += 1)
|
||||
{
|
||||
result.v[idx] = n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int
|
||||
eval_string2num_map_node_qsort_compare__num_ascending(EVAL_String2NumMapNode **a, EVAL_String2NumMapNode **b)
|
||||
{
|
||||
int result = 0;
|
||||
if(a[0]->num < b[0]->num)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
else if(a[0]->num > b[0]->num)
|
||||
{
|
||||
result = +1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2num_map_node_array_sort__in_place(EVAL_String2NumMapNodeArray *array)
|
||||
{
|
||||
quick_sort(array->v, array->count, sizeof(array->v[0]), eval_string2num_map_node_qsort_compare__num_ascending);
|
||||
}
|
||||
|
||||
//- rjf: string -> expr
|
||||
|
||||
internal EVAL_String2ExprMap
|
||||
eval_string2expr_map_make(Arena *arena, U64 slot_count)
|
||||
{
|
||||
EVAL_String2ExprMap map = {0};
|
||||
map.slots_count = slot_count;
|
||||
map.slots = push_array(arena, EVAL_String2ExprMapSlot, map.slots_count);
|
||||
return map;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2expr_map_insert(Arena *arena, EVAL_String2ExprMap *map, String8 string, EVAL_Expr *expr)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2ExprMapNode *existing_node = 0;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first;
|
||||
node != 0;
|
||||
node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0))
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node == 0)
|
||||
{
|
||||
EVAL_String2ExprMapNode *node = push_array(arena, EVAL_String2ExprMapNode, 1);
|
||||
SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next);
|
||||
node->string = push_str8_copy(arena, string);
|
||||
existing_node = node;
|
||||
}
|
||||
existing_node->expr = expr;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2expr_map_inc_poison(EVAL_String2ExprMap *map, String8 string)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first;
|
||||
node != 0;
|
||||
node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0))
|
||||
{
|
||||
node->poison_count += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2expr_map_dec_poison(EVAL_String2ExprMap *map, String8 string)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first;
|
||||
node != 0;
|
||||
node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0) && node->poison_count > 0)
|
||||
{
|
||||
node->poison_count -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal EVAL_Expr *
|
||||
eval_expr_from_string(EVAL_String2ExprMap *map, String8 string)
|
||||
{
|
||||
EVAL_Expr *expr = &eval_expr_nil;
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2ExprMapNode *existing_node = 0;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0) && node->poison_count == 0)
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node != 0)
|
||||
{
|
||||
expr = existing_node->expr;
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/eval.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
internal U64
|
||||
eval_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: Error List Building Functions
|
||||
|
||||
internal void
|
||||
eval_error(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, String8 text){
|
||||
EVAL_Error *error = push_array_no_zero(arena, EVAL_Error, 1);
|
||||
SLLQueuePush(list->first, list->last, error);
|
||||
list->count += 1;
|
||||
list->max_kind = Max(kind, list->max_kind);
|
||||
error->kind = kind;
|
||||
error->location = location;
|
||||
error->text = text;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_errorf(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, char *fmt, ...){
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 text = push_str8fv(arena, fmt, args);
|
||||
va_end(args);
|
||||
eval_error(arena, list, kind, location, text);
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_error_list_concat_in_place(EVAL_ErrorList *dst, EVAL_ErrorList *to_push){
|
||||
if (dst->last != 0){
|
||||
if (to_push->last != 0){
|
||||
dst->last->next = to_push->first;
|
||||
dst->last = to_push->last;
|
||||
dst->count += to_push->count;
|
||||
}
|
||||
}
|
||||
else{
|
||||
*dst = *to_push;
|
||||
}
|
||||
MemoryZeroStruct(to_push);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
//- rjf: string -> num
|
||||
|
||||
internal EVAL_String2NumMap
|
||||
eval_string2num_map_make(Arena *arena, U64 slot_count)
|
||||
{
|
||||
EVAL_String2NumMap map = {0};
|
||||
map.slots_count = slot_count;
|
||||
map.slots = push_array(arena, EVAL_String2NumMapSlot, map.slots_count);
|
||||
return map;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2num_map_insert(Arena *arena, EVAL_String2NumMap *map, String8 string, U64 num)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2NumMapNode *existing_node = 0;
|
||||
for(EVAL_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0) && node->num == num)
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node == 0)
|
||||
{
|
||||
EVAL_String2NumMapNode *node = push_array(arena, EVAL_String2NumMapNode, 1);
|
||||
SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next);
|
||||
SLLQueuePush_N(map->first, map->last, node, order_next);
|
||||
node->string = push_str8_copy(arena, string);
|
||||
node->num = num;
|
||||
map->node_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
internal U64
|
||||
eval_num_from_string(EVAL_String2NumMap *map, String8 string)
|
||||
{
|
||||
U64 num = 0;
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2NumMapNode *existing_node = 0;
|
||||
for(EVAL_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0))
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node != 0)
|
||||
{
|
||||
num = existing_node->num;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
internal EVAL_String2NumMapNodeArray
|
||||
eval_string2num_map_node_array_from_map(Arena *arena, EVAL_String2NumMap *map)
|
||||
{
|
||||
EVAL_String2NumMapNodeArray result = {0};
|
||||
result.count = map->node_count;
|
||||
result.v = push_array(arena, EVAL_String2NumMapNode *, result.count);
|
||||
U64 idx = 0;
|
||||
for(EVAL_String2NumMapNode *n = map->first; n != 0; n = n->order_next, idx += 1)
|
||||
{
|
||||
result.v[idx] = n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int
|
||||
eval_string2num_map_node_qsort_compare__num_ascending(EVAL_String2NumMapNode **a, EVAL_String2NumMapNode **b)
|
||||
{
|
||||
int result = 0;
|
||||
if(a[0]->num < b[0]->num)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
else if(a[0]->num > b[0]->num)
|
||||
{
|
||||
result = +1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2num_map_node_array_sort__in_place(EVAL_String2NumMapNodeArray *array)
|
||||
{
|
||||
quick_sort(array->v, array->count, sizeof(array->v[0]), eval_string2num_map_node_qsort_compare__num_ascending);
|
||||
}
|
||||
|
||||
//- rjf: string -> expr
|
||||
|
||||
internal EVAL_String2ExprMap
|
||||
eval_string2expr_map_make(Arena *arena, U64 slot_count)
|
||||
{
|
||||
EVAL_String2ExprMap map = {0};
|
||||
map.slots_count = slot_count;
|
||||
map.slots = push_array(arena, EVAL_String2ExprMapSlot, map.slots_count);
|
||||
return map;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2expr_map_insert(Arena *arena, EVAL_String2ExprMap *map, String8 string, EVAL_Expr *expr)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2ExprMapNode *existing_node = 0;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first;
|
||||
node != 0;
|
||||
node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0))
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node == 0)
|
||||
{
|
||||
EVAL_String2ExprMapNode *node = push_array(arena, EVAL_String2ExprMapNode, 1);
|
||||
SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next);
|
||||
node->string = push_str8_copy(arena, string);
|
||||
existing_node = node;
|
||||
}
|
||||
existing_node->expr = expr;
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2expr_map_inc_poison(EVAL_String2ExprMap *map, String8 string)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first;
|
||||
node != 0;
|
||||
node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0))
|
||||
{
|
||||
node->poison_count += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
eval_string2expr_map_dec_poison(EVAL_String2ExprMap *map, String8 string)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first;
|
||||
node != 0;
|
||||
node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0) && node->poison_count > 0)
|
||||
{
|
||||
node->poison_count -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal EVAL_Expr *
|
||||
eval_expr_from_string(EVAL_String2ExprMap *map, String8 string)
|
||||
{
|
||||
EVAL_Expr *expr = &eval_expr_nil;
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
U64 hash = eval_hash_from_string(string);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
EVAL_String2ExprMapNode *existing_node = 0;
|
||||
for(EVAL_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next)
|
||||
{
|
||||
if(str8_match(node->string, string, 0) && node->poison_count == 0)
|
||||
{
|
||||
existing_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node != 0)
|
||||
{
|
||||
expr = existing_node->expr;
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
+232
-232
@@ -1,232 +1,232 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_CORE_H
|
||||
#define EVAL_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Errors
|
||||
|
||||
typedef enum EVAL_ErrorKind
|
||||
{
|
||||
EVAL_ErrorKind_Null,
|
||||
EVAL_ErrorKind_MalformedInput,
|
||||
EVAL_ErrorKind_MissingInfo,
|
||||
EVAL_ErrorKind_ResolutionFailure,
|
||||
EVAL_ErrorKind_InterpretationError,
|
||||
EVAL_ErrorKind_COUNT
|
||||
}
|
||||
EVAL_ErrorKind;
|
||||
|
||||
typedef struct EVAL_Error EVAL_Error;
|
||||
struct EVAL_Error
|
||||
{
|
||||
EVAL_Error *next;
|
||||
EVAL_ErrorKind kind;
|
||||
void *location;
|
||||
String8 text;
|
||||
};
|
||||
|
||||
typedef struct EVAL_ErrorList EVAL_ErrorList;
|
||||
struct EVAL_ErrorList
|
||||
{
|
||||
EVAL_Error *first;
|
||||
EVAL_Error *last;
|
||||
EVAL_ErrorKind max_kind;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Operation Types
|
||||
|
||||
enum
|
||||
{
|
||||
EVAL_IRExtKind_Bytecode = RDI_EvalOp_COUNT,
|
||||
EVAL_IRExtKind_COUNT
|
||||
};
|
||||
|
||||
typedef struct EVAL_Op EVAL_Op;
|
||||
struct EVAL_Op
|
||||
{
|
||||
EVAL_Op *next;
|
||||
RDI_EvalOp opcode;
|
||||
union
|
||||
{
|
||||
U64 p;
|
||||
String8 bytecode;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct EVAL_OpList EVAL_OpList;
|
||||
struct EVAL_OpList
|
||||
{
|
||||
EVAL_Op *first_op;
|
||||
EVAL_Op *last_op;
|
||||
U32 op_count;
|
||||
U32 encoded_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "eval/generated/eval.meta.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Expression Tree Types
|
||||
|
||||
typedef enum EVAL_EvalMode
|
||||
{
|
||||
EVAL_EvalMode_NULL,
|
||||
EVAL_EvalMode_Value,
|
||||
EVAL_EvalMode_Addr,
|
||||
EVAL_EvalMode_Reg
|
||||
}
|
||||
EVAL_EvalMode;
|
||||
|
||||
typedef struct EVAL_Expr EVAL_Expr;
|
||||
struct EVAL_Expr
|
||||
{
|
||||
EVAL_ExprKind kind;
|
||||
void *location;
|
||||
union
|
||||
{
|
||||
EVAL_Expr *children[3];
|
||||
U32 u32;
|
||||
U64 u64;
|
||||
F32 f32;
|
||||
F64 f64;
|
||||
struct
|
||||
{
|
||||
EVAL_Expr *child;
|
||||
U64 u64;
|
||||
} child_and_constant;
|
||||
String8 name;
|
||||
struct
|
||||
{
|
||||
TG_Key type_key;
|
||||
String8 bytecode;
|
||||
EVAL_EvalMode mode;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: IR Tree Types
|
||||
|
||||
typedef struct EVAL_IRTree EVAL_IRTree;
|
||||
struct EVAL_IRTree{
|
||||
RDI_EvalOp op;
|
||||
EVAL_IRTree *children[3];
|
||||
union{
|
||||
U64 p;
|
||||
String8 bytecode;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct EVAL_IRTreeAndType EVAL_IRTreeAndType;
|
||||
struct EVAL_IRTreeAndType{
|
||||
EVAL_IRTree *tree;
|
||||
TG_Key type_key;
|
||||
EVAL_EvalMode mode;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Types
|
||||
|
||||
//- rjf: string -> num
|
||||
|
||||
typedef struct EVAL_String2NumMapNode EVAL_String2NumMapNode;
|
||||
struct EVAL_String2NumMapNode
|
||||
{
|
||||
EVAL_String2NumMapNode *order_next;
|
||||
EVAL_String2NumMapNode *hash_next;
|
||||
String8 string;
|
||||
U64 num;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2NumMapNodeArray EVAL_String2NumMapNodeArray;
|
||||
struct EVAL_String2NumMapNodeArray
|
||||
{
|
||||
EVAL_String2NumMapNode **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2NumMapSlot EVAL_String2NumMapSlot;
|
||||
struct EVAL_String2NumMapSlot
|
||||
{
|
||||
EVAL_String2NumMapNode *first;
|
||||
EVAL_String2NumMapNode *last;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2NumMap EVAL_String2NumMap;
|
||||
struct EVAL_String2NumMap
|
||||
{
|
||||
U64 slots_count;
|
||||
U64 node_count;
|
||||
EVAL_String2NumMapSlot *slots;
|
||||
EVAL_String2NumMapNode *first;
|
||||
EVAL_String2NumMapNode *last;
|
||||
};
|
||||
|
||||
//- rjf: string -> expr
|
||||
|
||||
typedef struct EVAL_String2ExprMapNode EVAL_String2ExprMapNode;
|
||||
struct EVAL_String2ExprMapNode
|
||||
{
|
||||
EVAL_String2ExprMapNode *hash_next;
|
||||
String8 string;
|
||||
EVAL_Expr *expr;
|
||||
U64 poison_count;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2ExprMapSlot EVAL_String2ExprMapSlot;
|
||||
struct EVAL_String2ExprMapSlot
|
||||
{
|
||||
EVAL_String2ExprMapNode *first;
|
||||
EVAL_String2ExprMapNode *last;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2ExprMap EVAL_String2ExprMap;
|
||||
struct EVAL_String2ExprMap
|
||||
{
|
||||
U64 slots_count;
|
||||
EVAL_String2ExprMapSlot *slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global read_only EVAL_Expr eval_expr_nil = {0};
|
||||
global read_only EVAL_IRTree eval_irtree_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
internal U64 eval_hash_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Error List Building Functions
|
||||
|
||||
internal void eval_error(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, String8 text);
|
||||
internal void eval_errorf(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, char *fmt, ...);
|
||||
internal void eval_error_list_concat_in_place(EVAL_ErrorList *dst, EVAL_ErrorList *to_push);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
//- rjf: string -> num
|
||||
internal EVAL_String2NumMap eval_string2num_map_make(Arena *arena, U64 slot_count);
|
||||
internal void eval_string2num_map_insert(Arena *arena, EVAL_String2NumMap *map, String8 string, U64 num);
|
||||
internal U64 eval_num_from_string(EVAL_String2NumMap *map, String8 string);
|
||||
internal EVAL_String2NumMapNodeArray eval_string2num_map_node_array_from_map(Arena *arena, EVAL_String2NumMap *map);
|
||||
internal int eval_string2num_map_node_qsort_compare__num_ascending(EVAL_String2NumMapNode **a, EVAL_String2NumMapNode **b);
|
||||
internal void eval_string2num_map_node_array_sort__in_place(EVAL_String2NumMapNodeArray *array);
|
||||
|
||||
//- rjf: string -> expr
|
||||
internal EVAL_String2ExprMap eval_string2expr_map_make(Arena *arena, U64 slot_count);
|
||||
internal void eval_string2expr_map_insert(Arena *arena, EVAL_String2ExprMap *map, String8 string, EVAL_Expr *expr);
|
||||
internal void eval_string2expr_map_inc_poison(EVAL_String2ExprMap *map, String8 string);
|
||||
internal void eval_string2expr_map_dec_poison(EVAL_String2ExprMap *map, String8 string);
|
||||
internal EVAL_Expr *eval_expr_from_string(EVAL_String2ExprMap *map, String8 string);
|
||||
|
||||
#endif // EVAL_CORE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_CORE_H
|
||||
#define EVAL_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Errors
|
||||
|
||||
typedef enum EVAL_ErrorKind
|
||||
{
|
||||
EVAL_ErrorKind_Null,
|
||||
EVAL_ErrorKind_MalformedInput,
|
||||
EVAL_ErrorKind_MissingInfo,
|
||||
EVAL_ErrorKind_ResolutionFailure,
|
||||
EVAL_ErrorKind_InterpretationError,
|
||||
EVAL_ErrorKind_COUNT
|
||||
}
|
||||
EVAL_ErrorKind;
|
||||
|
||||
typedef struct EVAL_Error EVAL_Error;
|
||||
struct EVAL_Error
|
||||
{
|
||||
EVAL_Error *next;
|
||||
EVAL_ErrorKind kind;
|
||||
void *location;
|
||||
String8 text;
|
||||
};
|
||||
|
||||
typedef struct EVAL_ErrorList EVAL_ErrorList;
|
||||
struct EVAL_ErrorList
|
||||
{
|
||||
EVAL_Error *first;
|
||||
EVAL_Error *last;
|
||||
EVAL_ErrorKind max_kind;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Operation Types
|
||||
|
||||
enum
|
||||
{
|
||||
EVAL_IRExtKind_Bytecode = RDI_EvalOp_COUNT,
|
||||
EVAL_IRExtKind_COUNT
|
||||
};
|
||||
|
||||
typedef struct EVAL_Op EVAL_Op;
|
||||
struct EVAL_Op
|
||||
{
|
||||
EVAL_Op *next;
|
||||
RDI_EvalOp opcode;
|
||||
union
|
||||
{
|
||||
U64 p;
|
||||
String8 bytecode;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct EVAL_OpList EVAL_OpList;
|
||||
struct EVAL_OpList
|
||||
{
|
||||
EVAL_Op *first_op;
|
||||
EVAL_Op *last_op;
|
||||
U32 op_count;
|
||||
U32 encoded_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "eval/generated/eval.meta.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Expression Tree Types
|
||||
|
||||
typedef enum EVAL_EvalMode
|
||||
{
|
||||
EVAL_EvalMode_NULL,
|
||||
EVAL_EvalMode_Value,
|
||||
EVAL_EvalMode_Addr,
|
||||
EVAL_EvalMode_Reg
|
||||
}
|
||||
EVAL_EvalMode;
|
||||
|
||||
typedef struct EVAL_Expr EVAL_Expr;
|
||||
struct EVAL_Expr
|
||||
{
|
||||
EVAL_ExprKind kind;
|
||||
void *location;
|
||||
union
|
||||
{
|
||||
EVAL_Expr *children[3];
|
||||
U32 u32;
|
||||
U64 u64;
|
||||
F32 f32;
|
||||
F64 f64;
|
||||
struct
|
||||
{
|
||||
EVAL_Expr *child;
|
||||
U64 u64;
|
||||
} child_and_constant;
|
||||
String8 name;
|
||||
struct
|
||||
{
|
||||
TG_Key type_key;
|
||||
String8 bytecode;
|
||||
EVAL_EvalMode mode;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: IR Tree Types
|
||||
|
||||
typedef struct EVAL_IRTree EVAL_IRTree;
|
||||
struct EVAL_IRTree{
|
||||
RDI_EvalOp op;
|
||||
EVAL_IRTree *children[3];
|
||||
union{
|
||||
U64 p;
|
||||
String8 bytecode;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct EVAL_IRTreeAndType EVAL_IRTreeAndType;
|
||||
struct EVAL_IRTreeAndType{
|
||||
EVAL_IRTree *tree;
|
||||
TG_Key type_key;
|
||||
EVAL_EvalMode mode;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Types
|
||||
|
||||
//- rjf: string -> num
|
||||
|
||||
typedef struct EVAL_String2NumMapNode EVAL_String2NumMapNode;
|
||||
struct EVAL_String2NumMapNode
|
||||
{
|
||||
EVAL_String2NumMapNode *order_next;
|
||||
EVAL_String2NumMapNode *hash_next;
|
||||
String8 string;
|
||||
U64 num;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2NumMapNodeArray EVAL_String2NumMapNodeArray;
|
||||
struct EVAL_String2NumMapNodeArray
|
||||
{
|
||||
EVAL_String2NumMapNode **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2NumMapSlot EVAL_String2NumMapSlot;
|
||||
struct EVAL_String2NumMapSlot
|
||||
{
|
||||
EVAL_String2NumMapNode *first;
|
||||
EVAL_String2NumMapNode *last;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2NumMap EVAL_String2NumMap;
|
||||
struct EVAL_String2NumMap
|
||||
{
|
||||
U64 slots_count;
|
||||
U64 node_count;
|
||||
EVAL_String2NumMapSlot *slots;
|
||||
EVAL_String2NumMapNode *first;
|
||||
EVAL_String2NumMapNode *last;
|
||||
};
|
||||
|
||||
//- rjf: string -> expr
|
||||
|
||||
typedef struct EVAL_String2ExprMapNode EVAL_String2ExprMapNode;
|
||||
struct EVAL_String2ExprMapNode
|
||||
{
|
||||
EVAL_String2ExprMapNode *hash_next;
|
||||
String8 string;
|
||||
EVAL_Expr *expr;
|
||||
U64 poison_count;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2ExprMapSlot EVAL_String2ExprMapSlot;
|
||||
struct EVAL_String2ExprMapSlot
|
||||
{
|
||||
EVAL_String2ExprMapNode *first;
|
||||
EVAL_String2ExprMapNode *last;
|
||||
};
|
||||
|
||||
typedef struct EVAL_String2ExprMap EVAL_String2ExprMap;
|
||||
struct EVAL_String2ExprMap
|
||||
{
|
||||
U64 slots_count;
|
||||
EVAL_String2ExprMapSlot *slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global read_only EVAL_Expr eval_expr_nil = {0};
|
||||
global read_only EVAL_IRTree eval_irtree_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
internal U64 eval_hash_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Error List Building Functions
|
||||
|
||||
internal void eval_error(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, String8 text);
|
||||
internal void eval_errorf(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, char *fmt, ...);
|
||||
internal void eval_error_list_concat_in_place(EVAL_ErrorList *dst, EVAL_ErrorList *to_push);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
//- rjf: string -> num
|
||||
internal EVAL_String2NumMap eval_string2num_map_make(Arena *arena, U64 slot_count);
|
||||
internal void eval_string2num_map_insert(Arena *arena, EVAL_String2NumMap *map, String8 string, U64 num);
|
||||
internal U64 eval_num_from_string(EVAL_String2NumMap *map, String8 string);
|
||||
internal EVAL_String2NumMapNodeArray eval_string2num_map_node_array_from_map(Arena *arena, EVAL_String2NumMap *map);
|
||||
internal int eval_string2num_map_node_qsort_compare__num_ascending(EVAL_String2NumMapNode **a, EVAL_String2NumMapNode **b);
|
||||
internal void eval_string2num_map_node_array_sort__in_place(EVAL_String2NumMapNodeArray *array);
|
||||
|
||||
//- rjf: string -> expr
|
||||
internal EVAL_String2ExprMap eval_string2expr_map_make(Arena *arena, U64 slot_count);
|
||||
internal void eval_string2expr_map_insert(Arena *arena, EVAL_String2ExprMap *map, String8 string, EVAL_Expr *expr);
|
||||
internal void eval_string2expr_map_inc_poison(EVAL_String2ExprMap *map, String8 string);
|
||||
internal void eval_string2expr_map_dec_poison(EVAL_String2ExprMap *map, String8 string);
|
||||
internal EVAL_Expr *eval_expr_from_string(EVAL_String2ExprMap *map, String8 string);
|
||||
|
||||
#endif // EVAL_CORE_H
|
||||
|
||||
+50
-50
@@ -1,50 +1,50 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Eval Decode Function
|
||||
|
||||
internal void
|
||||
eval_print_decode_from_bytecode(FILE *out, String8 bytecode){
|
||||
U8 *ptr = bytecode.str;
|
||||
U8 *opl = bytecode.str + bytecode.size;
|
||||
|
||||
for (;ptr < opl;){
|
||||
// consume opcode
|
||||
SYMS_EvalOp op = (SYMS_EvalOp)*ptr;
|
||||
if (op >= SYMS_EvalOp_COUNT){
|
||||
fprintf(out, "decode error: undefined op code\n");
|
||||
goto done;
|
||||
}
|
||||
U8 ctrlbits = syms_eval_opcode_ctrlbits[op];
|
||||
ptr += 1;
|
||||
|
||||
// decode
|
||||
U64 imm = 0;
|
||||
U32 decode_size = (ctrlbits >> SYMS_EvalOpCtrlBits_DecodeShft)&SYMS_EvalOpCtrlBits_DecodeMask;
|
||||
{
|
||||
U8 *next_ptr = ptr + decode_size;
|
||||
if (next_ptr > opl){
|
||||
fprintf(out, "decode error: expected constant goes past the end of bytecode\n");
|
||||
goto done;
|
||||
}
|
||||
// TODO(allen): to improve this:
|
||||
// gaurantee 8 bytes padding after the end of serialized bytecode
|
||||
// read 8 bytes and mask
|
||||
switch (decode_size){
|
||||
case 1: imm = *ptr; break;
|
||||
case 2: imm = *(U16*)ptr; break;
|
||||
case 4: imm = *(U32*)ptr; break;
|
||||
case 8: imm = *(U64*)ptr; break;
|
||||
}
|
||||
ptr = next_ptr;
|
||||
}
|
||||
|
||||
// op string & control bits
|
||||
SYMS_String8 op_string = syms_eval_opcode_strings[op];
|
||||
|
||||
// print
|
||||
fprintf(out, "%.*s 0x%llx\n", str8_varg(op_string), imm);
|
||||
}
|
||||
done:;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Eval Decode Function
|
||||
|
||||
internal void
|
||||
eval_print_decode_from_bytecode(FILE *out, String8 bytecode){
|
||||
U8 *ptr = bytecode.str;
|
||||
U8 *opl = bytecode.str + bytecode.size;
|
||||
|
||||
for (;ptr < opl;){
|
||||
// consume opcode
|
||||
SYMS_EvalOp op = (SYMS_EvalOp)*ptr;
|
||||
if (op >= SYMS_EvalOp_COUNT){
|
||||
fprintf(out, "decode error: undefined op code\n");
|
||||
goto done;
|
||||
}
|
||||
U8 ctrlbits = syms_eval_opcode_ctrlbits[op];
|
||||
ptr += 1;
|
||||
|
||||
// decode
|
||||
U64 imm = 0;
|
||||
U32 decode_size = (ctrlbits >> SYMS_EvalOpCtrlBits_DecodeShft)&SYMS_EvalOpCtrlBits_DecodeMask;
|
||||
{
|
||||
U8 *next_ptr = ptr + decode_size;
|
||||
if (next_ptr > opl){
|
||||
fprintf(out, "decode error: expected constant goes past the end of bytecode\n");
|
||||
goto done;
|
||||
}
|
||||
// TODO(allen): to improve this:
|
||||
// gaurantee 8 bytes padding after the end of serialized bytecode
|
||||
// read 8 bytes and mask
|
||||
switch (decode_size){
|
||||
case 1: imm = *ptr; break;
|
||||
case 2: imm = *(U16*)ptr; break;
|
||||
case 4: imm = *(U32*)ptr; break;
|
||||
case 8: imm = *(U64*)ptr; break;
|
||||
}
|
||||
ptr = next_ptr;
|
||||
}
|
||||
|
||||
// op string & control bits
|
||||
SYMS_String8 op_string = syms_eval_opcode_strings[op];
|
||||
|
||||
// print
|
||||
fprintf(out, "%.*s 0x%llx\n", str8_varg(op_string), imm);
|
||||
}
|
||||
done:;
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_DECODE_H
|
||||
#define EVAL_DECODE_H
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Eval Decode Function
|
||||
|
||||
internal void eval_print_decode_from_bytecode(FILE *out, String8 bytecode);
|
||||
|
||||
#endif //EVAL_DECODE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_DECODE_H
|
||||
#define EVAL_DECODE_H
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Eval Decode Function
|
||||
|
||||
internal void eval_print_decode_from_bytecode(FILE *out, String8 bytecode);
|
||||
|
||||
#endif //EVAL_DECODE_H
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "eval/eval_core.c"
|
||||
#include "eval/eval_compiler.c"
|
||||
#include "eval/eval_machine.c"
|
||||
#include "eval/eval_parser.c"
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "eval/eval_core.c"
|
||||
#include "eval/eval_compiler.c"
|
||||
#include "eval/eval_machine.c"
|
||||
#include "eval/eval_parser.c"
|
||||
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_INC_H
|
||||
#define EVAL_INC_H
|
||||
|
||||
#include "eval/eval_core.h"
|
||||
#include "eval/eval_compiler.h"
|
||||
#include "eval/eval_machine.h"
|
||||
#include "eval/eval_parser.h"
|
||||
|
||||
#endif // EVAL_INC_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_INC_H
|
||||
#define EVAL_INC_H
|
||||
|
||||
#include "eval/eval_core.h"
|
||||
#include "eval/eval_compiler.h"
|
||||
#include "eval/eval_machine.h"
|
||||
#include "eval/eval_parser.h"
|
||||
|
||||
#endif // EVAL_INC_H
|
||||
|
||||
+647
-647
File diff suppressed because it is too large
Load Diff
+48
-48
@@ -1,48 +1,48 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL2_MACHINE_H
|
||||
#define EVAL2_MACHINE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Eval Machine Types
|
||||
|
||||
typedef B32 EVAL_MemoryRead(void *u, void *out, U64 addr, U64 size);
|
||||
|
||||
typedef struct EVAL_Machine EVAL_Machine;
|
||||
struct EVAL_Machine
|
||||
{
|
||||
void *u;
|
||||
Architecture arch;
|
||||
EVAL_MemoryRead *memory_read;
|
||||
void *reg_data;
|
||||
U64 reg_size;
|
||||
U64 *module_base;
|
||||
U64 *frame_base;
|
||||
U64 *tls_base;
|
||||
};
|
||||
|
||||
typedef union EVAL_Slot EVAL_Slot;
|
||||
union EVAL_Slot
|
||||
{
|
||||
U64 u256[4];
|
||||
U64 u128[2];
|
||||
U64 u64;
|
||||
S64 s64;
|
||||
F64 f64;
|
||||
F32 f32;
|
||||
};
|
||||
|
||||
typedef struct EVAL_Result EVAL_Result;
|
||||
struct EVAL_Result
|
||||
{
|
||||
EVAL_Slot value;
|
||||
EVAL_ResultCode code;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Eval Machine Functions
|
||||
|
||||
internal EVAL_Result eval_interpret(EVAL_Machine *machine, String8 bytecode);
|
||||
|
||||
#endif //EVAL2_MACHINE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL2_MACHINE_H
|
||||
#define EVAL2_MACHINE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Eval Machine Types
|
||||
|
||||
typedef B32 EVAL_MemoryRead(void *u, void *out, U64 addr, U64 size);
|
||||
|
||||
typedef struct EVAL_Machine EVAL_Machine;
|
||||
struct EVAL_Machine
|
||||
{
|
||||
void *u;
|
||||
Architecture arch;
|
||||
EVAL_MemoryRead *memory_read;
|
||||
void *reg_data;
|
||||
U64 reg_size;
|
||||
U64 *module_base;
|
||||
U64 *frame_base;
|
||||
U64 *tls_base;
|
||||
};
|
||||
|
||||
typedef union EVAL_Slot EVAL_Slot;
|
||||
union EVAL_Slot
|
||||
{
|
||||
U64 u256[4];
|
||||
U64 u128[2];
|
||||
U64 u64;
|
||||
S64 s64;
|
||||
F64 f64;
|
||||
F32 f32;
|
||||
};
|
||||
|
||||
typedef struct EVAL_Result EVAL_Result;
|
||||
struct EVAL_Result
|
||||
{
|
||||
EVAL_Slot value;
|
||||
EVAL_ResultCode code;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Eval Machine Functions
|
||||
|
||||
internal EVAL_Result eval_interpret(EVAL_Machine *machine, String8 bytecode);
|
||||
|
||||
#endif //EVAL2_MACHINE_H
|
||||
|
||||
+1444
-1444
File diff suppressed because it is too large
Load Diff
+109
-109
@@ -1,109 +1,109 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_PARSER_H
|
||||
#define EVAL_PARSER_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Types
|
||||
|
||||
typedef enum EVAL_TokenKind
|
||||
{
|
||||
EVAL_TokenKind_Null,
|
||||
EVAL_TokenKind_Identifier,
|
||||
EVAL_TokenKind_Numeric,
|
||||
EVAL_TokenKind_StringLiteral,
|
||||
EVAL_TokenKind_CharLiteral,
|
||||
EVAL_TokenKind_Symbol,
|
||||
EVAL_TokenKind_COUNT
|
||||
}
|
||||
EVAL_TokenKind;
|
||||
|
||||
typedef struct EVAL_Token EVAL_Token;
|
||||
struct EVAL_Token
|
||||
{
|
||||
EVAL_TokenKind kind;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct EVAL_TokenChunkNode EVAL_TokenChunkNode;
|
||||
struct EVAL_TokenChunkNode
|
||||
{
|
||||
EVAL_TokenChunkNode *next;
|
||||
EVAL_Token *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct EVAL_TokenChunkList EVAL_TokenChunkList;
|
||||
struct EVAL_TokenChunkList
|
||||
{
|
||||
EVAL_TokenChunkNode *first;
|
||||
EVAL_TokenChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct EVAL_TokenArray EVAL_TokenArray;
|
||||
struct EVAL_TokenArray
|
||||
{
|
||||
EVAL_Token *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parser Types
|
||||
|
||||
typedef struct EVAL_ParseResult EVAL_ParseResult;
|
||||
struct EVAL_ParseResult
|
||||
{
|
||||
EVAL_Token *last_token;
|
||||
EVAL_Expr *expr;
|
||||
EVAL_ErrorList errors;
|
||||
};
|
||||
|
||||
typedef struct EVAL_ParseCtx EVAL_ParseCtx;
|
||||
struct EVAL_ParseCtx
|
||||
{
|
||||
Architecture arch;
|
||||
U64 ip_voff;
|
||||
RDI_Parsed *rdi;
|
||||
TG_Graph *type_graph;
|
||||
EVAL_String2NumMap *regs_map;
|
||||
EVAL_String2NumMap *reg_alias_map;
|
||||
EVAL_String2NumMap *locals_map;
|
||||
EVAL_String2NumMap *member_map;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global EVAL_String2NumMap eval_string2num_map_nil = {0};
|
||||
read_only global EVAL_String2ExprMap eval_string2expr_map_nil = {0};
|
||||
global read_only EVAL_ParseResult eval_parse_result_nil = {0, &eval_expr_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug-Info-Driven Map Building Fast Paths
|
||||
|
||||
internal EVAL_String2NumMap *eval_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff);
|
||||
internal EVAL_String2NumMap *eval_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokenization Functions
|
||||
|
||||
#define eval_token_at_it(it, arr) (((it) < (arr)->v+(arr)->count) ? (*(it)) : eval_token_zero())
|
||||
internal EVAL_Token eval_token_zero(void);
|
||||
internal void eval_token_chunk_list_push(Arena *arena, EVAL_TokenChunkList *list, U64 chunk_size, EVAL_Token *token);
|
||||
internal EVAL_TokenArray eval_token_array_from_chunk_list(Arena *arena, EVAL_TokenChunkList *list);
|
||||
internal EVAL_TokenArray eval_token_array_from_text(Arena *arena, String8 text);
|
||||
internal EVAL_TokenArray eval_token_array_make_first_opl(EVAL_Token *first, EVAL_Token *opl);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parser Functions
|
||||
|
||||
internal TG_Key eval_leaf_type_from_name(RDI_Parsed *rdi, String8 name);
|
||||
internal EVAL_ParseResult eval_parse_type_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens);
|
||||
internal EVAL_ParseResult eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens, S64 max_precedence);
|
||||
internal EVAL_ParseResult eval_parse_expr_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens);
|
||||
|
||||
#endif // EVAL_PARSER_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EVAL_PARSER_H
|
||||
#define EVAL_PARSER_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Types
|
||||
|
||||
typedef enum EVAL_TokenKind
|
||||
{
|
||||
EVAL_TokenKind_Null,
|
||||
EVAL_TokenKind_Identifier,
|
||||
EVAL_TokenKind_Numeric,
|
||||
EVAL_TokenKind_StringLiteral,
|
||||
EVAL_TokenKind_CharLiteral,
|
||||
EVAL_TokenKind_Symbol,
|
||||
EVAL_TokenKind_COUNT
|
||||
}
|
||||
EVAL_TokenKind;
|
||||
|
||||
typedef struct EVAL_Token EVAL_Token;
|
||||
struct EVAL_Token
|
||||
{
|
||||
EVAL_TokenKind kind;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct EVAL_TokenChunkNode EVAL_TokenChunkNode;
|
||||
struct EVAL_TokenChunkNode
|
||||
{
|
||||
EVAL_TokenChunkNode *next;
|
||||
EVAL_Token *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct EVAL_TokenChunkList EVAL_TokenChunkList;
|
||||
struct EVAL_TokenChunkList
|
||||
{
|
||||
EVAL_TokenChunkNode *first;
|
||||
EVAL_TokenChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct EVAL_TokenArray EVAL_TokenArray;
|
||||
struct EVAL_TokenArray
|
||||
{
|
||||
EVAL_Token *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parser Types
|
||||
|
||||
typedef struct EVAL_ParseResult EVAL_ParseResult;
|
||||
struct EVAL_ParseResult
|
||||
{
|
||||
EVAL_Token *last_token;
|
||||
EVAL_Expr *expr;
|
||||
EVAL_ErrorList errors;
|
||||
};
|
||||
|
||||
typedef struct EVAL_ParseCtx EVAL_ParseCtx;
|
||||
struct EVAL_ParseCtx
|
||||
{
|
||||
Architecture arch;
|
||||
U64 ip_voff;
|
||||
RDI_Parsed *rdi;
|
||||
TG_Graph *type_graph;
|
||||
EVAL_String2NumMap *regs_map;
|
||||
EVAL_String2NumMap *reg_alias_map;
|
||||
EVAL_String2NumMap *locals_map;
|
||||
EVAL_String2NumMap *member_map;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global EVAL_String2NumMap eval_string2num_map_nil = {0};
|
||||
read_only global EVAL_String2ExprMap eval_string2expr_map_nil = {0};
|
||||
global read_only EVAL_ParseResult eval_parse_result_nil = {0, &eval_expr_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug-Info-Driven Map Building Fast Paths
|
||||
|
||||
internal EVAL_String2NumMap *eval_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff);
|
||||
internal EVAL_String2NumMap *eval_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokenization Functions
|
||||
|
||||
#define eval_token_at_it(it, arr) (((it) < (arr)->v+(arr)->count) ? (*(it)) : eval_token_zero())
|
||||
internal EVAL_Token eval_token_zero(void);
|
||||
internal void eval_token_chunk_list_push(Arena *arena, EVAL_TokenChunkList *list, U64 chunk_size, EVAL_Token *token);
|
||||
internal EVAL_TokenArray eval_token_array_from_chunk_list(Arena *arena, EVAL_TokenChunkList *list);
|
||||
internal EVAL_TokenArray eval_token_array_from_text(Arena *arena, String8 text);
|
||||
internal EVAL_TokenArray eval_token_array_make_first_opl(EVAL_Token *first, EVAL_Token *opl);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parser Functions
|
||||
|
||||
internal TG_Key eval_leaf_type_from_name(RDI_Parsed *rdi, String8 name);
|
||||
internal EVAL_ParseResult eval_parse_type_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens);
|
||||
internal EVAL_ParseResult eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens, S64 max_precedence);
|
||||
internal EVAL_ParseResult eval_parse_expr_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens);
|
||||
|
||||
#endif // EVAL_PARSER_H
|
||||
|
||||
+100
-100
@@ -1,100 +1,100 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FILE_STREAM_H
|
||||
#define FILE_STREAM_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Path Info Cache Types
|
||||
|
||||
typedef struct FS_Node FS_Node;
|
||||
struct FS_Node
|
||||
{
|
||||
FS_Node *next;
|
||||
String8 path;
|
||||
U64 timestamp;
|
||||
B32 is_working;
|
||||
};
|
||||
|
||||
typedef struct FS_Slot FS_Slot;
|
||||
struct FS_Slot
|
||||
{
|
||||
FS_Node *first;
|
||||
FS_Node *last;
|
||||
};
|
||||
|
||||
typedef struct FS_Stripe FS_Stripe;
|
||||
struct FS_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle cv;
|
||||
OS_Handle rw_mutex;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct FS_Shared FS_Shared;
|
||||
struct FS_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
U64 change_gen;
|
||||
|
||||
// rjf: path info cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
FS_Slot *slots;
|
||||
FS_Stripe *stripes;
|
||||
|
||||
// rjf: user -> streamer ring buffer
|
||||
U64 u2s_ring_size;
|
||||
U8 *u2s_ring_base;
|
||||
U64 u2s_ring_write_pos;
|
||||
U64 u2s_ring_read_pos;
|
||||
OS_Handle u2s_ring_cv;
|
||||
OS_Handle u2s_ring_mutex;
|
||||
|
||||
// rjf: streamer threads
|
||||
U64 streamer_count;
|
||||
OS_Handle *streamers;
|
||||
|
||||
// rjf: change detector threads
|
||||
OS_Handle detector_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global FS_Shared *fs_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level API
|
||||
|
||||
internal void fs_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Change Generation
|
||||
|
||||
internal U64 fs_change_gen(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Interaction
|
||||
|
||||
internal U128 fs_hash_from_path(String8 path, U64 endt_us);
|
||||
internal U128 fs_key_from_path(String8 path);
|
||||
internal U64 fs_timestamp_from_path(String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Streamer Threads
|
||||
|
||||
internal B32 fs_u2s_enqueue_path(String8 path, U64 endt_us);
|
||||
internal String8 fs_u2s_dequeue_path(Arena *arena);
|
||||
|
||||
internal void fs_streamer_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Change Detector Thread
|
||||
|
||||
internal void fs_detector_thread__entry_point(void *p);
|
||||
|
||||
#endif // FILE_STREAM_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FILE_STREAM_H
|
||||
#define FILE_STREAM_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Path Info Cache Types
|
||||
|
||||
typedef struct FS_Node FS_Node;
|
||||
struct FS_Node
|
||||
{
|
||||
FS_Node *next;
|
||||
String8 path;
|
||||
U64 timestamp;
|
||||
B32 is_working;
|
||||
};
|
||||
|
||||
typedef struct FS_Slot FS_Slot;
|
||||
struct FS_Slot
|
||||
{
|
||||
FS_Node *first;
|
||||
FS_Node *last;
|
||||
};
|
||||
|
||||
typedef struct FS_Stripe FS_Stripe;
|
||||
struct FS_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle cv;
|
||||
OS_Handle rw_mutex;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct FS_Shared FS_Shared;
|
||||
struct FS_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
U64 change_gen;
|
||||
|
||||
// rjf: path info cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
FS_Slot *slots;
|
||||
FS_Stripe *stripes;
|
||||
|
||||
// rjf: user -> streamer ring buffer
|
||||
U64 u2s_ring_size;
|
||||
U8 *u2s_ring_base;
|
||||
U64 u2s_ring_write_pos;
|
||||
U64 u2s_ring_read_pos;
|
||||
OS_Handle u2s_ring_cv;
|
||||
OS_Handle u2s_ring_mutex;
|
||||
|
||||
// rjf: streamer threads
|
||||
U64 streamer_count;
|
||||
OS_Handle *streamers;
|
||||
|
||||
// rjf: change detector threads
|
||||
OS_Handle detector_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global FS_Shared *fs_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level API
|
||||
|
||||
internal void fs_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Change Generation
|
||||
|
||||
internal U64 fs_change_gen(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Interaction
|
||||
|
||||
internal U128 fs_hash_from_path(String8 path, U64 endt_us);
|
||||
internal U128 fs_key_from_path(String8 path);
|
||||
internal U64 fs_timestamp_from_path(String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Streamer Threads
|
||||
|
||||
internal B32 fs_u2s_enqueue_path(String8 path, U64 endt_us);
|
||||
internal String8 fs_u2s_dequeue_path(Arena *arena);
|
||||
|
||||
internal void fs_streamer_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Change Detector Thread
|
||||
|
||||
internal void fs_detector_thread__entry_point(void *p);
|
||||
|
||||
#endif // FILE_STREAM_H
|
||||
|
||||
+1063
-1063
File diff suppressed because it is too large
Load Diff
+270
-270
@@ -1,270 +1,270 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FONT_CACHE_H
|
||||
#define FONT_CACHE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Rasterization Flags
|
||||
|
||||
typedef U32 F_RasterFlags;
|
||||
enum
|
||||
{
|
||||
F_RasterFlag_Smooth = (1<<0),
|
||||
F_RasterFlag_Hinted = (1<<1),
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handles & Tags
|
||||
|
||||
typedef struct F_Hash F_Hash;
|
||||
struct F_Hash
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
typedef struct F_Tag F_Tag;
|
||||
struct F_Tag
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Draw Package Types (For Cache Queries)
|
||||
|
||||
typedef struct F_Piece F_Piece;
|
||||
struct F_Piece
|
||||
{
|
||||
R_Handle texture;
|
||||
Rng2S16 subrect;
|
||||
Vec2S16 offset;
|
||||
F32 advance;
|
||||
U16 decode_size;
|
||||
};
|
||||
|
||||
typedef struct F_PieceChunkNode F_PieceChunkNode;
|
||||
struct F_PieceChunkNode
|
||||
{
|
||||
F_PieceChunkNode *next;
|
||||
F_Piece *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct F_PieceChunkList F_PieceChunkList;
|
||||
struct F_PieceChunkList
|
||||
{
|
||||
F_PieceChunkNode *first;
|
||||
F_PieceChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 total_piece_count;
|
||||
};
|
||||
|
||||
typedef struct F_PieceArray F_PieceArray;
|
||||
struct F_PieceArray
|
||||
{
|
||||
F_Piece *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct F_Run F_Run;
|
||||
struct F_Run
|
||||
{
|
||||
F_PieceArray pieces;
|
||||
Vec2F32 dim;
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Font Path -> Handle * Metrics * Path Cache Types
|
||||
|
||||
typedef struct F_FontHashNode F_FontHashNode;
|
||||
struct F_FontHashNode
|
||||
{
|
||||
F_FontHashNode *hash_next;
|
||||
F_Tag tag;
|
||||
FP_Handle handle;
|
||||
FP_Metrics metrics;
|
||||
String8 path;
|
||||
};
|
||||
|
||||
typedef struct F_FontHashSlot F_FontHashSlot;
|
||||
struct F_FontHashSlot
|
||||
{
|
||||
F_FontHashNode *first;
|
||||
F_FontHashNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Rasterization Cache Types
|
||||
|
||||
typedef struct F_RasterCacheInfo F_RasterCacheInfo;
|
||||
struct F_RasterCacheInfo
|
||||
{
|
||||
Rng2S16 subrect;
|
||||
Vec2S16 raster_dim;
|
||||
S16 atlas_num;
|
||||
F32 advance;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2InfoRasterCacheNode F_Hash2InfoRasterCacheNode;
|
||||
struct F_Hash2InfoRasterCacheNode
|
||||
{
|
||||
F_Hash2InfoRasterCacheNode *hash_next;
|
||||
F_Hash2InfoRasterCacheNode *hash_prev;
|
||||
U64 hash;
|
||||
F_RasterCacheInfo info;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2InfoRasterCacheSlot F_Hash2InfoRasterCacheSlot;
|
||||
struct F_Hash2InfoRasterCacheSlot
|
||||
{
|
||||
F_Hash2InfoRasterCacheNode *first;
|
||||
F_Hash2InfoRasterCacheNode *last;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2StyleRasterCacheNode F_Hash2StyleRasterCacheNode;
|
||||
struct F_Hash2StyleRasterCacheNode
|
||||
{
|
||||
F_Hash2StyleRasterCacheNode *hash_next;
|
||||
F_Hash2StyleRasterCacheNode *hash_prev;
|
||||
U64 style_hash;
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
F32 column_width;
|
||||
F_RasterCacheInfo *utf8_class1_direct_map;
|
||||
U64 utf8_class1_direct_map_mask[4];
|
||||
U64 hash2info_slots_count;
|
||||
F_Hash2InfoRasterCacheSlot *hash2info_slots;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2StyleRasterCacheSlot F_Hash2StyleRasterCacheSlot;
|
||||
struct F_Hash2StyleRasterCacheSlot
|
||||
{
|
||||
F_Hash2StyleRasterCacheNode *first;
|
||||
F_Hash2StyleRasterCacheNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Atlas Types
|
||||
|
||||
typedef U32 F_AtlasRegionNodeFlags;
|
||||
enum
|
||||
{
|
||||
F_AtlasRegionNodeFlag_Taken = (1<<0),
|
||||
};
|
||||
|
||||
typedef struct F_AtlasRegionNode F_AtlasRegionNode;
|
||||
struct F_AtlasRegionNode
|
||||
{
|
||||
F_AtlasRegionNode *parent;
|
||||
F_AtlasRegionNode *children[Corner_COUNT];
|
||||
Vec2S16 max_free_size[Corner_COUNT];
|
||||
F_AtlasRegionNodeFlags flags;
|
||||
U64 num_allocated_descendants;
|
||||
};
|
||||
|
||||
typedef struct F_Atlas F_Atlas;
|
||||
struct F_Atlas
|
||||
{
|
||||
F_Atlas *next;
|
||||
F_Atlas *prev;
|
||||
R_Handle texture;
|
||||
Vec2S16 root_dim;
|
||||
F_AtlasRegionNode *root;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Metrics
|
||||
|
||||
typedef struct F_Metrics F_Metrics;
|
||||
struct F_Metrics
|
||||
{
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
F32 line_gap;
|
||||
F32 capital_height;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main State Type
|
||||
|
||||
typedef struct F_State F_State;
|
||||
struct F_State
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: font table
|
||||
U64 font_hash_table_size;
|
||||
F_FontHashSlot *font_hash_table;
|
||||
|
||||
// rjf: hash -> raster cache table
|
||||
U64 hash2style_slots_count;
|
||||
F_Hash2StyleRasterCacheSlot *hash2style_slots;
|
||||
|
||||
// rjf: atlas list
|
||||
F_Atlas *first_atlas;
|
||||
F_Atlas *last_atlas;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global F_State *f_state = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
internal F_Hash f_hash_from_string(String8 string);
|
||||
internal U64 f_little_hash_from_string(String8 string);
|
||||
internal Vec2S32 f_vertex_from_corner(Corner corner);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Font Tags
|
||||
|
||||
internal F_Tag f_tag_zero(void);
|
||||
internal B32 f_tag_match(F_Tag a, F_Tag b);
|
||||
internal FP_Handle f_handle_from_tag(F_Tag tag);
|
||||
internal FP_Metrics f_fp_metrics_from_tag(F_Tag tag);
|
||||
internal F_Tag f_tag_from_path(String8 path);
|
||||
internal F_Tag f_tag_from_static_data_string(String8 *data_ptr);
|
||||
internal String8 f_path_from_tag(F_Tag tag);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Atlas
|
||||
|
||||
internal Rng2S16 f_atlas_region_alloc(Arena *arena, F_Atlas *atlas, Vec2S16 needed_size);
|
||||
internal void f_atlas_region_release(F_Atlas *atlas, Rng2S16 region);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Piece Type Functions
|
||||
|
||||
internal F_Piece *f_piece_chunk_list_push_new(Arena *arena, F_PieceChunkList *list, U64 cap);
|
||||
internal void f_piece_chunk_list_push(Arena *arena, F_PieceChunkList *list, U64 cap, F_Piece *piece);
|
||||
internal F_PieceArray f_piece_array_from_chunk_list(Arena *arena, F_PieceChunkList *list);
|
||||
internal F_PieceArray f_piece_array_copy(Arena *arena, F_PieceArray *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Rasterization Cache
|
||||
|
||||
internal F_Hash2StyleRasterCacheNode *f_hash2style_from_tag_size_flags(F_Tag tag, F32 size, F_RasterFlags flags);
|
||||
internal F_Run f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, F_RasterFlags flags, String8 string);
|
||||
internal String8List f_wrapped_string_lines_from_font_size_string_max(Arena *arena, F_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, String8 string, F32 max);
|
||||
internal Vec2F32 f_dim_from_tag_size_string(F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8 string);
|
||||
internal Vec2F32 f_dim_from_tag_size_string_list(F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8List list);
|
||||
internal F32 f_column_size_from_tag_size(F_Tag tag, F32 size);
|
||||
internal U64 f_char_pos_from_tag_size_string_p(F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8 string, F32 p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Metrics
|
||||
|
||||
internal F_Metrics f_metrics_from_tag_size(F_Tag tag, F32 size);
|
||||
internal F32 f_line_height_from_metrics(F_Metrics *metrics);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Calls
|
||||
|
||||
internal void f_init(void);
|
||||
|
||||
#endif // FONT_CACHE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FONT_CACHE_H
|
||||
#define FONT_CACHE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Rasterization Flags
|
||||
|
||||
typedef U32 F_RasterFlags;
|
||||
enum
|
||||
{
|
||||
F_RasterFlag_Smooth = (1<<0),
|
||||
F_RasterFlag_Hinted = (1<<1),
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handles & Tags
|
||||
|
||||
typedef struct F_Hash F_Hash;
|
||||
struct F_Hash
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
typedef struct F_Tag F_Tag;
|
||||
struct F_Tag
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Draw Package Types (For Cache Queries)
|
||||
|
||||
typedef struct F_Piece F_Piece;
|
||||
struct F_Piece
|
||||
{
|
||||
R_Handle texture;
|
||||
Rng2S16 subrect;
|
||||
Vec2S16 offset;
|
||||
F32 advance;
|
||||
U16 decode_size;
|
||||
};
|
||||
|
||||
typedef struct F_PieceChunkNode F_PieceChunkNode;
|
||||
struct F_PieceChunkNode
|
||||
{
|
||||
F_PieceChunkNode *next;
|
||||
F_Piece *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct F_PieceChunkList F_PieceChunkList;
|
||||
struct F_PieceChunkList
|
||||
{
|
||||
F_PieceChunkNode *first;
|
||||
F_PieceChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 total_piece_count;
|
||||
};
|
||||
|
||||
typedef struct F_PieceArray F_PieceArray;
|
||||
struct F_PieceArray
|
||||
{
|
||||
F_Piece *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct F_Run F_Run;
|
||||
struct F_Run
|
||||
{
|
||||
F_PieceArray pieces;
|
||||
Vec2F32 dim;
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Font Path -> Handle * Metrics * Path Cache Types
|
||||
|
||||
typedef struct F_FontHashNode F_FontHashNode;
|
||||
struct F_FontHashNode
|
||||
{
|
||||
F_FontHashNode *hash_next;
|
||||
F_Tag tag;
|
||||
FP_Handle handle;
|
||||
FP_Metrics metrics;
|
||||
String8 path;
|
||||
};
|
||||
|
||||
typedef struct F_FontHashSlot F_FontHashSlot;
|
||||
struct F_FontHashSlot
|
||||
{
|
||||
F_FontHashNode *first;
|
||||
F_FontHashNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Rasterization Cache Types
|
||||
|
||||
typedef struct F_RasterCacheInfo F_RasterCacheInfo;
|
||||
struct F_RasterCacheInfo
|
||||
{
|
||||
Rng2S16 subrect;
|
||||
Vec2S16 raster_dim;
|
||||
S16 atlas_num;
|
||||
F32 advance;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2InfoRasterCacheNode F_Hash2InfoRasterCacheNode;
|
||||
struct F_Hash2InfoRasterCacheNode
|
||||
{
|
||||
F_Hash2InfoRasterCacheNode *hash_next;
|
||||
F_Hash2InfoRasterCacheNode *hash_prev;
|
||||
U64 hash;
|
||||
F_RasterCacheInfo info;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2InfoRasterCacheSlot F_Hash2InfoRasterCacheSlot;
|
||||
struct F_Hash2InfoRasterCacheSlot
|
||||
{
|
||||
F_Hash2InfoRasterCacheNode *first;
|
||||
F_Hash2InfoRasterCacheNode *last;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2StyleRasterCacheNode F_Hash2StyleRasterCacheNode;
|
||||
struct F_Hash2StyleRasterCacheNode
|
||||
{
|
||||
F_Hash2StyleRasterCacheNode *hash_next;
|
||||
F_Hash2StyleRasterCacheNode *hash_prev;
|
||||
U64 style_hash;
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
F32 column_width;
|
||||
F_RasterCacheInfo *utf8_class1_direct_map;
|
||||
U64 utf8_class1_direct_map_mask[4];
|
||||
U64 hash2info_slots_count;
|
||||
F_Hash2InfoRasterCacheSlot *hash2info_slots;
|
||||
};
|
||||
|
||||
typedef struct F_Hash2StyleRasterCacheSlot F_Hash2StyleRasterCacheSlot;
|
||||
struct F_Hash2StyleRasterCacheSlot
|
||||
{
|
||||
F_Hash2StyleRasterCacheNode *first;
|
||||
F_Hash2StyleRasterCacheNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Atlas Types
|
||||
|
||||
typedef U32 F_AtlasRegionNodeFlags;
|
||||
enum
|
||||
{
|
||||
F_AtlasRegionNodeFlag_Taken = (1<<0),
|
||||
};
|
||||
|
||||
typedef struct F_AtlasRegionNode F_AtlasRegionNode;
|
||||
struct F_AtlasRegionNode
|
||||
{
|
||||
F_AtlasRegionNode *parent;
|
||||
F_AtlasRegionNode *children[Corner_COUNT];
|
||||
Vec2S16 max_free_size[Corner_COUNT];
|
||||
F_AtlasRegionNodeFlags flags;
|
||||
U64 num_allocated_descendants;
|
||||
};
|
||||
|
||||
typedef struct F_Atlas F_Atlas;
|
||||
struct F_Atlas
|
||||
{
|
||||
F_Atlas *next;
|
||||
F_Atlas *prev;
|
||||
R_Handle texture;
|
||||
Vec2S16 root_dim;
|
||||
F_AtlasRegionNode *root;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Metrics
|
||||
|
||||
typedef struct F_Metrics F_Metrics;
|
||||
struct F_Metrics
|
||||
{
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
F32 line_gap;
|
||||
F32 capital_height;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main State Type
|
||||
|
||||
typedef struct F_State F_State;
|
||||
struct F_State
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: font table
|
||||
U64 font_hash_table_size;
|
||||
F_FontHashSlot *font_hash_table;
|
||||
|
||||
// rjf: hash -> raster cache table
|
||||
U64 hash2style_slots_count;
|
||||
F_Hash2StyleRasterCacheSlot *hash2style_slots;
|
||||
|
||||
// rjf: atlas list
|
||||
F_Atlas *first_atlas;
|
||||
F_Atlas *last_atlas;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global F_State *f_state = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
internal F_Hash f_hash_from_string(String8 string);
|
||||
internal U64 f_little_hash_from_string(String8 string);
|
||||
internal Vec2S32 f_vertex_from_corner(Corner corner);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Font Tags
|
||||
|
||||
internal F_Tag f_tag_zero(void);
|
||||
internal B32 f_tag_match(F_Tag a, F_Tag b);
|
||||
internal FP_Handle f_handle_from_tag(F_Tag tag);
|
||||
internal FP_Metrics f_fp_metrics_from_tag(F_Tag tag);
|
||||
internal F_Tag f_tag_from_path(String8 path);
|
||||
internal F_Tag f_tag_from_static_data_string(String8 *data_ptr);
|
||||
internal String8 f_path_from_tag(F_Tag tag);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Atlas
|
||||
|
||||
internal Rng2S16 f_atlas_region_alloc(Arena *arena, F_Atlas *atlas, Vec2S16 needed_size);
|
||||
internal void f_atlas_region_release(F_Atlas *atlas, Rng2S16 region);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Piece Type Functions
|
||||
|
||||
internal F_Piece *f_piece_chunk_list_push_new(Arena *arena, F_PieceChunkList *list, U64 cap);
|
||||
internal void f_piece_chunk_list_push(Arena *arena, F_PieceChunkList *list, U64 cap, F_Piece *piece);
|
||||
internal F_PieceArray f_piece_array_from_chunk_list(Arena *arena, F_PieceChunkList *list);
|
||||
internal F_PieceArray f_piece_array_copy(Arena *arena, F_PieceArray *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Rasterization Cache
|
||||
|
||||
internal F_Hash2StyleRasterCacheNode *f_hash2style_from_tag_size_flags(F_Tag tag, F32 size, F_RasterFlags flags);
|
||||
internal F_Run f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, F_RasterFlags flags, String8 string);
|
||||
internal String8List f_wrapped_string_lines_from_font_size_string_max(Arena *arena, F_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, String8 string, F32 max);
|
||||
internal Vec2F32 f_dim_from_tag_size_string(F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8 string);
|
||||
internal Vec2F32 f_dim_from_tag_size_string_list(F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8List list);
|
||||
internal F32 f_column_size_from_tag_size(F_Tag tag, F32 size);
|
||||
internal U64 f_char_pos_from_tag_size_string_p(F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8 string, F32 p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Metrics
|
||||
|
||||
internal F_Metrics f_metrics_from_tag_size(F_Tag tag, F32 size);
|
||||
internal F32 f_line_height_from_metrics(F_Metrics *metrics);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Calls
|
||||
|
||||
internal void f_init(void);
|
||||
|
||||
#endif // FONT_CACHE_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,18 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
|
||||
internal FP_Handle
|
||||
fp_handle_zero(void)
|
||||
{
|
||||
FP_Handle result = {0};
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
fp_handle_match(FP_Handle a, FP_Handle b)
|
||||
{
|
||||
return (a.u64[0] == b.u64[0] && a.u64[1] == b.u64[1]);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
|
||||
internal FP_Handle
|
||||
fp_handle_zero(void)
|
||||
{
|
||||
FP_Handle result = {0};
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
fp_handle_match(FP_Handle a, FP_Handle b)
|
||||
{
|
||||
return (a.u64[0] == b.u64[0] && a.u64[1] == b.u64[1]);
|
||||
}
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FONT_PROVIDER_H
|
||||
#define FONT_PROVIDER_H
|
||||
|
||||
#define fp_hook C_LINKAGE
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Types
|
||||
|
||||
typedef U32 FP_RasterFlags;
|
||||
enum
|
||||
{
|
||||
FP_RasterFlag_Smooth = (1<<0),
|
||||
FP_RasterFlag_Hinted = (1<<1),
|
||||
};
|
||||
|
||||
typedef struct FP_Handle FP_Handle;
|
||||
struct FP_Handle
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
typedef struct FP_Metrics FP_Metrics;
|
||||
struct FP_Metrics
|
||||
{
|
||||
F32 design_units_per_em;
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
F32 line_gap;
|
||||
F32 capital_height;
|
||||
};
|
||||
|
||||
typedef struct FP_RasterResult FP_RasterResult;
|
||||
struct FP_RasterResult
|
||||
{
|
||||
Vec2S16 atlas_dim;
|
||||
void *atlas;
|
||||
F32 advance;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
|
||||
internal FP_Handle fp_handle_zero(void);
|
||||
internal B32 fp_handle_match(FP_Handle a, FP_Handle b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Backend Hooks
|
||||
|
||||
fp_hook void fp_init(void);
|
||||
fp_hook FP_Handle fp_font_open(String8 path);
|
||||
fp_hook FP_Handle fp_font_open_from_static_data_string(String8 *data_ptr);
|
||||
fp_hook void fp_font_close(FP_Handle handle);
|
||||
fp_hook FP_Metrics fp_metrics_from_font(FP_Handle font);
|
||||
fp_hook NO_ASAN FP_RasterResult fp_raster(Arena *arena, FP_Handle font, F32 size, FP_RasterFlags flags, String8 string);
|
||||
|
||||
#endif // FONT_PROVIDER_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FONT_PROVIDER_H
|
||||
#define FONT_PROVIDER_H
|
||||
|
||||
#define fp_hook C_LINKAGE
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Types
|
||||
|
||||
typedef U32 FP_RasterFlags;
|
||||
enum
|
||||
{
|
||||
FP_RasterFlag_Smooth = (1<<0),
|
||||
FP_RasterFlag_Hinted = (1<<1),
|
||||
};
|
||||
|
||||
typedef struct FP_Handle FP_Handle;
|
||||
struct FP_Handle
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
typedef struct FP_Metrics FP_Metrics;
|
||||
struct FP_Metrics
|
||||
{
|
||||
F32 design_units_per_em;
|
||||
F32 ascent;
|
||||
F32 descent;
|
||||
F32 line_gap;
|
||||
F32 capital_height;
|
||||
};
|
||||
|
||||
typedef struct FP_RasterResult FP_RasterResult;
|
||||
struct FP_RasterResult
|
||||
{
|
||||
Vec2S16 atlas_dim;
|
||||
void *atlas;
|
||||
F32 advance;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
|
||||
internal FP_Handle fp_handle_zero(void);
|
||||
internal B32 fp_handle_match(FP_Handle a, FP_Handle b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Backend Hooks
|
||||
|
||||
fp_hook void fp_init(void);
|
||||
fp_hook FP_Handle fp_font_open(String8 path);
|
||||
fp_hook FP_Handle fp_font_open_from_static_data_string(String8 *data_ptr);
|
||||
fp_hook void fp_font_close(FP_Handle handle);
|
||||
fp_hook FP_Metrics fp_metrics_from_font(FP_Handle font);
|
||||
fp_hook NO_ASAN FP_RasterResult fp_raster(Arena *arena, FP_Handle font, F32 size, FP_RasterFlags flags, String8 string);
|
||||
|
||||
#endif // FONT_PROVIDER_H
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "font_provider.c"
|
||||
|
||||
#if FP_BACKEND == FP_BACKEND_DWRITE
|
||||
# include "dwrite/font_provider_dwrite.c"
|
||||
#else
|
||||
# error Font provider backend not specified.
|
||||
#endif
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "font_provider.c"
|
||||
|
||||
#if FP_BACKEND == FP_BACKEND_DWRITE
|
||||
# include "dwrite/font_provider_dwrite.c"
|
||||
#else
|
||||
# error Font provider backend not specified.
|
||||
#endif
|
||||
|
||||
+202
-202
@@ -1,202 +1,202 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FUZZY_SEARCH_H
|
||||
#define FUZZY_SEARCH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Result Types
|
||||
|
||||
typedef struct FZY_Item FZY_Item;
|
||||
struct FZY_Item
|
||||
{
|
||||
U64 idx; // indexes into whole space of parameter tables. [rdis[0] element count) [rdis[1] element count) ... [rdis[n] element count)
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunk FZY_ItemChunk;
|
||||
struct FZY_ItemChunk
|
||||
{
|
||||
FZY_ItemChunk *next;
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunkList FZY_ItemChunkList;
|
||||
struct FZY_ItemChunkList
|
||||
{
|
||||
FZY_ItemChunk *first;
|
||||
FZY_ItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemArray FZY_ItemArray;
|
||||
struct FZY_ItemArray
|
||||
{
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Parameter Types
|
||||
|
||||
typedef enum FZY_Target
|
||||
{
|
||||
FZY_Target_Procedures,
|
||||
FZY_Target_GlobalVariables,
|
||||
FZY_Target_ThreadVariables,
|
||||
FZY_Target_UDTs,
|
||||
FZY_Target_COUNT
|
||||
}
|
||||
FZY_Target;
|
||||
|
||||
typedef struct FZY_Params FZY_Params;
|
||||
struct FZY_Params
|
||||
{
|
||||
FZY_Target target;
|
||||
DI_KeyArray dbgi_keys;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct FZY_Bucket FZY_Bucket;
|
||||
struct FZY_Bucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 query;
|
||||
FZY_Params params;
|
||||
U64 params_hash;
|
||||
};
|
||||
|
||||
typedef struct FZY_Node FZY_Node;
|
||||
struct FZY_Node
|
||||
{
|
||||
FZY_Node *next;
|
||||
U128 key;
|
||||
U64 touch_count;
|
||||
U64 last_time_submitted_us;
|
||||
FZY_Bucket buckets[3];
|
||||
U64 gen;
|
||||
U64 submit_gen;
|
||||
FZY_ItemArray gen_items;
|
||||
};
|
||||
|
||||
typedef struct FZY_Slot FZY_Slot;
|
||||
struct FZY_Slot
|
||||
{
|
||||
FZY_Node *first;
|
||||
FZY_Node *last;
|
||||
};
|
||||
|
||||
typedef struct FZY_Stripe FZY_Stripe;
|
||||
struct FZY_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct FZY_Touch FZY_Touch;
|
||||
struct FZY_Touch
|
||||
{
|
||||
FZY_Touch *next;
|
||||
FZY_Node *node;
|
||||
};
|
||||
|
||||
typedef struct FZY_Scope FZY_Scope;
|
||||
struct FZY_Scope
|
||||
{
|
||||
FZY_Scope *next;
|
||||
FZY_Touch *first_touch;
|
||||
FZY_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct FZY_TCTX FZY_TCTX;
|
||||
struct FZY_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
FZY_Scope *free_scope;
|
||||
FZY_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
typedef struct FZY_Thread FZY_Thread;
|
||||
struct FZY_Thread
|
||||
{
|
||||
OS_Handle thread;
|
||||
OS_Handle u2f_ring_mutex;
|
||||
OS_Handle u2f_ring_cv;
|
||||
U64 u2f_ring_size;
|
||||
U8 *u2f_ring_base;
|
||||
U64 u2f_ring_write_pos;
|
||||
U64 u2f_ring_read_pos;
|
||||
};
|
||||
|
||||
typedef struct FZY_Shared FZY_Shared;
|
||||
struct FZY_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: search artifact cache table
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
FZY_Slot *slots;
|
||||
FZY_Stripe *stripes;
|
||||
|
||||
// rjf: threads
|
||||
U64 thread_count;
|
||||
FZY_Thread *threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global FZY_Shared *fzy_shared = 0;
|
||||
thread_static FZY_TCTX *fzy_tctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64 fzy_hash_from_string(U64 seed, String8 string);
|
||||
internal U64 fzy_hash_from_params(FZY_Params *params);
|
||||
internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx);
|
||||
internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, U64 element_idx);
|
||||
internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void fzy_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal FZY_Scope *fzy_scope_open(void);
|
||||
internal void fzy_scope_close(FZY_Scope *scope);
|
||||
internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookup Functions
|
||||
|
||||
internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Searcher Threads
|
||||
|
||||
internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us);
|
||||
internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out);
|
||||
|
||||
internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b);
|
||||
|
||||
internal void fzy_search_thread__entry_point(void *p);
|
||||
|
||||
#endif // FUZZY_SEARCH_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FUZZY_SEARCH_H
|
||||
#define FUZZY_SEARCH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Result Types
|
||||
|
||||
typedef struct FZY_Item FZY_Item;
|
||||
struct FZY_Item
|
||||
{
|
||||
U64 idx; // indexes into whole space of parameter tables. [rdis[0] element count) [rdis[1] element count) ... [rdis[n] element count)
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunk FZY_ItemChunk;
|
||||
struct FZY_ItemChunk
|
||||
{
|
||||
FZY_ItemChunk *next;
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunkList FZY_ItemChunkList;
|
||||
struct FZY_ItemChunkList
|
||||
{
|
||||
FZY_ItemChunk *first;
|
||||
FZY_ItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemArray FZY_ItemArray;
|
||||
struct FZY_ItemArray
|
||||
{
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Parameter Types
|
||||
|
||||
typedef enum FZY_Target
|
||||
{
|
||||
FZY_Target_Procedures,
|
||||
FZY_Target_GlobalVariables,
|
||||
FZY_Target_ThreadVariables,
|
||||
FZY_Target_UDTs,
|
||||
FZY_Target_COUNT
|
||||
}
|
||||
FZY_Target;
|
||||
|
||||
typedef struct FZY_Params FZY_Params;
|
||||
struct FZY_Params
|
||||
{
|
||||
FZY_Target target;
|
||||
DI_KeyArray dbgi_keys;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct FZY_Bucket FZY_Bucket;
|
||||
struct FZY_Bucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 query;
|
||||
FZY_Params params;
|
||||
U64 params_hash;
|
||||
};
|
||||
|
||||
typedef struct FZY_Node FZY_Node;
|
||||
struct FZY_Node
|
||||
{
|
||||
FZY_Node *next;
|
||||
U128 key;
|
||||
U64 touch_count;
|
||||
U64 last_time_submitted_us;
|
||||
FZY_Bucket buckets[3];
|
||||
U64 gen;
|
||||
U64 submit_gen;
|
||||
FZY_ItemArray gen_items;
|
||||
};
|
||||
|
||||
typedef struct FZY_Slot FZY_Slot;
|
||||
struct FZY_Slot
|
||||
{
|
||||
FZY_Node *first;
|
||||
FZY_Node *last;
|
||||
};
|
||||
|
||||
typedef struct FZY_Stripe FZY_Stripe;
|
||||
struct FZY_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct FZY_Touch FZY_Touch;
|
||||
struct FZY_Touch
|
||||
{
|
||||
FZY_Touch *next;
|
||||
FZY_Node *node;
|
||||
};
|
||||
|
||||
typedef struct FZY_Scope FZY_Scope;
|
||||
struct FZY_Scope
|
||||
{
|
||||
FZY_Scope *next;
|
||||
FZY_Touch *first_touch;
|
||||
FZY_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct FZY_TCTX FZY_TCTX;
|
||||
struct FZY_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
FZY_Scope *free_scope;
|
||||
FZY_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
typedef struct FZY_Thread FZY_Thread;
|
||||
struct FZY_Thread
|
||||
{
|
||||
OS_Handle thread;
|
||||
OS_Handle u2f_ring_mutex;
|
||||
OS_Handle u2f_ring_cv;
|
||||
U64 u2f_ring_size;
|
||||
U8 *u2f_ring_base;
|
||||
U64 u2f_ring_write_pos;
|
||||
U64 u2f_ring_read_pos;
|
||||
};
|
||||
|
||||
typedef struct FZY_Shared FZY_Shared;
|
||||
struct FZY_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: search artifact cache table
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
FZY_Slot *slots;
|
||||
FZY_Stripe *stripes;
|
||||
|
||||
// rjf: threads
|
||||
U64 thread_count;
|
||||
FZY_Thread *threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global FZY_Shared *fzy_shared = 0;
|
||||
thread_static FZY_TCTX *fzy_tctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64 fzy_hash_from_string(U64 seed, String8 string);
|
||||
internal U64 fzy_hash_from_params(FZY_Params *params);
|
||||
internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx);
|
||||
internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, U64 element_idx);
|
||||
internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void fzy_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal FZY_Scope *fzy_scope_open(void);
|
||||
internal void fzy_scope_close(FZY_Scope *scope);
|
||||
internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookup Functions
|
||||
|
||||
internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Searcher Threads
|
||||
|
||||
internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us);
|
||||
internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out);
|
||||
|
||||
internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b);
|
||||
|
||||
internal void fzy_search_thread__entry_point(void *p);
|
||||
|
||||
#endif // FUZZY_SEARCH_H
|
||||
|
||||
+148
-148
@@ -1,148 +1,148 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef GEO_CACHE_H
|
||||
#define GEO_CACHE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct GEO_Node GEO_Node;
|
||||
struct GEO_Node
|
||||
{
|
||||
GEO_Node *next;
|
||||
GEO_Node *prev;
|
||||
U128 hash;
|
||||
R_Handle buffer;
|
||||
B32 is_working;
|
||||
U64 scope_ref_count;
|
||||
U64 last_time_touched_us;
|
||||
U64 last_user_clock_idx_touched;
|
||||
U64 load_count;
|
||||
};
|
||||
|
||||
typedef struct GEO_Slot GEO_Slot;
|
||||
struct GEO_Slot
|
||||
{
|
||||
GEO_Node *first;
|
||||
GEO_Node *last;
|
||||
};
|
||||
|
||||
typedef struct GEO_Stripe GEO_Stripe;
|
||||
struct GEO_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
typedef struct GEO_Touch GEO_Touch;
|
||||
struct GEO_Touch
|
||||
{
|
||||
GEO_Touch *next;
|
||||
U128 hash;
|
||||
};
|
||||
|
||||
typedef struct GEO_Scope GEO_Scope;
|
||||
struct GEO_Scope
|
||||
{
|
||||
GEO_Scope *next;
|
||||
GEO_Touch *top_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context
|
||||
|
||||
typedef struct GEO_TCTX GEO_TCTX;
|
||||
struct GEO_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
GEO_Scope *free_scope;
|
||||
GEO_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct GEO_Shared GEO_Shared;
|
||||
struct GEO_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user clock
|
||||
U64 user_clock_idx;
|
||||
|
||||
// rjf: cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
GEO_Slot *slots;
|
||||
GEO_Stripe *stripes;
|
||||
GEO_Node **stripes_free_nodes;
|
||||
|
||||
// rjf: user -> xfer thread
|
||||
U64 u2x_ring_size;
|
||||
U8 *u2x_ring_base;
|
||||
U64 u2x_ring_write_pos;
|
||||
U64 u2x_ring_read_pos;
|
||||
OS_Handle u2x_ring_cv;
|
||||
OS_Handle u2x_ring_mutex;
|
||||
|
||||
// rjf: transfer threads
|
||||
U64 xfer_thread_count;
|
||||
OS_Handle *xfer_threads;
|
||||
|
||||
// rjf: evictor thread
|
||||
OS_Handle evictor_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static GEO_TCTX *geo_tctx = 0;
|
||||
global GEO_Shared *geo_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void geo_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context Initialization
|
||||
|
||||
internal void geo_tctx_ensure_inited(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void geo_user_clock_tick(void);
|
||||
internal U64 geo_user_clock_idx(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
internal GEO_Scope *geo_scope_open(void);
|
||||
internal void geo_scope_close(GEO_Scope *scope);
|
||||
internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal R_Handle geo_buffer_from_hash(GEO_Scope *scope, U128 hash);
|
||||
internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Transfer Threads
|
||||
|
||||
internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us);
|
||||
internal void geo_u2x_dequeue_req(U128 *hash_out);
|
||||
internal void geo_xfer_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor Threads
|
||||
|
||||
internal void geo_evictor_thread__entry_point(void *p);
|
||||
|
||||
#endif //GEO_CACHE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef GEO_CACHE_H
|
||||
#define GEO_CACHE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct GEO_Node GEO_Node;
|
||||
struct GEO_Node
|
||||
{
|
||||
GEO_Node *next;
|
||||
GEO_Node *prev;
|
||||
U128 hash;
|
||||
R_Handle buffer;
|
||||
B32 is_working;
|
||||
U64 scope_ref_count;
|
||||
U64 last_time_touched_us;
|
||||
U64 last_user_clock_idx_touched;
|
||||
U64 load_count;
|
||||
};
|
||||
|
||||
typedef struct GEO_Slot GEO_Slot;
|
||||
struct GEO_Slot
|
||||
{
|
||||
GEO_Node *first;
|
||||
GEO_Node *last;
|
||||
};
|
||||
|
||||
typedef struct GEO_Stripe GEO_Stripe;
|
||||
struct GEO_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
typedef struct GEO_Touch GEO_Touch;
|
||||
struct GEO_Touch
|
||||
{
|
||||
GEO_Touch *next;
|
||||
U128 hash;
|
||||
};
|
||||
|
||||
typedef struct GEO_Scope GEO_Scope;
|
||||
struct GEO_Scope
|
||||
{
|
||||
GEO_Scope *next;
|
||||
GEO_Touch *top_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context
|
||||
|
||||
typedef struct GEO_TCTX GEO_TCTX;
|
||||
struct GEO_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
GEO_Scope *free_scope;
|
||||
GEO_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct GEO_Shared GEO_Shared;
|
||||
struct GEO_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user clock
|
||||
U64 user_clock_idx;
|
||||
|
||||
// rjf: cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
GEO_Slot *slots;
|
||||
GEO_Stripe *stripes;
|
||||
GEO_Node **stripes_free_nodes;
|
||||
|
||||
// rjf: user -> xfer thread
|
||||
U64 u2x_ring_size;
|
||||
U8 *u2x_ring_base;
|
||||
U64 u2x_ring_write_pos;
|
||||
U64 u2x_ring_read_pos;
|
||||
OS_Handle u2x_ring_cv;
|
||||
OS_Handle u2x_ring_mutex;
|
||||
|
||||
// rjf: transfer threads
|
||||
U64 xfer_thread_count;
|
||||
OS_Handle *xfer_threads;
|
||||
|
||||
// rjf: evictor thread
|
||||
OS_Handle evictor_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static GEO_TCTX *geo_tctx = 0;
|
||||
global GEO_Shared *geo_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void geo_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context Initialization
|
||||
|
||||
internal void geo_tctx_ensure_inited(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void geo_user_clock_tick(void);
|
||||
internal U64 geo_user_clock_idx(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
internal GEO_Scope *geo_scope_open(void);
|
||||
internal void geo_scope_close(GEO_Scope *scope);
|
||||
internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal R_Handle geo_buffer_from_hash(GEO_Scope *scope, U128 hash);
|
||||
internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Transfer Threads
|
||||
|
||||
internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us);
|
||||
internal void geo_u2x_dequeue_req(U128 *hash_out);
|
||||
internal void geo_xfer_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor Threads
|
||||
|
||||
internal void geo_evictor_thread__entry_point(void *p);
|
||||
|
||||
#endif //GEO_CACHE_H
|
||||
|
||||
+150
-150
@@ -1,150 +1,150 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef HASH_STORE_H
|
||||
#define HASH_STORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct HS_KeyNode HS_KeyNode;
|
||||
struct HS_KeyNode
|
||||
{
|
||||
HS_KeyNode *next;
|
||||
U128 key;
|
||||
U128 hash_history[2];
|
||||
U64 hash_history_gen;
|
||||
};
|
||||
|
||||
typedef struct HS_KeySlot HS_KeySlot;
|
||||
struct HS_KeySlot
|
||||
{
|
||||
HS_KeyNode *first;
|
||||
HS_KeyNode *last;
|
||||
};
|
||||
|
||||
typedef struct HS_Node HS_Node;
|
||||
struct HS_Node
|
||||
{
|
||||
HS_Node *next;
|
||||
HS_Node *prev;
|
||||
U128 hash;
|
||||
Arena *arena;
|
||||
String8 data;
|
||||
U64 scope_ref_count;
|
||||
U64 key_ref_count;
|
||||
};
|
||||
|
||||
typedef struct HS_Slot HS_Slot;
|
||||
struct HS_Slot
|
||||
{
|
||||
HS_Node *first;
|
||||
HS_Node *last;
|
||||
};
|
||||
|
||||
typedef struct HS_Stripe HS_Stripe;
|
||||
struct HS_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
typedef struct HS_Touch HS_Touch;
|
||||
struct HS_Touch
|
||||
{
|
||||
HS_Touch *next;
|
||||
U128 hash;
|
||||
};
|
||||
|
||||
typedef struct HS_Scope HS_Scope;
|
||||
struct HS_Scope
|
||||
{
|
||||
HS_Scope *next;
|
||||
HS_Touch *top_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context
|
||||
|
||||
typedef struct HS_TCTX HS_TCTX;
|
||||
struct HS_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
HS_Scope *free_scope;
|
||||
HS_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct HS_Shared HS_Shared;
|
||||
struct HS_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: main data cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
HS_Slot *slots;
|
||||
HS_Stripe *stripes;
|
||||
HS_Node **stripes_free_nodes;
|
||||
|
||||
// rjf: key cache
|
||||
U64 key_slots_count;
|
||||
U64 key_stripes_count;
|
||||
HS_KeySlot *key_slots;
|
||||
HS_Stripe *key_stripes;
|
||||
|
||||
// rjf: evictor thread
|
||||
OS_Handle evictor_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static HS_TCTX *hs_tctx = 0;
|
||||
global HS_Shared *hs_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U128 hs_hash_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void hs_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context Initialization
|
||||
|
||||
internal void hs_tctx_ensure_inited(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Submission/Derefs
|
||||
|
||||
internal U128 hs_submit_data(U128 key, Arena **data_arena, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
internal HS_Scope *hs_scope_open(void);
|
||||
internal void hs_scope_close(HS_Scope *scope);
|
||||
internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal U128 hs_hash_from_key(U128 key, U64 rewind_count);
|
||||
internal String8 hs_data_from_hash(HS_Scope *scope, U128 hash);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor Thread
|
||||
|
||||
internal void hs_evictor_thread__entry_point(void *p);
|
||||
|
||||
#endif // HASH_STORE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef HASH_STORE_H
|
||||
#define HASH_STORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct HS_KeyNode HS_KeyNode;
|
||||
struct HS_KeyNode
|
||||
{
|
||||
HS_KeyNode *next;
|
||||
U128 key;
|
||||
U128 hash_history[2];
|
||||
U64 hash_history_gen;
|
||||
};
|
||||
|
||||
typedef struct HS_KeySlot HS_KeySlot;
|
||||
struct HS_KeySlot
|
||||
{
|
||||
HS_KeyNode *first;
|
||||
HS_KeyNode *last;
|
||||
};
|
||||
|
||||
typedef struct HS_Node HS_Node;
|
||||
struct HS_Node
|
||||
{
|
||||
HS_Node *next;
|
||||
HS_Node *prev;
|
||||
U128 hash;
|
||||
Arena *arena;
|
||||
String8 data;
|
||||
U64 scope_ref_count;
|
||||
U64 key_ref_count;
|
||||
};
|
||||
|
||||
typedef struct HS_Slot HS_Slot;
|
||||
struct HS_Slot
|
||||
{
|
||||
HS_Node *first;
|
||||
HS_Node *last;
|
||||
};
|
||||
|
||||
typedef struct HS_Stripe HS_Stripe;
|
||||
struct HS_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
typedef struct HS_Touch HS_Touch;
|
||||
struct HS_Touch
|
||||
{
|
||||
HS_Touch *next;
|
||||
U128 hash;
|
||||
};
|
||||
|
||||
typedef struct HS_Scope HS_Scope;
|
||||
struct HS_Scope
|
||||
{
|
||||
HS_Scope *next;
|
||||
HS_Touch *top_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context
|
||||
|
||||
typedef struct HS_TCTX HS_TCTX;
|
||||
struct HS_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
HS_Scope *free_scope;
|
||||
HS_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct HS_Shared HS_Shared;
|
||||
struct HS_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: main data cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
HS_Slot *slots;
|
||||
HS_Stripe *stripes;
|
||||
HS_Node **stripes_free_nodes;
|
||||
|
||||
// rjf: key cache
|
||||
U64 key_slots_count;
|
||||
U64 key_stripes_count;
|
||||
HS_KeySlot *key_slots;
|
||||
HS_Stripe *key_stripes;
|
||||
|
||||
// rjf: evictor thread
|
||||
OS_Handle evictor_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static HS_TCTX *hs_tctx = 0;
|
||||
global HS_Shared *hs_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U128 hs_hash_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void hs_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context Initialization
|
||||
|
||||
internal void hs_tctx_ensure_inited(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Submission/Derefs
|
||||
|
||||
internal U128 hs_submit_data(U128 key, Arena **data_arena, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
internal HS_Scope *hs_scope_open(void);
|
||||
internal void hs_scope_close(HS_Scope *scope);
|
||||
internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal U128 hs_hash_from_key(U128 key, U64 rewind_count);
|
||||
internal String8 hs_data_from_hash(HS_Scope *scope, U128 hash);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor Thread
|
||||
|
||||
internal void hs_evictor_thread__entry_point(void *p);
|
||||
|
||||
#endif // HASH_STORE_H
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
+43
-43
@@ -1,43 +1,43 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef ICO_H
|
||||
#define ICO_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: ICO File Format Types
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct ICO_Header ICO_Header;
|
||||
struct ICO_Header
|
||||
{
|
||||
U16 reserved_padding; // must be 0
|
||||
U16 image_type; // if 1 -> ICO, if 2 -> CUR
|
||||
U16 num_images;
|
||||
};
|
||||
|
||||
typedef struct ICO_Entry ICO_Entry;
|
||||
struct ICO_Entry
|
||||
{
|
||||
U8 image_width_px;
|
||||
U8 image_height_px;
|
||||
U8 num_colors;
|
||||
U8 reserved_padding; // should be 0
|
||||
union
|
||||
{
|
||||
U16 ico_color_planes; // in ICO
|
||||
U16 cur_hotspot_x_px; // in CUR
|
||||
};
|
||||
union
|
||||
{
|
||||
U16 ico_bits_per_pixel; // in ICO
|
||||
U16 cur_hotspot_y_px; // in CUR
|
||||
};
|
||||
U32 image_data_size;
|
||||
U32 image_data_off;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // ICO_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef ICO_H
|
||||
#define ICO_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: ICO File Format Types
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct ICO_Header ICO_Header;
|
||||
struct ICO_Header
|
||||
{
|
||||
U16 reserved_padding; // must be 0
|
||||
U16 image_type; // if 1 -> ICO, if 2 -> CUR
|
||||
U16 num_images;
|
||||
};
|
||||
|
||||
typedef struct ICO_Entry ICO_Entry;
|
||||
struct ICO_Entry
|
||||
{
|
||||
U8 image_width_px;
|
||||
U8 image_height_px;
|
||||
U8 num_colors;
|
||||
U8 reserved_padding; // should be 0
|
||||
union
|
||||
{
|
||||
U16 ico_color_planes; // in ICO
|
||||
U16 cur_hotspot_x_px; // in CUR
|
||||
};
|
||||
union
|
||||
{
|
||||
U16 ico_bits_per_pixel; // in ICO
|
||||
U16 cur_hotspot_y_px; // in CUR
|
||||
};
|
||||
U32 image_data_size;
|
||||
U32 image_data_off;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // ICO_H
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADDBG_MARKUP_H
|
||||
#define RADDBG_MARKUP_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ Usage Macros
|
||||
|
||||
#define raddbg_is_attached(...) raddbg_is_attached__impl()
|
||||
#define raddbg_thread_name(fmt, ...) raddbg_thread_name__impl((fmt), __VA_ARGS__)
|
||||
#define raddbg_thread_color_hex(hexcode) raddbg_thread_color__impl((hexcode))
|
||||
#define raddbg_thread_color_rgba(r, g, b, a) raddbg_thread_color__impl((unsigned int)(((r)*255) << 24) | (unsigned int)(((g)*255) << 16) | (unsigned int)(((b)*255) << 8) | (unsigned int)((a)*255))
|
||||
#define raddbg_break(...) raddbg_break__impl()
|
||||
#define raddbg_break_if(expr, ...) ((expr) ? raddbg_break__impl() : (void)0)
|
||||
#define raddbg_watch(fmt, ...) raddbg_watch__impl((fmt), __VA_ARGS__)
|
||||
#define raddbg_pin(expr, ...) /* NOTE(rjf): inspected by debugger ui - does not change program execution */
|
||||
#define raddbg_log(fmt, ...) raddbg_log__impl((fmt), __VA_ARGS__)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Win32 Implementations
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
//- types
|
||||
|
||||
typedef unsigned long DWORD;
|
||||
typedef char const *LPCSTR;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
typedef struct THREADNAME_INFO THREADNAME_INFO;
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
DWORD dwType;
|
||||
LPCSTR szName;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwFlags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
//- implementations
|
||||
|
||||
static inline int
|
||||
raddbg_is_attached__impl(void)
|
||||
{
|
||||
// TODO(rjf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
raddbg_thread_name__impl(char *fmt, ...)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
static inline void
|
||||
raddbg_thread_color__impl(unsigned int hexcode)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
#define raddbg_break__impl() (__debugbreak())
|
||||
|
||||
static inline void
|
||||
raddbg_watch__impl(char *fmt, ...)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
static inline void
|
||||
raddbg_log__impl(char *fmt, ...)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
#endif // RADDBG_MARKUP_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADDBG_MARKUP_H
|
||||
#define RADDBG_MARKUP_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ Usage Macros
|
||||
|
||||
#define raddbg_is_attached(...) raddbg_is_attached__impl()
|
||||
#define raddbg_thread_name(fmt, ...) raddbg_thread_name__impl((fmt), __VA_ARGS__)
|
||||
#define raddbg_thread_color_hex(hexcode) raddbg_thread_color__impl((hexcode))
|
||||
#define raddbg_thread_color_rgba(r, g, b, a) raddbg_thread_color__impl((unsigned int)(((r)*255) << 24) | (unsigned int)(((g)*255) << 16) | (unsigned int)(((b)*255) << 8) | (unsigned int)((a)*255))
|
||||
#define raddbg_break(...) raddbg_break__impl()
|
||||
#define raddbg_break_if(expr, ...) ((expr) ? raddbg_break__impl() : (void)0)
|
||||
#define raddbg_watch(fmt, ...) raddbg_watch__impl((fmt), __VA_ARGS__)
|
||||
#define raddbg_pin(expr, ...) /* NOTE(rjf): inspected by debugger ui - does not change program execution */
|
||||
#define raddbg_log(fmt, ...) raddbg_log__impl((fmt), __VA_ARGS__)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Win32 Implementations
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
//- types
|
||||
|
||||
typedef unsigned long DWORD;
|
||||
typedef char const *LPCSTR;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
typedef struct THREADNAME_INFO THREADNAME_INFO;
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
DWORD dwType;
|
||||
LPCSTR szName;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwFlags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
//- implementations
|
||||
|
||||
static inline int
|
||||
raddbg_is_attached__impl(void)
|
||||
{
|
||||
// TODO(rjf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
raddbg_thread_name__impl(char *fmt, ...)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
static inline void
|
||||
raddbg_thread_color__impl(unsigned int hexcode)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
#define raddbg_break__impl() (__debugbreak())
|
||||
|
||||
static inline void
|
||||
raddbg_watch__impl(char *fmt, ...)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
static inline void
|
||||
raddbg_log__impl(char *fmt, ...)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
#endif // RADDBG_MARKUP_H
|
||||
|
||||
@@ -1,224 +1,224 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ RAD Debug Info, (R)AD(D)BG(I) Format Parsing Library
|
||||
//
|
||||
// Defines helper types and functions for extracting data from
|
||||
// RDI files.
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Usage Samples
|
||||
//
|
||||
#if 0
|
||||
// Procedure Name -> Line
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *name = "mule_main";
|
||||
RDI_Procedure *procedure = rdi_procedure_from_name_cstr(rdi, name); // 1. name -> procedure
|
||||
RDI_U64 procedure_first_voff = rdi_first_voff_from_procedure(rdi, procedure); // 2. procedure -> virtual offset
|
||||
RDI_Line line = rdi_line_from_voff(rdi, procedure_first_voff); // 3. virtual offset -> line
|
||||
RDI_SourceFile *file = rdi_source_file_from_line(rdi, &line); // 4. line -> source file
|
||||
RDI_U64 file_path_size = 0; // 5. source file -> path
|
||||
RDI_U8 *file_path = rdi_normal_path_from_source_file(rdi, file, &file_path_size);
|
||||
printf("%s is at %.*s:%u\n", name, (int)file_path_size, file_path, line.line_num);
|
||||
}
|
||||
|
||||
// Line -> Procedure Name
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *path = "c:/devel/raddebugger/src/mule/mule_main.cpp";
|
||||
RDI_U32 line_num = 2557;
|
||||
RDI_SourceFile *file = rdi_source_file_from_normal_path_cstr(rdi, path); // 1. path -> source file
|
||||
RDI_U64 voff = rdi_first_voff_from_source_file_line_num(rdi, file, line_num); // 2. (source file, line) -> virtual offset
|
||||
RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); // 3. virtual offset -> procedure
|
||||
RDI_U64 name_size = 0; // 4. procedure -> name
|
||||
RDI_U8 *name = rdi_name_from_procedure(rdi, procedure, &name_size);
|
||||
printf("%s:%u is inside %.*s\n", path, line_num, (int)name_size, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RDI_FORMAT_PARSE_H
|
||||
#define RDI_FORMAT_PARSE_H
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Parsed Information Types
|
||||
|
||||
typedef enum RDI_ParseStatus
|
||||
{
|
||||
RDI_ParseStatus_Good = 0,
|
||||
RDI_ParseStatus_HeaderDoesNotMatch = 1,
|
||||
RDI_ParseStatus_UnsupportedVersionNumber = 2,
|
||||
RDI_ParseStatus_InvalidDataSecionLayout = 3,
|
||||
RDI_ParseStatus_MissingRequiredSection = 4,
|
||||
}
|
||||
RDI_ParseStatus;
|
||||
|
||||
typedef struct RDI_Parsed RDI_Parsed;
|
||||
struct RDI_Parsed
|
||||
{
|
||||
RDI_U8 *raw_data;
|
||||
RDI_U64 raw_data_size;
|
||||
RDI_Section *sections;
|
||||
RDI_U64 sections_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedLineTable RDI_ParsedLineTable;
|
||||
struct RDI_ParsedLineTable
|
||||
{
|
||||
// NOTE: Mapping VOFF -> LINE_INFO
|
||||
//
|
||||
// * [ voff[i], voff[i + 1] ) forms the voff range
|
||||
// * for the line info at lines[i] (and cols[i] if i < col_count)
|
||||
RDI_U64* voffs; // [count + 1] sorted
|
||||
RDI_Line* lines; // [count]
|
||||
RDI_Column* cols; // [col_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 col_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedSourceLineMap RDI_ParsedSourceLineMap;
|
||||
struct RDI_ParsedSourceLineMap
|
||||
{
|
||||
// NOTE: Mapping LINE_NUMBER -> VOFFs
|
||||
//
|
||||
// * nums[i] gives a line number
|
||||
// * that line number has one or more associated voffs
|
||||
//
|
||||
// * to find all associated voffs for the line number nums[i] :
|
||||
// * let k span over the range [ ranges[i], ranges[i + 1] )
|
||||
// * voffs[k] gives the associated voffs
|
||||
RDI_U32* nums; // [count] sorted
|
||||
RDI_U32* ranges; // [count + 1]
|
||||
RDI_U64* voffs; // [voff_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 voff_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedNameMap RDI_ParsedNameMap;
|
||||
struct RDI_ParsedNameMap
|
||||
{
|
||||
RDI_NameMapBucket *buckets;
|
||||
RDI_NameMapNode *nodes;
|
||||
RDI_U64 bucket_count;
|
||||
RDI_U64 node_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Global Nils
|
||||
|
||||
static union
|
||||
{
|
||||
RDI_TopLevelInfo top_level_info;
|
||||
RDI_BinarySection binary_section;
|
||||
RDI_FilePathNode file_path_node;
|
||||
RDI_SourceFile source_file;
|
||||
RDI_LineTable line_table;
|
||||
RDI_SourceLineMap source_line_map;
|
||||
RDI_Line line;
|
||||
RDI_Column column;
|
||||
RDI_Unit unit;
|
||||
RDI_VMapEntry vmap_entry;
|
||||
RDI_TypeNode type_node;
|
||||
RDI_UDT udt;
|
||||
RDI_Member member;
|
||||
RDI_EnumMember enum_member;
|
||||
RDI_GlobalVariable global_variable;
|
||||
RDI_ThreadVariable thread_variable;
|
||||
RDI_Procedure procedure;
|
||||
RDI_Scope scope;
|
||||
RDI_U64 voff;
|
||||
RDI_LocationBlock location_block;
|
||||
RDI_Local local;
|
||||
}
|
||||
rdi_nil_element_union = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Top-Level Parsing API
|
||||
|
||||
RDI_PROC RDI_ParseStatus rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Base Parsed Info Extraction Helpers
|
||||
|
||||
//- section table/element raw data extraction
|
||||
RDI_PROC void *rdi_section_raw_data_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_SectionEncoding *encoding_out, RDI_U64 *size_out);
|
||||
RDI_PROC void *rdi_section_raw_table_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 *count_out);
|
||||
RDI_PROC void *rdi_section_raw_element_from_kind_idx(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 idx);
|
||||
#define rdi_table_from_name(rdi, name, count_out) (RDI_SectionElementType_##name *)rdi_section_raw_table_from_kind((rdi), RDI_SectionKind_##name, (count_out))
|
||||
#define rdi_element_from_name_idx(rdi, name, idx) (RDI_SectionElementType_##name *)rdi_section_raw_element_from_kind_idx((rdi), RDI_SectionKind_##name, (idx))
|
||||
|
||||
//- info about whole parse
|
||||
RDI_PROC RDI_U64 rdi_decompressed_size_from_parsed(RDI_Parsed *rdi);
|
||||
|
||||
//- strings
|
||||
RDI_PROC RDI_U8 *rdi_string_from_idx(RDI_Parsed *rdi, RDI_U32 idx, RDI_U64 *len_out);
|
||||
|
||||
//- index runs
|
||||
RDI_PROC RDI_U32 *rdi_idx_run_from_first_count(RDI_Parsed *rdi, RDI_U32 raw_first, RDI_U32 raw_count, RDI_U32 *n_out);
|
||||
|
||||
//- line info
|
||||
RDI_PROC void rdi_parsed_from_line_table(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_ParsedLineTable *out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_range_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff, RDI_U64 *n_out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff);
|
||||
RDI_PROC void rdi_parsed_from_source_line_map(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_ParsedSourceLineMap *out);
|
||||
RDI_PROC RDI_U64 *rdi_line_voffs_from_num(RDI_ParsedSourceLineMap *map, RDI_U32 linenum, RDI_U32 *n_out);
|
||||
|
||||
//- vmap lookups
|
||||
RDI_PROC RDI_U64 rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U64 vmap_count, RDI_U64 voff);
|
||||
|
||||
//- name maps
|
||||
RDI_PROC RDI_NameMap *rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind);
|
||||
RDI_PROC void rdi_name_map_parse(RDI_Parsed* p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out);
|
||||
RDI_PROC RDI_NameMapNode *rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, RDI_U8 *str, RDI_U64 len);
|
||||
RDI_PROC RDI_U32 *rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ High-Level Composite Lookup Functions
|
||||
|
||||
//- procedures
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_Scope *rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
|
||||
//- scopes
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_Scope *rdi_scope_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
|
||||
//- units
|
||||
RDI_PROC RDI_Unit *rdi_unit_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_LineTable *rdi_line_table_from_unit(RDI_Parsed *rdi, RDI_Unit *unit);
|
||||
|
||||
//- line tables
|
||||
RDI_PROC RDI_Line rdi_line_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Line rdi_line_from_line_table_voff(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_U64 voff);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_line(RDI_Parsed *rdi, RDI_Line *line);
|
||||
|
||||
//- source files
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_normal_path_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_FilePathNode *rdi_file_path_node_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_SourceLineMap *rdi_source_line_map_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_file_line_num(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U32 line_num);
|
||||
|
||||
//- source line maps
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_line_map_num(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_U32 line_num);
|
||||
|
||||
//- file path nodes
|
||||
RDI_PROC RDI_FilePathNode *rdi_parent_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node, RDI_U64 *len_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Parser Helpers
|
||||
|
||||
#define rdi_parse__min(a,b) (((a)<(b))?(a):(b))
|
||||
RDI_PROC RDI_U64 rdi_cstring_length(char *cstr);
|
||||
|
||||
#endif // RDI_FORMAT_PARSE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ RAD Debug Info, (R)AD(D)BG(I) Format Parsing Library
|
||||
//
|
||||
// Defines helper types and functions for extracting data from
|
||||
// RDI files.
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Usage Samples
|
||||
//
|
||||
#if 0
|
||||
// Procedure Name -> Line
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *name = "mule_main";
|
||||
RDI_Procedure *procedure = rdi_procedure_from_name_cstr(rdi, name); // 1. name -> procedure
|
||||
RDI_U64 procedure_first_voff = rdi_first_voff_from_procedure(rdi, procedure); // 2. procedure -> virtual offset
|
||||
RDI_Line line = rdi_line_from_voff(rdi, procedure_first_voff); // 3. virtual offset -> line
|
||||
RDI_SourceFile *file = rdi_source_file_from_line(rdi, &line); // 4. line -> source file
|
||||
RDI_U64 file_path_size = 0; // 5. source file -> path
|
||||
RDI_U8 *file_path = rdi_normal_path_from_source_file(rdi, file, &file_path_size);
|
||||
printf("%s is at %.*s:%u\n", name, (int)file_path_size, file_path, line.line_num);
|
||||
}
|
||||
|
||||
// Line -> Procedure Name
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *path = "c:/devel/raddebugger/src/mule/mule_main.cpp";
|
||||
RDI_U32 line_num = 2557;
|
||||
RDI_SourceFile *file = rdi_source_file_from_normal_path_cstr(rdi, path); // 1. path -> source file
|
||||
RDI_U64 voff = rdi_first_voff_from_source_file_line_num(rdi, file, line_num); // 2. (source file, line) -> virtual offset
|
||||
RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); // 3. virtual offset -> procedure
|
||||
RDI_U64 name_size = 0; // 4. procedure -> name
|
||||
RDI_U8 *name = rdi_name_from_procedure(rdi, procedure, &name_size);
|
||||
printf("%s:%u is inside %.*s\n", path, line_num, (int)name_size, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RDI_FORMAT_PARSE_H
|
||||
#define RDI_FORMAT_PARSE_H
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Parsed Information Types
|
||||
|
||||
typedef enum RDI_ParseStatus
|
||||
{
|
||||
RDI_ParseStatus_Good = 0,
|
||||
RDI_ParseStatus_HeaderDoesNotMatch = 1,
|
||||
RDI_ParseStatus_UnsupportedVersionNumber = 2,
|
||||
RDI_ParseStatus_InvalidDataSecionLayout = 3,
|
||||
RDI_ParseStatus_MissingRequiredSection = 4,
|
||||
}
|
||||
RDI_ParseStatus;
|
||||
|
||||
typedef struct RDI_Parsed RDI_Parsed;
|
||||
struct RDI_Parsed
|
||||
{
|
||||
RDI_U8 *raw_data;
|
||||
RDI_U64 raw_data_size;
|
||||
RDI_Section *sections;
|
||||
RDI_U64 sections_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedLineTable RDI_ParsedLineTable;
|
||||
struct RDI_ParsedLineTable
|
||||
{
|
||||
// NOTE: Mapping VOFF -> LINE_INFO
|
||||
//
|
||||
// * [ voff[i], voff[i + 1] ) forms the voff range
|
||||
// * for the line info at lines[i] (and cols[i] if i < col_count)
|
||||
RDI_U64* voffs; // [count + 1] sorted
|
||||
RDI_Line* lines; // [count]
|
||||
RDI_Column* cols; // [col_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 col_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedSourceLineMap RDI_ParsedSourceLineMap;
|
||||
struct RDI_ParsedSourceLineMap
|
||||
{
|
||||
// NOTE: Mapping LINE_NUMBER -> VOFFs
|
||||
//
|
||||
// * nums[i] gives a line number
|
||||
// * that line number has one or more associated voffs
|
||||
//
|
||||
// * to find all associated voffs for the line number nums[i] :
|
||||
// * let k span over the range [ ranges[i], ranges[i + 1] )
|
||||
// * voffs[k] gives the associated voffs
|
||||
RDI_U32* nums; // [count] sorted
|
||||
RDI_U32* ranges; // [count + 1]
|
||||
RDI_U64* voffs; // [voff_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 voff_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedNameMap RDI_ParsedNameMap;
|
||||
struct RDI_ParsedNameMap
|
||||
{
|
||||
RDI_NameMapBucket *buckets;
|
||||
RDI_NameMapNode *nodes;
|
||||
RDI_U64 bucket_count;
|
||||
RDI_U64 node_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Global Nils
|
||||
|
||||
static union
|
||||
{
|
||||
RDI_TopLevelInfo top_level_info;
|
||||
RDI_BinarySection binary_section;
|
||||
RDI_FilePathNode file_path_node;
|
||||
RDI_SourceFile source_file;
|
||||
RDI_LineTable line_table;
|
||||
RDI_SourceLineMap source_line_map;
|
||||
RDI_Line line;
|
||||
RDI_Column column;
|
||||
RDI_Unit unit;
|
||||
RDI_VMapEntry vmap_entry;
|
||||
RDI_TypeNode type_node;
|
||||
RDI_UDT udt;
|
||||
RDI_Member member;
|
||||
RDI_EnumMember enum_member;
|
||||
RDI_GlobalVariable global_variable;
|
||||
RDI_ThreadVariable thread_variable;
|
||||
RDI_Procedure procedure;
|
||||
RDI_Scope scope;
|
||||
RDI_U64 voff;
|
||||
RDI_LocationBlock location_block;
|
||||
RDI_Local local;
|
||||
}
|
||||
rdi_nil_element_union = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Top-Level Parsing API
|
||||
|
||||
RDI_PROC RDI_ParseStatus rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Base Parsed Info Extraction Helpers
|
||||
|
||||
//- section table/element raw data extraction
|
||||
RDI_PROC void *rdi_section_raw_data_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_SectionEncoding *encoding_out, RDI_U64 *size_out);
|
||||
RDI_PROC void *rdi_section_raw_table_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 *count_out);
|
||||
RDI_PROC void *rdi_section_raw_element_from_kind_idx(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 idx);
|
||||
#define rdi_table_from_name(rdi, name, count_out) (RDI_SectionElementType_##name *)rdi_section_raw_table_from_kind((rdi), RDI_SectionKind_##name, (count_out))
|
||||
#define rdi_element_from_name_idx(rdi, name, idx) (RDI_SectionElementType_##name *)rdi_section_raw_element_from_kind_idx((rdi), RDI_SectionKind_##name, (idx))
|
||||
|
||||
//- info about whole parse
|
||||
RDI_PROC RDI_U64 rdi_decompressed_size_from_parsed(RDI_Parsed *rdi);
|
||||
|
||||
//- strings
|
||||
RDI_PROC RDI_U8 *rdi_string_from_idx(RDI_Parsed *rdi, RDI_U32 idx, RDI_U64 *len_out);
|
||||
|
||||
//- index runs
|
||||
RDI_PROC RDI_U32 *rdi_idx_run_from_first_count(RDI_Parsed *rdi, RDI_U32 raw_first, RDI_U32 raw_count, RDI_U32 *n_out);
|
||||
|
||||
//- line info
|
||||
RDI_PROC void rdi_parsed_from_line_table(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_ParsedLineTable *out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_range_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff, RDI_U64 *n_out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff);
|
||||
RDI_PROC void rdi_parsed_from_source_line_map(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_ParsedSourceLineMap *out);
|
||||
RDI_PROC RDI_U64 *rdi_line_voffs_from_num(RDI_ParsedSourceLineMap *map, RDI_U32 linenum, RDI_U32 *n_out);
|
||||
|
||||
//- vmap lookups
|
||||
RDI_PROC RDI_U64 rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U64 vmap_count, RDI_U64 voff);
|
||||
|
||||
//- name maps
|
||||
RDI_PROC RDI_NameMap *rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind);
|
||||
RDI_PROC void rdi_name_map_parse(RDI_Parsed* p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out);
|
||||
RDI_PROC RDI_NameMapNode *rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, RDI_U8 *str, RDI_U64 len);
|
||||
RDI_PROC RDI_U32 *rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ High-Level Composite Lookup Functions
|
||||
|
||||
//- procedures
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_Scope *rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
|
||||
//- scopes
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_Scope *rdi_scope_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
|
||||
//- units
|
||||
RDI_PROC RDI_Unit *rdi_unit_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_LineTable *rdi_line_table_from_unit(RDI_Parsed *rdi, RDI_Unit *unit);
|
||||
|
||||
//- line tables
|
||||
RDI_PROC RDI_Line rdi_line_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Line rdi_line_from_line_table_voff(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_U64 voff);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_line(RDI_Parsed *rdi, RDI_Line *line);
|
||||
|
||||
//- source files
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_normal_path_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_FilePathNode *rdi_file_path_node_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_SourceLineMap *rdi_source_line_map_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_file_line_num(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U32 line_num);
|
||||
|
||||
//- source line maps
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_line_map_num(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_U32 line_num);
|
||||
|
||||
//- file path nodes
|
||||
RDI_PROC RDI_FilePathNode *rdi_parent_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node, RDI_U64 *len_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Parser Helpers
|
||||
|
||||
#define rdi_parse__min(a,b) (((a)<(b))?(a):(b))
|
||||
RDI_PROC RDI_U64 rdi_cstring_length(char *cstr);
|
||||
|
||||
#endif // RDI_FORMAT_PARSE_H
|
||||
|
||||
+1093
-1093
File diff suppressed because it is too large
Load Diff
+302
-302
@@ -1,302 +1,302 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MDESK_H
|
||||
#define MDESK_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Messages
|
||||
|
||||
typedef enum MD_MsgKind
|
||||
{
|
||||
MD_MsgKind_Null,
|
||||
MD_MsgKind_Note,
|
||||
MD_MsgKind_Warning,
|
||||
MD_MsgKind_Error,
|
||||
MD_MsgKind_FatalError,
|
||||
}
|
||||
MD_MsgKind;
|
||||
|
||||
typedef struct MD_Msg MD_Msg;
|
||||
struct MD_Msg
|
||||
{
|
||||
MD_Msg *next;
|
||||
struct MD_Node *node;
|
||||
MD_MsgKind kind;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct MD_MsgList MD_MsgList;
|
||||
struct MD_MsgList
|
||||
{
|
||||
MD_Msg *first;
|
||||
MD_Msg *last;
|
||||
U64 count;
|
||||
MD_MsgKind worst_message_kind;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Types
|
||||
|
||||
typedef U32 MD_TokenFlags;
|
||||
enum
|
||||
{
|
||||
// rjf: base kind info
|
||||
MD_TokenFlag_Identifier = (1<<0),
|
||||
MD_TokenFlag_Numeric = (1<<1),
|
||||
MD_TokenFlag_StringLiteral = (1<<2),
|
||||
MD_TokenFlag_Symbol = (1<<3),
|
||||
MD_TokenFlag_Reserved = (1<<4),
|
||||
MD_TokenFlag_Comment = (1<<5),
|
||||
MD_TokenFlag_Whitespace = (1<<6),
|
||||
MD_TokenFlag_Newline = (1<<7),
|
||||
|
||||
// rjf: decoration info
|
||||
MD_TokenFlag_StringSingleQuote = (1<<8),
|
||||
MD_TokenFlag_StringDoubleQuote = (1<<9),
|
||||
MD_TokenFlag_StringTick = (1<<10),
|
||||
MD_TokenFlag_StringTriplet = (1<<11),
|
||||
|
||||
// rjf: error info
|
||||
MD_TokenFlag_BrokenComment = (1<<12),
|
||||
MD_TokenFlag_BrokenStringLiteral = (1<<13),
|
||||
MD_TokenFlag_BadCharacter = (1<<14),
|
||||
};
|
||||
|
||||
typedef U32 MD_TokenGroups;
|
||||
enum
|
||||
{
|
||||
MD_TokenGroup_Comment = MD_TokenFlag_Comment,
|
||||
MD_TokenGroup_Whitespace = (MD_TokenFlag_Whitespace|
|
||||
MD_TokenFlag_Newline),
|
||||
MD_TokenGroup_Irregular = (MD_TokenGroup_Comment|
|
||||
MD_TokenGroup_Whitespace),
|
||||
MD_TokenGroup_Regular = ~MD_TokenGroup_Irregular,
|
||||
MD_TokenGroup_Label = (MD_TokenFlag_Identifier|
|
||||
MD_TokenFlag_Numeric|
|
||||
MD_TokenFlag_StringLiteral|
|
||||
MD_TokenFlag_Symbol),
|
||||
MD_TokenGroup_Error = (MD_TokenFlag_BrokenComment|
|
||||
MD_TokenFlag_BrokenStringLiteral|
|
||||
MD_TokenFlag_BadCharacter),
|
||||
};
|
||||
|
||||
typedef struct MD_Token MD_Token;
|
||||
struct MD_Token
|
||||
{
|
||||
Rng1U64 range;
|
||||
MD_TokenFlags flags;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenChunkNode MD_TokenChunkNode;
|
||||
struct MD_TokenChunkNode
|
||||
{
|
||||
MD_TokenChunkNode *next;
|
||||
MD_Token *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenChunkList MD_TokenChunkList;
|
||||
struct MD_TokenChunkList
|
||||
{
|
||||
MD_TokenChunkNode *first;
|
||||
MD_TokenChunkNode *last;
|
||||
U64 chunk_count;
|
||||
U64 total_token_count;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenArray MD_TokenArray;
|
||||
struct MD_TokenArray
|
||||
{
|
||||
MD_Token *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Types
|
||||
|
||||
typedef enum MD_NodeKind
|
||||
{
|
||||
MD_NodeKind_Nil,
|
||||
MD_NodeKind_File,
|
||||
MD_NodeKind_ErrorMarker,
|
||||
MD_NodeKind_Main,
|
||||
MD_NodeKind_Tag,
|
||||
MD_NodeKind_List,
|
||||
MD_NodeKind_Reference,
|
||||
MD_NodeKind_COUNT
|
||||
}
|
||||
MD_NodeKind;
|
||||
|
||||
typedef U64 MD_NodeFlags;
|
||||
enum
|
||||
{
|
||||
MD_NodeFlag_MaskSetDelimiters = (0x3F<<0),
|
||||
MD_NodeFlag_HasParenLeft = (1<<0),
|
||||
MD_NodeFlag_HasParenRight = (1<<1),
|
||||
MD_NodeFlag_HasBracketLeft = (1<<2),
|
||||
MD_NodeFlag_HasBracketRight = (1<<3),
|
||||
MD_NodeFlag_HasBraceLeft = (1<<4),
|
||||
MD_NodeFlag_HasBraceRight = (1<<5),
|
||||
|
||||
MD_NodeFlag_MaskSeparators = (0xF<<6),
|
||||
MD_NodeFlag_IsBeforeSemicolon = (1<<6),
|
||||
MD_NodeFlag_IsAfterSemicolon = (1<<7),
|
||||
MD_NodeFlag_IsBeforeComma = (1<<8),
|
||||
MD_NodeFlag_IsAfterComma = (1<<9),
|
||||
|
||||
MD_NodeFlag_MaskStringDelimiters = (0xF<<10),
|
||||
MD_NodeFlag_StringSingleQuote = (1<<10),
|
||||
MD_NodeFlag_StringDoubleQuote = (1<<11),
|
||||
MD_NodeFlag_StringTick = (1<<12),
|
||||
MD_NodeFlag_StringTriplet = (1<<13),
|
||||
|
||||
MD_NodeFlag_MaskLabelKind = (0xF<<14),
|
||||
MD_NodeFlag_Numeric = (1<<14),
|
||||
MD_NodeFlag_Identifier = (1<<15),
|
||||
MD_NodeFlag_StringLiteral = (1<<16),
|
||||
MD_NodeFlag_Symbol = (1<<17),
|
||||
};
|
||||
#define MD_NodeFlag_AfterFromBefore(f) ((f) << 1)
|
||||
|
||||
typedef struct MD_Node MD_Node;
|
||||
struct MD_Node
|
||||
{
|
||||
// rjf: tree links
|
||||
MD_Node *next;
|
||||
MD_Node *prev;
|
||||
MD_Node *parent;
|
||||
MD_Node *first;
|
||||
MD_Node *last;
|
||||
|
||||
// rjf: tag links
|
||||
MD_Node *first_tag;
|
||||
MD_Node *last_tag;
|
||||
|
||||
// rjf: node info
|
||||
MD_NodeKind kind;
|
||||
MD_NodeFlags flags;
|
||||
String8 string;
|
||||
String8 raw_string;
|
||||
|
||||
// rjf: source code info
|
||||
U64 src_offset;
|
||||
};
|
||||
|
||||
typedef struct MD_NodeRec MD_NodeRec;
|
||||
struct MD_NodeRec
|
||||
{
|
||||
MD_Node *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text -> Tokens Types
|
||||
|
||||
typedef struct MD_TokenizeResult MD_TokenizeResult;
|
||||
struct MD_TokenizeResult
|
||||
{
|
||||
MD_TokenArray tokens;
|
||||
MD_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokens -> Tree Types
|
||||
|
||||
typedef struct MD_ParseResult MD_ParseResult;
|
||||
struct MD_ParseResult
|
||||
{
|
||||
MD_Node *root;
|
||||
MD_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global read_only MD_Node md_nil_node =
|
||||
{
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Type Functions
|
||||
|
||||
internal void md_msg_list_push(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, String8 string);
|
||||
internal void md_msg_list_pushf(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, char *fmt, ...);
|
||||
internal void md_msg_list_concat_in_place(MD_MsgList *dst, MD_MsgList *to_push);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Type Functions
|
||||
|
||||
internal MD_Token md_token_make(Rng1U64 range, MD_TokenFlags flags);
|
||||
internal B32 md_token_match(MD_Token a, MD_Token b);
|
||||
internal String8List md_string_list_from_token_flags(Arena *arena, MD_TokenFlags flags);
|
||||
internal void md_token_chunk_list_push(Arena *arena, MD_TokenChunkList *list, U64 cap, MD_Token token);
|
||||
internal MD_TokenArray md_token_array_from_chunk_list(Arena *arena, MD_TokenChunkList *chunks);
|
||||
internal String8 md_content_string_from_token_flags_str8(MD_TokenFlags flags, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Type Functions
|
||||
|
||||
//- rjf: flag conversions
|
||||
internal MD_NodeFlags md_node_flags_from_token_flags(MD_TokenFlags flags);
|
||||
|
||||
//- rjf: nil
|
||||
internal B32 md_node_is_nil(MD_Node *node);
|
||||
|
||||
//- rjf: iteration
|
||||
#define MD_EachNode(it, first) MD_Node *it = first; !md_node_is_nil(it); it = it->next
|
||||
internal MD_NodeRec md_node_rec_depth_first(MD_Node *node, MD_Node *subtree_root, U64 child_off, U64 sib_off);
|
||||
#define md_node_rec_depth_first_pre(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, first), OffsetOf(MD_Node, next))
|
||||
#define md_node_rec_depth_first_pre_rev(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, last), OffsetOf(MD_Node, prev))
|
||||
|
||||
//- rjf: tree building
|
||||
internal MD_Node *md_push_node(Arena *arena, MD_NodeKind kind, MD_NodeFlags flags, String8 string, String8 raw_string, U64 src_offset);
|
||||
internal void md_node_push_child(MD_Node *parent, MD_Node *node);
|
||||
internal void md_node_push_tag(MD_Node *parent, MD_Node *node);
|
||||
|
||||
//- rjf: tree introspection
|
||||
internal MD_Node * md_node_from_chain_string(MD_Node *first, MD_Node *opl, String8 string, StringMatchFlags flags);
|
||||
internal MD_Node * md_node_from_chain_index(MD_Node *first, MD_Node *opl, U64 index);
|
||||
internal MD_Node * md_node_from_chain_flags(MD_Node *first, MD_Node *opl, MD_NodeFlags flags);
|
||||
internal U64 md_index_from_node(MD_Node *node);
|
||||
internal MD_Node * md_root_from_node(MD_Node *node);
|
||||
internal MD_Node * md_child_from_string(MD_Node *node, String8 child_string, StringMatchFlags flags);
|
||||
internal MD_Node * md_tag_from_string(MD_Node *node, String8 tag_string, StringMatchFlags flags);
|
||||
internal MD_Node * md_child_from_index(MD_Node *node, U64 index);
|
||||
internal MD_Node * md_tag_from_index(MD_Node *node, U64 index);
|
||||
internal MD_Node * md_tag_arg_from_index(MD_Node *node, String8 tag_string, StringMatchFlags flags, U64 index);
|
||||
internal MD_Node * md_tag_arg_from_string(MD_Node *node, String8 tag_string, StringMatchFlags tag_str_flags, String8 arg_string, StringMatchFlags arg_str_flags);
|
||||
internal B32 md_node_has_child(MD_Node *node, String8 string, StringMatchFlags flags);
|
||||
internal B32 md_node_has_tag(MD_Node *node, String8 string, StringMatchFlags flags);
|
||||
internal U64 md_child_count_from_node(MD_Node *node);
|
||||
internal U64 md_tag_count_from_node(MD_Node *node);
|
||||
|
||||
//- rjf: tree comparison
|
||||
internal B32 md_node_deep_match(MD_Node *a, MD_Node *b, StringMatchFlags flags);
|
||||
internal B32 md_node_match(MD_Node *a, MD_Node *b, StringMatchFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text -> Tokens Functions
|
||||
|
||||
internal MD_TokenizeResult md_tokenize_from_text(Arena *arena, String8 text);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokens -> Tree Functions
|
||||
|
||||
internal MD_ParseResult md_parse_from_text_tokens(Arena *arena, String8 filename, String8 text, MD_TokenArray tokens);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tree -> Text Functions
|
||||
|
||||
internal String8List md_debug_string_list_from_tree(Arena *arena, MD_Node *root);
|
||||
|
||||
#endif // MDESK_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MDESK_H
|
||||
#define MDESK_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Messages
|
||||
|
||||
typedef enum MD_MsgKind
|
||||
{
|
||||
MD_MsgKind_Null,
|
||||
MD_MsgKind_Note,
|
||||
MD_MsgKind_Warning,
|
||||
MD_MsgKind_Error,
|
||||
MD_MsgKind_FatalError,
|
||||
}
|
||||
MD_MsgKind;
|
||||
|
||||
typedef struct MD_Msg MD_Msg;
|
||||
struct MD_Msg
|
||||
{
|
||||
MD_Msg *next;
|
||||
struct MD_Node *node;
|
||||
MD_MsgKind kind;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct MD_MsgList MD_MsgList;
|
||||
struct MD_MsgList
|
||||
{
|
||||
MD_Msg *first;
|
||||
MD_Msg *last;
|
||||
U64 count;
|
||||
MD_MsgKind worst_message_kind;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Types
|
||||
|
||||
typedef U32 MD_TokenFlags;
|
||||
enum
|
||||
{
|
||||
// rjf: base kind info
|
||||
MD_TokenFlag_Identifier = (1<<0),
|
||||
MD_TokenFlag_Numeric = (1<<1),
|
||||
MD_TokenFlag_StringLiteral = (1<<2),
|
||||
MD_TokenFlag_Symbol = (1<<3),
|
||||
MD_TokenFlag_Reserved = (1<<4),
|
||||
MD_TokenFlag_Comment = (1<<5),
|
||||
MD_TokenFlag_Whitespace = (1<<6),
|
||||
MD_TokenFlag_Newline = (1<<7),
|
||||
|
||||
// rjf: decoration info
|
||||
MD_TokenFlag_StringSingleQuote = (1<<8),
|
||||
MD_TokenFlag_StringDoubleQuote = (1<<9),
|
||||
MD_TokenFlag_StringTick = (1<<10),
|
||||
MD_TokenFlag_StringTriplet = (1<<11),
|
||||
|
||||
// rjf: error info
|
||||
MD_TokenFlag_BrokenComment = (1<<12),
|
||||
MD_TokenFlag_BrokenStringLiteral = (1<<13),
|
||||
MD_TokenFlag_BadCharacter = (1<<14),
|
||||
};
|
||||
|
||||
typedef U32 MD_TokenGroups;
|
||||
enum
|
||||
{
|
||||
MD_TokenGroup_Comment = MD_TokenFlag_Comment,
|
||||
MD_TokenGroup_Whitespace = (MD_TokenFlag_Whitespace|
|
||||
MD_TokenFlag_Newline),
|
||||
MD_TokenGroup_Irregular = (MD_TokenGroup_Comment|
|
||||
MD_TokenGroup_Whitespace),
|
||||
MD_TokenGroup_Regular = ~MD_TokenGroup_Irregular,
|
||||
MD_TokenGroup_Label = (MD_TokenFlag_Identifier|
|
||||
MD_TokenFlag_Numeric|
|
||||
MD_TokenFlag_StringLiteral|
|
||||
MD_TokenFlag_Symbol),
|
||||
MD_TokenGroup_Error = (MD_TokenFlag_BrokenComment|
|
||||
MD_TokenFlag_BrokenStringLiteral|
|
||||
MD_TokenFlag_BadCharacter),
|
||||
};
|
||||
|
||||
typedef struct MD_Token MD_Token;
|
||||
struct MD_Token
|
||||
{
|
||||
Rng1U64 range;
|
||||
MD_TokenFlags flags;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenChunkNode MD_TokenChunkNode;
|
||||
struct MD_TokenChunkNode
|
||||
{
|
||||
MD_TokenChunkNode *next;
|
||||
MD_Token *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenChunkList MD_TokenChunkList;
|
||||
struct MD_TokenChunkList
|
||||
{
|
||||
MD_TokenChunkNode *first;
|
||||
MD_TokenChunkNode *last;
|
||||
U64 chunk_count;
|
||||
U64 total_token_count;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenArray MD_TokenArray;
|
||||
struct MD_TokenArray
|
||||
{
|
||||
MD_Token *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Types
|
||||
|
||||
typedef enum MD_NodeKind
|
||||
{
|
||||
MD_NodeKind_Nil,
|
||||
MD_NodeKind_File,
|
||||
MD_NodeKind_ErrorMarker,
|
||||
MD_NodeKind_Main,
|
||||
MD_NodeKind_Tag,
|
||||
MD_NodeKind_List,
|
||||
MD_NodeKind_Reference,
|
||||
MD_NodeKind_COUNT
|
||||
}
|
||||
MD_NodeKind;
|
||||
|
||||
typedef U64 MD_NodeFlags;
|
||||
enum
|
||||
{
|
||||
MD_NodeFlag_MaskSetDelimiters = (0x3F<<0),
|
||||
MD_NodeFlag_HasParenLeft = (1<<0),
|
||||
MD_NodeFlag_HasParenRight = (1<<1),
|
||||
MD_NodeFlag_HasBracketLeft = (1<<2),
|
||||
MD_NodeFlag_HasBracketRight = (1<<3),
|
||||
MD_NodeFlag_HasBraceLeft = (1<<4),
|
||||
MD_NodeFlag_HasBraceRight = (1<<5),
|
||||
|
||||
MD_NodeFlag_MaskSeparators = (0xF<<6),
|
||||
MD_NodeFlag_IsBeforeSemicolon = (1<<6),
|
||||
MD_NodeFlag_IsAfterSemicolon = (1<<7),
|
||||
MD_NodeFlag_IsBeforeComma = (1<<8),
|
||||
MD_NodeFlag_IsAfterComma = (1<<9),
|
||||
|
||||
MD_NodeFlag_MaskStringDelimiters = (0xF<<10),
|
||||
MD_NodeFlag_StringSingleQuote = (1<<10),
|
||||
MD_NodeFlag_StringDoubleQuote = (1<<11),
|
||||
MD_NodeFlag_StringTick = (1<<12),
|
||||
MD_NodeFlag_StringTriplet = (1<<13),
|
||||
|
||||
MD_NodeFlag_MaskLabelKind = (0xF<<14),
|
||||
MD_NodeFlag_Numeric = (1<<14),
|
||||
MD_NodeFlag_Identifier = (1<<15),
|
||||
MD_NodeFlag_StringLiteral = (1<<16),
|
||||
MD_NodeFlag_Symbol = (1<<17),
|
||||
};
|
||||
#define MD_NodeFlag_AfterFromBefore(f) ((f) << 1)
|
||||
|
||||
typedef struct MD_Node MD_Node;
|
||||
struct MD_Node
|
||||
{
|
||||
// rjf: tree links
|
||||
MD_Node *next;
|
||||
MD_Node *prev;
|
||||
MD_Node *parent;
|
||||
MD_Node *first;
|
||||
MD_Node *last;
|
||||
|
||||
// rjf: tag links
|
||||
MD_Node *first_tag;
|
||||
MD_Node *last_tag;
|
||||
|
||||
// rjf: node info
|
||||
MD_NodeKind kind;
|
||||
MD_NodeFlags flags;
|
||||
String8 string;
|
||||
String8 raw_string;
|
||||
|
||||
// rjf: source code info
|
||||
U64 src_offset;
|
||||
};
|
||||
|
||||
typedef struct MD_NodeRec MD_NodeRec;
|
||||
struct MD_NodeRec
|
||||
{
|
||||
MD_Node *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text -> Tokens Types
|
||||
|
||||
typedef struct MD_TokenizeResult MD_TokenizeResult;
|
||||
struct MD_TokenizeResult
|
||||
{
|
||||
MD_TokenArray tokens;
|
||||
MD_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokens -> Tree Types
|
||||
|
||||
typedef struct MD_ParseResult MD_ParseResult;
|
||||
struct MD_ParseResult
|
||||
{
|
||||
MD_Node *root;
|
||||
MD_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global read_only MD_Node md_nil_node =
|
||||
{
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Type Functions
|
||||
|
||||
internal void md_msg_list_push(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, String8 string);
|
||||
internal void md_msg_list_pushf(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, char *fmt, ...);
|
||||
internal void md_msg_list_concat_in_place(MD_MsgList *dst, MD_MsgList *to_push);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Type Functions
|
||||
|
||||
internal MD_Token md_token_make(Rng1U64 range, MD_TokenFlags flags);
|
||||
internal B32 md_token_match(MD_Token a, MD_Token b);
|
||||
internal String8List md_string_list_from_token_flags(Arena *arena, MD_TokenFlags flags);
|
||||
internal void md_token_chunk_list_push(Arena *arena, MD_TokenChunkList *list, U64 cap, MD_Token token);
|
||||
internal MD_TokenArray md_token_array_from_chunk_list(Arena *arena, MD_TokenChunkList *chunks);
|
||||
internal String8 md_content_string_from_token_flags_str8(MD_TokenFlags flags, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Type Functions
|
||||
|
||||
//- rjf: flag conversions
|
||||
internal MD_NodeFlags md_node_flags_from_token_flags(MD_TokenFlags flags);
|
||||
|
||||
//- rjf: nil
|
||||
internal B32 md_node_is_nil(MD_Node *node);
|
||||
|
||||
//- rjf: iteration
|
||||
#define MD_EachNode(it, first) MD_Node *it = first; !md_node_is_nil(it); it = it->next
|
||||
internal MD_NodeRec md_node_rec_depth_first(MD_Node *node, MD_Node *subtree_root, U64 child_off, U64 sib_off);
|
||||
#define md_node_rec_depth_first_pre(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, first), OffsetOf(MD_Node, next))
|
||||
#define md_node_rec_depth_first_pre_rev(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, last), OffsetOf(MD_Node, prev))
|
||||
|
||||
//- rjf: tree building
|
||||
internal MD_Node *md_push_node(Arena *arena, MD_NodeKind kind, MD_NodeFlags flags, String8 string, String8 raw_string, U64 src_offset);
|
||||
internal void md_node_push_child(MD_Node *parent, MD_Node *node);
|
||||
internal void md_node_push_tag(MD_Node *parent, MD_Node *node);
|
||||
|
||||
//- rjf: tree introspection
|
||||
internal MD_Node * md_node_from_chain_string(MD_Node *first, MD_Node *opl, String8 string, StringMatchFlags flags);
|
||||
internal MD_Node * md_node_from_chain_index(MD_Node *first, MD_Node *opl, U64 index);
|
||||
internal MD_Node * md_node_from_chain_flags(MD_Node *first, MD_Node *opl, MD_NodeFlags flags);
|
||||
internal U64 md_index_from_node(MD_Node *node);
|
||||
internal MD_Node * md_root_from_node(MD_Node *node);
|
||||
internal MD_Node * md_child_from_string(MD_Node *node, String8 child_string, StringMatchFlags flags);
|
||||
internal MD_Node * md_tag_from_string(MD_Node *node, String8 tag_string, StringMatchFlags flags);
|
||||
internal MD_Node * md_child_from_index(MD_Node *node, U64 index);
|
||||
internal MD_Node * md_tag_from_index(MD_Node *node, U64 index);
|
||||
internal MD_Node * md_tag_arg_from_index(MD_Node *node, String8 tag_string, StringMatchFlags flags, U64 index);
|
||||
internal MD_Node * md_tag_arg_from_string(MD_Node *node, String8 tag_string, StringMatchFlags tag_str_flags, String8 arg_string, StringMatchFlags arg_str_flags);
|
||||
internal B32 md_node_has_child(MD_Node *node, String8 string, StringMatchFlags flags);
|
||||
internal B32 md_node_has_tag(MD_Node *node, String8 string, StringMatchFlags flags);
|
||||
internal U64 md_child_count_from_node(MD_Node *node);
|
||||
internal U64 md_tag_count_from_node(MD_Node *node);
|
||||
|
||||
//- rjf: tree comparison
|
||||
internal B32 md_node_deep_match(MD_Node *a, MD_Node *b, StringMatchFlags flags);
|
||||
internal B32 md_node_match(MD_Node *a, MD_Node *b, StringMatchFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text -> Tokens Functions
|
||||
|
||||
internal MD_TokenizeResult md_tokenize_from_text(Arena *arena, String8 text);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokens -> Tree Functions
|
||||
|
||||
internal MD_ParseResult md_parse_from_text_tokens(Arena *arena, String8 filename, String8 text, MD_TokenArray tokens);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tree -> Text Functions
|
||||
|
||||
internal String8List md_debug_string_list_from_tree(Arena *arena, MD_Node *root);
|
||||
|
||||
#endif // MDESK_H
|
||||
|
||||
+1136
-1136
File diff suppressed because it is too large
Load Diff
+329
-329
@@ -1,329 +1,329 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef METAGEN_H
|
||||
#define METAGEN_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Type
|
||||
|
||||
typedef struct MG_Msg MG_Msg;
|
||||
struct MG_Msg
|
||||
{
|
||||
String8 location;
|
||||
String8 kind;
|
||||
String8 msg;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgNode MG_MsgNode;
|
||||
struct MG_MsgNode
|
||||
{
|
||||
MG_MsgNode *next;
|
||||
MG_Msg v;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgList MG_MsgList;
|
||||
struct MG_MsgList
|
||||
{
|
||||
MG_MsgNode *first;
|
||||
MG_MsgNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Artifact Types
|
||||
|
||||
typedef struct MG_FileParse MG_FileParse;
|
||||
struct MG_FileParse
|
||||
{
|
||||
MD_Node *root;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseNode MG_FileParseNode;
|
||||
struct MG_FileParseNode
|
||||
{
|
||||
MG_FileParseNode *next;
|
||||
MG_FileParse v;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseList MG_FileParseList;
|
||||
struct MG_FileParseList
|
||||
{
|
||||
MG_FileParseNode *first;
|
||||
MG_FileParseNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Type
|
||||
|
||||
typedef struct MG_MapNode MG_MapNode;
|
||||
struct MG_MapNode
|
||||
{
|
||||
MG_MapNode *next;
|
||||
String8 key;
|
||||
void *val;
|
||||
};
|
||||
|
||||
typedef struct MG_MapSlot MG_MapSlot;
|
||||
struct MG_MapSlot
|
||||
{
|
||||
MG_MapNode *first;
|
||||
MG_MapNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_Map MG_Map;
|
||||
struct MG_Map
|
||||
{
|
||||
MG_MapSlot *slots;
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Types
|
||||
|
||||
typedef enum MG_StrExprOpKind
|
||||
{
|
||||
MG_StrExprOpKind_Null,
|
||||
MG_StrExprOpKind_Prefix,
|
||||
MG_StrExprOpKind_Postfix,
|
||||
MG_StrExprOpKind_Binary,
|
||||
MG_StrExprOpKind_COUNT
|
||||
}
|
||||
MG_StrExprOpKind;
|
||||
|
||||
typedef enum MG_StrExprOp
|
||||
{
|
||||
MG_StrExprOp_Null,
|
||||
|
||||
#define MG_StrExprOp_FirstString MG_StrExprOp_Dot
|
||||
MG_StrExprOp_Dot,
|
||||
MG_StrExprOp_ExpandIfTrue,
|
||||
MG_StrExprOp_Concat,
|
||||
MG_StrExprOp_BumpToColumn,
|
||||
#define MG_StrExprOp_LastString MG_StrExprOp_BumpToColumn
|
||||
|
||||
#define MG_StrExprOp_FirstNumeric MG_StrExprOp_Add
|
||||
MG_StrExprOp_Add,
|
||||
MG_StrExprOp_Subtract,
|
||||
MG_StrExprOp_Multiply,
|
||||
MG_StrExprOp_Divide,
|
||||
MG_StrExprOp_Modulo,
|
||||
MG_StrExprOp_LeftShift,
|
||||
MG_StrExprOp_RightShift,
|
||||
MG_StrExprOp_BitwiseAnd,
|
||||
MG_StrExprOp_BitwiseOr,
|
||||
MG_StrExprOp_BitwiseXor,
|
||||
MG_StrExprOp_BitwiseNegate,
|
||||
MG_StrExprOp_BooleanAnd,
|
||||
MG_StrExprOp_BooleanOr,
|
||||
MG_StrExprOp_BooleanNot,
|
||||
MG_StrExprOp_Equals,
|
||||
MG_StrExprOp_DoesNotEqual,
|
||||
#define MG_StrExprOp_LastNumeric MG_StrExprOp_DoesNotEqual
|
||||
|
||||
MG_StrExprOp_COUNT,
|
||||
}
|
||||
MG_StrExprOp;
|
||||
|
||||
typedef struct MG_StrExpr MG_StrExpr;
|
||||
struct MG_StrExpr
|
||||
{
|
||||
MG_StrExpr *parent;
|
||||
MG_StrExpr *left;
|
||||
MG_StrExpr *right;
|
||||
MG_StrExprOp op;
|
||||
MD_Node *node;
|
||||
};
|
||||
|
||||
typedef struct MG_StrExprParseResult MG_StrExprParseResult;
|
||||
struct MG_StrExprParseResult
|
||||
{
|
||||
MG_StrExpr *root;
|
||||
MD_MsgList msgs;
|
||||
MD_Node *next_node;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Types
|
||||
|
||||
typedef struct MG_NodeArray MG_NodeArray;
|
||||
struct MG_NodeArray
|
||||
{
|
||||
MD_Node **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct MG_NodeGrid MG_NodeGrid;
|
||||
struct MG_NodeGrid
|
||||
{
|
||||
U64 x_stride;
|
||||
U64 y_stride;
|
||||
MG_NodeArray cells;
|
||||
MG_NodeArray row_parents;
|
||||
};
|
||||
|
||||
typedef enum MG_ColumnKind
|
||||
{
|
||||
MG_ColumnKind_DirectCell,
|
||||
MG_ColumnKind_CheckForTag,
|
||||
MG_ColumnKind_TagChild,
|
||||
MG_ColumnKind_COUNT
|
||||
}
|
||||
MG_ColumnKind;
|
||||
|
||||
typedef struct MG_ColumnDesc MG_ColumnDesc;
|
||||
struct MG_ColumnDesc
|
||||
{
|
||||
String8 name;
|
||||
MG_ColumnKind kind;
|
||||
String8 tag_name;
|
||||
};
|
||||
|
||||
typedef struct MG_ColumnDescArray MG_ColumnDescArray;
|
||||
struct MG_ColumnDescArray
|
||||
{
|
||||
U64 count;
|
||||
MG_ColumnDesc *v;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandTask MG_TableExpandTask;
|
||||
struct MG_TableExpandTask
|
||||
{
|
||||
MG_TableExpandTask *next;
|
||||
String8 expansion_label;
|
||||
MG_NodeGrid *grid;
|
||||
MG_ColumnDescArray column_descs;
|
||||
U64 count;
|
||||
U64 idx;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandInfo MG_TableExpandInfo;
|
||||
struct MG_TableExpandInfo
|
||||
{
|
||||
MG_TableExpandTask *first_expand_task;
|
||||
String8 missing_value_fallback;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Output Path Types
|
||||
|
||||
typedef struct MG_Layer MG_Layer;
|
||||
struct MG_Layer
|
||||
{
|
||||
String8 key;
|
||||
B32 is_library;
|
||||
String8 gen_folder_name;
|
||||
String8 h_name_override;
|
||||
String8 c_name_override;
|
||||
String8List enums;
|
||||
String8List structs;
|
||||
String8List h_functions;
|
||||
String8List h_tables;
|
||||
String8List h_catchall;
|
||||
String8List h_header;
|
||||
String8List h_footer;
|
||||
String8List c_functions;
|
||||
String8List c_tables;
|
||||
String8List c_catchall;
|
||||
String8List c_header;
|
||||
String8List c_footer;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerNode MG_LayerNode;
|
||||
struct MG_LayerNode
|
||||
{
|
||||
MG_LayerNode *next;
|
||||
MG_Layer v;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerSlot MG_LayerSlot;
|
||||
struct MG_LayerSlot
|
||||
{
|
||||
MG_LayerNode *first;
|
||||
MG_LayerNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_State MG_State;
|
||||
struct MG_State
|
||||
{
|
||||
U64 slots_count;
|
||||
MG_LayerSlot *slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global Arena *mg_arena = 0;
|
||||
global MG_State *mg_state = 0;
|
||||
read_only global MG_StrExpr mg_str_expr_nil = {&mg_str_expr_nil, &mg_str_expr_nil, &mg_str_expr_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 mg_hash_from_string(String8 string);
|
||||
internal TxtPt mg_txt_pt_from_string_off(String8 string, U64 off);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Lists
|
||||
|
||||
internal void mg_msg_list_push(Arena *arena, MG_MsgList *msgs, MG_Msg *msg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Escaping
|
||||
|
||||
internal String8 mg_escaped_from_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Wrapping
|
||||
|
||||
internal String8List mg_wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String-Izing
|
||||
|
||||
internal String8 mg_c_string_literal_from_multiline_string(String8 string);
|
||||
internal String8 mg_c_array_literal_contents_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
internal MG_Map mg_push_map(Arena *arena, U64 slot_count);
|
||||
internal void *mg_map_ptr_from_string(MG_Map *map, String8 string);
|
||||
internal void mg_map_insert_ptr(Arena *arena, MG_Map *map, String8 string, void *val);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Parsing
|
||||
|
||||
internal MG_StrExpr *mg_push_str_expr(Arena *arena, MG_StrExprOp op, MD_Node *node);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node *opl, S8 min_prec);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl(Arena *arena, MD_Node *first, MD_Node *opl);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_root(Arena *arena, MD_Node *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Functions
|
||||
|
||||
internal MG_NodeArray mg_node_array_make(Arena *arena, U64 count);
|
||||
internal MG_NodeArray mg_child_array_from_node(Arena *arena, MD_Node *node);
|
||||
internal MG_NodeGrid mg_node_grid_make_from_node(Arena *arena, MD_Node *root);
|
||||
internal MG_NodeArray mg_row_from_index(MG_NodeGrid grid, U64 index);
|
||||
internal MG_NodeArray mg_column_from_index(Arena *arena, MG_NodeGrid grid, U64 index);
|
||||
internal MD_Node *mg_node_from_grid_xy(MG_NodeGrid grid, U64 x, U64 y);
|
||||
|
||||
internal MG_ColumnDescArray mg_column_desc_array_make(Arena *arena, U64 count, MG_ColumnDesc *descs);
|
||||
internal MG_ColumnDescArray mg_column_desc_array_from_tag(Arena *arena, MD_Node *tag);
|
||||
internal U64 mg_column_index_from_name(MG_ColumnDescArray descs, String8 name);
|
||||
internal String8 mg_string_from_row_desc_idx(MD_Node *row_parent, MG_ColumnDescArray descs, U64 idx);
|
||||
|
||||
internal S64 mg_eval_table_expand_expr__numeric(MG_StrExpr *expr, MG_TableExpandInfo *info);
|
||||
internal void mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpandInfo *info, String8List *out);
|
||||
internal void mg_loop_table_column_expansion(Arena *arena, String8 strexpr, MG_TableExpandInfo *info, MG_TableExpandTask *task, String8List *out);
|
||||
internal String8List mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_column_desc_map, String8 fallback, MD_Node *gen);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Layer Lookup Functions
|
||||
|
||||
internal String8 mg_layer_key_from_path(String8 path);
|
||||
internal MG_Layer *mg_layer_from_key(String8 key);
|
||||
|
||||
#endif //METAGEN_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef METAGEN_H
|
||||
#define METAGEN_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Type
|
||||
|
||||
typedef struct MG_Msg MG_Msg;
|
||||
struct MG_Msg
|
||||
{
|
||||
String8 location;
|
||||
String8 kind;
|
||||
String8 msg;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgNode MG_MsgNode;
|
||||
struct MG_MsgNode
|
||||
{
|
||||
MG_MsgNode *next;
|
||||
MG_Msg v;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgList MG_MsgList;
|
||||
struct MG_MsgList
|
||||
{
|
||||
MG_MsgNode *first;
|
||||
MG_MsgNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Artifact Types
|
||||
|
||||
typedef struct MG_FileParse MG_FileParse;
|
||||
struct MG_FileParse
|
||||
{
|
||||
MD_Node *root;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseNode MG_FileParseNode;
|
||||
struct MG_FileParseNode
|
||||
{
|
||||
MG_FileParseNode *next;
|
||||
MG_FileParse v;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseList MG_FileParseList;
|
||||
struct MG_FileParseList
|
||||
{
|
||||
MG_FileParseNode *first;
|
||||
MG_FileParseNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Type
|
||||
|
||||
typedef struct MG_MapNode MG_MapNode;
|
||||
struct MG_MapNode
|
||||
{
|
||||
MG_MapNode *next;
|
||||
String8 key;
|
||||
void *val;
|
||||
};
|
||||
|
||||
typedef struct MG_MapSlot MG_MapSlot;
|
||||
struct MG_MapSlot
|
||||
{
|
||||
MG_MapNode *first;
|
||||
MG_MapNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_Map MG_Map;
|
||||
struct MG_Map
|
||||
{
|
||||
MG_MapSlot *slots;
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Types
|
||||
|
||||
typedef enum MG_StrExprOpKind
|
||||
{
|
||||
MG_StrExprOpKind_Null,
|
||||
MG_StrExprOpKind_Prefix,
|
||||
MG_StrExprOpKind_Postfix,
|
||||
MG_StrExprOpKind_Binary,
|
||||
MG_StrExprOpKind_COUNT
|
||||
}
|
||||
MG_StrExprOpKind;
|
||||
|
||||
typedef enum MG_StrExprOp
|
||||
{
|
||||
MG_StrExprOp_Null,
|
||||
|
||||
#define MG_StrExprOp_FirstString MG_StrExprOp_Dot
|
||||
MG_StrExprOp_Dot,
|
||||
MG_StrExprOp_ExpandIfTrue,
|
||||
MG_StrExprOp_Concat,
|
||||
MG_StrExprOp_BumpToColumn,
|
||||
#define MG_StrExprOp_LastString MG_StrExprOp_BumpToColumn
|
||||
|
||||
#define MG_StrExprOp_FirstNumeric MG_StrExprOp_Add
|
||||
MG_StrExprOp_Add,
|
||||
MG_StrExprOp_Subtract,
|
||||
MG_StrExprOp_Multiply,
|
||||
MG_StrExprOp_Divide,
|
||||
MG_StrExprOp_Modulo,
|
||||
MG_StrExprOp_LeftShift,
|
||||
MG_StrExprOp_RightShift,
|
||||
MG_StrExprOp_BitwiseAnd,
|
||||
MG_StrExprOp_BitwiseOr,
|
||||
MG_StrExprOp_BitwiseXor,
|
||||
MG_StrExprOp_BitwiseNegate,
|
||||
MG_StrExprOp_BooleanAnd,
|
||||
MG_StrExprOp_BooleanOr,
|
||||
MG_StrExprOp_BooleanNot,
|
||||
MG_StrExprOp_Equals,
|
||||
MG_StrExprOp_DoesNotEqual,
|
||||
#define MG_StrExprOp_LastNumeric MG_StrExprOp_DoesNotEqual
|
||||
|
||||
MG_StrExprOp_COUNT,
|
||||
}
|
||||
MG_StrExprOp;
|
||||
|
||||
typedef struct MG_StrExpr MG_StrExpr;
|
||||
struct MG_StrExpr
|
||||
{
|
||||
MG_StrExpr *parent;
|
||||
MG_StrExpr *left;
|
||||
MG_StrExpr *right;
|
||||
MG_StrExprOp op;
|
||||
MD_Node *node;
|
||||
};
|
||||
|
||||
typedef struct MG_StrExprParseResult MG_StrExprParseResult;
|
||||
struct MG_StrExprParseResult
|
||||
{
|
||||
MG_StrExpr *root;
|
||||
MD_MsgList msgs;
|
||||
MD_Node *next_node;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Types
|
||||
|
||||
typedef struct MG_NodeArray MG_NodeArray;
|
||||
struct MG_NodeArray
|
||||
{
|
||||
MD_Node **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct MG_NodeGrid MG_NodeGrid;
|
||||
struct MG_NodeGrid
|
||||
{
|
||||
U64 x_stride;
|
||||
U64 y_stride;
|
||||
MG_NodeArray cells;
|
||||
MG_NodeArray row_parents;
|
||||
};
|
||||
|
||||
typedef enum MG_ColumnKind
|
||||
{
|
||||
MG_ColumnKind_DirectCell,
|
||||
MG_ColumnKind_CheckForTag,
|
||||
MG_ColumnKind_TagChild,
|
||||
MG_ColumnKind_COUNT
|
||||
}
|
||||
MG_ColumnKind;
|
||||
|
||||
typedef struct MG_ColumnDesc MG_ColumnDesc;
|
||||
struct MG_ColumnDesc
|
||||
{
|
||||
String8 name;
|
||||
MG_ColumnKind kind;
|
||||
String8 tag_name;
|
||||
};
|
||||
|
||||
typedef struct MG_ColumnDescArray MG_ColumnDescArray;
|
||||
struct MG_ColumnDescArray
|
||||
{
|
||||
U64 count;
|
||||
MG_ColumnDesc *v;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandTask MG_TableExpandTask;
|
||||
struct MG_TableExpandTask
|
||||
{
|
||||
MG_TableExpandTask *next;
|
||||
String8 expansion_label;
|
||||
MG_NodeGrid *grid;
|
||||
MG_ColumnDescArray column_descs;
|
||||
U64 count;
|
||||
U64 idx;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandInfo MG_TableExpandInfo;
|
||||
struct MG_TableExpandInfo
|
||||
{
|
||||
MG_TableExpandTask *first_expand_task;
|
||||
String8 missing_value_fallback;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Output Path Types
|
||||
|
||||
typedef struct MG_Layer MG_Layer;
|
||||
struct MG_Layer
|
||||
{
|
||||
String8 key;
|
||||
B32 is_library;
|
||||
String8 gen_folder_name;
|
||||
String8 h_name_override;
|
||||
String8 c_name_override;
|
||||
String8List enums;
|
||||
String8List structs;
|
||||
String8List h_functions;
|
||||
String8List h_tables;
|
||||
String8List h_catchall;
|
||||
String8List h_header;
|
||||
String8List h_footer;
|
||||
String8List c_functions;
|
||||
String8List c_tables;
|
||||
String8List c_catchall;
|
||||
String8List c_header;
|
||||
String8List c_footer;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerNode MG_LayerNode;
|
||||
struct MG_LayerNode
|
||||
{
|
||||
MG_LayerNode *next;
|
||||
MG_Layer v;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerSlot MG_LayerSlot;
|
||||
struct MG_LayerSlot
|
||||
{
|
||||
MG_LayerNode *first;
|
||||
MG_LayerNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_State MG_State;
|
||||
struct MG_State
|
||||
{
|
||||
U64 slots_count;
|
||||
MG_LayerSlot *slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global Arena *mg_arena = 0;
|
||||
global MG_State *mg_state = 0;
|
||||
read_only global MG_StrExpr mg_str_expr_nil = {&mg_str_expr_nil, &mg_str_expr_nil, &mg_str_expr_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 mg_hash_from_string(String8 string);
|
||||
internal TxtPt mg_txt_pt_from_string_off(String8 string, U64 off);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Lists
|
||||
|
||||
internal void mg_msg_list_push(Arena *arena, MG_MsgList *msgs, MG_Msg *msg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Escaping
|
||||
|
||||
internal String8 mg_escaped_from_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Wrapping
|
||||
|
||||
internal String8List mg_wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String-Izing
|
||||
|
||||
internal String8 mg_c_string_literal_from_multiline_string(String8 string);
|
||||
internal String8 mg_c_array_literal_contents_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
internal MG_Map mg_push_map(Arena *arena, U64 slot_count);
|
||||
internal void *mg_map_ptr_from_string(MG_Map *map, String8 string);
|
||||
internal void mg_map_insert_ptr(Arena *arena, MG_Map *map, String8 string, void *val);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Parsing
|
||||
|
||||
internal MG_StrExpr *mg_push_str_expr(Arena *arena, MG_StrExprOp op, MD_Node *node);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node *opl, S8 min_prec);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl(Arena *arena, MD_Node *first, MD_Node *opl);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_root(Arena *arena, MD_Node *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Functions
|
||||
|
||||
internal MG_NodeArray mg_node_array_make(Arena *arena, U64 count);
|
||||
internal MG_NodeArray mg_child_array_from_node(Arena *arena, MD_Node *node);
|
||||
internal MG_NodeGrid mg_node_grid_make_from_node(Arena *arena, MD_Node *root);
|
||||
internal MG_NodeArray mg_row_from_index(MG_NodeGrid grid, U64 index);
|
||||
internal MG_NodeArray mg_column_from_index(Arena *arena, MG_NodeGrid grid, U64 index);
|
||||
internal MD_Node *mg_node_from_grid_xy(MG_NodeGrid grid, U64 x, U64 y);
|
||||
|
||||
internal MG_ColumnDescArray mg_column_desc_array_make(Arena *arena, U64 count, MG_ColumnDesc *descs);
|
||||
internal MG_ColumnDescArray mg_column_desc_array_from_tag(Arena *arena, MD_Node *tag);
|
||||
internal U64 mg_column_index_from_name(MG_ColumnDescArray descs, String8 name);
|
||||
internal String8 mg_string_from_row_desc_idx(MD_Node *row_parent, MG_ColumnDescArray descs, U64 idx);
|
||||
|
||||
internal S64 mg_eval_table_expand_expr__numeric(MG_StrExpr *expr, MG_TableExpandInfo *info);
|
||||
internal void mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpandInfo *info, String8List *out);
|
||||
internal void mg_loop_table_column_expansion(Arena *arena, String8 strexpr, MG_TableExpandInfo *info, MG_TableExpandTask *task, String8List *out);
|
||||
internal String8List mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_column_desc_map, String8 fallback, MD_Node *gen);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Layer Lookup Functions
|
||||
|
||||
internal String8 mg_layer_key_from_path(String8 path);
|
||||
internal MG_Layer *mg_layer_from_key(String8 key);
|
||||
|
||||
#endif //METAGEN_H
|
||||
|
||||
+286
-286
@@ -1,286 +1,286 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Parser Functions
|
||||
|
||||
internal MSF_Parsed*
|
||||
msf_parsed_from_data(Arena *arena, String8 msf_data)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
MSF_Parsed *result = 0;
|
||||
|
||||
//- determine msf type
|
||||
U32 index_size = 0;
|
||||
if(msf_data.size >= MSF_MIN_SIZE)
|
||||
{
|
||||
if(str8_match(msf_data, str8_lit(msf_msf20_magic), StringMatchFlag_RightSideSloppy))
|
||||
{
|
||||
index_size = 2;
|
||||
}
|
||||
else if(str8_match(msf_data, str8_lit(msf_msf70_magic), StringMatchFlag_RightSideSloppy))
|
||||
{
|
||||
index_size = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if(index_size == 2 || index_size == 4)
|
||||
{
|
||||
//- extract info from header
|
||||
U32 block_size_raw = 0;
|
||||
U32 whole_file_block_count_raw = 0;
|
||||
U32 directory_size_raw = 0;
|
||||
U32 directory_super_map_raw = 0;
|
||||
if(index_size == 2)
|
||||
{
|
||||
MSF_Header20 *header = (MSF_Header20*)(msf_data.str + MSF_MSF20_MAGIC_SIZE);
|
||||
block_size_raw = header->block_size;
|
||||
whole_file_block_count_raw = header->block_count;
|
||||
directory_size_raw = header->directory_size;
|
||||
}
|
||||
else if(index_size == 4)
|
||||
{
|
||||
MSF_Header70 *header = (MSF_Header70*)(msf_data.str + MSF_MSF70_MAGIC_SIZE);
|
||||
block_size_raw = header->block_size;
|
||||
whole_file_block_count_raw = header->block_count;
|
||||
directory_size_raw = header->directory_size;
|
||||
directory_super_map_raw = header->directory_super_map;
|
||||
}
|
||||
|
||||
//- setup important sizes & counts
|
||||
|
||||
// (blocks)
|
||||
U32 block_size = ClampTop(block_size_raw, msf_data.size);
|
||||
|
||||
// (whole file block count)
|
||||
U32 whole_file_block_count_max = CeilIntegerDiv(msf_data.size, block_size);
|
||||
U32 whole_file_block_count = ClampTop(whole_file_block_count_raw, whole_file_block_count_max);
|
||||
|
||||
// (directory)
|
||||
U32 directory_size = ClampTop(directory_size_raw, msf_data.size);
|
||||
U32 block_count_in_directory = CeilIntegerDiv(directory_size, block_size);
|
||||
|
||||
// (map)
|
||||
U32 directory_map_size = block_count_in_directory*index_size;
|
||||
U32 block_count_in_directory_map = CeilIntegerDiv(directory_map_size, block_size);
|
||||
|
||||
// Layout of the "directory":
|
||||
//
|
||||
// super map: [s1, s2, s3, ...]
|
||||
// map: s1 -> [i1, i2, i3, ...]; s2 -> [...]; s3 -> [...]; ...
|
||||
// directory: i1 -> [data]; i2 -> [data]; i3 -> [data]; ... i1 -> [data]; ...
|
||||
//
|
||||
// The "data" in the directory describes streams:
|
||||
// PDB20:
|
||||
// struct Pdb20StreamSize{
|
||||
// U32 size;
|
||||
// U32 unknown; // looks like kind codes or revision counters or something
|
||||
// }
|
||||
// struct{
|
||||
// U32 stream_count;
|
||||
// Pdb20StreamSize stream_sizes[stream_count];
|
||||
// U16 stream_indices[stream_count][...];
|
||||
// }
|
||||
//
|
||||
// PDB70:
|
||||
// struct{
|
||||
// U32 stream_count;
|
||||
// U32 stream_sizes[stream_count];
|
||||
// U32 stream_indices[stream_count][...];
|
||||
// }
|
||||
|
||||
//- parse stream directory
|
||||
U8 *directory_buf = push_array(scratch.arena, U8, directory_size);
|
||||
B32 got_directory = 1;
|
||||
{
|
||||
U32 directory_super_map_dummy = 0;
|
||||
U32 *directory_super_map = 0;
|
||||
U32 directory_map_block_skip_size = 0;
|
||||
if (index_size == 2){
|
||||
directory_super_map = &directory_super_map_dummy;
|
||||
directory_map_block_skip_size =
|
||||
MSF_MSF20_MAGIC_SIZE + OffsetOf(MSF_Header20, directory_map);
|
||||
}
|
||||
else{
|
||||
U64 super_map_off =
|
||||
MSF_MSF70_MAGIC_SIZE + OffsetOf(MSF_Header70, directory_super_map);
|
||||
directory_super_map = (U32*)(msf_data.str + super_map_off);
|
||||
}
|
||||
|
||||
U32 max_index_count_in_map_block = (block_size - directory_map_block_skip_size)/index_size;
|
||||
|
||||
// for each index in super map ...
|
||||
U8 *out_ptr = directory_buf;
|
||||
U32 *super_map_ptr = directory_super_map;
|
||||
for (U32 i = 0; i < block_count_in_directory_map; i += 1, super_map_ptr += 1){
|
||||
U32 directory_map_block_index = *super_map_ptr;
|
||||
if (directory_map_block_index >= whole_file_block_count){
|
||||
got_directory = 0;
|
||||
goto parse_directory_done;
|
||||
}
|
||||
|
||||
U64 directory_map_block_off = (U64)(directory_map_block_index)*block_size;
|
||||
U8 *directory_map_block_base = (msf_data.str + directory_map_block_off);
|
||||
|
||||
// clamp index count by end of directory
|
||||
U32 index_count = 0;
|
||||
{
|
||||
U32 directory_pos = (U32)(out_ptr - directory_buf);
|
||||
U32 remaining_size = directory_size - directory_pos;
|
||||
U32 remaining_map_block_count = CeilIntegerDiv(remaining_size, block_size);
|
||||
index_count = ClampTop(max_index_count_in_map_block, remaining_map_block_count);
|
||||
}
|
||||
|
||||
// for each index in map ...
|
||||
U8 *map_ptr = directory_map_block_base + directory_map_block_skip_size;
|
||||
for (U32 j = 0; j < index_count; j += 1, map_ptr += index_size){
|
||||
|
||||
// read index
|
||||
U32 directory_block_index = 0;
|
||||
if (index_size == 4){
|
||||
directory_block_index = *(U32*)(map_ptr);
|
||||
}
|
||||
else{
|
||||
directory_block_index = *(U16*)(map_ptr);
|
||||
}
|
||||
if (directory_block_index >= whole_file_block_count){
|
||||
got_directory = 0;
|
||||
goto parse_directory_done;
|
||||
}
|
||||
|
||||
U64 directory_block_off = (U64)(directory_block_index)*block_size;
|
||||
U8 *directory_block_base = (msf_data.str + directory_block_off);
|
||||
|
||||
// clamp copy size by end of directory
|
||||
U32 copy_size = 0;
|
||||
{
|
||||
U32 directory_pos = (U32)(out_ptr - directory_buf);
|
||||
U32 remaining_size = directory_size - directory_pos;
|
||||
copy_size = ClampTop(block_size, remaining_size);
|
||||
}
|
||||
|
||||
// copy block data
|
||||
MemoryCopy(out_ptr, directory_block_base, copy_size);
|
||||
out_ptr += copy_size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
parse_directory_done:;
|
||||
}
|
||||
|
||||
//- parse streams from directory
|
||||
U32 stream_count = 0;
|
||||
B32 got_streams = 0;
|
||||
String8 *streams = 0;
|
||||
|
||||
if(got_directory)
|
||||
{
|
||||
got_streams = 1;
|
||||
|
||||
// read stream count
|
||||
U32 stream_count_raw = *(U32*)(directory_buf);
|
||||
|
||||
// setup counts, sizes, and offsets
|
||||
U32 size_of_stream_entry = 4;
|
||||
if (index_size == 2){
|
||||
size_of_stream_entry = 8;
|
||||
}
|
||||
U32 stream_count_max = (directory_size - 4)/size_of_stream_entry;
|
||||
U32 stream_count__inner = ClampTop(stream_count_raw, stream_count_max);
|
||||
U32 all_stream_entries_off = 4;
|
||||
U32 all_indices_off = all_stream_entries_off + stream_count__inner*size_of_stream_entry;
|
||||
|
||||
// set output buffer and count
|
||||
stream_count = stream_count__inner;
|
||||
streams = push_array(arena, String8, stream_count);
|
||||
|
||||
// iterate sizes and indices in lock step
|
||||
U32 entry_cursor = all_stream_entries_off;
|
||||
U32 index_cursor = all_indices_off;
|
||||
String8 *stream_ptr = streams;
|
||||
for (U32 i = 0; i < stream_count; i += 1)
|
||||
{
|
||||
// read stream size
|
||||
U32 stream_size_raw = *(U32*)(directory_buf + entry_cursor);
|
||||
if (stream_size_raw == 0xffffffff){
|
||||
stream_size_raw = 0;
|
||||
}
|
||||
|
||||
// compute block count
|
||||
U32 stream_block_count_raw = CeilIntegerDiv(stream_size_raw, block_size);
|
||||
U32 stream_block_count_max = (directory_size - index_cursor)/index_size;;
|
||||
U32 stream_block_count = ClampTop(stream_block_count_raw, stream_block_count_max);
|
||||
U32 stream_size = ClampTop(stream_size_raw, stream_block_count*block_size);
|
||||
|
||||
// copy stream data
|
||||
U8 *stream_buf = push_array(arena, U8, stream_size);
|
||||
stream_ptr->str = stream_buf;
|
||||
stream_ptr->size = stream_size;
|
||||
|
||||
U32 sub_index_cursor = index_cursor;
|
||||
U8 *stream_out_ptr = stream_buf;
|
||||
for (U32 i = 0; i < stream_block_count; i += 1, sub_index_cursor += index_size){
|
||||
|
||||
// read index
|
||||
U32 stream_block_index = 0;
|
||||
if (index_size == 4){
|
||||
stream_block_index = *(U32*)(directory_buf + sub_index_cursor);
|
||||
}
|
||||
else{
|
||||
stream_block_index = *(U16*)(directory_buf + sub_index_cursor);
|
||||
}
|
||||
if (stream_block_index >= whole_file_block_count){
|
||||
got_streams = 0;
|
||||
goto parse_streams_done;
|
||||
}
|
||||
|
||||
U64 stream_block_off = (U64)(stream_block_index)*block_size;
|
||||
U8 *stream_block_base = (msf_data.str + stream_block_off);
|
||||
|
||||
// clamp copy size by end of stream
|
||||
U32 copy_size = 0;
|
||||
{
|
||||
U32 stream_pos = (U32)(stream_out_ptr - stream_buf);
|
||||
U32 remaining_size = stream_size - stream_pos;
|
||||
copy_size = ClampTop(block_size, remaining_size);
|
||||
}
|
||||
|
||||
// copy block data
|
||||
MemoryCopy(stream_out_ptr, stream_block_base, copy_size);
|
||||
stream_out_ptr += copy_size;
|
||||
}
|
||||
|
||||
// advance cursors
|
||||
entry_cursor += size_of_stream_entry;
|
||||
index_cursor = sub_index_cursor;
|
||||
stream_ptr += 1;
|
||||
}
|
||||
|
||||
parse_streams_done:;
|
||||
}
|
||||
|
||||
if(got_streams)
|
||||
{
|
||||
result = push_array(arena, MSF_Parsed, 1);
|
||||
result->streams = streams;
|
||||
result->stream_count = stream_count;
|
||||
result->block_size = block_size;
|
||||
result->block_count = whole_file_block_count;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn)
|
||||
{
|
||||
String8 result = {0};
|
||||
if(sn < msf->stream_count)
|
||||
{
|
||||
result = msf->streams[sn];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Parser Functions
|
||||
|
||||
internal MSF_Parsed*
|
||||
msf_parsed_from_data(Arena *arena, String8 msf_data)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
MSF_Parsed *result = 0;
|
||||
|
||||
//- determine msf type
|
||||
U32 index_size = 0;
|
||||
if(msf_data.size >= MSF_MIN_SIZE)
|
||||
{
|
||||
if(str8_match(msf_data, str8_lit(msf_msf20_magic), StringMatchFlag_RightSideSloppy))
|
||||
{
|
||||
index_size = 2;
|
||||
}
|
||||
else if(str8_match(msf_data, str8_lit(msf_msf70_magic), StringMatchFlag_RightSideSloppy))
|
||||
{
|
||||
index_size = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if(index_size == 2 || index_size == 4)
|
||||
{
|
||||
//- extract info from header
|
||||
U32 block_size_raw = 0;
|
||||
U32 whole_file_block_count_raw = 0;
|
||||
U32 directory_size_raw = 0;
|
||||
U32 directory_super_map_raw = 0;
|
||||
if(index_size == 2)
|
||||
{
|
||||
MSF_Header20 *header = (MSF_Header20*)(msf_data.str + MSF_MSF20_MAGIC_SIZE);
|
||||
block_size_raw = header->block_size;
|
||||
whole_file_block_count_raw = header->block_count;
|
||||
directory_size_raw = header->directory_size;
|
||||
}
|
||||
else if(index_size == 4)
|
||||
{
|
||||
MSF_Header70 *header = (MSF_Header70*)(msf_data.str + MSF_MSF70_MAGIC_SIZE);
|
||||
block_size_raw = header->block_size;
|
||||
whole_file_block_count_raw = header->block_count;
|
||||
directory_size_raw = header->directory_size;
|
||||
directory_super_map_raw = header->directory_super_map;
|
||||
}
|
||||
|
||||
//- setup important sizes & counts
|
||||
|
||||
// (blocks)
|
||||
U32 block_size = ClampTop(block_size_raw, msf_data.size);
|
||||
|
||||
// (whole file block count)
|
||||
U32 whole_file_block_count_max = CeilIntegerDiv(msf_data.size, block_size);
|
||||
U32 whole_file_block_count = ClampTop(whole_file_block_count_raw, whole_file_block_count_max);
|
||||
|
||||
// (directory)
|
||||
U32 directory_size = ClampTop(directory_size_raw, msf_data.size);
|
||||
U32 block_count_in_directory = CeilIntegerDiv(directory_size, block_size);
|
||||
|
||||
// (map)
|
||||
U32 directory_map_size = block_count_in_directory*index_size;
|
||||
U32 block_count_in_directory_map = CeilIntegerDiv(directory_map_size, block_size);
|
||||
|
||||
// Layout of the "directory":
|
||||
//
|
||||
// super map: [s1, s2, s3, ...]
|
||||
// map: s1 -> [i1, i2, i3, ...]; s2 -> [...]; s3 -> [...]; ...
|
||||
// directory: i1 -> [data]; i2 -> [data]; i3 -> [data]; ... i1 -> [data]; ...
|
||||
//
|
||||
// The "data" in the directory describes streams:
|
||||
// PDB20:
|
||||
// struct Pdb20StreamSize{
|
||||
// U32 size;
|
||||
// U32 unknown; // looks like kind codes or revision counters or something
|
||||
// }
|
||||
// struct{
|
||||
// U32 stream_count;
|
||||
// Pdb20StreamSize stream_sizes[stream_count];
|
||||
// U16 stream_indices[stream_count][...];
|
||||
// }
|
||||
//
|
||||
// PDB70:
|
||||
// struct{
|
||||
// U32 stream_count;
|
||||
// U32 stream_sizes[stream_count];
|
||||
// U32 stream_indices[stream_count][...];
|
||||
// }
|
||||
|
||||
//- parse stream directory
|
||||
U8 *directory_buf = push_array(scratch.arena, U8, directory_size);
|
||||
B32 got_directory = 1;
|
||||
{
|
||||
U32 directory_super_map_dummy = 0;
|
||||
U32 *directory_super_map = 0;
|
||||
U32 directory_map_block_skip_size = 0;
|
||||
if (index_size == 2){
|
||||
directory_super_map = &directory_super_map_dummy;
|
||||
directory_map_block_skip_size =
|
||||
MSF_MSF20_MAGIC_SIZE + OffsetOf(MSF_Header20, directory_map);
|
||||
}
|
||||
else{
|
||||
U64 super_map_off =
|
||||
MSF_MSF70_MAGIC_SIZE + OffsetOf(MSF_Header70, directory_super_map);
|
||||
directory_super_map = (U32*)(msf_data.str + super_map_off);
|
||||
}
|
||||
|
||||
U32 max_index_count_in_map_block = (block_size - directory_map_block_skip_size)/index_size;
|
||||
|
||||
// for each index in super map ...
|
||||
U8 *out_ptr = directory_buf;
|
||||
U32 *super_map_ptr = directory_super_map;
|
||||
for (U32 i = 0; i < block_count_in_directory_map; i += 1, super_map_ptr += 1){
|
||||
U32 directory_map_block_index = *super_map_ptr;
|
||||
if (directory_map_block_index >= whole_file_block_count){
|
||||
got_directory = 0;
|
||||
goto parse_directory_done;
|
||||
}
|
||||
|
||||
U64 directory_map_block_off = (U64)(directory_map_block_index)*block_size;
|
||||
U8 *directory_map_block_base = (msf_data.str + directory_map_block_off);
|
||||
|
||||
// clamp index count by end of directory
|
||||
U32 index_count = 0;
|
||||
{
|
||||
U32 directory_pos = (U32)(out_ptr - directory_buf);
|
||||
U32 remaining_size = directory_size - directory_pos;
|
||||
U32 remaining_map_block_count = CeilIntegerDiv(remaining_size, block_size);
|
||||
index_count = ClampTop(max_index_count_in_map_block, remaining_map_block_count);
|
||||
}
|
||||
|
||||
// for each index in map ...
|
||||
U8 *map_ptr = directory_map_block_base + directory_map_block_skip_size;
|
||||
for (U32 j = 0; j < index_count; j += 1, map_ptr += index_size){
|
||||
|
||||
// read index
|
||||
U32 directory_block_index = 0;
|
||||
if (index_size == 4){
|
||||
directory_block_index = *(U32*)(map_ptr);
|
||||
}
|
||||
else{
|
||||
directory_block_index = *(U16*)(map_ptr);
|
||||
}
|
||||
if (directory_block_index >= whole_file_block_count){
|
||||
got_directory = 0;
|
||||
goto parse_directory_done;
|
||||
}
|
||||
|
||||
U64 directory_block_off = (U64)(directory_block_index)*block_size;
|
||||
U8 *directory_block_base = (msf_data.str + directory_block_off);
|
||||
|
||||
// clamp copy size by end of directory
|
||||
U32 copy_size = 0;
|
||||
{
|
||||
U32 directory_pos = (U32)(out_ptr - directory_buf);
|
||||
U32 remaining_size = directory_size - directory_pos;
|
||||
copy_size = ClampTop(block_size, remaining_size);
|
||||
}
|
||||
|
||||
// copy block data
|
||||
MemoryCopy(out_ptr, directory_block_base, copy_size);
|
||||
out_ptr += copy_size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
parse_directory_done:;
|
||||
}
|
||||
|
||||
//- parse streams from directory
|
||||
U32 stream_count = 0;
|
||||
B32 got_streams = 0;
|
||||
String8 *streams = 0;
|
||||
|
||||
if(got_directory)
|
||||
{
|
||||
got_streams = 1;
|
||||
|
||||
// read stream count
|
||||
U32 stream_count_raw = *(U32*)(directory_buf);
|
||||
|
||||
// setup counts, sizes, and offsets
|
||||
U32 size_of_stream_entry = 4;
|
||||
if (index_size == 2){
|
||||
size_of_stream_entry = 8;
|
||||
}
|
||||
U32 stream_count_max = (directory_size - 4)/size_of_stream_entry;
|
||||
U32 stream_count__inner = ClampTop(stream_count_raw, stream_count_max);
|
||||
U32 all_stream_entries_off = 4;
|
||||
U32 all_indices_off = all_stream_entries_off + stream_count__inner*size_of_stream_entry;
|
||||
|
||||
// set output buffer and count
|
||||
stream_count = stream_count__inner;
|
||||
streams = push_array(arena, String8, stream_count);
|
||||
|
||||
// iterate sizes and indices in lock step
|
||||
U32 entry_cursor = all_stream_entries_off;
|
||||
U32 index_cursor = all_indices_off;
|
||||
String8 *stream_ptr = streams;
|
||||
for (U32 i = 0; i < stream_count; i += 1)
|
||||
{
|
||||
// read stream size
|
||||
U32 stream_size_raw = *(U32*)(directory_buf + entry_cursor);
|
||||
if (stream_size_raw == 0xffffffff){
|
||||
stream_size_raw = 0;
|
||||
}
|
||||
|
||||
// compute block count
|
||||
U32 stream_block_count_raw = CeilIntegerDiv(stream_size_raw, block_size);
|
||||
U32 stream_block_count_max = (directory_size - index_cursor)/index_size;;
|
||||
U32 stream_block_count = ClampTop(stream_block_count_raw, stream_block_count_max);
|
||||
U32 stream_size = ClampTop(stream_size_raw, stream_block_count*block_size);
|
||||
|
||||
// copy stream data
|
||||
U8 *stream_buf = push_array(arena, U8, stream_size);
|
||||
stream_ptr->str = stream_buf;
|
||||
stream_ptr->size = stream_size;
|
||||
|
||||
U32 sub_index_cursor = index_cursor;
|
||||
U8 *stream_out_ptr = stream_buf;
|
||||
for (U32 i = 0; i < stream_block_count; i += 1, sub_index_cursor += index_size){
|
||||
|
||||
// read index
|
||||
U32 stream_block_index = 0;
|
||||
if (index_size == 4){
|
||||
stream_block_index = *(U32*)(directory_buf + sub_index_cursor);
|
||||
}
|
||||
else{
|
||||
stream_block_index = *(U16*)(directory_buf + sub_index_cursor);
|
||||
}
|
||||
if (stream_block_index >= whole_file_block_count){
|
||||
got_streams = 0;
|
||||
goto parse_streams_done;
|
||||
}
|
||||
|
||||
U64 stream_block_off = (U64)(stream_block_index)*block_size;
|
||||
U8 *stream_block_base = (msf_data.str + stream_block_off);
|
||||
|
||||
// clamp copy size by end of stream
|
||||
U32 copy_size = 0;
|
||||
{
|
||||
U32 stream_pos = (U32)(stream_out_ptr - stream_buf);
|
||||
U32 remaining_size = stream_size - stream_pos;
|
||||
copy_size = ClampTop(block_size, remaining_size);
|
||||
}
|
||||
|
||||
// copy block data
|
||||
MemoryCopy(stream_out_ptr, stream_block_base, copy_size);
|
||||
stream_out_ptr += copy_size;
|
||||
}
|
||||
|
||||
// advance cursors
|
||||
entry_cursor += size_of_stream_entry;
|
||||
index_cursor = sub_index_cursor;
|
||||
stream_ptr += 1;
|
||||
}
|
||||
|
||||
parse_streams_done:;
|
||||
}
|
||||
|
||||
if(got_streams)
|
||||
{
|
||||
result = push_array(arena, MSF_Parsed, 1);
|
||||
result->streams = streams;
|
||||
result->stream_count = stream_count;
|
||||
result->block_size = block_size;
|
||||
result->block_count = whole_file_block_count;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn)
|
||||
{
|
||||
String8 result = {0};
|
||||
if(sn < msf->stream_count)
|
||||
{
|
||||
result = msf->streams[sn];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
+65
-65
@@ -1,65 +1,65 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MSF_H
|
||||
#define MSF_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Format Types
|
||||
|
||||
#define MSF_INVALID_STREAM_NUMBER 0xFFFF
|
||||
typedef U16 MSF_StreamNumber;
|
||||
|
||||
static char msf_msf20_magic[] = "Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0";
|
||||
static char msf_msf70_magic[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0";
|
||||
|
||||
#define MSF_MSF20_MAGIC_SIZE 44
|
||||
#define MSF_MSF70_MAGIC_SIZE 32
|
||||
#define MSF_MAX_MAGIC_SIZE 44
|
||||
|
||||
typedef struct MSF_Header20 MSF_Header20;
|
||||
struct MSF_Header20
|
||||
{
|
||||
U32 block_size;
|
||||
U16 free_block_map_block;
|
||||
U16 block_count;
|
||||
U32 directory_size;
|
||||
U32 unknown;
|
||||
U16 directory_map;
|
||||
};
|
||||
|
||||
typedef struct MSF_Header70 MSF_Header70;
|
||||
struct MSF_Header70
|
||||
{
|
||||
U32 block_size;
|
||||
U32 free_block_map_block;
|
||||
U32 block_count;
|
||||
U32 directory_size;
|
||||
U32 unknown;
|
||||
U32 directory_super_map;
|
||||
};
|
||||
|
||||
// magic(20) + header(20) = 44 + 20 = 64
|
||||
// magic(70) + header(70) = 32 + 24 = 56
|
||||
|
||||
#define MSF_MIN_SIZE 64
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Parser Helper Types
|
||||
|
||||
typedef struct MSF_Parsed MSF_Parsed;
|
||||
struct MSF_Parsed
|
||||
{
|
||||
String8 *streams;
|
||||
U64 stream_count;
|
||||
U64 block_size;
|
||||
U64 block_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Parser Functions
|
||||
|
||||
internal MSF_Parsed* msf_parsed_from_data(Arena *arena, String8 msf_data);
|
||||
internal String8 msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn);
|
||||
|
||||
#endif // MSF_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MSF_H
|
||||
#define MSF_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Format Types
|
||||
|
||||
#define MSF_INVALID_STREAM_NUMBER 0xFFFF
|
||||
typedef U16 MSF_StreamNumber;
|
||||
|
||||
static char msf_msf20_magic[] = "Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0";
|
||||
static char msf_msf70_magic[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0";
|
||||
|
||||
#define MSF_MSF20_MAGIC_SIZE 44
|
||||
#define MSF_MSF70_MAGIC_SIZE 32
|
||||
#define MSF_MAX_MAGIC_SIZE 44
|
||||
|
||||
typedef struct MSF_Header20 MSF_Header20;
|
||||
struct MSF_Header20
|
||||
{
|
||||
U32 block_size;
|
||||
U16 free_block_map_block;
|
||||
U16 block_count;
|
||||
U32 directory_size;
|
||||
U32 unknown;
|
||||
U16 directory_map;
|
||||
};
|
||||
|
||||
typedef struct MSF_Header70 MSF_Header70;
|
||||
struct MSF_Header70
|
||||
{
|
||||
U32 block_size;
|
||||
U32 free_block_map_block;
|
||||
U32 block_count;
|
||||
U32 directory_size;
|
||||
U32 unknown;
|
||||
U32 directory_super_map;
|
||||
};
|
||||
|
||||
// magic(20) + header(20) = 44 + 20 = 64
|
||||
// magic(70) + header(70) = 32 + 24 = 56
|
||||
|
||||
#define MSF_MIN_SIZE 64
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Parser Helper Types
|
||||
|
||||
typedef struct MSF_Parsed MSF_Parsed;
|
||||
struct MSF_Parsed
|
||||
{
|
||||
String8 *streams;
|
||||
U64 stream_count;
|
||||
U64 block_size;
|
||||
U64 block_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSF Parser Functions
|
||||
|
||||
internal MSF_Parsed* msf_parsed_from_data(Arena *arena, String8 msf_data);
|
||||
internal String8 msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn);
|
||||
|
||||
#endif // MSF_H
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
bias = (bias^x)&7;
|
||||
x -= bias;
|
||||
x *= 2;
|
||||
x *= x;
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
bias = (bias^x)&7;
|
||||
x -= bias;
|
||||
x *= 2;
|
||||
x *= x;
|
||||
x += bias;
|
||||
+106
-106
@@ -1,106 +1,106 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
/*
|
||||
* Program to run in debugger organized to provide tests for
|
||||
* single threaded stepping, breakpoints, evaluation.
|
||||
*/
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Complex Types
|
||||
|
||||
#include <complex.h>
|
||||
|
||||
void
|
||||
c_type_coverage_eval_tests(void){
|
||||
#if _WIN32
|
||||
_Fcomplex x = _FCbuild(0.f, 1.f);
|
||||
_Dcomplex y = _Cbuild(0.f, -1.f);
|
||||
|
||||
#else
|
||||
float complex x = 0.f + 1.f*I;
|
||||
double complex y = 0.0 - 1.0*I;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Reuse Type Names From Another Module
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct Basics{
|
||||
double a;
|
||||
float b;
|
||||
unsigned long long c;
|
||||
long long d;
|
||||
unsigned int e;
|
||||
int f;
|
||||
unsigned short g;
|
||||
short h;
|
||||
unsigned char i;
|
||||
char j;
|
||||
|
||||
int z;
|
||||
} Basics;
|
||||
|
||||
typedef struct Basics_Stdint{
|
||||
double x1;
|
||||
float x2;
|
||||
uint64_t x3;
|
||||
int64_t x4;
|
||||
uint32_t x5;
|
||||
int32_t x6;
|
||||
uint16_t x7;
|
||||
int16_t x8;
|
||||
uint8_t x9;
|
||||
int8_t x0;
|
||||
} Basics_Stdint;
|
||||
|
||||
typedef struct Pair{
|
||||
int i;
|
||||
float f;
|
||||
} Pair;
|
||||
|
||||
void
|
||||
c_versions_of_same_types(void){
|
||||
Basics basics = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
|
||||
Basics_Stdint basics_stdint = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
|
||||
Pair memory_[] = {
|
||||
{100, 1.f},
|
||||
{101, 2.f},
|
||||
{102, 4.f},
|
||||
{103, 8.f},
|
||||
{104, 16.f},
|
||||
{105, 32.f},
|
||||
};
|
||||
|
||||
int x = memory_[3].i + basics.f;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Bitfields
|
||||
|
||||
typedef struct TypeWithBitfield TypeWithBitfield;
|
||||
struct TypeWithBitfield
|
||||
{
|
||||
int v : 14;
|
||||
int w : 4;
|
||||
int x : 32;
|
||||
int y : 4;
|
||||
int z : 10;
|
||||
};
|
||||
|
||||
void
|
||||
c_type_with_bitfield_usage(void)
|
||||
{
|
||||
TypeWithBitfield b = {0};
|
||||
b.v = 100;
|
||||
b.w = 6;
|
||||
b.x = 434512;
|
||||
b.y = 7;
|
||||
b.z = 12;
|
||||
int x = (b.v + b.x);
|
||||
int y = (b.y - b.z);
|
||||
int z = (b.w) + 5;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
/*
|
||||
* Program to run in debugger organized to provide tests for
|
||||
* single threaded stepping, breakpoints, evaluation.
|
||||
*/
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Complex Types
|
||||
|
||||
#include <complex.h>
|
||||
|
||||
void
|
||||
c_type_coverage_eval_tests(void){
|
||||
#if _WIN32
|
||||
_Fcomplex x = _FCbuild(0.f, 1.f);
|
||||
_Dcomplex y = _Cbuild(0.f, -1.f);
|
||||
|
||||
#else
|
||||
float complex x = 0.f + 1.f*I;
|
||||
double complex y = 0.0 - 1.0*I;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Reuse Type Names From Another Module
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct Basics{
|
||||
double a;
|
||||
float b;
|
||||
unsigned long long c;
|
||||
long long d;
|
||||
unsigned int e;
|
||||
int f;
|
||||
unsigned short g;
|
||||
short h;
|
||||
unsigned char i;
|
||||
char j;
|
||||
|
||||
int z;
|
||||
} Basics;
|
||||
|
||||
typedef struct Basics_Stdint{
|
||||
double x1;
|
||||
float x2;
|
||||
uint64_t x3;
|
||||
int64_t x4;
|
||||
uint32_t x5;
|
||||
int32_t x6;
|
||||
uint16_t x7;
|
||||
int16_t x8;
|
||||
uint8_t x9;
|
||||
int8_t x0;
|
||||
} Basics_Stdint;
|
||||
|
||||
typedef struct Pair{
|
||||
int i;
|
||||
float f;
|
||||
} Pair;
|
||||
|
||||
void
|
||||
c_versions_of_same_types(void){
|
||||
Basics basics = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
|
||||
Basics_Stdint basics_stdint = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
|
||||
Pair memory_[] = {
|
||||
{100, 1.f},
|
||||
{101, 2.f},
|
||||
{102, 4.f},
|
||||
{103, 8.f},
|
||||
{104, 16.f},
|
||||
{105, 32.f},
|
||||
};
|
||||
|
||||
int x = memory_[3].i + basics.f;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Bitfields
|
||||
|
||||
typedef struct TypeWithBitfield TypeWithBitfield;
|
||||
struct TypeWithBitfield
|
||||
{
|
||||
int v : 14;
|
||||
int w : 4;
|
||||
int x : 32;
|
||||
int y : 4;
|
||||
int z : 10;
|
||||
};
|
||||
|
||||
void
|
||||
c_type_with_bitfield_usage(void)
|
||||
{
|
||||
TypeWithBitfield b = {0};
|
||||
b.v = 100;
|
||||
b.w = 6;
|
||||
b.x = 434512;
|
||||
b.y = 7;
|
||||
b.z = 12;
|
||||
int x = (b.v + b.x);
|
||||
int y = (b.y - b.z);
|
||||
int z = (b.w) + 5;
|
||||
}
|
||||
|
||||
+9
-9
@@ -1,10 +1,10 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
/*
|
||||
* Program to run in debugger organized to provide tests for
|
||||
* single threaded stepping, breakpoints, evaluation.
|
||||
*/
|
||||
|
||||
void c_type_coverage_eval_tests(void);
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
/*
|
||||
* Program to run in debugger organized to provide tests for
|
||||
* single threaded stepping, breakpoints, evaluation.
|
||||
*/
|
||||
|
||||
void c_type_coverage_eval_tests(void);
|
||||
void c_type_with_bitfield_usage(void);
|
||||
@@ -1,48 +1,48 @@
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int lib_loaded = 0;
|
||||
HANDLE lib = {0};
|
||||
FILETIME lib_last_filetime = {0};
|
||||
int (*get_number)(void) = 0;
|
||||
for(;;)
|
||||
{
|
||||
//- rjf: hot-load dll
|
||||
{
|
||||
HANDLE file = CreateFileA("mule_hotload_module.dll", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILETIME modified = {0};
|
||||
if(GetFileTime(file, 0, 0, &modified) &&
|
||||
CompareFileTime(&lib_last_filetime, &modified) == -1)
|
||||
{
|
||||
for(int reloaded = 0; !reloaded;)
|
||||
{
|
||||
if(lib_loaded)
|
||||
{
|
||||
FreeLibrary(lib);
|
||||
lib_loaded = 0;
|
||||
}
|
||||
BOOL copy_worked = CopyFile("mule_hotload_module.dll", "mule_hotload_module_temp.dll", 0);
|
||||
lib = LoadLibraryA("mule_hotload_module_temp.dll");
|
||||
if(lib != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
reloaded = 1;
|
||||
lib_last_filetime = modified;
|
||||
get_number = (int(*)(void))GetProcAddress(lib, "get_number");
|
||||
lib_loaded = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(file);
|
||||
}
|
||||
int number = get_number();
|
||||
printf("got a number: %i\n", number);
|
||||
if(number == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Sleep(1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int lib_loaded = 0;
|
||||
HANDLE lib = {0};
|
||||
FILETIME lib_last_filetime = {0};
|
||||
int (*get_number)(void) = 0;
|
||||
for(;;)
|
||||
{
|
||||
//- rjf: hot-load dll
|
||||
{
|
||||
HANDLE file = CreateFileA("mule_hotload_module.dll", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILETIME modified = {0};
|
||||
if(GetFileTime(file, 0, 0, &modified) &&
|
||||
CompareFileTime(&lib_last_filetime, &modified) == -1)
|
||||
{
|
||||
for(int reloaded = 0; !reloaded;)
|
||||
{
|
||||
if(lib_loaded)
|
||||
{
|
||||
FreeLibrary(lib);
|
||||
lib_loaded = 0;
|
||||
}
|
||||
BOOL copy_worked = CopyFile("mule_hotload_module.dll", "mule_hotload_module_temp.dll", 0);
|
||||
lib = LoadLibraryA("mule_hotload_module_temp.dll");
|
||||
if(lib != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
reloaded = 1;
|
||||
lib_last_filetime = modified;
|
||||
get_number = (int(*)(void))GetProcAddress(lib, "get_number");
|
||||
lib_loaded = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(file);
|
||||
}
|
||||
int number = get_number();
|
||||
printf("got a number: %i\n", number);
|
||||
if(number == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Sleep(1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
__declspec(dllexport) int
|
||||
get_number(void)
|
||||
{
|
||||
int sum = 0;
|
||||
for(int i = 0; i < 100; i += 1)
|
||||
{
|
||||
sum += i;
|
||||
sum += i;
|
||||
sum += 1;
|
||||
}
|
||||
sum = 1000;
|
||||
return sum;
|
||||
}
|
||||
__declspec(dllexport) int
|
||||
get_number(void)
|
||||
{
|
||||
int sum = 0;
|
||||
for(int i = 0; i < 100; i += 1)
|
||||
{
|
||||
sum += i;
|
||||
sum += i;
|
||||
sum += 1;
|
||||
}
|
||||
sum = 1000;
|
||||
return sum;
|
||||
}
|
||||
|
||||
+42
-42
@@ -1,42 +1,42 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if _WIN32
|
||||
#define export_function extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define export_function extern "C"
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
# define thread_var __declspec(thread)
|
||||
#else
|
||||
# define thread_var __thread
|
||||
#endif
|
||||
|
||||
typedef struct Basics Basics;
|
||||
struct Basics
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
};
|
||||
|
||||
thread_var float tls_a = 1.015625f;
|
||||
thread_var int tls_b = -100;
|
||||
|
||||
export_function void
|
||||
dll_tls_eval_test(void)
|
||||
{
|
||||
tls_a *= 1.5f;
|
||||
tls_b *= -2;
|
||||
}
|
||||
|
||||
export_function void
|
||||
dll_type_eval_tests(void)
|
||||
{
|
||||
Basics basics1 = {1, 2, 3, 4};
|
||||
Basics basics2 = {4, 5, 6, 7};
|
||||
int x = 0;
|
||||
(void)x;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if _WIN32
|
||||
#define export_function extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define export_function extern "C"
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
# define thread_var __declspec(thread)
|
||||
#else
|
||||
# define thread_var __thread
|
||||
#endif
|
||||
|
||||
typedef struct Basics Basics;
|
||||
struct Basics
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
};
|
||||
|
||||
thread_var float tls_a = 1.015625f;
|
||||
thread_var int tls_b = -100;
|
||||
|
||||
export_function void
|
||||
dll_tls_eval_test(void)
|
||||
{
|
||||
tls_a *= 1.5f;
|
||||
tls_b *= -2;
|
||||
}
|
||||
|
||||
export_function void
|
||||
dll_type_eval_tests(void)
|
||||
{
|
||||
Basics basics1 = {1, 2, 3, 4};
|
||||
Basics basics2 = {4, 5, 6, 7};
|
||||
int x = 0;
|
||||
(void)x;
|
||||
}
|
||||
|
||||
+119
-119
@@ -1,119 +1,119 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
static int important_s32 = 0;
|
||||
static float important_f32 = 0;
|
||||
|
||||
#if _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
do_something_with_intermediate_values(void)
|
||||
{
|
||||
static int another_important_s32 = 0;
|
||||
static float another_important_f32 = 0;
|
||||
|
||||
another_important_s32 = (int)important_f32;
|
||||
another_important_f32 = (float)important_s32;
|
||||
|
||||
#if _WIN32
|
||||
char buffer[256] = "Hello, World!\n";
|
||||
buffer[0] += important_s32 + another_important_s32;
|
||||
buffer[1] += (int)another_important_f32 * important_f32;
|
||||
OutputDebugStringA(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
store_important_s32(int *ptr)
|
||||
{
|
||||
important_s32 = *ptr;
|
||||
}
|
||||
|
||||
static void
|
||||
store_important_f32(float *ptr)
|
||||
{
|
||||
important_f32 = *ptr;
|
||||
}
|
||||
|
||||
void
|
||||
optimized_build_eval_tests(void)
|
||||
{
|
||||
int simple_sum = 0;
|
||||
for(int i = 0; i < 10000; i += 1)
|
||||
{
|
||||
simple_sum += i;
|
||||
}
|
||||
store_important_s32(&simple_sum);
|
||||
|
||||
do_something_with_intermediate_values();
|
||||
|
||||
static struct {float x, y;} vec2s[] =
|
||||
{
|
||||
{ 10.f, 76.f },
|
||||
{ 40.f, 50.f },
|
||||
{ -230.f, 20.f },
|
||||
{ 27.f, 27.f },
|
||||
{ 57.f, -57.f },
|
||||
{ -37.f, 97.f },
|
||||
{ 99.f, 67.f },
|
||||
{ 99.f, 37.f },
|
||||
{ 99.f, 57.f },
|
||||
};
|
||||
{
|
||||
struct{float x, y;}sum = {0};
|
||||
int count = sizeof(vec2s)/sizeof(vec2s[0]);
|
||||
for(int i = 0; i < count; i += 1)
|
||||
{
|
||||
sum.x += vec2s[i].x;
|
||||
sum.y += vec2s[i].y;
|
||||
}
|
||||
struct{float x, y;}avg = {sum.x/count, sum.y/count};
|
||||
float f32 = avg.x * avg.y;
|
||||
store_important_f32(&f32);
|
||||
}
|
||||
|
||||
do_something_with_intermediate_values();
|
||||
|
||||
int factorial = 1;
|
||||
for(int i = 10; i > 0; i -= 1)
|
||||
{
|
||||
factorial *= i;
|
||||
}
|
||||
store_important_s32(&factorial);
|
||||
|
||||
do_something_with_intermediate_values();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Struct Parameters Eval
|
||||
|
||||
struct OptimizedBasics{
|
||||
char a;
|
||||
unsigned char b;
|
||||
short c;
|
||||
unsigned short d;
|
||||
int e;
|
||||
unsigned int f;
|
||||
long long g;
|
||||
unsigned long long h;
|
||||
float i;
|
||||
double j;
|
||||
};
|
||||
|
||||
static void
|
||||
optimized_struct_parameter_helper(int *ptr, OptimizedBasics basics)
|
||||
{
|
||||
basics.a += *ptr;
|
||||
basics.a += 1;
|
||||
basics.a += 1;
|
||||
}
|
||||
|
||||
void
|
||||
optimized_struct_parameters_eval_tests(void)
|
||||
{
|
||||
int x = 10;
|
||||
OptimizedBasics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
|
||||
optimized_struct_parameter_helper(&x, basics);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
static int important_s32 = 0;
|
||||
static float important_f32 = 0;
|
||||
|
||||
#if _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
do_something_with_intermediate_values(void)
|
||||
{
|
||||
static int another_important_s32 = 0;
|
||||
static float another_important_f32 = 0;
|
||||
|
||||
another_important_s32 = (int)important_f32;
|
||||
another_important_f32 = (float)important_s32;
|
||||
|
||||
#if _WIN32
|
||||
char buffer[256] = "Hello, World!\n";
|
||||
buffer[0] += important_s32 + another_important_s32;
|
||||
buffer[1] += (int)another_important_f32 * important_f32;
|
||||
OutputDebugStringA(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
store_important_s32(int *ptr)
|
||||
{
|
||||
important_s32 = *ptr;
|
||||
}
|
||||
|
||||
static void
|
||||
store_important_f32(float *ptr)
|
||||
{
|
||||
important_f32 = *ptr;
|
||||
}
|
||||
|
||||
void
|
||||
optimized_build_eval_tests(void)
|
||||
{
|
||||
int simple_sum = 0;
|
||||
for(int i = 0; i < 10000; i += 1)
|
||||
{
|
||||
simple_sum += i;
|
||||
}
|
||||
store_important_s32(&simple_sum);
|
||||
|
||||
do_something_with_intermediate_values();
|
||||
|
||||
static struct {float x, y;} vec2s[] =
|
||||
{
|
||||
{ 10.f, 76.f },
|
||||
{ 40.f, 50.f },
|
||||
{ -230.f, 20.f },
|
||||
{ 27.f, 27.f },
|
||||
{ 57.f, -57.f },
|
||||
{ -37.f, 97.f },
|
||||
{ 99.f, 67.f },
|
||||
{ 99.f, 37.f },
|
||||
{ 99.f, 57.f },
|
||||
};
|
||||
{
|
||||
struct{float x, y;}sum = {0};
|
||||
int count = sizeof(vec2s)/sizeof(vec2s[0]);
|
||||
for(int i = 0; i < count; i += 1)
|
||||
{
|
||||
sum.x += vec2s[i].x;
|
||||
sum.y += vec2s[i].y;
|
||||
}
|
||||
struct{float x, y;}avg = {sum.x/count, sum.y/count};
|
||||
float f32 = avg.x * avg.y;
|
||||
store_important_f32(&f32);
|
||||
}
|
||||
|
||||
do_something_with_intermediate_values();
|
||||
|
||||
int factorial = 1;
|
||||
for(int i = 10; i > 0; i -= 1)
|
||||
{
|
||||
factorial *= i;
|
||||
}
|
||||
store_important_s32(&factorial);
|
||||
|
||||
do_something_with_intermediate_values();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Struct Parameters Eval
|
||||
|
||||
struct OptimizedBasics{
|
||||
char a;
|
||||
unsigned char b;
|
||||
short c;
|
||||
unsigned short d;
|
||||
int e;
|
||||
unsigned int f;
|
||||
long long g;
|
||||
unsigned long long h;
|
||||
float i;
|
||||
double j;
|
||||
};
|
||||
|
||||
static void
|
||||
optimized_struct_parameter_helper(int *ptr, OptimizedBasics basics)
|
||||
{
|
||||
basics.a += *ptr;
|
||||
basics.a += 1;
|
||||
basics.a += 1;
|
||||
}
|
||||
|
||||
void
|
||||
optimized_struct_parameters_eval_tests(void)
|
||||
{
|
||||
int x = 10;
|
||||
OptimizedBasics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
|
||||
optimized_struct_parameter_helper(&x, basics);
|
||||
}
|
||||
|
||||
+61
-61
@@ -1,61 +1,61 @@
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include "mule_peb_trample_reload.c"
|
||||
|
||||
static void
|
||||
HideModuleFromWindowsReload(HMODULE ModuleToFlush)
|
||||
{
|
||||
/* NOTE(casey): Normally you cannot "reload" an executable module with the same name,
|
||||
because Windows checks a linked list of loaded modules and assumes that if
|
||||
it's already loaded, it doesn't need to reload it, even though it may have to because
|
||||
it has changed on disk.
|
||||
|
||||
This solution to that problem comes from some excellent spelunking by Martins Mozeiko,
|
||||
who figured out that you could overwrite the filenames Windows stores in your process's
|
||||
loaded module table, thus thwarting the Windows filename check against loaded modules,
|
||||
allowing you to reload an existing module that has changed without requiring it to
|
||||
have a different filename!
|
||||
*/
|
||||
|
||||
PEB *Peb = (PEB *)__readgsqword(offsetof(TEB, ProcessEnvironmentBlock));
|
||||
LIST_ENTRY *Head = &Peb->Ldr->InMemoryOrderModuleList;
|
||||
for(LIST_ENTRY *Entry = Head->Flink;
|
||||
Entry != Head;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
LDR_DATA_TABLE_ENTRY *Mod = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
|
||||
if(Mod->DllBase == ModuleToFlush)
|
||||
{
|
||||
ZeroMemory(Mod->FullDllName.Buffer, Mod->FullDllName.Length);
|
||||
Mod->DllBase = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argument_count, char **arguments)
|
||||
{
|
||||
char *exe_name = arguments[0];
|
||||
HANDLE last_module = GetModuleHandle(0);
|
||||
int (*loop_iteration_function)(int it) = (int (*)(int))GetProcAddress(last_module, "loop_iteration");
|
||||
FILETIME last_filetime = {0};
|
||||
int should_exit = 0;
|
||||
for(int it = 0; !should_exit; it += 1)
|
||||
{
|
||||
int result = loop_iteration_function(it);
|
||||
printf("%i\n", result);
|
||||
Sleep(50);
|
||||
FILETIME current_filetime = {0};
|
||||
HANDLE current_exe_file = CreateFile(exe_name, 0, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
GetFileTime(current_exe_file, 0, 0, ¤t_filetime);
|
||||
CloseHandle(current_exe_file);
|
||||
if(it != 0 && CompareFileTime(&last_filetime, ¤t_filetime) < 0)
|
||||
{
|
||||
HideModuleFromWindowsReload(last_module);
|
||||
last_module = LoadLibrary(arguments[0]);
|
||||
loop_iteration_function = (int (*)(int))GetProcAddress(last_module, "loop_iteration");
|
||||
}
|
||||
last_filetime = current_filetime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include "mule_peb_trample_reload.c"
|
||||
|
||||
static void
|
||||
HideModuleFromWindowsReload(HMODULE ModuleToFlush)
|
||||
{
|
||||
/* NOTE(casey): Normally you cannot "reload" an executable module with the same name,
|
||||
because Windows checks a linked list of loaded modules and assumes that if
|
||||
it's already loaded, it doesn't need to reload it, even though it may have to because
|
||||
it has changed on disk.
|
||||
|
||||
This solution to that problem comes from some excellent spelunking by Martins Mozeiko,
|
||||
who figured out that you could overwrite the filenames Windows stores in your process's
|
||||
loaded module table, thus thwarting the Windows filename check against loaded modules,
|
||||
allowing you to reload an existing module that has changed without requiring it to
|
||||
have a different filename!
|
||||
*/
|
||||
|
||||
PEB *Peb = (PEB *)__readgsqword(offsetof(TEB, ProcessEnvironmentBlock));
|
||||
LIST_ENTRY *Head = &Peb->Ldr->InMemoryOrderModuleList;
|
||||
for(LIST_ENTRY *Entry = Head->Flink;
|
||||
Entry != Head;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
LDR_DATA_TABLE_ENTRY *Mod = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
|
||||
if(Mod->DllBase == ModuleToFlush)
|
||||
{
|
||||
ZeroMemory(Mod->FullDllName.Buffer, Mod->FullDllName.Length);
|
||||
Mod->DllBase = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argument_count, char **arguments)
|
||||
{
|
||||
char *exe_name = arguments[0];
|
||||
HANDLE last_module = GetModuleHandle(0);
|
||||
int (*loop_iteration_function)(int it) = (int (*)(int))GetProcAddress(last_module, "loop_iteration");
|
||||
FILETIME last_filetime = {0};
|
||||
int should_exit = 0;
|
||||
for(int it = 0; !should_exit; it += 1)
|
||||
{
|
||||
int result = loop_iteration_function(it);
|
||||
printf("%i\n", result);
|
||||
Sleep(50);
|
||||
FILETIME current_filetime = {0};
|
||||
HANDLE current_exe_file = CreateFile(exe_name, 0, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
GetFileTime(current_exe_file, 0, 0, ¤t_filetime);
|
||||
CloseHandle(current_exe_file);
|
||||
if(it != 0 && CompareFileTime(&last_filetime, ¤t_filetime) < 0)
|
||||
{
|
||||
HideModuleFromWindowsReload(last_module);
|
||||
last_module = LoadLibrary(arguments[0]);
|
||||
loop_iteration_function = (int (*)(int))GetProcAddress(last_module, "loop_iteration");
|
||||
}
|
||||
last_filetime = current_filetime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
__declspec(dllexport) int
|
||||
loop_iteration(int it)
|
||||
{
|
||||
//return 111;
|
||||
#if 1
|
||||
int sum = 0;
|
||||
for(int i = 0; i < 1000; i += 1)
|
||||
{
|
||||
sum += it*i;
|
||||
}
|
||||
return sum;
|
||||
#endif
|
||||
}
|
||||
__declspec(dllexport) int
|
||||
loop_iteration(int it)
|
||||
{
|
||||
//return 111;
|
||||
#if 1
|
||||
int sum = 0;
|
||||
for(int i = 0; i < 1000; i += 1)
|
||||
{
|
||||
sum += it*i;
|
||||
}
|
||||
return sum;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MUTABLE_TEXT_H
|
||||
#define MUTABLE_TEXT_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct MTX_Node MTX_Node;
|
||||
struct MTX_Node
|
||||
{
|
||||
MTX_Node *next;
|
||||
MTX_Node *prev;
|
||||
U128 key;
|
||||
};
|
||||
|
||||
typedef struct MTX_Slot MTX_Slot;
|
||||
struct MTX_Slot
|
||||
{
|
||||
MTX_Node *first;
|
||||
MTX_Node *last;
|
||||
};
|
||||
|
||||
typedef struct MTX_Stripe MTX_Stripe;
|
||||
struct MTX_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
MTX_Node *free_node;
|
||||
OS_Handle rw_mutex;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Mutation Thread Types
|
||||
|
||||
typedef struct MTX_Op MTX_Op;
|
||||
struct MTX_Op
|
||||
{
|
||||
Rng1U64 range;
|
||||
String8 replace;
|
||||
};
|
||||
|
||||
typedef struct MTX_MutThread MTX_MutThread;
|
||||
struct MTX_MutThread
|
||||
{
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_read_pos;
|
||||
U64 ring_write_pos;
|
||||
OS_Handle cv;
|
||||
OS_Handle mutex;
|
||||
OS_Handle thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct MTX_Shared MTX_Shared;
|
||||
struct MTX_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: buffer cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
MTX_Slot *slots;
|
||||
MTX_Stripe *stripes;
|
||||
|
||||
// rjf: mut threads
|
||||
U64 mut_threads_count;
|
||||
MTX_MutThread *mut_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global MTX_Shared *mtx_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void mtx_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Buffer Operations
|
||||
|
||||
internal void mtx_push_op(U128 buffer_key, MTX_Op op);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Mutation Threads
|
||||
|
||||
internal void mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op);
|
||||
internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out);
|
||||
internal void mtx_mut_thread__entry_point(void *p);
|
||||
|
||||
#endif // MUTABLE_TEXT_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MUTABLE_TEXT_H
|
||||
#define MUTABLE_TEXT_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct MTX_Node MTX_Node;
|
||||
struct MTX_Node
|
||||
{
|
||||
MTX_Node *next;
|
||||
MTX_Node *prev;
|
||||
U128 key;
|
||||
};
|
||||
|
||||
typedef struct MTX_Slot MTX_Slot;
|
||||
struct MTX_Slot
|
||||
{
|
||||
MTX_Node *first;
|
||||
MTX_Node *last;
|
||||
};
|
||||
|
||||
typedef struct MTX_Stripe MTX_Stripe;
|
||||
struct MTX_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
MTX_Node *free_node;
|
||||
OS_Handle rw_mutex;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Mutation Thread Types
|
||||
|
||||
typedef struct MTX_Op MTX_Op;
|
||||
struct MTX_Op
|
||||
{
|
||||
Rng1U64 range;
|
||||
String8 replace;
|
||||
};
|
||||
|
||||
typedef struct MTX_MutThread MTX_MutThread;
|
||||
struct MTX_MutThread
|
||||
{
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_read_pos;
|
||||
U64 ring_write_pos;
|
||||
OS_Handle cv;
|
||||
OS_Handle mutex;
|
||||
OS_Handle thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct MTX_Shared MTX_Shared;
|
||||
struct MTX_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: buffer cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
MTX_Slot *slots;
|
||||
MTX_Stripe *stripes;
|
||||
|
||||
// rjf: mut threads
|
||||
U64 mut_threads_count;
|
||||
MTX_MutThread *mut_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global MTX_Shared *mtx_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void mtx_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Buffer Operations
|
||||
|
||||
internal void mtx_push_op(U128 buffer_key, MTX_Op op);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Mutation Threads
|
||||
|
||||
internal void mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op);
|
||||
internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out);
|
||||
internal void mtx_mut_thread__entry_point(void *p);
|
||||
|
||||
#endif // MUTABLE_TEXT_H
|
||||
|
||||
+161
-161
@@ -1,161 +1,161 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="String8">
|
||||
<DisplayString>{size,str}</DisplayString>
|
||||
<StringView>size,str</StringView>
|
||||
</Type>
|
||||
|
||||
<Type Name="String8Node">
|
||||
<DisplayString>{{ string={string.size,string.str} next={next} }}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="String8List">
|
||||
<DisplayString Condition="node_count == 0">empty</DisplayString>
|
||||
<DisplayString>{{node count={node_count} total size={total_size} first={first->string} last={last->string} }} </DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[node count]">node_count</Item>
|
||||
<Item Name="[total size]">total_size</Item>
|
||||
<LinkedListItems>
|
||||
<Size>node_count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>string</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="String8Array">
|
||||
<DisplayString>{{ count={count} pointer={strings} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>strings</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec2F32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="[length squared]">x*x + y*y</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec2S32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="[length squared]">x*x + y*y</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec2S64">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="[length squared]">x*x + y*y</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec3F32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec3S32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec4F32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="w">w</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z + w*w</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec4S32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="w">w</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z + w*w</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1U32">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1S32">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1U64">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1S64">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1F32">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="CmdLineOpt">
|
||||
<DisplayString>{{ name={string} hash={hash} value_string={value_string} value_stirngs={value_strings} }}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="CmdLineOptList">
|
||||
<DisplayString>{{ count={count} first={first} }} </DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="String8">
|
||||
<DisplayString>{size,str}</DisplayString>
|
||||
<StringView>size,str</StringView>
|
||||
</Type>
|
||||
|
||||
<Type Name="String8Node">
|
||||
<DisplayString>{{ string={string.size,string.str} next={next} }}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="String8List">
|
||||
<DisplayString Condition="node_count == 0">empty</DisplayString>
|
||||
<DisplayString>{{node count={node_count} total size={total_size} first={first->string} last={last->string} }} </DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[node count]">node_count</Item>
|
||||
<Item Name="[total size]">total_size</Item>
|
||||
<LinkedListItems>
|
||||
<Size>node_count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>string</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="String8Array">
|
||||
<DisplayString>{{ count={count} pointer={strings} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>strings</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec2F32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="[length squared]">x*x + y*y</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec2S32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="[length squared]">x*x + y*y</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec2S64">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="[length squared]">x*x + y*y</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec3F32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec3S32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec4F32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="w">w</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z + w*w</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Vec4S32">
|
||||
<Expand>
|
||||
<Item Name="x">x</Item>
|
||||
<Item Name="y">y</Item>
|
||||
<Item Name="z">z</Item>
|
||||
<Item Name="w">w</Item>
|
||||
<Item Name="[length squared]">x*x + y*y + z*z + w*w</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1U32">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1S32">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1U64">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1S64">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1F32">
|
||||
<DisplayString>{{ min={min} max={max} [dim]={max - min} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="min">min</Item>
|
||||
<Item Name="max">max</Item>
|
||||
<Item Name="[dim]">max - min</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="CmdLineOpt">
|
||||
<DisplayString>{{ name={string} hash={hash} value_string={value_string} value_stirngs={value_strings} }}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="CmdLineOptList">
|
||||
<DisplayString>{{ count={count} first={first} }} </DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
|
||||
+172
-172
@@ -1,172 +1,172 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tables
|
||||
|
||||
@table(name, display_string, cfg_string)
|
||||
OS_KeyTable:
|
||||
{
|
||||
{Null "Invalid Key" "null" }
|
||||
{Esc "Escape" "esc" }
|
||||
{F1 "F1" "f1" }
|
||||
{F2 "F2" "f2" }
|
||||
{F3 "F3" "f3" }
|
||||
{F4 "F4" "f4" }
|
||||
{F5 "F5" "f5" }
|
||||
{F6 "F6" "f6" }
|
||||
{F7 "F7" "f7" }
|
||||
{F8 "F8" "f8" }
|
||||
{F9 "F9" "f9" }
|
||||
{F10 "F10" "f10" }
|
||||
{F11 "F11" "f11" }
|
||||
{F12 "F12" "f12" }
|
||||
{F13 "F13" "f13" }
|
||||
{F14 "F14" "f14" }
|
||||
{F15 "F15" "f15" }
|
||||
{F16 "F16" "f16" }
|
||||
{F17 "F17" "f17" }
|
||||
{F18 "F18" "f18" }
|
||||
{F19 "F19" "f19" }
|
||||
{F20 "F20" "f20" }
|
||||
{F21 "F21" "f21" }
|
||||
{F22 "F22" "f22" }
|
||||
{F23 "F23" "f23" }
|
||||
{F24 "F24" "f24" }
|
||||
{Tick "Tick" "tick" }
|
||||
{0 "0" "0" }
|
||||
{1 "1" "1" }
|
||||
{2 "2" "2" }
|
||||
{3 "3" "3" }
|
||||
{4 "4" "4" }
|
||||
{5 "5" "5" }
|
||||
{6 "6" "6" }
|
||||
{7 "7" "7" }
|
||||
{8 "8" "8" }
|
||||
{9 "9" "9" }
|
||||
{Minus "Minus" "minus" }
|
||||
{Equal "Equal" "equal" }
|
||||
{Backspace "Backspace" "backspace" }
|
||||
{Tab "Tab" "tab" }
|
||||
{Q "Q" "q" }
|
||||
{W "W" "w" }
|
||||
{E "E" "e" }
|
||||
{R "R" "r" }
|
||||
{T "T" "t" }
|
||||
{Y "Y" "y" }
|
||||
{U "U" "u" }
|
||||
{I "I" "i" }
|
||||
{O "O" "o" }
|
||||
{P "P" "p" }
|
||||
{LeftBracket "Left Bracket" "left_bracket" }
|
||||
{RightBracket "Right Bracket" "right_bracket" }
|
||||
{BackSlash "Back Slash" "backslash" }
|
||||
{CapsLock "Caps Lock" "caps_lock" }
|
||||
{A "A" "a" }
|
||||
{S "S" "s" }
|
||||
{D "D" "d" }
|
||||
{F "F" "f" }
|
||||
{G "G" "g" }
|
||||
{H "H" "h" }
|
||||
{J "J" "j" }
|
||||
{K "K" "k" }
|
||||
{L "L" "l" }
|
||||
{Semicolon "Semicolon" "semicolon" }
|
||||
{Quote "Quote" "quote" }
|
||||
{Return "Return" "return" }
|
||||
{Shift "Shift" "shift" }
|
||||
{Z "Z" "z" }
|
||||
{X "X" "x" }
|
||||
{C "C" "c" }
|
||||
{V "V" "v" }
|
||||
{B "B" "b" }
|
||||
{N "N" "n" }
|
||||
{M "M" "m" }
|
||||
{Comma "Comma" "comma" }
|
||||
{Period "Period" "period" }
|
||||
{Slash "Slash" "slash" }
|
||||
{Ctrl "Ctrl" "ctrl" }
|
||||
{Alt "Alt" "alt" }
|
||||
{Space "Space" "space" }
|
||||
{Menu "Menu" "menu" }
|
||||
{ScrollLock "Scroll Lock" "scroll_lock" }
|
||||
{Pause "Pause" "pause" }
|
||||
{Insert "Insert" "insert" }
|
||||
{Home "Home" "home" }
|
||||
{PageUp "Page Up" "page_up" }
|
||||
{Delete "Delete" "delete" }
|
||||
{End "End" "end" }
|
||||
{PageDown "Page Down" "page_down" }
|
||||
{Up "Up" "up" }
|
||||
{Left "Left" "left" }
|
||||
{Down "Down" "down" }
|
||||
{Right "Right" "right" }
|
||||
{Ex0 "Ex0" "ex0" }
|
||||
{Ex1 "Ex1" "ex1" }
|
||||
{Ex2 "Ex2" "ex2" }
|
||||
{Ex3 "Ex3" "ex3" }
|
||||
{Ex4 "Ex4" "ex4" }
|
||||
{Ex5 "Ex5" "ex5" }
|
||||
{Ex6 "Ex6" "ex6" }
|
||||
{Ex7 "Ex7" "ex7" }
|
||||
{Ex8 "Ex8" "ex8" }
|
||||
{Ex9 "Ex9" "ex9" }
|
||||
{Ex10 "Ex10" "ex10" }
|
||||
{Ex11 "Ex11" "ex11" }
|
||||
{Ex12 "Ex12" "ex12" }
|
||||
{Ex13 "Ex13" "ex13" }
|
||||
{Ex14 "Ex14" "ex14" }
|
||||
{Ex15 "Ex15" "ex15" }
|
||||
{Ex16 "Ex16" "ex16" }
|
||||
{Ex17 "Ex17" "ex17" }
|
||||
{Ex18 "Ex18" "ex18" }
|
||||
{Ex19 "Ex19" "ex19" }
|
||||
{Ex20 "Ex20" "ex20" }
|
||||
{Ex21 "Ex21" "ex21" }
|
||||
{Ex22 "Ex22" "ex22" }
|
||||
{Ex23 "Ex23" "ex23" }
|
||||
{Ex24 "Ex24" "ex24" }
|
||||
{Ex25 "Ex25" "ex25" }
|
||||
{Ex26 "Ex26" "ex26" }
|
||||
{Ex27 "Ex27" "ex27" }
|
||||
{Ex28 "Ex28" "ex28" }
|
||||
{Ex29 "Ex29" "ex29" }
|
||||
{NumLock "Num Lock" "num_lock" }
|
||||
{NumSlash "Numpad Slash" "numpad_slash" }
|
||||
{NumStar "Numpad Star" "numpad_star" }
|
||||
{NumMinus "Numpad Minus" "numpad_minus" }
|
||||
{NumPlus "Numpad Plus" "numpad_plus" }
|
||||
{NumPeriod "Numpad Period" "numpad_period" }
|
||||
{Num0 "Numpad 0" "numpad_0" }
|
||||
{Num1 "Numpad 1" "numpad_1" }
|
||||
{Num2 "Numpad 2" "numpad_2" }
|
||||
{Num3 "Numpad 3" "numpad_3" }
|
||||
{Num4 "Numpad 4" "numpad_4" }
|
||||
{Num5 "Numpad 5" "numpad_5" }
|
||||
{Num6 "Numpad 6" "numpad_6" }
|
||||
{Num7 "Numpad 7" "numpad_7" }
|
||||
{Num8 "Numpad 8" "numpad_8" }
|
||||
{Num9 "Numpad 9" "numpad_9" }
|
||||
{LeftMouseButton "Left Mouse Button" "left_mouse" }
|
||||
{MiddleMouseButton "Middle Mouse Button" "middle_mouse" }
|
||||
{RightMouseButton "Right Mouse Button" "right_mouse" }
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@enum OS_Key:
|
||||
{
|
||||
@expand(OS_KeyTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@data(String8) os_g_key_display_string_table:
|
||||
{
|
||||
@expand(OS_KeyTable a) `str8_lit_comp("$(a.display_string)")`;
|
||||
}
|
||||
|
||||
@data(String8) os_g_key_cfg_string_table:
|
||||
{
|
||||
@expand(OS_KeyTable a) `str8_lit_comp("$(a.cfg_string)")`;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tables
|
||||
|
||||
@table(name, display_string, cfg_string)
|
||||
OS_KeyTable:
|
||||
{
|
||||
{Null "Invalid Key" "null" }
|
||||
{Esc "Escape" "esc" }
|
||||
{F1 "F1" "f1" }
|
||||
{F2 "F2" "f2" }
|
||||
{F3 "F3" "f3" }
|
||||
{F4 "F4" "f4" }
|
||||
{F5 "F5" "f5" }
|
||||
{F6 "F6" "f6" }
|
||||
{F7 "F7" "f7" }
|
||||
{F8 "F8" "f8" }
|
||||
{F9 "F9" "f9" }
|
||||
{F10 "F10" "f10" }
|
||||
{F11 "F11" "f11" }
|
||||
{F12 "F12" "f12" }
|
||||
{F13 "F13" "f13" }
|
||||
{F14 "F14" "f14" }
|
||||
{F15 "F15" "f15" }
|
||||
{F16 "F16" "f16" }
|
||||
{F17 "F17" "f17" }
|
||||
{F18 "F18" "f18" }
|
||||
{F19 "F19" "f19" }
|
||||
{F20 "F20" "f20" }
|
||||
{F21 "F21" "f21" }
|
||||
{F22 "F22" "f22" }
|
||||
{F23 "F23" "f23" }
|
||||
{F24 "F24" "f24" }
|
||||
{Tick "Tick" "tick" }
|
||||
{0 "0" "0" }
|
||||
{1 "1" "1" }
|
||||
{2 "2" "2" }
|
||||
{3 "3" "3" }
|
||||
{4 "4" "4" }
|
||||
{5 "5" "5" }
|
||||
{6 "6" "6" }
|
||||
{7 "7" "7" }
|
||||
{8 "8" "8" }
|
||||
{9 "9" "9" }
|
||||
{Minus "Minus" "minus" }
|
||||
{Equal "Equal" "equal" }
|
||||
{Backspace "Backspace" "backspace" }
|
||||
{Tab "Tab" "tab" }
|
||||
{Q "Q" "q" }
|
||||
{W "W" "w" }
|
||||
{E "E" "e" }
|
||||
{R "R" "r" }
|
||||
{T "T" "t" }
|
||||
{Y "Y" "y" }
|
||||
{U "U" "u" }
|
||||
{I "I" "i" }
|
||||
{O "O" "o" }
|
||||
{P "P" "p" }
|
||||
{LeftBracket "Left Bracket" "left_bracket" }
|
||||
{RightBracket "Right Bracket" "right_bracket" }
|
||||
{BackSlash "Back Slash" "backslash" }
|
||||
{CapsLock "Caps Lock" "caps_lock" }
|
||||
{A "A" "a" }
|
||||
{S "S" "s" }
|
||||
{D "D" "d" }
|
||||
{F "F" "f" }
|
||||
{G "G" "g" }
|
||||
{H "H" "h" }
|
||||
{J "J" "j" }
|
||||
{K "K" "k" }
|
||||
{L "L" "l" }
|
||||
{Semicolon "Semicolon" "semicolon" }
|
||||
{Quote "Quote" "quote" }
|
||||
{Return "Return" "return" }
|
||||
{Shift "Shift" "shift" }
|
||||
{Z "Z" "z" }
|
||||
{X "X" "x" }
|
||||
{C "C" "c" }
|
||||
{V "V" "v" }
|
||||
{B "B" "b" }
|
||||
{N "N" "n" }
|
||||
{M "M" "m" }
|
||||
{Comma "Comma" "comma" }
|
||||
{Period "Period" "period" }
|
||||
{Slash "Slash" "slash" }
|
||||
{Ctrl "Ctrl" "ctrl" }
|
||||
{Alt "Alt" "alt" }
|
||||
{Space "Space" "space" }
|
||||
{Menu "Menu" "menu" }
|
||||
{ScrollLock "Scroll Lock" "scroll_lock" }
|
||||
{Pause "Pause" "pause" }
|
||||
{Insert "Insert" "insert" }
|
||||
{Home "Home" "home" }
|
||||
{PageUp "Page Up" "page_up" }
|
||||
{Delete "Delete" "delete" }
|
||||
{End "End" "end" }
|
||||
{PageDown "Page Down" "page_down" }
|
||||
{Up "Up" "up" }
|
||||
{Left "Left" "left" }
|
||||
{Down "Down" "down" }
|
||||
{Right "Right" "right" }
|
||||
{Ex0 "Ex0" "ex0" }
|
||||
{Ex1 "Ex1" "ex1" }
|
||||
{Ex2 "Ex2" "ex2" }
|
||||
{Ex3 "Ex3" "ex3" }
|
||||
{Ex4 "Ex4" "ex4" }
|
||||
{Ex5 "Ex5" "ex5" }
|
||||
{Ex6 "Ex6" "ex6" }
|
||||
{Ex7 "Ex7" "ex7" }
|
||||
{Ex8 "Ex8" "ex8" }
|
||||
{Ex9 "Ex9" "ex9" }
|
||||
{Ex10 "Ex10" "ex10" }
|
||||
{Ex11 "Ex11" "ex11" }
|
||||
{Ex12 "Ex12" "ex12" }
|
||||
{Ex13 "Ex13" "ex13" }
|
||||
{Ex14 "Ex14" "ex14" }
|
||||
{Ex15 "Ex15" "ex15" }
|
||||
{Ex16 "Ex16" "ex16" }
|
||||
{Ex17 "Ex17" "ex17" }
|
||||
{Ex18 "Ex18" "ex18" }
|
||||
{Ex19 "Ex19" "ex19" }
|
||||
{Ex20 "Ex20" "ex20" }
|
||||
{Ex21 "Ex21" "ex21" }
|
||||
{Ex22 "Ex22" "ex22" }
|
||||
{Ex23 "Ex23" "ex23" }
|
||||
{Ex24 "Ex24" "ex24" }
|
||||
{Ex25 "Ex25" "ex25" }
|
||||
{Ex26 "Ex26" "ex26" }
|
||||
{Ex27 "Ex27" "ex27" }
|
||||
{Ex28 "Ex28" "ex28" }
|
||||
{Ex29 "Ex29" "ex29" }
|
||||
{NumLock "Num Lock" "num_lock" }
|
||||
{NumSlash "Numpad Slash" "numpad_slash" }
|
||||
{NumStar "Numpad Star" "numpad_star" }
|
||||
{NumMinus "Numpad Minus" "numpad_minus" }
|
||||
{NumPlus "Numpad Plus" "numpad_plus" }
|
||||
{NumPeriod "Numpad Period" "numpad_period" }
|
||||
{Num0 "Numpad 0" "numpad_0" }
|
||||
{Num1 "Numpad 1" "numpad_1" }
|
||||
{Num2 "Numpad 2" "numpad_2" }
|
||||
{Num3 "Numpad 3" "numpad_3" }
|
||||
{Num4 "Numpad 4" "numpad_4" }
|
||||
{Num5 "Numpad 5" "numpad_5" }
|
||||
{Num6 "Numpad 6" "numpad_6" }
|
||||
{Num7 "Numpad 7" "numpad_7" }
|
||||
{Num8 "Numpad 8" "numpad_8" }
|
||||
{Num9 "Numpad 9" "numpad_9" }
|
||||
{LeftMouseButton "Left Mouse Button" "left_mouse" }
|
||||
{MiddleMouseButton "Middle Mouse Button" "middle_mouse" }
|
||||
{RightMouseButton "Right Mouse Button" "right_mouse" }
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@enum OS_Key:
|
||||
{
|
||||
@expand(OS_KeyTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@data(String8) os_g_key_display_string_table:
|
||||
{
|
||||
@expand(OS_KeyTable a) `str8_lit_comp("$(a.display_string)")`;
|
||||
}
|
||||
|
||||
@data(String8) os_g_key_cfg_string_table:
|
||||
{
|
||||
@expand(OS_KeyTable a) `str8_lit_comp("$(a.cfg_string)")`;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef OS_GFX_STUB_H
|
||||
#define OS_GFX_STUB_H
|
||||
|
||||
#endif // OS_GFX_STUB_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef OS_GFX_STUB_H
|
||||
#define OS_GFX_STUB_H
|
||||
|
||||
#endif // OS_GFX_STUB_H
|
||||
|
||||
+16
-16
@@ -1,16 +1,16 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef PATH_H
|
||||
#define PATH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Path Helper Functions
|
||||
|
||||
internal StringMatchFlags path_match_flags_from_os(OperatingSystem os);
|
||||
internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src);
|
||||
internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src);
|
||||
internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out);
|
||||
internal String8 path_normalized_from_string(Arena *arena, String8 path);
|
||||
|
||||
#endif //PATH_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef PATH_H
|
||||
#define PATH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Path Helper Functions
|
||||
|
||||
internal StringMatchFlags path_match_flags_from_os(OperatingSystem os);
|
||||
internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src);
|
||||
internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src);
|
||||
internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out);
|
||||
internal String8 path_normalized_from_string(Arena *arena, String8 path);
|
||||
|
||||
#endif //PATH_H
|
||||
|
||||
+462
-462
@@ -1,462 +1,462 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef PDB_H
|
||||
#define PDB_H
|
||||
|
||||
// https://github.com/microsoft/microsoft-pdb/tree/master/PDB
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format Types
|
||||
|
||||
typedef U32 PDB_Version;
|
||||
enum{
|
||||
PDB_Version_VC2 = 19941610,
|
||||
PDB_Version_VC4 = 19950623,
|
||||
PDB_Version_VC41 = 19950814,
|
||||
PDB_Version_VC50 = 19960307,
|
||||
PDB_Version_VC98 = 19970604,
|
||||
PDB_Version_VC70_DEP = 19990604,
|
||||
PDB_Version_VC70 = 20000404,
|
||||
PDB_Version_VC80 = 20030901,
|
||||
PDB_Version_VC110 = 20091201,
|
||||
PDB_Version_VC140 = 20140508
|
||||
};
|
||||
|
||||
typedef U16 PDB_ModIndex;
|
||||
typedef U32 PDB_StringIndex;
|
||||
|
||||
typedef enum PDB_FixedStream{
|
||||
PDB_FixedStream_PdbInfo = 1,
|
||||
PDB_FixedStream_Tpi = 2,
|
||||
PDB_FixedStream_Dbi = 3,
|
||||
PDB_FixedStream_Ipi = 4
|
||||
} PDB_FixedStream;
|
||||
|
||||
typedef enum PDB_NamedStream{
|
||||
PDB_NamedStream_HEADER_BLOCK,
|
||||
PDB_NamedStream_STRTABLE,
|
||||
PDB_NamedStream_LINK_INFO,
|
||||
PDB_NamedStream_COUNT
|
||||
} PDB_NamedStream;
|
||||
|
||||
typedef struct PDB_InfoHeader{
|
||||
PDB_Version version;
|
||||
U32 time;
|
||||
U32 age;
|
||||
} PDB_InfoHeader;
|
||||
|
||||
enum{
|
||||
PDB_StrtblHeader_MAGIC = 0xEFFEEFFE
|
||||
};
|
||||
|
||||
typedef struct PDB_StrtblHeader{
|
||||
U32 magic;
|
||||
U32 version;
|
||||
} PDB_StrtblHeader;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format DBI Types
|
||||
|
||||
typedef U32 PDB_DbiStream;
|
||||
enum{
|
||||
PDB_DbiStream_FPO,
|
||||
PDB_DbiStream_EXCEPTION,
|
||||
PDB_DbiStream_FIXUP,
|
||||
PDB_DbiStream_OMAP_TO_SRC,
|
||||
PDB_DbiStream_OMAP_FROM_SRC,
|
||||
PDB_DbiStream_SECTION_HEADER,
|
||||
PDB_DbiStream_TOKEN_RDI_MAP,
|
||||
PDB_DbiStream_XDATA,
|
||||
PDB_DbiStream_PDATA,
|
||||
PDB_DbiStream_NEW_FPO,
|
||||
PDB_DbiStream_SECTION_HEADER_ORIG,
|
||||
PDB_DbiStream_COUNT
|
||||
};
|
||||
|
||||
typedef U32 PDB_DbiHeaderSignature;
|
||||
enum{
|
||||
PDB_DbiHeaderSignature_V1 = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
typedef U32 PDB_DbiVersion;
|
||||
enum{
|
||||
PDB_DbiVersion_41 = 930803,
|
||||
PDB_DbiVersion_50 = 19960307,
|
||||
PDB_DbiVersion_60 = 19970606,
|
||||
PDB_DbiVersion_70 = 19990903,
|
||||
PDB_DbiVersion_110 = 20091201,
|
||||
};
|
||||
|
||||
typedef U16 PDB_DbiBuildNumber;
|
||||
#define PDB_DbiBuildNumberNewFormatFlag 0x8000
|
||||
#define PDB_DbiBuildNumberMinor(bn) ((bn)&0xFF)
|
||||
#define PDB_DbiBuildNumberMajor(bn) (((bn) >> 8)&0x7F)
|
||||
#define PDB_DbiBuildNumberNewFormat(bn) (!!((bn)&PDB_DbiBuildNumberNewFormatFlag))
|
||||
#define PDB_DbiBuildNumber(maj, min) \
|
||||
(PDB_DbiBuildNumberNewFormatFlag | ((min)&0xFF) | (((maj)&0x7F) << 16))
|
||||
|
||||
typedef U16 PDB_DbiHeaderFlags;
|
||||
enum{
|
||||
PDB_DbiHeaderFlag_Incremental = 0x1,
|
||||
PDB_DbiHeaderFlag_Stripped = 0x2,
|
||||
PDB_DbiHeaderFlag_CTypes = 0x4
|
||||
};
|
||||
|
||||
typedef struct PDB_DbiHeader{
|
||||
PDB_DbiHeaderSignature sig;
|
||||
PDB_DbiVersion version;
|
||||
U32 age;
|
||||
MSF_StreamNumber gsi_sn;
|
||||
PDB_DbiBuildNumber build_number;
|
||||
|
||||
MSF_StreamNumber psi_sn;
|
||||
U16 pdb_version;
|
||||
|
||||
MSF_StreamNumber sym_sn;
|
||||
U16 pdb_version2;
|
||||
|
||||
U32 module_info_size;
|
||||
U32 sec_con_size;
|
||||
U32 sec_map_size;
|
||||
U32 file_info_size;
|
||||
|
||||
U32 tsm_size;
|
||||
U32 mfc_index;
|
||||
U32 dbg_header_size;
|
||||
U32 ec_info_size;
|
||||
|
||||
PDB_DbiHeaderFlags flags;
|
||||
COFF_MachineType machine;
|
||||
|
||||
U32 reserved;
|
||||
} PDB_DbiHeader;
|
||||
|
||||
// (this is not "literally" defined by the format - but helpful to have)
|
||||
typedef enum PDB_DbiRange{
|
||||
PDB_DbiRange_ModuleInfo,
|
||||
PDB_DbiRange_SecCon,
|
||||
PDB_DbiRange_SecMap,
|
||||
PDB_DbiRange_FileInfo,
|
||||
PDB_DbiRange_TSM,
|
||||
PDB_DbiRange_EcInfo,
|
||||
PDB_DbiRange_DbgHeader,
|
||||
PDB_DbiRange_COUNT
|
||||
} PDB_DbiRange;
|
||||
|
||||
// "ModuleInfo" DBI range
|
||||
|
||||
typedef U32 PDB_DbiSectionContribVersion;
|
||||
#define PDB_DbiSectionContribVersion_1 (0xeffe0000u + 19970605u)
|
||||
#define PDB_DbiSectionContribVersion_2 (0xeffe0000u + 20140516u)
|
||||
|
||||
typedef struct PDB_DbiSectionContrib40{
|
||||
CV_SectionIndex sec;
|
||||
U32 sec_off;
|
||||
U32 size;
|
||||
U32 flags;
|
||||
PDB_ModIndex mod;
|
||||
} PDB_DbiSectionContrib40;
|
||||
|
||||
typedef struct PDB_DbiSectionContrib{
|
||||
PDB_DbiSectionContrib40 base;
|
||||
U32 data_crc;
|
||||
U32 reloc_crc;
|
||||
} PDB_DbiSectionContrib;
|
||||
|
||||
typedef struct PDB_DbiSectionContrib2{
|
||||
PDB_DbiSectionContrib40 base;
|
||||
U32 data_crc;
|
||||
U32 reloc_crc;
|
||||
U32 sec_coff;
|
||||
} PDB_DbiSectionContrib2;
|
||||
|
||||
typedef struct PDB_DbiCompUnitHeader{
|
||||
U32 unused;
|
||||
PDB_DbiSectionContrib contribution;
|
||||
U16 flags; // unknown
|
||||
|
||||
MSF_StreamNumber sn;
|
||||
U32 symbols_size;
|
||||
U32 c11_lines_size;
|
||||
U32 c13_lines_size;
|
||||
|
||||
U16 num_contrib_files;
|
||||
U16 unused2;
|
||||
U32 file_names_offset;
|
||||
|
||||
PDB_StringIndex src_file;
|
||||
PDB_StringIndex pdb_file;
|
||||
|
||||
// U8[] module_name (null terminated)
|
||||
// U8[] obj_name (null terminated)
|
||||
} PDB_DbiCompUnitHeader;
|
||||
|
||||
// (this is not "literally" defined by the format - but helpful to have)
|
||||
typedef enum{
|
||||
PDB_DbiCompUnitRange_Symbols,
|
||||
PDB_DbiCompUnitRange_C11,
|
||||
PDB_DbiCompUnitRange_C13,
|
||||
PDB_DbiCompUnitRange_COUNT
|
||||
} PDB_DbiCompUnitRange;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format TPI Types
|
||||
|
||||
typedef U32 PDB_TpiVersion;
|
||||
enum{
|
||||
PDB_TpiVersion_INTV_VC2 = 920924,
|
||||
PDB_TpiVersion_IMPV40 = 19950410,
|
||||
PDB_TpiVersion_IMPV41 = 19951122,
|
||||
PDB_TpiVersion_IMPV50_INTERIM = 19960307,
|
||||
PDB_TpiVersion_IMPV50 = 19961031,
|
||||
PDB_TpiVersion_IMPV70 = 19990903,
|
||||
PDB_TpiVersion_IMPV80 = 20040203,
|
||||
};
|
||||
|
||||
typedef struct PDB_TpiHeader{
|
||||
// (HDR)
|
||||
PDB_TpiVersion version;
|
||||
U32 header_size;
|
||||
U32 ti_lo;
|
||||
U32 ti_hi;
|
||||
U32 leaf_data_size;
|
||||
|
||||
// (PdbTpiHash)
|
||||
MSF_StreamNumber hash_sn;
|
||||
MSF_StreamNumber hash_sn_aux;
|
||||
U32 hash_key_size;
|
||||
U32 hash_bucket_count;
|
||||
U32 hash_vals_off;
|
||||
U32 hash_vals_size;
|
||||
U32 itype_off;
|
||||
U32 itype_size;
|
||||
U32 hash_adj_off;
|
||||
U32 hash_adj_size;
|
||||
} PDB_TpiHeader;
|
||||
|
||||
typedef struct PDB_TpiOffHint{
|
||||
CV_TypeId itype;
|
||||
U32 off;
|
||||
} PDB_TpiOffHint;
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format GSI Types
|
||||
|
||||
typedef U32 PDB_GsiSignature;
|
||||
enum{
|
||||
PDB_GsiSignature_Basic = 0xffffffff,
|
||||
};
|
||||
|
||||
typedef U32 PDB_GsiVersion;
|
||||
enum{
|
||||
PDB_GsiVersion_V70 = 0xeffe0000 + 19990810,
|
||||
};
|
||||
|
||||
typedef struct PDB_GsiHeader{
|
||||
PDB_GsiSignature signature;
|
||||
PDB_GsiVersion version;
|
||||
U32 hr_len;
|
||||
U32 num_buckets;
|
||||
} PDB_GsiHeader;
|
||||
|
||||
typedef struct PDB_GsiHashRecord{
|
||||
U32 symbol_off;
|
||||
U32 cref;
|
||||
} PDB_GsiHashRecord;
|
||||
|
||||
typedef struct PDB_PsiHeader{
|
||||
U32 sym_hash_size;
|
||||
U32 addr_map_size;
|
||||
U32 thunk_count;
|
||||
U32 thunk_size;
|
||||
CV_SectionIndex isec_thunk_table;
|
||||
U16 padding;
|
||||
U32 sec_thunk_table_off;
|
||||
U32 sec_count;
|
||||
} PDB_PsiHeader;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Parser Types
|
||||
|
||||
typedef struct PDB_InfoNode{
|
||||
struct PDB_InfoNode *next;
|
||||
String8 string;
|
||||
MSF_StreamNumber sn;
|
||||
} PDB_InfoNode;
|
||||
|
||||
typedef struct PDB_Info{
|
||||
PDB_InfoNode *first;
|
||||
PDB_InfoNode *last;
|
||||
COFF_Guid auth_guid;
|
||||
} PDB_Info;
|
||||
|
||||
typedef struct PDB_NamedStreamTable{
|
||||
MSF_StreamNumber sn[PDB_NamedStream_COUNT];
|
||||
} PDB_NamedStreamTable;
|
||||
|
||||
typedef struct PDB_Strtbl{
|
||||
String8 data;
|
||||
U32 bucket_count;
|
||||
U32 strblock_min;
|
||||
U32 strblock_max;
|
||||
U32 buckets_min;
|
||||
U32 buckets_max;
|
||||
} PDB_Strtbl;
|
||||
|
||||
typedef struct PDB_DbiParsed{
|
||||
String8 data;
|
||||
COFF_MachineType machine_type;
|
||||
MSF_StreamNumber gsi_sn;
|
||||
MSF_StreamNumber psi_sn;
|
||||
MSF_StreamNumber sym_sn;
|
||||
|
||||
U64 range_off[(U64)(PDB_DbiRange_COUNT) + 1];
|
||||
MSF_StreamNumber dbg_streams[PDB_DbiStream_COUNT];
|
||||
} PDB_DbiParsed;
|
||||
|
||||
typedef struct PDB_TpiParsed{
|
||||
String8 data;
|
||||
|
||||
// leaf info
|
||||
U64 leaf_first;
|
||||
U64 leaf_opl;
|
||||
U32 itype_first;
|
||||
U32 itype_opl;
|
||||
|
||||
// hash info
|
||||
MSF_StreamNumber hash_sn;
|
||||
MSF_StreamNumber hash_sn_aux;
|
||||
U32 hash_key_size;
|
||||
U32 hash_bucket_count;
|
||||
U32 hash_vals_off;
|
||||
U32 hash_vals_size;
|
||||
U32 itype_off;
|
||||
U32 itype_size;
|
||||
U32 hash_adj_off;
|
||||
U32 hash_adj_size;
|
||||
|
||||
} PDB_TpiParsed;
|
||||
|
||||
typedef struct PDB_TpiHashBlock{
|
||||
struct PDB_TpiHashBlock *next;
|
||||
U32 local_count;
|
||||
CV_TypeId itypes[13]; // 13 = (64 - 12)/4
|
||||
} PDB_TpiHashBlock;
|
||||
|
||||
typedef struct PDB_TpiHashParsed{
|
||||
String8 data;
|
||||
String8 aux_data;
|
||||
|
||||
PDB_TpiHashBlock **buckets;
|
||||
U32 bucket_count;
|
||||
U32 bucket_mask;
|
||||
} PDB_TpiHashParsed;
|
||||
|
||||
typedef struct PDB_GsiBucket{
|
||||
U32 *offs;
|
||||
U64 count;
|
||||
} PDB_GsiBucket;
|
||||
|
||||
typedef struct PDB_GsiParsed{
|
||||
PDB_GsiBucket buckets[4096];
|
||||
} PDB_GsiParsed;
|
||||
|
||||
typedef struct PDB_CompUnit{
|
||||
MSF_StreamNumber sn;
|
||||
U32 range_off[(U32)(PDB_DbiCompUnitRange_COUNT) + 1];
|
||||
|
||||
String8 obj_name;
|
||||
String8 group_name;
|
||||
} PDB_CompUnit;
|
||||
|
||||
typedef struct PDB_CoffSectionArray{
|
||||
COFF_SectionHeader *sections;
|
||||
U64 count;
|
||||
} PDB_CoffSectionArray;
|
||||
|
||||
typedef struct PDB_CompUnitNode{
|
||||
struct PDB_CompUnitNode *next;
|
||||
PDB_CompUnit unit;
|
||||
} PDB_CompUnitNode;
|
||||
|
||||
typedef struct PDB_CompUnitArray{
|
||||
PDB_CompUnit **units;
|
||||
U64 count;
|
||||
} PDB_CompUnitArray;
|
||||
|
||||
typedef struct PDB_CompUnitContribution{
|
||||
U32 mod;
|
||||
U64 voff_first;
|
||||
U64 voff_opl;
|
||||
} PDB_CompUnitContribution;
|
||||
|
||||
typedef struct PDB_CompUnitContributionArray{
|
||||
PDB_CompUnitContribution *contributions;
|
||||
U64 count;
|
||||
} PDB_CompUnitContributionArray;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Parser Functions
|
||||
|
||||
internal PDB_Info* pdb_info_from_data(Arena *arena, String8 pdb_info_data);
|
||||
internal PDB_NamedStreamTable*pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info);
|
||||
internal PDB_Strtbl* pdb_strtbl_from_data(Arena *arena, String8 strtbl_data);
|
||||
|
||||
internal PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 dbi_data);
|
||||
internal PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 tpi_data);
|
||||
internal PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena,
|
||||
PDB_Strtbl *strtbl,
|
||||
PDB_TpiParsed *tpi,
|
||||
String8 tpi_hash_data,
|
||||
String8 tpi_hash_aux_data);
|
||||
internal PDB_GsiParsed* pdb_gsi_from_data(Arena *arena, String8 gsi_data);
|
||||
|
||||
internal PDB_CoffSectionArray*pdb_coff_section_array_from_data(Arena *arena,
|
||||
String8 section_data);
|
||||
|
||||
internal PDB_CompUnitArray* pdb_comp_unit_array_from_data(Arena *arena,
|
||||
String8 module_info_data);
|
||||
|
||||
internal PDB_CompUnitContributionArray*
|
||||
pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 seccontrib_data,
|
||||
PDB_CoffSectionArray *sections);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Definition Functions
|
||||
|
||||
internal U32 pdb_string_hash1(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Dbi Functions
|
||||
|
||||
internal String8 pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range);
|
||||
internal String8 pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit,
|
||||
PDB_DbiCompUnitRange range);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Tpi Functions
|
||||
|
||||
internal String8 pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi);
|
||||
|
||||
internal CV_TypeIdArray pdb_tpi_itypes_from_name(Arena *arena,
|
||||
PDB_TpiHashParsed *tpi_hash,
|
||||
CV_LeafParsed *tpi_leaf,
|
||||
String8 name,
|
||||
B32 compare_unique_name,
|
||||
U32 output_cap);
|
||||
|
||||
internal CV_TypeId pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash,
|
||||
CV_LeafParsed *tpi_leaf,
|
||||
String8 name,
|
||||
B32 compare_unique_name);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Strtbl Functions
|
||||
|
||||
internal String8 pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off);
|
||||
internal String8 pdb_strtbl_string_from_index(PDB_Strtbl *strtbl,
|
||||
PDB_StringIndex idx);
|
||||
|
||||
#endif // PDB_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef PDB_H
|
||||
#define PDB_H
|
||||
|
||||
// https://github.com/microsoft/microsoft-pdb/tree/master/PDB
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format Types
|
||||
|
||||
typedef U32 PDB_Version;
|
||||
enum{
|
||||
PDB_Version_VC2 = 19941610,
|
||||
PDB_Version_VC4 = 19950623,
|
||||
PDB_Version_VC41 = 19950814,
|
||||
PDB_Version_VC50 = 19960307,
|
||||
PDB_Version_VC98 = 19970604,
|
||||
PDB_Version_VC70_DEP = 19990604,
|
||||
PDB_Version_VC70 = 20000404,
|
||||
PDB_Version_VC80 = 20030901,
|
||||
PDB_Version_VC110 = 20091201,
|
||||
PDB_Version_VC140 = 20140508
|
||||
};
|
||||
|
||||
typedef U16 PDB_ModIndex;
|
||||
typedef U32 PDB_StringIndex;
|
||||
|
||||
typedef enum PDB_FixedStream{
|
||||
PDB_FixedStream_PdbInfo = 1,
|
||||
PDB_FixedStream_Tpi = 2,
|
||||
PDB_FixedStream_Dbi = 3,
|
||||
PDB_FixedStream_Ipi = 4
|
||||
} PDB_FixedStream;
|
||||
|
||||
typedef enum PDB_NamedStream{
|
||||
PDB_NamedStream_HEADER_BLOCK,
|
||||
PDB_NamedStream_STRTABLE,
|
||||
PDB_NamedStream_LINK_INFO,
|
||||
PDB_NamedStream_COUNT
|
||||
} PDB_NamedStream;
|
||||
|
||||
typedef struct PDB_InfoHeader{
|
||||
PDB_Version version;
|
||||
U32 time;
|
||||
U32 age;
|
||||
} PDB_InfoHeader;
|
||||
|
||||
enum{
|
||||
PDB_StrtblHeader_MAGIC = 0xEFFEEFFE
|
||||
};
|
||||
|
||||
typedef struct PDB_StrtblHeader{
|
||||
U32 magic;
|
||||
U32 version;
|
||||
} PDB_StrtblHeader;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format DBI Types
|
||||
|
||||
typedef U32 PDB_DbiStream;
|
||||
enum{
|
||||
PDB_DbiStream_FPO,
|
||||
PDB_DbiStream_EXCEPTION,
|
||||
PDB_DbiStream_FIXUP,
|
||||
PDB_DbiStream_OMAP_TO_SRC,
|
||||
PDB_DbiStream_OMAP_FROM_SRC,
|
||||
PDB_DbiStream_SECTION_HEADER,
|
||||
PDB_DbiStream_TOKEN_RDI_MAP,
|
||||
PDB_DbiStream_XDATA,
|
||||
PDB_DbiStream_PDATA,
|
||||
PDB_DbiStream_NEW_FPO,
|
||||
PDB_DbiStream_SECTION_HEADER_ORIG,
|
||||
PDB_DbiStream_COUNT
|
||||
};
|
||||
|
||||
typedef U32 PDB_DbiHeaderSignature;
|
||||
enum{
|
||||
PDB_DbiHeaderSignature_V1 = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
typedef U32 PDB_DbiVersion;
|
||||
enum{
|
||||
PDB_DbiVersion_41 = 930803,
|
||||
PDB_DbiVersion_50 = 19960307,
|
||||
PDB_DbiVersion_60 = 19970606,
|
||||
PDB_DbiVersion_70 = 19990903,
|
||||
PDB_DbiVersion_110 = 20091201,
|
||||
};
|
||||
|
||||
typedef U16 PDB_DbiBuildNumber;
|
||||
#define PDB_DbiBuildNumberNewFormatFlag 0x8000
|
||||
#define PDB_DbiBuildNumberMinor(bn) ((bn)&0xFF)
|
||||
#define PDB_DbiBuildNumberMajor(bn) (((bn) >> 8)&0x7F)
|
||||
#define PDB_DbiBuildNumberNewFormat(bn) (!!((bn)&PDB_DbiBuildNumberNewFormatFlag))
|
||||
#define PDB_DbiBuildNumber(maj, min) \
|
||||
(PDB_DbiBuildNumberNewFormatFlag | ((min)&0xFF) | (((maj)&0x7F) << 16))
|
||||
|
||||
typedef U16 PDB_DbiHeaderFlags;
|
||||
enum{
|
||||
PDB_DbiHeaderFlag_Incremental = 0x1,
|
||||
PDB_DbiHeaderFlag_Stripped = 0x2,
|
||||
PDB_DbiHeaderFlag_CTypes = 0x4
|
||||
};
|
||||
|
||||
typedef struct PDB_DbiHeader{
|
||||
PDB_DbiHeaderSignature sig;
|
||||
PDB_DbiVersion version;
|
||||
U32 age;
|
||||
MSF_StreamNumber gsi_sn;
|
||||
PDB_DbiBuildNumber build_number;
|
||||
|
||||
MSF_StreamNumber psi_sn;
|
||||
U16 pdb_version;
|
||||
|
||||
MSF_StreamNumber sym_sn;
|
||||
U16 pdb_version2;
|
||||
|
||||
U32 module_info_size;
|
||||
U32 sec_con_size;
|
||||
U32 sec_map_size;
|
||||
U32 file_info_size;
|
||||
|
||||
U32 tsm_size;
|
||||
U32 mfc_index;
|
||||
U32 dbg_header_size;
|
||||
U32 ec_info_size;
|
||||
|
||||
PDB_DbiHeaderFlags flags;
|
||||
COFF_MachineType machine;
|
||||
|
||||
U32 reserved;
|
||||
} PDB_DbiHeader;
|
||||
|
||||
// (this is not "literally" defined by the format - but helpful to have)
|
||||
typedef enum PDB_DbiRange{
|
||||
PDB_DbiRange_ModuleInfo,
|
||||
PDB_DbiRange_SecCon,
|
||||
PDB_DbiRange_SecMap,
|
||||
PDB_DbiRange_FileInfo,
|
||||
PDB_DbiRange_TSM,
|
||||
PDB_DbiRange_EcInfo,
|
||||
PDB_DbiRange_DbgHeader,
|
||||
PDB_DbiRange_COUNT
|
||||
} PDB_DbiRange;
|
||||
|
||||
// "ModuleInfo" DBI range
|
||||
|
||||
typedef U32 PDB_DbiSectionContribVersion;
|
||||
#define PDB_DbiSectionContribVersion_1 (0xeffe0000u + 19970605u)
|
||||
#define PDB_DbiSectionContribVersion_2 (0xeffe0000u + 20140516u)
|
||||
|
||||
typedef struct PDB_DbiSectionContrib40{
|
||||
CV_SectionIndex sec;
|
||||
U32 sec_off;
|
||||
U32 size;
|
||||
U32 flags;
|
||||
PDB_ModIndex mod;
|
||||
} PDB_DbiSectionContrib40;
|
||||
|
||||
typedef struct PDB_DbiSectionContrib{
|
||||
PDB_DbiSectionContrib40 base;
|
||||
U32 data_crc;
|
||||
U32 reloc_crc;
|
||||
} PDB_DbiSectionContrib;
|
||||
|
||||
typedef struct PDB_DbiSectionContrib2{
|
||||
PDB_DbiSectionContrib40 base;
|
||||
U32 data_crc;
|
||||
U32 reloc_crc;
|
||||
U32 sec_coff;
|
||||
} PDB_DbiSectionContrib2;
|
||||
|
||||
typedef struct PDB_DbiCompUnitHeader{
|
||||
U32 unused;
|
||||
PDB_DbiSectionContrib contribution;
|
||||
U16 flags; // unknown
|
||||
|
||||
MSF_StreamNumber sn;
|
||||
U32 symbols_size;
|
||||
U32 c11_lines_size;
|
||||
U32 c13_lines_size;
|
||||
|
||||
U16 num_contrib_files;
|
||||
U16 unused2;
|
||||
U32 file_names_offset;
|
||||
|
||||
PDB_StringIndex src_file;
|
||||
PDB_StringIndex pdb_file;
|
||||
|
||||
// U8[] module_name (null terminated)
|
||||
// U8[] obj_name (null terminated)
|
||||
} PDB_DbiCompUnitHeader;
|
||||
|
||||
// (this is not "literally" defined by the format - but helpful to have)
|
||||
typedef enum{
|
||||
PDB_DbiCompUnitRange_Symbols,
|
||||
PDB_DbiCompUnitRange_C11,
|
||||
PDB_DbiCompUnitRange_C13,
|
||||
PDB_DbiCompUnitRange_COUNT
|
||||
} PDB_DbiCompUnitRange;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format TPI Types
|
||||
|
||||
typedef U32 PDB_TpiVersion;
|
||||
enum{
|
||||
PDB_TpiVersion_INTV_VC2 = 920924,
|
||||
PDB_TpiVersion_IMPV40 = 19950410,
|
||||
PDB_TpiVersion_IMPV41 = 19951122,
|
||||
PDB_TpiVersion_IMPV50_INTERIM = 19960307,
|
||||
PDB_TpiVersion_IMPV50 = 19961031,
|
||||
PDB_TpiVersion_IMPV70 = 19990903,
|
||||
PDB_TpiVersion_IMPV80 = 20040203,
|
||||
};
|
||||
|
||||
typedef struct PDB_TpiHeader{
|
||||
// (HDR)
|
||||
PDB_TpiVersion version;
|
||||
U32 header_size;
|
||||
U32 ti_lo;
|
||||
U32 ti_hi;
|
||||
U32 leaf_data_size;
|
||||
|
||||
// (PdbTpiHash)
|
||||
MSF_StreamNumber hash_sn;
|
||||
MSF_StreamNumber hash_sn_aux;
|
||||
U32 hash_key_size;
|
||||
U32 hash_bucket_count;
|
||||
U32 hash_vals_off;
|
||||
U32 hash_vals_size;
|
||||
U32 itype_off;
|
||||
U32 itype_size;
|
||||
U32 hash_adj_off;
|
||||
U32 hash_adj_size;
|
||||
} PDB_TpiHeader;
|
||||
|
||||
typedef struct PDB_TpiOffHint{
|
||||
CV_TypeId itype;
|
||||
U32 off;
|
||||
} PDB_TpiOffHint;
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Format GSI Types
|
||||
|
||||
typedef U32 PDB_GsiSignature;
|
||||
enum{
|
||||
PDB_GsiSignature_Basic = 0xffffffff,
|
||||
};
|
||||
|
||||
typedef U32 PDB_GsiVersion;
|
||||
enum{
|
||||
PDB_GsiVersion_V70 = 0xeffe0000 + 19990810,
|
||||
};
|
||||
|
||||
typedef struct PDB_GsiHeader{
|
||||
PDB_GsiSignature signature;
|
||||
PDB_GsiVersion version;
|
||||
U32 hr_len;
|
||||
U32 num_buckets;
|
||||
} PDB_GsiHeader;
|
||||
|
||||
typedef struct PDB_GsiHashRecord{
|
||||
U32 symbol_off;
|
||||
U32 cref;
|
||||
} PDB_GsiHashRecord;
|
||||
|
||||
typedef struct PDB_PsiHeader{
|
||||
U32 sym_hash_size;
|
||||
U32 addr_map_size;
|
||||
U32 thunk_count;
|
||||
U32 thunk_size;
|
||||
CV_SectionIndex isec_thunk_table;
|
||||
U16 padding;
|
||||
U32 sec_thunk_table_off;
|
||||
U32 sec_count;
|
||||
} PDB_PsiHeader;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Parser Types
|
||||
|
||||
typedef struct PDB_InfoNode{
|
||||
struct PDB_InfoNode *next;
|
||||
String8 string;
|
||||
MSF_StreamNumber sn;
|
||||
} PDB_InfoNode;
|
||||
|
||||
typedef struct PDB_Info{
|
||||
PDB_InfoNode *first;
|
||||
PDB_InfoNode *last;
|
||||
COFF_Guid auth_guid;
|
||||
} PDB_Info;
|
||||
|
||||
typedef struct PDB_NamedStreamTable{
|
||||
MSF_StreamNumber sn[PDB_NamedStream_COUNT];
|
||||
} PDB_NamedStreamTable;
|
||||
|
||||
typedef struct PDB_Strtbl{
|
||||
String8 data;
|
||||
U32 bucket_count;
|
||||
U32 strblock_min;
|
||||
U32 strblock_max;
|
||||
U32 buckets_min;
|
||||
U32 buckets_max;
|
||||
} PDB_Strtbl;
|
||||
|
||||
typedef struct PDB_DbiParsed{
|
||||
String8 data;
|
||||
COFF_MachineType machine_type;
|
||||
MSF_StreamNumber gsi_sn;
|
||||
MSF_StreamNumber psi_sn;
|
||||
MSF_StreamNumber sym_sn;
|
||||
|
||||
U64 range_off[(U64)(PDB_DbiRange_COUNT) + 1];
|
||||
MSF_StreamNumber dbg_streams[PDB_DbiStream_COUNT];
|
||||
} PDB_DbiParsed;
|
||||
|
||||
typedef struct PDB_TpiParsed{
|
||||
String8 data;
|
||||
|
||||
// leaf info
|
||||
U64 leaf_first;
|
||||
U64 leaf_opl;
|
||||
U32 itype_first;
|
||||
U32 itype_opl;
|
||||
|
||||
// hash info
|
||||
MSF_StreamNumber hash_sn;
|
||||
MSF_StreamNumber hash_sn_aux;
|
||||
U32 hash_key_size;
|
||||
U32 hash_bucket_count;
|
||||
U32 hash_vals_off;
|
||||
U32 hash_vals_size;
|
||||
U32 itype_off;
|
||||
U32 itype_size;
|
||||
U32 hash_adj_off;
|
||||
U32 hash_adj_size;
|
||||
|
||||
} PDB_TpiParsed;
|
||||
|
||||
typedef struct PDB_TpiHashBlock{
|
||||
struct PDB_TpiHashBlock *next;
|
||||
U32 local_count;
|
||||
CV_TypeId itypes[13]; // 13 = (64 - 12)/4
|
||||
} PDB_TpiHashBlock;
|
||||
|
||||
typedef struct PDB_TpiHashParsed{
|
||||
String8 data;
|
||||
String8 aux_data;
|
||||
|
||||
PDB_TpiHashBlock **buckets;
|
||||
U32 bucket_count;
|
||||
U32 bucket_mask;
|
||||
} PDB_TpiHashParsed;
|
||||
|
||||
typedef struct PDB_GsiBucket{
|
||||
U32 *offs;
|
||||
U64 count;
|
||||
} PDB_GsiBucket;
|
||||
|
||||
typedef struct PDB_GsiParsed{
|
||||
PDB_GsiBucket buckets[4096];
|
||||
} PDB_GsiParsed;
|
||||
|
||||
typedef struct PDB_CompUnit{
|
||||
MSF_StreamNumber sn;
|
||||
U32 range_off[(U32)(PDB_DbiCompUnitRange_COUNT) + 1];
|
||||
|
||||
String8 obj_name;
|
||||
String8 group_name;
|
||||
} PDB_CompUnit;
|
||||
|
||||
typedef struct PDB_CoffSectionArray{
|
||||
COFF_SectionHeader *sections;
|
||||
U64 count;
|
||||
} PDB_CoffSectionArray;
|
||||
|
||||
typedef struct PDB_CompUnitNode{
|
||||
struct PDB_CompUnitNode *next;
|
||||
PDB_CompUnit unit;
|
||||
} PDB_CompUnitNode;
|
||||
|
||||
typedef struct PDB_CompUnitArray{
|
||||
PDB_CompUnit **units;
|
||||
U64 count;
|
||||
} PDB_CompUnitArray;
|
||||
|
||||
typedef struct PDB_CompUnitContribution{
|
||||
U32 mod;
|
||||
U64 voff_first;
|
||||
U64 voff_opl;
|
||||
} PDB_CompUnitContribution;
|
||||
|
||||
typedef struct PDB_CompUnitContributionArray{
|
||||
PDB_CompUnitContribution *contributions;
|
||||
U64 count;
|
||||
} PDB_CompUnitContributionArray;
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Parser Functions
|
||||
|
||||
internal PDB_Info* pdb_info_from_data(Arena *arena, String8 pdb_info_data);
|
||||
internal PDB_NamedStreamTable*pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info);
|
||||
internal PDB_Strtbl* pdb_strtbl_from_data(Arena *arena, String8 strtbl_data);
|
||||
|
||||
internal PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 dbi_data);
|
||||
internal PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 tpi_data);
|
||||
internal PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena,
|
||||
PDB_Strtbl *strtbl,
|
||||
PDB_TpiParsed *tpi,
|
||||
String8 tpi_hash_data,
|
||||
String8 tpi_hash_aux_data);
|
||||
internal PDB_GsiParsed* pdb_gsi_from_data(Arena *arena, String8 gsi_data);
|
||||
|
||||
internal PDB_CoffSectionArray*pdb_coff_section_array_from_data(Arena *arena,
|
||||
String8 section_data);
|
||||
|
||||
internal PDB_CompUnitArray* pdb_comp_unit_array_from_data(Arena *arena,
|
||||
String8 module_info_data);
|
||||
|
||||
internal PDB_CompUnitContributionArray*
|
||||
pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 seccontrib_data,
|
||||
PDB_CoffSectionArray *sections);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Definition Functions
|
||||
|
||||
internal U32 pdb_string_hash1(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Dbi Functions
|
||||
|
||||
internal String8 pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range);
|
||||
internal String8 pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit,
|
||||
PDB_DbiCompUnitRange range);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Tpi Functions
|
||||
|
||||
internal String8 pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi);
|
||||
|
||||
internal CV_TypeIdArray pdb_tpi_itypes_from_name(Arena *arena,
|
||||
PDB_TpiHashParsed *tpi_hash,
|
||||
CV_LeafParsed *tpi_leaf,
|
||||
String8 name,
|
||||
B32 compare_unique_name,
|
||||
U32 output_cap);
|
||||
|
||||
internal CV_TypeId pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash,
|
||||
CV_LeafParsed *tpi_leaf,
|
||||
String8 name,
|
||||
B32 compare_unique_name);
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Strtbl Functions
|
||||
|
||||
internal String8 pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off);
|
||||
internal String8 pdb_strtbl_string_from_index(PDB_Strtbl *strtbl,
|
||||
PDB_StringIndex idx);
|
||||
|
||||
#endif // PDB_H
|
||||
|
||||
+26
-26
@@ -1,26 +1,26 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Stringize Functions
|
||||
|
||||
internal void
|
||||
pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash){
|
||||
U32 bucket_count = hash->bucket_count;
|
||||
str8_list_pushf(arena, out, "bucket_count=%u\n\n", bucket_count);
|
||||
for (U32 i = 0; i < bucket_count; i += 1){
|
||||
if (hash->buckets[i] != 0){
|
||||
str8_list_pushf(arena, out, "bucket[%u]:\n", i);
|
||||
for (PDB_TpiHashBlock *block = hash->buckets[i];
|
||||
block != 0;
|
||||
block = block->next){
|
||||
U32 local_count = block->local_count;
|
||||
CV_TypeId *itype_ptr = block->itypes;
|
||||
for (U32 j = 0; j < local_count; j += 1, itype_ptr += 1){
|
||||
str8_list_pushf(arena, out, " %u\n", *itype_ptr);
|
||||
}
|
||||
}
|
||||
str8_list_push(arena, out, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Stringize Functions
|
||||
|
||||
internal void
|
||||
pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash){
|
||||
U32 bucket_count = hash->bucket_count;
|
||||
str8_list_pushf(arena, out, "bucket_count=%u\n\n", bucket_count);
|
||||
for (U32 i = 0; i < bucket_count; i += 1){
|
||||
if (hash->buckets[i] != 0){
|
||||
str8_list_pushf(arena, out, "bucket[%u]:\n", i);
|
||||
for (PDB_TpiHashBlock *block = hash->buckets[i];
|
||||
block != 0;
|
||||
block = block->next){
|
||||
U32 local_count = block->local_count;
|
||||
CV_TypeId *itype_ptr = block->itypes;
|
||||
for (U32 j = 0; j < local_count; j += 1, itype_ptr += 1){
|
||||
str8_list_pushf(arena, out, " %u\n", *itype_ptr);
|
||||
}
|
||||
}
|
||||
str8_list_push(arena, out, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef PDB_STRINGIZE_H
|
||||
#define PDB_STRINGIZE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Stringize Functions
|
||||
|
||||
internal void pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash);
|
||||
|
||||
#endif // PDB_STRINGIZE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef PDB_STRINGIZE_H
|
||||
#define PDB_STRINGIZE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ PDB Stringize Functions
|
||||
|
||||
internal void pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash);
|
||||
|
||||
#endif // PDB_STRINGIZE_H
|
||||
|
||||
+17
-17
@@ -1,17 +1,17 @@
|
||||
; Copyright (c) 2024 Epic Games Tools
|
||||
; Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
; $ c:\devel\projects\bin\win32\nasm src\pe\dos_program.asm -fbin -o dos_program.bin
|
||||
|
||||
BITS 16
|
||||
|
||||
SEGMENT CODE
|
||||
push cs ; copy psp segment address to ds
|
||||
pop ds
|
||||
mov dx, msg ; set print string
|
||||
mov ah, 9h ; print to stdout
|
||||
int 21h
|
||||
mov ax, 0x4c01 ; terminate with return code 1 in al
|
||||
int 0x21
|
||||
|
||||
msg: DB "This program cannot be run in DOS mode.$",0
|
||||
ALIGN 8, DB
|
||||
; Copyright (c) 2024 Epic Games Tools
|
||||
; Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
; $ c:\devel\projects\bin\win32\nasm src\pe\dos_program.asm -fbin -o dos_program.bin
|
||||
|
||||
BITS 16
|
||||
|
||||
SEGMENT CODE
|
||||
push cs ; copy psp segment address to ds
|
||||
pop ds
|
||||
mov dx, msg ; set print string
|
||||
mov ah, 9h ; print to stdout
|
||||
int 21h
|
||||
mov ax, 0x4c01 ; terminate with return code 1 in al
|
||||
int 0x21
|
||||
|
||||
msg: DB "This program cannot be run in DOS mode.$",0
|
||||
ALIGN 8, DB
|
||||
|
||||
+815
-815
File diff suppressed because it is too large
Load Diff
+773
-773
File diff suppressed because it is too large
Load Diff
+788
-788
File diff suppressed because it is too large
Load Diff
+78
-78
@@ -1,78 +1,78 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RDI_DUMP_H
|
||||
#define RDI_DUMP_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RADDBG Stringize Helper Types
|
||||
|
||||
typedef struct RDI_FilePathBundle RDI_FilePathBundle;
|
||||
struct RDI_FilePathBundle
|
||||
{
|
||||
RDI_FilePathNode *file_paths;
|
||||
U64 file_path_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_UDTMemberBundle RDI_UDTMemberBundle;
|
||||
struct RDI_UDTMemberBundle
|
||||
{
|
||||
RDI_Member *members;
|
||||
RDI_EnumMember *enum_members;
|
||||
U32 member_count;
|
||||
U32 enum_member_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ScopeBundle RDI_ScopeBundle;
|
||||
struct RDI_ScopeBundle
|
||||
{
|
||||
RDI_Scope *scopes;
|
||||
U64 *scope_voffs;
|
||||
RDI_Local *locals;
|
||||
RDI_LocationBlock *location_blocks;
|
||||
U8 *location_data;
|
||||
U32 scope_count;
|
||||
U32 scope_voff_count;
|
||||
U32 local_count;
|
||||
U32 location_block_count;
|
||||
U32 location_data_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RDI Enum -> String Functions
|
||||
|
||||
internal String8 rdi_string_from_data_section_kind(RDI_SectionKind v);
|
||||
internal String8 rdi_string_from_arch(RDI_Arch v);
|
||||
internal String8 rdi_string_from_language(RDI_Language v);
|
||||
internal String8 rdi_string_from_type_kind(RDI_TypeKind v);
|
||||
internal String8 rdi_string_from_member_kind(RDI_MemberKind v);
|
||||
internal String8 rdi_string_from_local_kind(RDI_LocalKind v);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RDI Flags -> String Functions
|
||||
|
||||
internal void rdi_stringize_binary_section_flags(Arena *arena, String8List *out, RDI_BinarySectionFlags flags);
|
||||
internal void rdi_stringize_type_modifier_flags(Arena *arena, String8List *out, RDI_TypeModifierFlags flags);
|
||||
internal void rdi_stringize_udt_flags(Arena *arena, String8List *out, RDI_UDTFlags flags);
|
||||
internal void rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RDI Compound Stringize Functions
|
||||
|
||||
internal void rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *rdi, U32 indent_level);
|
||||
internal void rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_TopLevelInfo *tli, U32 indent_level);
|
||||
internal void rdi_stringize_binary_section(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_BinarySection *bin_section, U32 indent_level);
|
||||
internal void rdi_stringize_file_path(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_FilePathBundle *bundle, RDI_FilePathNode *file_path, U32 indent_level);
|
||||
internal void rdi_stringize_source_file(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceFile *source_file, U32 indent_level);
|
||||
internal void rdi_stringize_line_table(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_LineTable *line_table, U32 indent_level);
|
||||
internal void rdi_stringize_source_line_map(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceLineMap *map, U32 indent_level);
|
||||
internal void rdi_stringize_unit(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Unit *unit, U32 indent_level);
|
||||
internal void rdi_stringize_type_node(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_TypeNode *type, U32 indent_level);
|
||||
internal void rdi_stringize_udt(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_UDTMemberBundle *bundle, RDI_UDT *udt, U32 indent_level);
|
||||
internal void rdi_stringize_global_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_GlobalVariable *global_variable, U32 indent_level);
|
||||
internal void rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_ThreadVariable *thread_var, U32 indent_level);
|
||||
internal void rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Procedure *proc, U32 indent_level);
|
||||
internal void rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level);
|
||||
internal void rdi_stringize_inline_site(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_InlineSite *inline_site, U32 indent_level);
|
||||
|
||||
#endif // RDI_DUMP_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RDI_DUMP_H
|
||||
#define RDI_DUMP_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RADDBG Stringize Helper Types
|
||||
|
||||
typedef struct RDI_FilePathBundle RDI_FilePathBundle;
|
||||
struct RDI_FilePathBundle
|
||||
{
|
||||
RDI_FilePathNode *file_paths;
|
||||
U64 file_path_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_UDTMemberBundle RDI_UDTMemberBundle;
|
||||
struct RDI_UDTMemberBundle
|
||||
{
|
||||
RDI_Member *members;
|
||||
RDI_EnumMember *enum_members;
|
||||
U32 member_count;
|
||||
U32 enum_member_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ScopeBundle RDI_ScopeBundle;
|
||||
struct RDI_ScopeBundle
|
||||
{
|
||||
RDI_Scope *scopes;
|
||||
U64 *scope_voffs;
|
||||
RDI_Local *locals;
|
||||
RDI_LocationBlock *location_blocks;
|
||||
U8 *location_data;
|
||||
U32 scope_count;
|
||||
U32 scope_voff_count;
|
||||
U32 local_count;
|
||||
U32 location_block_count;
|
||||
U32 location_data_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RDI Enum -> String Functions
|
||||
|
||||
internal String8 rdi_string_from_data_section_kind(RDI_SectionKind v);
|
||||
internal String8 rdi_string_from_arch(RDI_Arch v);
|
||||
internal String8 rdi_string_from_language(RDI_Language v);
|
||||
internal String8 rdi_string_from_type_kind(RDI_TypeKind v);
|
||||
internal String8 rdi_string_from_member_kind(RDI_MemberKind v);
|
||||
internal String8 rdi_string_from_local_kind(RDI_LocalKind v);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RDI Flags -> String Functions
|
||||
|
||||
internal void rdi_stringize_binary_section_flags(Arena *arena, String8List *out, RDI_BinarySectionFlags flags);
|
||||
internal void rdi_stringize_type_modifier_flags(Arena *arena, String8List *out, RDI_TypeModifierFlags flags);
|
||||
internal void rdi_stringize_udt_flags(Arena *arena, String8List *out, RDI_UDTFlags flags);
|
||||
internal void rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: RDI Compound Stringize Functions
|
||||
|
||||
internal void rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *rdi, U32 indent_level);
|
||||
internal void rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_TopLevelInfo *tli, U32 indent_level);
|
||||
internal void rdi_stringize_binary_section(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_BinarySection *bin_section, U32 indent_level);
|
||||
internal void rdi_stringize_file_path(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_FilePathBundle *bundle, RDI_FilePathNode *file_path, U32 indent_level);
|
||||
internal void rdi_stringize_source_file(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceFile *source_file, U32 indent_level);
|
||||
internal void rdi_stringize_line_table(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_LineTable *line_table, U32 indent_level);
|
||||
internal void rdi_stringize_source_line_map(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceLineMap *map, U32 indent_level);
|
||||
internal void rdi_stringize_unit(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Unit *unit, U32 indent_level);
|
||||
internal void rdi_stringize_type_node(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_TypeNode *type, U32 indent_level);
|
||||
internal void rdi_stringize_udt(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_UDTMemberBundle *bundle, RDI_UDT *udt, U32 indent_level);
|
||||
internal void rdi_stringize_global_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_GlobalVariable *global_variable, U32 indent_level);
|
||||
internal void rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_ThreadVariable *thread_var, U32 indent_level);
|
||||
internal void rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Procedure *proc, U32 indent_level);
|
||||
internal void rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level);
|
||||
internal void rdi_stringize_inline_site(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_InlineSite *inline_site, U32 indent_level);
|
||||
|
||||
#endif // RDI_DUMP_H
|
||||
|
||||
+519
-519
File diff suppressed because it is too large
Load Diff
@@ -1,52 +1,52 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "lib_rdi_format/rdi_format.c"
|
||||
#include "lib_rdi_format/rdi_format_parse.c"
|
||||
|
||||
internal void
|
||||
rdi_decompress_parsed(U8 *decompressed_data, U64 decompressed_size, RDI_Parsed *og_rdi)
|
||||
{
|
||||
// rjf: copy header
|
||||
RDI_Header *src_header = (RDI_Header *)og_rdi->raw_data;
|
||||
RDI_Header *dst_header = (RDI_Header *)decompressed_data;
|
||||
{
|
||||
MemoryCopy(dst_header, src_header, sizeof(RDI_Header));
|
||||
}
|
||||
|
||||
// rjf: copy & adjust sections for decompressed version
|
||||
if(og_rdi->sections_count != 0)
|
||||
{
|
||||
RDI_Section *dsec_base = (RDI_Section *)(decompressed_data + dst_header->data_section_off);
|
||||
MemoryCopy(dsec_base, (U8 *)og_rdi->raw_data + src_header->data_section_off, sizeof(RDI_Section) * og_rdi->sections_count);
|
||||
U64 off = dst_header->data_section_off + sizeof(RDI_Section) * og_rdi->sections_count;
|
||||
off += 7;
|
||||
off -= off%8;
|
||||
for(U64 idx = 0; idx < og_rdi->sections_count; idx += 1)
|
||||
{
|
||||
dsec_base[idx].encoding = RDI_SectionEncoding_Unpacked;
|
||||
dsec_base[idx].off = off;
|
||||
dsec_base[idx].encoded_size = dsec_base[idx].unpacked_size;
|
||||
off += dsec_base[idx].unpacked_size;
|
||||
off += 7;
|
||||
off -= off%8;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: decompress sections into new decompressed file buffer
|
||||
if(og_rdi->sections_count != 0)
|
||||
{
|
||||
RDI_Section *src_first = og_rdi->sections;
|
||||
RDI_Section *dst_first = (RDI_Section *)(decompressed_data + dst_header->data_section_off);
|
||||
RDI_Section *src_opl = src_first + og_rdi->sections_count;
|
||||
RDI_Section *dst_opl = dst_first + og_rdi->sections_count;
|
||||
for(RDI_Section *src = src_first, *dst = dst_first;
|
||||
src < src_opl && dst < dst_opl;
|
||||
src += 1, dst += 1)
|
||||
{
|
||||
rr_lzb_simple_decode((U8*)og_rdi->raw_data + src->off, src->encoded_size,
|
||||
decompressed_data + dst->off, dst->unpacked_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "lib_rdi_format/rdi_format.c"
|
||||
#include "lib_rdi_format/rdi_format_parse.c"
|
||||
|
||||
internal void
|
||||
rdi_decompress_parsed(U8 *decompressed_data, U64 decompressed_size, RDI_Parsed *og_rdi)
|
||||
{
|
||||
// rjf: copy header
|
||||
RDI_Header *src_header = (RDI_Header *)og_rdi->raw_data;
|
||||
RDI_Header *dst_header = (RDI_Header *)decompressed_data;
|
||||
{
|
||||
MemoryCopy(dst_header, src_header, sizeof(RDI_Header));
|
||||
}
|
||||
|
||||
// rjf: copy & adjust sections for decompressed version
|
||||
if(og_rdi->sections_count != 0)
|
||||
{
|
||||
RDI_Section *dsec_base = (RDI_Section *)(decompressed_data + dst_header->data_section_off);
|
||||
MemoryCopy(dsec_base, (U8 *)og_rdi->raw_data + src_header->data_section_off, sizeof(RDI_Section) * og_rdi->sections_count);
|
||||
U64 off = dst_header->data_section_off + sizeof(RDI_Section) * og_rdi->sections_count;
|
||||
off += 7;
|
||||
off -= off%8;
|
||||
for(U64 idx = 0; idx < og_rdi->sections_count; idx += 1)
|
||||
{
|
||||
dsec_base[idx].encoding = RDI_SectionEncoding_Unpacked;
|
||||
dsec_base[idx].off = off;
|
||||
dsec_base[idx].encoded_size = dsec_base[idx].unpacked_size;
|
||||
off += dsec_base[idx].unpacked_size;
|
||||
off += 7;
|
||||
off -= off%8;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: decompress sections into new decompressed file buffer
|
||||
if(og_rdi->sections_count != 0)
|
||||
{
|
||||
RDI_Section *src_first = og_rdi->sections;
|
||||
RDI_Section *dst_first = (RDI_Section *)(decompressed_data + dst_header->data_section_off);
|
||||
RDI_Section *src_opl = src_first + og_rdi->sections_count;
|
||||
RDI_Section *dst_opl = dst_first + og_rdi->sections_count;
|
||||
for(RDI_Section *src = src_first, *dst = dst_first;
|
||||
src < src_opl && dst < dst_opl;
|
||||
src += 1, dst += 1)
|
||||
{
|
||||
rr_lzb_simple_decode((U8*)og_rdi->raw_data + src->off, src->encoded_size,
|
||||
decompressed_data + dst->off, dst->unpacked_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RDI_FORMAT_LOCAL_H
|
||||
#define RDI_FORMAT_LOCAL_H
|
||||
|
||||
#include "lib_rdi_format/rdi_format.h"
|
||||
#include "lib_rdi_format/rdi_format_parse.h"
|
||||
|
||||
internal void rdi_decompress_parsed(U8 *decompressed_data, U64 decompressed_size, RDI_Parsed *og_rdi);
|
||||
|
||||
#endif // RDI_FORMAT_LOCAL_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RDI_FORMAT_LOCAL_H
|
||||
#define RDI_FORMAT_LOCAL_H
|
||||
|
||||
#include "lib_rdi_format/rdi_format.h"
|
||||
#include "lib_rdi_format/rdi_format_parse.h"
|
||||
|
||||
internal void rdi_decompress_parsed(U8 *decompressed_data, U64 decompressed_size, RDI_Parsed *og_rdi);
|
||||
|
||||
#endif // RDI_FORMAT_LOCAL_H
|
||||
|
||||
+1888
-1888
File diff suppressed because it is too large
Load Diff
+1493
-1493
File diff suppressed because it is too large
Load Diff
@@ -1,102 +1,102 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ DWARF Stringize Functions
|
||||
|
||||
static char dwarf_spaces[] = " ";
|
||||
|
||||
static void
|
||||
dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent){
|
||||
String8 unit_type_string = dwarf_string_from_unit_type((DWARF_UnitType)unit->unit_type);
|
||||
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces,
|
||||
unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*sunit_type=%.*s\n", indent, dwarf_spaces,
|
||||
str8_varg(unit_type_string));
|
||||
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
|
||||
unit->address_size);
|
||||
str8_list_pushf(arena, out, "%.*sabbrev_off=0x%llx\n", indent, dwarf_spaces,
|
||||
unit->abbrev_off);
|
||||
|
||||
switch (unit->unit_type){
|
||||
case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile:
|
||||
{
|
||||
str8_list_pushf(arena, out, "%.*sdwo_id=%llu\n", indent, dwarf_spaces, unit->dwo_id);
|
||||
}break;
|
||||
|
||||
case DWARF_UnitType_type: case DWARF_UnitType_split_type:
|
||||
{
|
||||
str8_list_pushf(arena, out, "%.*stype_signature=%llu\n", indent, dwarf_spaces,
|
||||
unit->type_signature);
|
||||
str8_list_pushf(arena, out, "%.*stype_offset=%llu\n", indent, dwarf_spaces,
|
||||
unit->type_offset);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit,
|
||||
U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off);
|
||||
str8_list_pushf(arena, out, "%.*sinfo_length=0x%llx\n", indent, dwarf_spaces,
|
||||
unit->info_length);
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*scomp_unit_count=%u\n", indent, dwarf_spaces,
|
||||
unit->comp_unit_count);
|
||||
str8_list_pushf(arena, out, "%.*slocal_type_unit_count=%u\n", indent, dwarf_spaces,
|
||||
unit->local_type_unit_count);
|
||||
str8_list_pushf(arena, out, "%.*sforeign_type_unit_count=%u\n", indent, dwarf_spaces,
|
||||
unit->foreign_type_unit_count);
|
||||
str8_list_pushf(arena, out, "%.*sbucket_count=%u\n", indent, dwarf_spaces,
|
||||
unit->bucket_count);
|
||||
str8_list_pushf(arena, out, "%.*sname_count=%u\n", indent, dwarf_spaces, unit->name_count);
|
||||
str8_list_pushf(arena, out, "%.*sabbrev_table_size=%u\n", indent, dwarf_spaces,
|
||||
unit->abbrev_table_size);
|
||||
str8_list_pushf(arena, out, "%.*saugmentation_string=%.*s\n", indent, dwarf_spaces,
|
||||
str8_varg(unit->augmentation_string));
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
|
||||
unit->address_size);
|
||||
str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces,
|
||||
unit->segment_selector_size);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off);
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces,
|
||||
unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->dwarf_version);
|
||||
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
|
||||
unit->address_size);
|
||||
str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces,
|
||||
unit->segment_selector_size);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ DWARF Stringize Functions
|
||||
|
||||
static char dwarf_spaces[] = " ";
|
||||
|
||||
static void
|
||||
dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent){
|
||||
String8 unit_type_string = dwarf_string_from_unit_type((DWARF_UnitType)unit->unit_type);
|
||||
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces,
|
||||
unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*sunit_type=%.*s\n", indent, dwarf_spaces,
|
||||
str8_varg(unit_type_string));
|
||||
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
|
||||
unit->address_size);
|
||||
str8_list_pushf(arena, out, "%.*sabbrev_off=0x%llx\n", indent, dwarf_spaces,
|
||||
unit->abbrev_off);
|
||||
|
||||
switch (unit->unit_type){
|
||||
case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile:
|
||||
{
|
||||
str8_list_pushf(arena, out, "%.*sdwo_id=%llu\n", indent, dwarf_spaces, unit->dwo_id);
|
||||
}break;
|
||||
|
||||
case DWARF_UnitType_type: case DWARF_UnitType_split_type:
|
||||
{
|
||||
str8_list_pushf(arena, out, "%.*stype_signature=%llu\n", indent, dwarf_spaces,
|
||||
unit->type_signature);
|
||||
str8_list_pushf(arena, out, "%.*stype_offset=%llu\n", indent, dwarf_spaces,
|
||||
unit->type_offset);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit,
|
||||
U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off);
|
||||
str8_list_pushf(arena, out, "%.*sinfo_length=0x%llx\n", indent, dwarf_spaces,
|
||||
unit->info_length);
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*scomp_unit_count=%u\n", indent, dwarf_spaces,
|
||||
unit->comp_unit_count);
|
||||
str8_list_pushf(arena, out, "%.*slocal_type_unit_count=%u\n", indent, dwarf_spaces,
|
||||
unit->local_type_unit_count);
|
||||
str8_list_pushf(arena, out, "%.*sforeign_type_unit_count=%u\n", indent, dwarf_spaces,
|
||||
unit->foreign_type_unit_count);
|
||||
str8_list_pushf(arena, out, "%.*sbucket_count=%u\n", indent, dwarf_spaces,
|
||||
unit->bucket_count);
|
||||
str8_list_pushf(arena, out, "%.*sname_count=%u\n", indent, dwarf_spaces, unit->name_count);
|
||||
str8_list_pushf(arena, out, "%.*sabbrev_table_size=%u\n", indent, dwarf_spaces,
|
||||
unit->abbrev_table_size);
|
||||
str8_list_pushf(arena, out, "%.*saugmentation_string=%.*s\n", indent, dwarf_spaces,
|
||||
str8_varg(unit->augmentation_string));
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
|
||||
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
|
||||
unit->address_size);
|
||||
str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces,
|
||||
unit->segment_selector_size);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off);
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent){
|
||||
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
|
||||
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
|
||||
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
|
||||
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces,
|
||||
unit->offset_size);
|
||||
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->dwarf_version);
|
||||
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
|
||||
unit->address_size);
|
||||
str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces,
|
||||
unit->segment_selector_size);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user