646 changed files with 165745 additions and 378642 deletions
-1
View File
@@ -1 +0,0 @@
*.sh text=auto eol=lf
+6 -30
View File
@@ -13,17 +13,6 @@ jobs:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
target:
- raddbg
- radlink
- radbin
compiler:
- msvc
- clang
mode:
- debug
- release
steps:
- name: checkout
uses: actions/checkout@v2
@@ -31,22 +20,9 @@ jobs:
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
run-torture:
runs-on: windows-2022
steps:
# - name: Install ASAN
# shell: cmd
# run: |
# "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" modify --installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" --quiet --force --norestart --add Microsoft.VisualStudio.Component.VC.ASAN
- name: checkout
uses: actions/checkout@v2
- name: run-torture
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build radlink asan debug no_meta || exit /b 1
call build torture debug no_meta || exit /b 1
cd build
torture -l:radlink || exit /b 1
call build raddbg msvc debug || exit /b 1
call build raddbg_from_pdb msvc debug || exit /b 1
call build raddbg_from_dwarf msvc debug || exit /b 1
call build raddbg clang debug || exit /b 1
call build raddbg_from_pdb clang debug || exit /b 1
call build raddbg_from_dwarf clang debug || exit /b 1
-1
View File
@@ -1,4 +1,3 @@
/build/
/local/
*~
.vscode/settings.json
-137
View File
@@ -1,137 +0,0 @@
# v0.9.24-alpha
## Debugger Changes
- Added the ability for the debugger to load, use, and evaluate using debug
info, even when not actively debugging. The debugger will now keep a process'
debug info loaded, even after the process ends. It stores the set of loaded
debug info files in the project configuration file, meaning it will also
automatically load the same debug info across many runs. Debug info can also
be loaded manually (without ever launching a process) with the
`Load Debug Info` command. There is also a new tab, `Debug Info`, which allows
viewing and managing the set of loaded debug info files.
- Improved the debugger's behavior when used as a drag & drop target, to allow
for debug info loading as an option (when relevant), and to better handle the
case where many files (potentially of different types) are dropped together.
- Improved debug info searching performance and reponsiveness in large projects.
- Fixed some crashes and incorrect results with the new `list` view.
- Fixed some cases where RDIs did not contain some basic types from their
originating PDBs.
- Allowed `.` and `->` operators to be used with array types.
- Fixed the debugger's treatment of quoted command line arguments when building
targets. In previous versions, calling `raddbg main.exe "foo bar baz"` would
create a target `main.exe` with arguments `foo bar baz` (dropping the quotes).
This is now fixed, such that the target's arguments string will also contain
the quotes, and pass them to the target when launched.
- Fixed the debugger not correctly responding (through font and UI scale) to DPI
changes.
- Fixed the debugger incorrectly generating conflicting source line info records
in PDB -> RDI conversion, which in some scenarios was preventing source line
maps from working (leading to breakpoint resolution failing).
- Other small fixes, improvements, and tweaks.
# v0.9.23-alpha
## Debugger Changes
- Further improved PDB -> RDI conversion performance & memory usage.
- Adjusted limits for the amount of PDB -> RDI conversion work that the
debugger will kick off, to prevent PDB -> RDI conversion interfering with
debuggee performance.
- Reintroduced the `list` lens, which gathers all nodes in a linked list, and
visualizes them as a flat list of pointers (the same as how an array of
pointers is visualized).
- Fixed a crash when closing empty Geometry 3D views. (#652, #657)
- Fixed the debugger not visualizing `enum` types when evaluated through a
bitfield type. (#655)
- Fixed the PDB -> RDI conversion not correctly generating location information
for function parameters, when the EXE/PDB were built to include support for
Edit and Continue (`-ZI` switch). (#656)
## Binary Utility Changes
- Fixed a crash when using the `--compress` option, when generating RDI files.
# v0.9.22-alpha
## Debugger Changes
- Further improved PDB -> RDI conversion performance.
- Capped the number of additional threads / processes spawned for PDB -> RDI
conversion.
- Prioritize PDB -> RDI conversion based on what is actually found to be
necessary by the debugger, rather than converting all PDBs in the order in
which they're discovered.
- Added preliminary support for DWARF -> RDI conversion on Windows.
- The debugger now relies on source file checksums to determine whether or not
a source file is out-of-date with respect to what was compiled when debug info
was produced, rather than just the modification timestamp.
- The debugger now will rely on debug info to detect the language of source code
files, if it cannot infer from the source file's extension, or view settings.
This will enable features like syntax highlighting and hover evaluation in
cases like `.inl` files being included in C++ projects.
- The debugger now will restore the last focused window when continuing
automatically. (#245, #596)
- Watch tables have been simplified in that they no longer have a separate
column for evaluation types, since this was usually taking a lot more space
than it deserved. The type of evaluations is still displayed in watch table
cells, and it can always be evaluated directly via `typeof`.
- Type evaluations have been simplified in watch tables as well; they no longer
have untitled columns for sizes and offsets, this is instead displayed as
an extra note by default. Similar behavior to the original behavior can still
be obtained using the `columns` view, if needed.
- The debugger no longer uses complex `union` types for most registers, and
instead just displays the register value plainly.
- The hover evaluation UI has been made larger when needed.
- The debugger now prefers matching global, function, and type identifiers to
the most relevant debug info and module in context; this fixes evaluation in
some multi-process debugging contexts. (#581)
- Fixed the debugger unnecessarily stripping `enum` type information when
accessed through array operators. (#634)
- The debugger now understands a standalone `unsigned` keyword as an
`unsigned int` type, to match C rules.
- The debugger now uses the current working directory to form the working
directory for targets specified on the command line, to match behavior when
running a command from the command line without the debugger.
- Improved call stack computation performance.
- Improved debugger memory usage over long periods of time.
- Fixed string-pointer comparison not working with not-equal (`!=`) operations.
- Fixed a bug which was causing bad debuggee performance on some threads after
some interactions with the debugger controller.
- Fixed incorrect results when adding two register values. (#642)
- Fixed the interpretation of register expressions in visualizers. (#649)
- Fixed "forever loading" states in disassembly views in some cases. (#643)
- Fixed jittering on window resizing. (#636)
- Fixed the bitmap visualizer crashing in some circumstances relating to
unsupported bitmap sizes. (#444, #563)
- Fixed a crash when an empty `cast()` expression would be evaluated. (#625)
- Fixed a crash when an invalid expression would be visualized using the `text`
view. (#647)
## Linker Changes
- Changed symbol resolution in libaries to match MSVC behavior.
- Optimized image building step to reduce memory usage.
- Linker memory maps all input files by default to lower memory usage.
(`/RAD_MEMORY_MAP_FILES`)
- If debug info is available, linker uses it to show file and line number for
unresolved relocations.
- Improved base relocation build performance for large images, cutting build
time by 70%.
- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability
with existing response files
- Implemented section garbage collection (`/OPT:REF`)
- Fixed bug where thread local variables pointed to incorrect types.
- Changed rules for weak and undefined symbols, now weak symbol is not allowed
to replace an undefined symbol.
- Linker no longer creates thunks for imports that don't require them.
## Binary Utility Changes
- The binary utility, like the debugger, now can convert DWARF debug info to
RDI files. When both DWARF and PDB info is present, it can now convert both,
and produce a single final RDI file with all information.
- Textual dumping of RDI files is now done in parallel, massively improving
dumping performance.
- PDB -> Breakpad conversion performance has now been parallelized to a greater
degree, improving performance.
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) Epic Games Tools
Copyright (c) 2024 Epic Games Tools
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in
+137 -240
View File
@@ -1,93 +1,42 @@
# 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. You can find pre-built release binaries
[here](https://github.com/EpicGamesExt/raddebugger/releases)._
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 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](https://github.com/EpicGamesExt/raddebugger/issues), along with any
information you can gather, like dump files (along with the build you used),
instructions to reproduce, test executables, and so on.
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.
In addition to the debugger, we aim to further improve the toolchain with two
additional related technologies: **(1)** the RAD Debug Info (RDI) format, and
**(2)** the RAD Linker.
You can download pre-built binaries for the debugger
[here](https://github.com/EpicGames/raddebugger/releases).
## The RAD Debug Info (RDI) Format
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 RADDBG debug info 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 RADDBG format on-demand. This conversion process
is currently an unoptimized reference version. Nevertheless it's still quite
fast for smaller PDB files (in many cases faster than many other programs
simply deserialize the PDBs). It is much slower for much larger projects at the
moment, but we expect this will vastly improve overtime.
The RAD Debug Info (RDI) format is our custom debug information format, which
the debugger parses and uses, rather than the debug information natively
produced by toolchains, like PDB or DWARF. To work with these existing
toolchains, we convert PDB (and eventually PE/ELF files with embedded DWARF)
into the RDI format on-demand.
The RADDBG format is currently specified in code, in the files within the
`src/raddbg_format` folder. The other relevant folders for working with the
format are:
The RDI format is currently specified in code, in the files within the
`src/lib_rdi` folder. In [`rdi.h`](src/lib_rdi/rdi.h) and
[`rdi.c`](src/lib_rdi/rdi.c), the types and functions which define the format
itself are specified. In [`rdi_parse.h`](src/lib_rdi/rdi_parse.h) and
[`rdi_parse.c`](src/lib_rdi/rdi_parse.c), helpers for parsing the format are
included.
- `raddbg_cons`: The RADDBG construction layer, for constructing RADDBG files.
- `raddbg_convert`: Our implementation of PDB-to-RADDBG (and an in-progress
implementation of a DWARF-to-RADDBG) conversion.
- `raddbg_dump`: Code for textually dumping information from RADDBG files.
We also have an in-progress library for constructing and serializing RDI data,
located within the `src/lib_rdi_make` folder.
## Development Setup Instructions
Our `radbin` utility (accessible through the debugger too, via the `--bin`
command line argument) is capable of converting native debug information formats
to RDI, and of producing textual dumps of contents stored within RDI files.
**Note: Currently, only x64 Windows development is supported.**
## The RAD Linker
The RAD Linker is a new performance linker for generating x64 PE/COFF binaries.
It is designed to be very fast when creating gigantic executables. It generates
standard PDB files for debugging, but it can also (optionally) natively create
RAD Debug Info too, which is useful both to eliminate on-demand conversion time
when debugging, but also for huge executables that otherwise create broken
PDBs that overflow internal 32-bit tables.
The RAD Linker is primarily optimized to handle huge linking projects. In our
test cases (where debug info is multiple gigabytes), we see 50% faster link
times.
The command line syntax is fully compatible with MSVC; you can get a full list
of implemented switches from `/help`.
Our current designed-for use case for the linker is to help with the
compile-debug cycle of huge projects. We don't yet have support for
link-time-optimizations, but this feature is on the road map.
By default, the linker spawns as many threads as there are cores, so if you plan
to run multiple linkers in parallel, you can limit the number of thread workers
via `/rad_workers`.
We also have support for large memory pages, which, when enabled, reduce link
time by another 25%. To link with large pages, you need to explicitly request
them via `/rad_large_pages`. Large pages are off by default, since Windows
support for large pages is a bit buggy; we recommend they only be used in Docker
or VM images where the environment is reset after each link. In a standard
Windows environment, using large pages otherwise will fragment memory quickly,
forcing a reboot. We are working on a Linux port of the linker that will be able
to build with large pages robustly.
A benchmark of the linker's performance is below:
![AMD Ryzen Threadripper PRO 3995WX 64-Cores, 256 GiB RAM (Windows x64)](https://github.com/user-attachments/assets/a95b382a-76b4-4a4c-b809-b61fe25e667a)
---
# Project Development Setup Instructions
**NOTE: Currently, only x64 Windows development is supported for the project.**
## 1. Installing the Required Tools (MSVC & Windows SDK)
### 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
@@ -96,7 +45,7 @@ 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
### 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.
@@ -140,63 +89,45 @@ You should see the following output:
[msvc compile]
[default mode, assuming `raddbg` build]
metagen_main.c
searching C:\devel\raddebugger/src... 458 files found
parsing metadesk... 16 metadesk files parsed
gathering tables... 97 tables found
searching C:\devel\raddebugger/src... 299 files found
parsing metadesk... 12 metadesk files parsed
gathering tables... 37 tables found
generating layer code...
raddbg_main.c
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`.
This `raddbg.exe` will have been built in **debug mode**, which is not built
with optimizations, and may perform worse. To produce a
**release mode executable**, run `build.bat` with a `release` argument:
```
build release
```
This build will take significantly longer.
By default, `build.bat` only builds the debugger if no arguments (or just
`release`) are passed, but additional arguments can be passed to build the RAD
Linker, or the `radbin` CLI binary file utility:
```
build radlink release
build radbin release
```
---
# Project Roadmap
## Short-To-Medium-Term Roadmap
### The Initial Alpha Battle-Testing Phase
The first priority for the project is to ensure that the most crucial components
are functioning extremely reliably for local, x64, Windows development.
For the debugger, 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. For the linker, this is a matter of reliability and
convergence with existing linker behavior.
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 we've 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, we still
expect some issues, and are prioritizing these issues being resolved first.
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.
We also hope to continue to improve performance in this phase. For the debugger,
this primarily includes frontend performance, introducing caches when economical
to do so, and tightening existing systems up. For the linker, it has been mostly
tuned thus far for giant projects, and so we'd like to improve linking speed for
small-to-mid sized projects as well.
For the linker, there are also a number of features to come, like
dead-code-elimination (`/opt:ref`), and link-time-optimizations with the help
of `clang` (we won't support LTCG from MSVC, since it is undocumented).
Additionally, the debug info conversion process is not fast (nor wide) enough
to support extremely large projects. This is for two reasons: (a) the
PDB-to-RADDBG converter is an unoptimized reference implementation, and (b) the
debugger learns of new modules (and thus which PDBs to load) in a
serially-dependent way (this is necessarily the case for correct debugging
results). We expect that the conversion process' performance can be massively
improved, and also that some heuristics can be used to begin converting PDBs
to RADDBGs before the debugger knows those PDBs are needed, thus ensuring the
associated RADDBG files are ready instantaneously when the associated modules
are finally loaded by the debugger. Improving this situation is a major part of
this phase, as it will make the debugger much more usable for large projects.
### Local x64 Linux Debugging Phase
@@ -212,10 +143,11 @@ 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/unwind` layer to support x64 ELF unwinding (currently, there
is only an x64 PE unwinding implementation).
- Creating a DWARF-to-RADDBG converter (in the same way that we've built a PDB-
to-RADDBG converter). A partial implementation of this is in
`src/raddbg_convert/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
@@ -237,10 +169,6 @@ 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.
---
# Codebase Introduction
## Top-Level Directory Descriptions
- `data`: Small binary files which are used when building, either to embed
@@ -251,10 +179,9 @@ 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. Not
checked in to version control.
- `local`: Local files, used for local build configuration input files.
## Layer Descriptions
## 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
@@ -279,88 +206,56 @@ 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`.
A list of the layers in the codebase and their associated namespaces is below:
- `artifact_cache` (`AC_`): Implements an asynchronously-filled cache of
computation artifacts, which are automatically evicted when not accessed. Used
for asynchronously streaming and caching process memory and file system
contents, as well as asynchronously preparing visualizer data.
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
memory allocators, helper macros, command-line parsing, and so on. Requires
no other codebase layers.
- `codeview` (`CV_`): Code for parsing and writing the CodeView format.
- `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File
memory allocators, helper macros, command-line parsing, and so on. Depends
on no other codebase layers.
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
Format) file format.
- `content` (`C_`): Implements a cache for general data blobs, keyed by a
128-bit hash of the data. Also implements a keying system on top, where keys
refer to a unique identity which corresponds to a history of 128-bit hashes.
Used as a general data store by other layers.
- `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.
- `dbg_engine` (`D_`): Implements the core debugger system, without any
graphical components. This contains top-level logic for things like stepping,
launching, freezing threads, mid-run breakpoint addition, some caches, and so
on.
- `dbg_info` (`DI_`): Implements asynchronous debug info conversion and loading.
Maintains a cache for loaded debug info. Loads RAD Debug Info (RDI) files.
Launches separate processes for on-demand conversion to the RDI format if
necessary. Also provides various asynchronous operations for using debug info,
like fuzzy searching across all records in loaded debug info.
- `demon` (`DMN_`): An abstraction layer for local-machine, low-level process
- `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` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug
info stored in the RADDBG format. Users ask for debug info for a particular
executable, 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 RADDBG 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`.
- `disasm` (`DASM_`): Implements disassembly generation, including exposing the
ability to compute and cache disassembly asynchronously.
- `draw` (`DR_`): 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.
- `dwarf` (`DW_`): Code for parsing the DWARF format.
- `eh` (`EH_`): Code for parsing the EH frame format.
- `elf` (`ELF_`): Code for parsing the ELF format.
- `eval` (`E_`): A compiler for an expression language, built for evaluation of
variables, registers, types, and more, from debugger-attached processes,
debug info, debugger state, and files. Broken into several phases mostly
corresponding to traditional compiler phases: lexer, parser, type-checker, IR
generation, and IR evaluation.
- `eval_visualization` (`EV_`): Implements the core non-graphical evaluation
visualization engine, which can be used to visualize evaluations (provided by
the `eval` layer) in a number of ways. Implements core data structures and
transforms for watch tables.
- `file_stream` (`FS_`): Implements asynchronous file streaming, storing the
artifacts inside of the cache implemented by the `content` and
`artifact_cache` layers, hot-reloading the contents of files when they change.
Allows callers to map file paths to data hashes, which can then be used to
obtain the file's data.
- `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in
CPU-side data for text shaping, and in GPU texture atlases for rasterized
glyphs. All cache information is sourced from the `font_provider` abstraction
layer.
- `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.
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
programs to work with various features in the debugger. Does not depend on
`base`, and can be independently relocated to other codebases.
- `lib_rdi` (`RDI_`): Standalone library which defines the core RDI types
and helper functions for reading and writing the RDI debug info file format.
Does not depend on `base`, and can be independently relocated to other
codebases.
- `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info
data. Does not depend on `base`, and can be independently relocated
to other codebases.
- `linker` (`LNK_`): The layer which implements the RAD Linker executable
itself.
- `mdesk` (`MD_`): Code for parsing Metadesk files (stored as `.mdesk`), which
is the JSON-like (technically a JSON superset) text format used for the
debugger's user and project configuration files and metacode, which is parsed
and used to generate code with the `metagen` layer.
- `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.
- `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
@@ -369,13 +264,14 @@ A list of the layers in the codebase and their associated namespaces is below:
tables, which are then used to produce e.g. C `enum`s and a number of
associated data tables. There are also a number of other generation features,
like embedding binary files or complex multi-line strings into source code.
- `msf` (`MSF_`): Code for parsing and writing the MSF file format.
- `msvc_crt` (`MSCRT_`): Code for parsing that's specific to the MSVC CRT.
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.
- `mule` (no namespace): Test executables for battle testing debugger
functionality.
- `mutable_text` (`MTX_`): Implements an asynchronously-filled-and-mutated
cache for text buffers which are mutated across time. In the debugger, this is
used to implement the `Output` log.
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
types in other debuggers.
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
@@ -384,29 +280,23 @@ A list of the layers in the codebase and their associated namespaces is below:
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
graphical operating system features under an abstract API, which is
implemented per-target-operating-system.
- `pdb` (`PDB_`): Code for parsing and writing the PDB file format.
- `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file
format.
- `radbin` (`RB_`): The layer implementing the `radbin` binary utility
executable.
- `raddbg` (`RD_`): The layer which ties everything together for the main
graphical debugger executable. Implements the debugger's graphical frontend,
all of the debugger-specific UI, the debugger executable's command line
interface, and all of the built-in visualizers.
- `rdi` (`RDI_`): A layer which includes the `lib_rdi` layer and bundles it with
codebase-specific helpers, to easily include the library in codebase programs,
and have it be integrated with codebase constructs.
- `rdi_from_coff` (`C2R_`): Code for converting information in COFF files to the
equivalent RDI data.
- `rdi_from_dwarf` (`D2R_`): In-progress code for converting DWARF to the
equivalent RDI data.
- `rdi_from_elf` (`E2R_`)): Code for converting ELF data to the equivalent RDI
data.
- `rdi_from_pdb` (`P2R_`): Code for converting PDB data to the equivalent RDI
data.
- `rdi_make` (`RDIM_`): A layer which includes the `lib_rdi_make` layer and
bundles it with codebase-specific helpers, to easily include the library in
codebase programs, and have it be integrated with codebase constructs.
- `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.
- `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.
- `raddbg_cons` (`CONS_`): Implements an API for constructing files of the
RADDBG debug info file format.
- `raddbg_dump` (`DUMP_`): A dumper utility program for dumping textualizations
of RADDBG debug info files.
- `raddbg_format` (`RADDBG_`): Standalone types and helper functions for the
RADDBG debug info file format. Does not depend on `base`.
- `raddbg_markup` (`RADDBG_`): Standalone header file for marking up user
programs to work with various features in the `raddbg` debugger. Does not
depend on `base`.
- `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.
@@ -415,14 +305,21 @@ A list of the layers in the codebase and their associated namespaces is below:
level drawing API - this layer is strictly for minimally abstracting on an
as-needed basis. Higher level drawing features are implemented in the `draw`
layer.
- `scratch` (no namespace): Scratch space for small and transient test programs.
- `tester` (no namespace): A program used for automated testing.
- `text` (`TXT_`): Implements text processing functions, like parsing line
breaks, and lexing and parsing source code. Also offers an API to do this
asynchronously.
- `third_party` (no namespace): External code from other projects, which some
layers in the codebase depend on. All external code is included and built
directly within the codebase.
- `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
RADDBG 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.
- `unwind` (`UNW_`): Code for generating unwind information from threads, for
supported operating systems and architectures.
+40 -92
View File
@@ -1,22 +1,21 @@
@echo off
setlocal enabledelayedexpansion
setlocal
cd /D "%~dp0"
:restart
:: --- Usage Notes (2024/1/10) ------------------------------------------------
::
:: This is a central build script for the RAD Debugger project, for use in
:: Windows development environments. It takes a list of simple alphanumeric-
:: only arguments which control (a) what is built, (b) which compiler & linker
:: are used, and (c) extra high-level build options. By default, if no options
:: are passed, then the main "raddbg" graphical debugger is built.
:: This is a central build script for the RAD Debugger project. It takes a list
:: of simple alphanumeric-only arguments which control (a) what is built, (b)
:: which compiler & linker are used, and (c) extra high-level build options. By
:: default, if no options are passed, then the main "raddbg" graphical debugger
:: is built.
::
:: Below is a non-exhaustive list of possible ways to use the script:
:: `build raddbg`
:: `build raddbg clang`
:: `build raddbg release`
:: `build raddbg asan telemetry`
:: `build rdi_from_pdb`
:: `build raddbg_from_pdb`
::
:: For a full list of possible build targets and their build command lines,
:: search for @build_targets in this file.
@@ -25,10 +24,9 @@ cd /D "%~dp0"
::
:: - `asan`: enable address sanitizer
:: - `telemetry`: enable RAD telemetry profiling support
:: - `spall`: enable spall profiling support
:: --- Unpack Arguments -------------------------------------------------------
for %%a in (%*) do set "%%~a=1"
for %%a in (%*) do set "%%a=1"
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
if not "%release%"=="1" set debug=1
if "%debug%"=="1" set release=0 && echo [debug mode]
@@ -36,62 +34,34 @@ if "%release%"=="1" set debug=0 && echo [release mode]
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
if "%clang%"=="1" set msvc=0 && echo [clang compile]
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
:: --- Unpack Command Line Build Arguments ------------------------------------
set auto_compile_flags=
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info]
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
if "%pgo%"=="1" (
where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1
if "%clang%"=="1" (
if "%pgo_run%" == "1" (
call llvm-profdata merge %LLVM_PROFILE_FILE% -output=%~dp0build\build.profdata || exit /b 1
set auto_compile_flags=%auto_compile_flags% -fprofile-use=%~dp0build\build.profdata
set pgo_run=0
) else (
echo [pgo enabled]
set auto_compile_flags=%auto_compile_flags% -fprofile-generate -mllvm -vp-counters-per-site=5
set LLVM_PROFILE_FILE=%~dp0build\build.profraw
set pgo_run=1
)
) else (
echo ERROR: PGO build is not supported with current compiler
exit /b 1
)
)
:: --- Compile/Link Line Definitions ------------------------------------------
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf
set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf
set cl_debug= call cl /Od %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DNDEBUG %cl_common% %auto_compile_flags%
set clang_debug= call clang -g -O0 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DNDEBUG %clang_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" logo.res
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res
set cl_out= /out:
set cl_linker=
set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 -msha
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf
set clang_out= -o
set clang_linker= -Xlinker
:: --- Per-Build Settings -----------------------------------------------------
set gfx=-DOS_FEATURE_GRAPHICAL=1
set net=-DOS_FEATURE_SOCKET=1
set link_dll=-DLL
set link_icon=logo.res
if "%msvc%"=="1" set linker=%cl_linker%
if "%clang%"=="1" set linker=%clang_linker%
if "%msvc%"=="1" set only_compile=/c
if "%clang%"=="1" set only_compile=-c
if "%msvc%"=="1" set EHsc=/EHsc
if "%clang%"=="1" set EHsc=
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
if "%msvc%"=="1" set rc=call rc
if "%clang%"=="1" set rc=call llvm-rc
if "%msvc%"=="1" set rc=rc.exe
if "%clang%"=="1" set rc=llvm-rc.exe
:: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug%
@@ -115,12 +85,11 @@ pushd build
popd
:: --- Get Current Git Commit Id ----------------------------------------------
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DRADDBG_GIT=\"%%i\"
:: --- Build & Run Metaprogram ------------------------------------------------
if "%meta%"=="1" (
echo [doing metagen]
if "%no_meta%"=="1" echo [skipping metagen]
if not "%no_meta%"=="1" (
pushd build
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
metagen.exe || exit /b 1
@@ -129,44 +98,23 @@ if "%meta%"=="1" (
:: --- Build Everything (@build_targets) --------------------------------------
pushd build
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
if "%eval_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\eval_scratch.c %compile_link% %out%eval_scratch.exe || exit /b 1
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture.c %compile_link% %out%torture.exe || exit /b1
if "%mule_peb_trample%"=="1" (
set didbuild=1
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb
if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi
%compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1
move mule_peb_trample_new.exe mule_peb_trample.exe
)
if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1
if "%raddbg_from_pdb%"=="1" %compile% ..\src\raddbg_convert\pdb\raddbg_from_pdb_main.c %compile_link% %out%raddbg_from_pdb.exe || exit /b 1
if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe || exit /b 1
if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe || exit /b 1
if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1
if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1
if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
popd
:: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" (
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
exit /b 1
)
:: --- PGO Run ----------------------------------------------------------------
if "%pgo_run%"=="1" (
if "%radlink%"=="1" (
pushd local\lyra_pgo
call %~dp0build\radlink @lyra.rsp /rad_alt_pch_dir:%~dp0local\lyra_pgo || exit /b 1
popd
)
goto restart
)
:: --- Unset ------------------------------------------------------------------
for %%a in (%*) do set "%%a=0"
set raddbg=
set compile=
set compile_link=
set out=
set msvc=
set debug=
-81
View File
@@ -1,81 +0,0 @@
#!/bin/bash
set -eu
cd "$(dirname "$0")"
# --- Unpack Arguments --------------------------------------------------------
for arg in "$@"; do declare $arg='1'; done
if [ ! -v gcc ]; then clang=1; fi
if [ ! -v release ]; then debug=1; fi
if [ -v debug ]; then echo "[debug mode]"; fi
if [ -v release ]; then echo "[release mode]"; fi
if [ -v clang ]; then compiler="${CC:-clang}"; echo "[clang compile]"; fi
if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
# --- Unpack Command Line Build Arguments -------------------------------------
auto_compile_flags=''
# --- Get Current Git Commit Id -----------------------------------------------
git_hash=$(git describe --always --dirty)
git_hash_full=$(git rev-parse HEAD)
# --- Compile/Link Line Definitions -------------------------------------------
clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
clang_link="-lpthread -lm -lrt -ldl"
clang_out="-o"
gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
gcc_link="-lpthread -lm -lrt -ldl"
gcc_out="-o"
# --- Per-Build Settings ------------------------------------------------------
link_dll="-fPIC"
link_os_gfx="-lX11 -lXext"
link_render="-lGL -lEGL"
link_font_provider="-lfreetype"
# --- Choose Compile/Link Lines -----------------------------------------------
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
if [ -v gcc ]; then compile_release="$gcc_release"; fi
if [ -v gcc ]; then compile_link="$gcc_link"; fi
if [ -v gcc ]; then out="$gcc_out"; fi
if [ -v clang ]; then compile_debug="$clang_debug"; fi
if [ -v clang ]; then compile_release="$clang_release"; fi
if [ -v clang ]; then compile_link="$clang_link"; fi
if [ -v clang ]; then out="$clang_out"; fi
if [ -v debug ]; then compile="$compile_debug"; fi
if [ -v release ]; then compile="$compile_release"; fi
# --- Prep Directories --------------------------------------------------------
mkdir -p build
mkdir -p local
# --- Build & Run Metaprogram -------------------------------------------------
if [ -v no_meta ]; then echo "[skipping metagen]"; fi
if [ ! -v no_meta ]
then
cd build
$compile_debug ../src/metagen/metagen_main.c $compile_link $out metagen
./metagen
cd ..
fi
# --- Build Everything (@build_targets) ---------------------------------------
cd build
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $link_font_provider $out raddbg; fi
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
if [ -v rdi_breakpad_from_pdb ]; then didbuild=1 && $compile ../src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c $compile_link $out rdi_breakpad_from_pdb; fi
if [ -v ryan_scratch ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $link_render $link_font_provider $out ryan_scratch; fi
cd ..
# --- Warn On No Builds -------------------------------------------------------
if [ ! -v didbuild ]
then
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh rdi_from_pdb\`."
exit 1
fi
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+86 -58
View File
@@ -45,73 +45,101 @@ load_paths =
commands =
{
//- rjf: [raddbg]
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [scratch]
.f2 = { .win = "build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [textperf]
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [tester]
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta tester", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [radbin]
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: running target
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: local target builds
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_from_pdb = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_from_dwarf = { .win = "build rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_dump = { .win = "build rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_breakpad_from_pdb = { .win = "build rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_ryan_scratch = { .win = "build ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_main = { .win = "build mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_module = { .win = "build mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_hotload = { .win = "build mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_peb_trample = { .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: wsl target builds
.build_raddbg_wsl = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_from_pdb_wsl = { .win = "wsl ./build.sh rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_from_dwarf_wsl = { .win = "wsl ./build.sh rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_dump_wsl = { .win = "wsl ./build.sh rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_rdi_breakpad_from_pdb_wsl = { .win = "wsl ./build.sh rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_ryan_scratch_wsl = { .win = "wsl ./build.sh ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_main_wsl = { .win = "wsl ./build.sh mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_module_wsl = { .win = "wsl ./build.sh mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_hotload_wsl = { .win = "wsl ./build.sh mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_peb_trample_wsl = { .win = "wsl ./build.sh mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: local target runs
.run_raddbg = { .win = "pushd build && raddbg.exe && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.rjf_f1 =
{
.win = "build raddbg telemetry",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.rjf_f2 =
{
.win = "build raddbg_from_pdb",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.rjf_f3 =
{
.win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --profile:local_dev.raddbg_profile && popd",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg =
{
.win = "build raddbg",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg_release_telemetry =
{
.win = "build raddbg release telemetry",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg_from_pdb =
{
.win = "build raddbg_from_pdb",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg_dump =
{
.win = "build raddbg_dump",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_mule_main =
{
.win = "build mule_main",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.run_raddbg =
{
.win = "pushd build && raddbg.exe && popd",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
};
fkey_command =
{
.F1 = "f1",
.F2 = "f2",
.F3 = "f3",
.F1 = "build_raddbg",
.F3 = "run_raddbg",
};
fkey_command_override =
{
.rjf =
{
.F1 = "f1",
.F2 = "f2",
.F3 = "f3",
.F1 = "rjf_f1",
.F2 = "rjf_f2",
.F3 = "rjf_f3",
},
};
-21
View File
@@ -1,21 +0,0 @@
@echo off
setlocal
cd /D "%~dp0"
echo --- getting test data folder path ---------------------------------------------
if not exist .\local\test_data_path.txt (
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
goto :EOF
)
set /p test_data_folder=<.\local\test_data_path.txt
echo test data path: %test_data_folder%
echo:
echo --- building all testing executables ------------------------------------------
call build rdi_from_pdb rdi_dump raddbg radlink tester
echo:
echo --- running tests -------------------------------------------------------------
pushd build
call tester.exe --test_data:%test_data_folder%
popd
+1
View File
@@ -4,6 +4,7 @@ $path_root = git rev-parse --show-toplevel
if ($IsWindows) {
$devshell = Join-Path $path_root 'scripts/helpers/devshell.ps1'
# This HandmadeHero implementation is only designed for 64-bit systems
& $devshell -arch amd64
}
-654
View File
@@ -1,654 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Layer Initialization
internal void
ac_init(void)
{
Arena *arena = arena_alloc();
ac_shared = push_array(arena, AC_Shared, 1);
ac_shared->arena = arena;
ac_shared->cache_slots_count = 256;
ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count);
ac_shared->cache_stripes = stripe_array_alloc(arena);
for EachElement(idx, ac_shared->req_batches)
{
ac_shared->req_batches[idx].mutex = mutex_alloc();
ac_shared->req_batches[idx].arena = arena_alloc();
}
ac_shared->cancel_thread = thread_launch(ac_cancel_thread_entry_point, 0);
ac_shared->cancel_thread_mutex = mutex_alloc();
mutex_take(ac_shared->cancel_thread_mutex);
}
////////////////////////////////
//~ rjf: Cache Lookups
internal AC_Artifact
ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us)
{
ProfBeginFunction();
AC_RequestBatch *req_batch = &ac_shared->req_batches[params->flags & AC_Flag_HighPriority ? 0 : 1];
//- rjf: create function -> cache
AC_Cache *cache = 0;
{
U64 cache_hash = u64_hash_from_str8(str8_struct(&params->create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
{
RWMutexScope(cache_stripe->rw_mutex, write_mode)
{
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
{
if(c->create == params->create)
{
cache = c;
break;
}
}
if(write_mode && cache == 0)
{
cache = push_array(cache_stripe->arena, AC_Cache, 1);
SLLStackPush(ac_shared->cache_slots[cache_slot_idx], cache);
cache->create = params->create;
cache->destroy = params->destroy;
cache->slots_count = Max(256, params->slots_count);
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
cache->stripes = stripe_array_alloc(cache_stripe->arena);
}
}
if(cache != 0)
{
break;
}
}
}
//- rjf: unpack key
U64 hash = u64_hash_from_str8(key);
U64 slot_idx = hash%cache->slots_count;
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
//- rjf: cache * key -> existing artifact
B32 artifact_is_stale = 1;
B32 got_artifact = 0;
B32 need_request = 0;
AC_Artifact artifact = {0};
RWMutexScope(stripe->rw_mutex, 0)
{
for(AC_Node *n = slot->first; n != 0; n = n->next)
{
if(str8_match(n->key, key, 0))
{
ins_atomic_u64_eval_assign(&n->last_requested_gen, params->gen);
B32 is_stale = (n->last_completed_gen != params->gen);
if(ins_atomic_u64_eval(&n->completion_count) != 0 && (!is_stale || !(params->flags & AC_Flag_WaitForFresh)))
{
got_artifact = 1;
artifact_is_stale = is_stale;
artifact = n->val;
access_touch(access, &n->access_pt, stripe->cv);
}
if(is_stale)
{
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
need_request = got_task;
}
break;
}
}
}
//- rjf: didn't get artifact we want? -> fall back to slow path
if(!got_artifact || need_request)
{
RWMutexScope(stripe->rw_mutex, 1) for(;;)
{
B32 out_of_time = (os_now_microseconds() >= endt_us);
// rjf: find node in cache
AC_Node *node = 0;
for(AC_Node *n = slot->first; n != 0; n = n->next)
{
if(str8_match(n->key, key, 0))
{
node = n;
break;
}
}
// rjf: no node? -> create
if(node == 0)
{
need_request = 1;
node = stripe->free;
if(node)
{
stripe->free = node->next;
}
else
{
node = push_array_no_zero(stripe->arena, AC_Node, 1);
}
MemoryZeroStruct(node);
DLLPushBack(slot->first, slot->last, node);
// TODO(rjf): string allocator for keys
node->key = str8_copy(stripe->arena, key);
node->working_count = 1;
node->evict_threshold_us = params->evict_threshold_us;
}
node->access_pt.last_time_touched_us = os_now_microseconds();
node->access_pt.last_update_idx_touched = update_tick_idx();
// rjf: request
if(need_request)
{
need_request = 0;
MutexScope(req_batch->mutex)
{
AC_RequestNode *n = push_array(req_batch->arena, AC_RequestNode, 1);
if(params->flags & AC_Flag_Wide)
{
SLLQueuePush(req_batch->first_wide, req_batch->last_wide, n);
req_batch->wide_count += 1;
}
else
{
SLLQueuePush(req_batch->first_thin, req_batch->last_thin, n);
req_batch->thin_count += 1;
}
n->v.key = str8_copy(req_batch->arena, key);
n->v.gen = params->gen;
n->v.cancel_signal = &node->cancelled;
n->v.create = params->create;
}
cond_var_broadcast(async_tick_start_cond_var);
ins_atomic_u32_eval_assign(&async_loop_again, 1);
if(params->flags & AC_Flag_HighPriority)
{
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1);
}
}
// rjf: get value from node, if possible
if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time))
{
got_artifact = 1;
artifact_is_stale = (node->last_completed_gen == params->gen);
artifact = node->val;
access_touch(access, &node->access_pt, stripe->cv);
}
// rjf: abort if needed
if(out_of_time || got_artifact || is_async_thread)
{
break;
}
// rjf: wait for results
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, endt_us);
}
}
//- rjf: report staleness
if(params->stale_out)
{
params->stale_out[0] = artifact_is_stale;
}
ProfEnd();
return artifact;
}
////////////////////////////////
//~ rjf: Asynchronous Tick
internal void
ac_async_tick(void)
{
Temp scratch = scratch_begin(0, 0);
//////////////////////////////
//- rjf: enable cancellation scanning
//
if(lane_idx() == 0)
{
mutex_drop(ac_shared->cancel_thread_mutex);
}
//////////////////////////////
//- rjf: do eviction pass across all caches
//
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
{
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
RWMutexScope(cache_stripe->rw_mutex, 0)
{
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
{
Rng1U64 slot_range = lane_range(cache->slots_count);
for EachInRange(slot_idx, slot_range)
{
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
{
B32 slot_has_work = 0;
RWMutexScope(stripe->rw_mutex, write_mode)
{
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
{
next = n->next;
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) == 0)
{
slot_has_work = 1;
if(!write_mode)
{
break;
}
else
{
DLLRemove(slot->first, slot->last, n);
n->next = (AC_Node *)stripe->free;
stripe->free = n;
if(cache->destroy)
{
cache->destroy(n->val);
}
}
}
}
}
if(!slot_has_work)
{
break;
}
}
}
}
}
}
//////////////////////////////
//- rjf: gather requests
//
typedef struct RequestBatchTask RequestBatchTask;
struct RequestBatchTask
{
AC_Request *wide;
U64 wide_count;
AC_Request *thin;
U64 thin_count;
};
RequestBatchTask *tasks = 0;
U64 tasks_count = 0;
if(lane_idx() == 0)
{
tasks_count = 2;
tasks = push_array(scratch.arena, RequestBatchTask, tasks_count);
for EachElement(task_idx, ac_shared->req_batches)
{
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
{
tasks[task_idx].wide_count = batch->wide_count;
tasks[task_idx].thin_count = batch->thin_count;
tasks[task_idx].wide = push_array(scratch.arena, AC_Request, tasks[task_idx].wide_count);
tasks[task_idx].thin = push_array(scratch.arena, AC_Request, tasks[task_idx].thin_count);
{
U64 idx = 0;
for EachNode(n, AC_RequestNode, batch->first_wide)
{
MemoryCopyStruct(&tasks[task_idx].wide[idx], &n->v);
tasks[task_idx].wide[idx].key = str8_copy(scratch.arena, tasks[task_idx].wide[idx].key);
idx += 1;
}
}
{
U64 idx = 0;
for EachNode(n, AC_RequestNode, batch->first_thin)
{
MemoryCopyStruct(&tasks[task_idx].thin[idx], &n->v);
tasks[task_idx].thin[idx].key = str8_copy(scratch.arena, tasks[task_idx].thin[idx].key);
idx += 1;
}
}
arena_clear(batch->arena);
batch->first_wide = batch->last_wide = batch->first_thin = batch->last_thin = 0;
batch->wide_count = batch->thin_count = 0;
}
}
}
lane_sync_u64(&tasks, 0);
lane_sync_u64(&tasks_count, 0);
lane_sync();
//////////////////////////////
//- rjf: do all requests
//
for EachIndex(task_idx, tasks_count)
{
lane_sync();
RequestBatchTask *task = &tasks[task_idx];
//- rjf: set up cancellation signal
U64 cancelled = 0;
U64 *cancelled_ptr = 0;
if(lane_idx() == 0)
{
cancelled_ptr = &cancelled;
}
lane_sync_u64(&cancelled_ptr, 0);
//- rjf: do all wide requests for this priority
U64 done_wide_count = 0;
ProfScope("wide requests (p%I64u)", task_idx)
{
for EachIndex(idx, task->wide_count)
{
lane_sync();
AC_Request *r = &task->wide[idx];
// rjf: any new higher priority tasks? -> cancel
if(lane_idx() == 0)
{
if(task_idx == 1 && idx != 0 && ins_atomic_u32_eval(&async_loop_again_high_priority))
{
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
}
}
lane_sync();
// rjf: cancelled? -> exit
if(ins_atomic_u32_eval(cancelled_ptr))
{
break;
}
// rjf: compute val
B32 retry = 0;
U64 gen = r->gen;
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
// rjf: retry? -> resubmit request
if(retry && lane_idx() == 0)
{
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
{
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
SLLQueuePush(batch->first_wide, batch->last_wide, n);
batch->wide_count += 1;
MemoryCopyStruct(&n->v, r);
n->v.key = str8_copy(batch->arena, n->v.key);
}
ins_atomic_u32_eval_assign(&async_loop_again, 1);
}
// rjf: create function -> cache
AC_Cache *cache = 0;
if(!retry && lane_idx() == 0)
{
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
RWMutexScope(cache_stripe->rw_mutex, 0)
{
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
{
if(c->create == r->create)
{
cache = c;
break;
}
}
}
}
// rjf: write value into cache
if(!retry && lane_idx() == 0)
{
U64 hash = u64_hash_from_str8(r->key);
U64 slot_idx = hash%cache->slots_count;
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
RWMutexScope(stripe->rw_mutex, 1)
{
for(AC_Node *n = slot->first; n != 0; n = n->next)
{
if(str8_match(n->key, r->key, 0))
{
n->last_completed_gen = gen;
n->val = val;
ins_atomic_u64_dec_eval(&n->working_count);
ins_atomic_u64_inc_eval(&n->completion_count);
}
}
}
cond_var_broadcast(stripe->cv);
}
// rjf: increment count
lane_sync();
done_wide_count += 1;
}
}
lane_sync();
//- rjf: do all thin requests for this priority
U64 done_thin_count = 0;
ProfScope("thin requests (p%I64u)", task_idx)
{
U64 req_take_counter = 0;
U64 *req_take_counter_ptr = 0;
if(lane_idx() == 0)
{
req_take_counter_ptr = &req_take_counter;
}
lane_sync_u64(&req_take_counter_ptr, 0);
for(;;)
{
// rjf: any new higher priority tasks? -> cancel
if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2 &&
ins_atomic_u32_eval(&async_loop_again_high_priority))
{
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
}
// rjf: cancelled? -> exit
if(ins_atomic_u64_eval(cancelled_ptr))
{
break;
}
// rjf: take next task
U64 req_idx = ins_atomic_u64_inc_eval(req_take_counter_ptr) - 1;
if(req_idx >= task->thin_count) { break; }
AC_Request *r = &task->thin[req_idx];
// rjf: push thin lane ctx
U64 thin_lane_ctx_broadcast_memory = 0;
LaneCtx thin_lane_ctx = {0, 1, {0}, &thin_lane_ctx_broadcast_memory};
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
// rjf: compute val
B32 retry = 0;
U64 gen = r->gen;
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
// rjf: restore wide lane ctx
lane_ctx(lane_ctx_restore);
// rjf: retry? -> resubmit request
if(retry)
{
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
{
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
SLLQueuePush(batch->first_thin, batch->last_thin, n);
batch->thin_count += 1;
MemoryCopyStruct(&n->v, r);
n->v.key = str8_copy(batch->arena, n->v.key);
}
ins_atomic_u32_eval_assign(&async_loop_again, 1);
}
// rjf: create function -> cache
AC_Cache *cache = 0;
if(!retry)
{
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
RWMutexScope(cache_stripe->rw_mutex, 0)
{
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
{
if(c->create == r->create)
{
cache = c;
break;
}
}
}
}
// rjf: write value into cache
if(!retry)
{
U64 hash = u64_hash_from_str8(r->key);
U64 slot_idx = hash%cache->slots_count;
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
RWMutexScope(stripe->rw_mutex, 1)
{
for(AC_Node *n = slot->first; n != 0; n = n->next)
{
if(str8_match(n->key, r->key, 0))
{
n->last_completed_gen = gen;
n->val = val;
ins_atomic_u64_dec_eval(&n->working_count);
ins_atomic_u64_inc_eval(&n->completion_count);
}
}
}
cond_var_broadcast(stripe->cv);
}
}
lane_sync();
done_thin_count = ins_atomic_u64_eval(req_take_counter_ptr);
lane_sync();
}
//- rjf: cancelled early, unfinished tasks? -> defer to next tick
if(lane_idx() == 0 && task_idx > 0)
{
B32 need_another_try = (done_wide_count < task->wide_count || done_thin_count < task->thin_count);
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
{
// rjf: push leftover wide tasks
for(U64 idx = done_wide_count; idx < task->wide_count; idx += 1)
{
AC_Request *r = &task->wide[idx];
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
SLLQueuePush(batch->first_wide, batch->last_wide, n);
batch->wide_count += 1;
MemoryCopyStruct(&n->v, r);
n->v.key = str8_copy(batch->arena, n->v.key);
}
// rjf: push leftover thin tasks
for(U64 idx = done_thin_count; idx < task->thin_count; idx += 1)
{
AC_Request *r = &task->thin[idx];
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
SLLQueuePush(batch->first_thin, batch->last_thin, n);
batch->thin_count += 1;
MemoryCopyStruct(&n->v, r);
n->v.key = str8_copy(batch->arena, n->v.key);
}
}
if(need_another_try)
{
ins_atomic_u32_eval_assign(&async_loop_again, 1);
}
}
lane_sync();
}
lane_sync();
//////////////////////////////
//- rjf: disable cancellation scanning
//
if(lane_idx() == 0)
{
mutex_take(ac_shared->cancel_thread_mutex);
}
scratch_end(scratch);
}
////////////////////////////////
//~ rjf: Cancel Thread
internal void
ac_cancel_thread_entry_point(void *p)
{
for(;;)
{
os_sleep_milliseconds(50);
MutexScope(ac_shared->cancel_thread_mutex)
{
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
{
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
RWMutexScope(cache_stripe->rw_mutex, 0)
{
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
{
Rng1U64 slot_range = lane_range(cache->slots_count);
for EachInRange(slot_idx, slot_range)
{
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
{
B32 slot_has_work = 0;
RWMutexScope(stripe->rw_mutex, write_mode)
{
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
{
next = n->next;
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) > 0)
{
slot_has_work = 1;
if(!write_mode)
{
break;
}
else
{
n->cancelled = 1;
}
}
}
}
if(!slot_has_work)
{
break;
}
}
}
}
}
}
}
}
}
-161
View File
@@ -1,161 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARTIFACT_CACHE_H
#define ARTIFACT_CACHE_H
////////////////////////////////
//~ rjf: Artifact Handle Type
typedef struct AC_Artifact AC_Artifact;
struct AC_Artifact
{
U64 u64[4];
};
////////////////////////////////
//~ rjf: Artifact Computation Function Types
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
typedef void AC_DestroyFunctionType(AC_Artifact artifact);
typedef U32 AC_Flags;
typedef enum AC_FlagsEnum
{
AC_Flag_WaitForFresh = (1<<0),
AC_Flag_HighPriority = (1<<1),
AC_Flag_Wide = (1<<2),
}
AC_FlagsEnum;
typedef struct AC_ArtifactParams AC_ArtifactParams;
struct AC_ArtifactParams
{
AC_CreateFunctionType *create;
AC_DestroyFunctionType *destroy;
U64 slots_count;
U64 gen;
U64 evict_threshold_us;
B32 *stale_out;
AC_Flags flags;
};
////////////////////////////////
//~ rjf: Cache Types
typedef struct AC_Request AC_Request;
struct AC_Request
{
String8 key;
U64 gen;
B32 *cancel_signal;
AC_CreateFunctionType *create;
};
typedef struct AC_RequestNode AC_RequestNode;
struct AC_RequestNode
{
AC_RequestNode *next;
AC_Request v;
};
typedef struct AC_Node AC_Node;
struct AC_Node
{
AC_Node *next;
AC_Node *prev;
// rjf: key/gen/value
String8 key;
U64 last_requested_gen;
U64 last_completed_gen;
AC_Artifact val;
// rjf: metadata
AccessPt access_pt;
U64 working_count;
U64 completion_count;
U64 evict_threshold_us;
B32 cancelled;
U64 _unused_;
};
typedef struct AC_Slot AC_Slot;
struct AC_Slot
{
AC_Node *first;
AC_Node *last;
};
typedef struct AC_Cache AC_Cache;
struct AC_Cache
{
// rjf: link / key for cache-cache
AC_Cache *next;
AC_CreateFunctionType *create;
AC_DestroyFunctionType *destroy;
// rjf: artifact cache
U64 slots_count;
AC_Slot *slots;
StripeArray stripes;
};
typedef struct AC_RequestBatch AC_RequestBatch;
struct AC_RequestBatch
{
Mutex mutex;
Arena *arena;
AC_RequestNode *first_wide;
AC_RequestNode *last_wide;
AC_RequestNode *first_thin;
AC_RequestNode *last_thin;
U64 wide_count;
U64 thin_count;
};
typedef struct AC_Shared AC_Shared;
struct AC_Shared
{
Arena *arena;
// rjf: cache cache
U64 cache_slots_count;
AC_Cache **cache_slots;
StripeArray cache_stripes;
// rjf: requests
AC_RequestBatch req_batches[2]; // 0: high priority, 1: low priority
// rjf: cancel thread
Thread cancel_thread;
Mutex cancel_thread_mutex;
};
////////////////////////////////
//~ rjf: Globals
global AC_Shared *ac_shared = 0;
////////////////////////////////
//~ rjf: Layer Initialization
internal void ac_init(void);
////////////////////////////////
//~ rjf: Cache Lookups
internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us);
#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), .evict_threshold_us = (2000000), __VA_ARGS__}, (endt_us))
////////////////////////////////
//~ rjf: Asynchronous Tick
internal void ac_async_tick(void);
////////////////////////////////
//~ rjf: Cancel Thread
internal void ac_cancel_thread_entry_point(void *p);
#endif // ARTIFACT_CACHE_H
+227 -174
View File
@@ -1,192 +1,176 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Arena Functions
//- rjf: arena creation/destruction
// Implementation
internal Arena *
arena_alloc_(ArenaParams *params)
arena_alloc__sized(U64 init_res, U64 init_cmt)
{
// rjf: round up reserve/commit sizes
U64 reserve_size = params->reserve_size;
U64 commit_size = params->commit_size;
if(params->flags & ArenaFlag_LargePages)
{
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
}
else
{
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
}
ProfBeginFunction();
Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res);
// rjf: reserve/commit initial block
void *base = params->optional_backing_buffer;
if(base == 0)
void *memory = 0;
U64 res = 0;
U64 cmt = 0;
B32 large_pages = os_large_pages_enabled();
if(large_pages)
{
if(params->flags & ArenaFlag_LargePages)
{
base = os_reserve_large(reserve_size);
os_commit_large(base, commit_size);
}
else
{
base = os_reserve(reserve_size);
os_commit(base, commit_size);
}
raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
}
// rjf: panic on arena creation failure
#if OS_FEATURE_GRAPHICAL
if(Unlikely(base == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
}
U64 page_size = os_large_page_size();
res = AlignPow2(init_res, page_size);
#if OS_WINDOWS
cmt = res;
#else
cmt = AlignPow2(init_cmt, page_size);
#endif
memory = os_reserve_large(res);
if(!os_commit_large(memory, cmt))
{
memory = 0;
os_release(memory, res);
}
}
else
{
U64 page_size = os_page_size();
res = AlignPow2(init_res, page_size);
cmt = AlignPow2(init_cmt, page_size);
memory = os_reserve(res);
if(!os_commit(memory, cmt))
{
memory = 0;
os_release(memory, res);
}
}
// rjf: extract arena header & fill
Arena *arena = (Arena *)base;
Arena *arena = (Arena*)memory;
if(arena)
{
AsanPoisonMemoryRegion(memory, cmt);
AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE);
arena->prev = 0;
arena->current = arena;
arena->flags = params->flags;
arena->cmt_size = params->commit_size;
arena->res_size = params->reserve_size;
arena->base_pos = 0;
arena->pos = ARENA_HEADER_SIZE;
arena->cmt = commit_size;
arena->res = reserve_size;
arena->allocation_site_file = params->allocation_site_file;
arena->allocation_site_line = params->allocation_site_line;
#if ARENA_FREE_LIST
arena->free_last = 0;
arena->cmt = cmt;
arena->res = res;
arena->align = 8;
#if ENABLE_DEV
arena->dev = 0;
#endif
AsanPoisonMemoryRegion(base, commit_size);
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
arena->grow = 1;
arena->large_pages = large_pages;
}
ProfEnd();
return arena;
}
internal Arena *
arena_alloc(void)
{
ProfBeginFunction();
U64 init_res, init_cmt;
if (os_large_pages_enabled()) {
init_res = ARENA_RESERVE_SIZE_LARGE_PAGES;
init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES;
} else {
init_res = ARENA_RESERVE_SIZE;
init_cmt = ARENA_COMMIT_SIZE;
}
Arena *arena = arena_alloc__sized(init_res, init_cmt);
ProfEnd();
return arena;
}
internal void
arena_release(Arena *arena)
{
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
{
prev = n->prev;
os_release(n, n->res);
for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) {
prev = node->prev;
os_release(node, node->res);
}
}
//- rjf: arena push/pop core functions
internal U64
arena_huge_push_threshold(void)
{
U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE;
U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1;
return threshold;
}
internal void *
arena_push(Arena *arena, U64 size, U64 align, B32 zero)
arena_push__impl(Arena *arena, U64 size)
{
Arena *current = arena->current;
U64 pos_pre = AlignPow2(current->pos, align);
U64 pos_pst = pos_pre + size;
U64 pos_mem = AlignPow2(current->pos, arena->align);
U64 pos_new = pos_mem + size;
// rjf: chain, if needed
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
{
Arena *new_block = 0;
if (current->res < pos_new && arena->grow) {
Arena *new_block;
#if ARENA_FREE_LIST
{
Arena *prev_block;
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
{
if(new_block->res >= AlignPow2(new_block->pos, align) + size)
{
if(prev_block)
{
prev_block->prev = new_block->prev;
// normal growth path
if (size < arena_huge_push_threshold()) {
new_block = arena_alloc();
}
else
{
arena->free_last = new_block->prev;
}
break;
}
}
}
#endif
if(new_block == 0)
{
U64 res_size = current->res_size;
U64 cmt_size = current->cmt_size;
if(size + ARENA_HEADER_SIZE > res_size)
{
res_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
cmt_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
}
new_block = arena_alloc(.reserve_size = res_size,
.commit_size = cmt_size,
.flags = current->flags,
.allocation_site_file = current->allocation_site_file,
.allocation_site_line = current->allocation_site_line);
// huge growth path
else {
U64 new_block_size = size + ARENA_HEADER_SIZE;
new_block = arena_alloc__sized(new_block_size, new_block_size);
}
if (new_block) {
new_block->base_pos = current->base_pos + current->res;
SLLStackPush_N(arena->current, new_block, prev);
current = new_block;
pos_pre = AlignPow2(current->pos, align);
pos_pst = pos_pre + size;
}
// rjf: compute the size we need to zero
U64 size_to_zero = 0;
if(zero)
{
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
}
// rjf: commit new pages, if needed
if(current->cmt < pos_pst)
{
U64 cmt_pst_aligned = pos_pst + current->cmt_size-1;
cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size;
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
U64 cmt_size = cmt_pst_clamped - current->cmt;
U8 *cmt_ptr = (U8 *)current + current->cmt;
if(current->flags & ArenaFlag_LargePages)
{
os_commit_large(cmt_ptr, cmt_size);
}
else
{
os_commit(cmt_ptr, cmt_size);
}
current->cmt = cmt_pst_clamped;
}
// rjf: push onto current block
void *result = 0;
if(current->cmt >= pos_pst)
{
result = (U8 *)current+pos_pre;
current->pos = pos_pst;
AsanUnpoisonMemoryRegion(result, size);
if(size_to_zero != 0)
{
MemoryZero(result, size_to_zero);
pos_mem = AlignPow2(current->pos, current->align);
pos_new = pos_mem + size;
}
}
// rjf: panic on failure
if (current->cmt < pos_new) {
U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size;
B32 is_cmt_ok;
if (current->large_pages) {
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES);
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
cmt_new_size = cmt_new_clamped - current->cmt;
is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size);
} else {
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE);
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
cmt_new_size = cmt_new_clamped - current->cmt;
is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size);
}
if (is_cmt_ok) {
current->cmt = cmt_new_clamped;
}
}
void *memory = 0;
if (current->cmt >= pos_new) {
memory = (U8*)current + pos_mem;
current->pos = pos_new;
AsanUnpoisonMemoryRegion(memory, size);
}
#if OS_FEATURE_GRAPHICAL
if(Unlikely(result == 0))
if(Unlikely(memory == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
os_exit_process(1);
}
#endif
return result;
return memory;
}
internal U64
@@ -198,34 +182,95 @@ arena_pos(Arena *arena)
}
internal void
arena_pop_to(Arena *arena, U64 pos)
arena_pop_to(Arena *arena, U64 big_pos_unclamped)
{
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
Arena *current = arena->current;
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped);
#if ARENA_FREE_LIST
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{
prev = current->prev;
current->pos = ARENA_HEADER_SIZE;
SLLStackPush_N(arena->free_last, current, prev);
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res - ARENA_HEADER_SIZE);
}
#else
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{
// unroll the chain
Arena *current = arena->current;
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) {
prev = current->prev;
os_release(current, current->res);
}
#endif
AssertAlways(current);
arena->current = current;
// compute arena-relative position
U64 new_pos = big_pos - current->base_pos;
AssertAlways(new_pos <= current->pos);
// poison popped memory block
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
// update position
current->pos = new_pos;
}
//- rjf: arena push/pop helpers
internal void
arena_absorb(Arena *arena, Arena *sub)
{
#if ENABLE_DEV
arena_annotate_absorb__dev(arena, sub);
#endif
// base adjustment
Arena *current = arena->current;
U64 base_adjust = current->base_pos + current->res;
for (Arena *node = sub->current; node != 0; node = node->prev) {
node->base_pos += base_adjust;
}
// attach sub to arena
sub->prev = arena->current;
arena->current = sub->current;
sub->current = sub;
}
////////////////////////////////
// Wrappers
internal void *
arena_push(Arena *arena, U64 size)
{
void *memory = arena_push__impl(arena, size);
#if ENABLE_DEV
arena_annotate_push__dev(arena, size, memory);
#endif
return memory;
}
internal void *
arena_push_contiguous(Arena *arena, U64 size)
{
B32 restore = arena->grow;
arena->grow = 0;
void *memory = arena_push(arena, size);
arena->grow = restore;
#if ENABLE_DEV
arena_annotate_push__dev(arena, size, memory);
#endif
return memory;
}
internal void
arena_push_align(Arena *arena, U64 align)
{
Assert(IsPow2(align));
U64 amt = AlignPadPow2(arena->pos, align);
void *ptr = arena_push(arena, amt);
MemoryZero(ptr, amt);
}
internal void
arena_put_back(Arena *arena, U64 amt)
{
U64 pos_old = arena_pos(arena);
U64 pos_new = pos_old;
if (amt < pos_old) {
pos_new = pos_old - amt;
}
arena_pop_to(arena, pos_new);
}
internal void
arena_clear(Arena *arena)
@@ -233,20 +278,6 @@ arena_clear(Arena *arena)
arena_pop_to(arena, 0);
}
internal void
arena_pop(Arena *arena, U64 amt)
{
U64 pos_old = arena_pos(arena);
U64 pos_new = pos_old;
if(amt < pos_old)
{
pos_new = pos_old - amt;
}
arena_pop_to(arena, pos_new);
}
//- rjf: temporary arena scopes
internal Temp
temp_begin(Arena *arena)
{
@@ -260,3 +291,25 @@ temp_end(Temp temp)
{
arena_pop_to(temp.arena, temp.pos);
}
////////////////////////////////
//~ NOTE(allen): "Mini-Arena" Helper
internal B32
ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){
B32 result = 0;
U8 *cmt = (U8*)*cmtptr;
if (cmt < (U8*)pos){
U64 cmt_size_raw = (U8*)pos - cmt;
U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size);
if (os_commit(cmt, cmt_size)){
*cmtptr = cmt + cmt_size;
result = 1;
}
}
else{
result = 1;
}
return(result);
}
+52 -46
View File
@@ -1,51 +1,45 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_ARENA_H
#define BASE_ARENA_H
////////////////////////////////
//~ rjf: Arena Types
//~ rjf: Constants
#define ARENA_HEADER_SIZE 128
typedef U64 ArenaFlags;
enum
{
ArenaFlag_NoChain = (1<<0),
ArenaFlag_LargePages = (1<<1),
};
#ifndef ARENA_RESERVE_SIZE
# define ARENA_RESERVE_SIZE MB(64)
#endif
#ifndef ARENA_COMMIT_SIZE
# define ARENA_COMMIT_SIZE KB(64)
#endif
typedef struct ArenaParams ArenaParams;
struct ArenaParams
{
ArenaFlags flags;
U64 reserve_size;
U64 commit_size;
void *optional_backing_buffer;
char *allocation_site_file;
int allocation_site_line;
};
#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES
# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8)
#endif
#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES
# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2)
#endif
////////////////////////////////
//~ rjf: Arena Types
typedef struct Arena Arena;
struct Arena
{
Arena *prev; // previous arena in chain
Arena *current; // current arena in chain
ArenaFlags flags;
U64 cmt_size;
U64 res_size;
struct Arena *prev;
struct Arena *current;
U64 base_pos;
U64 pos;
U64 cmt;
U64 res;
char *allocation_site_file;
int allocation_site_line;
#if ARENA_FREE_LIST
Arena *free_last;
#endif
U64 align;
struct ArenaDev *dev;
B8 grow;
B8 large_pages;
};
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
typedef struct Temp Temp;
struct Temp
@@ -55,34 +49,46 @@ struct Temp
};
////////////////////////////////
//~ rjf: Arena Functions
// Implementation
global U64 arena_default_reserve_size = MB(64);
global U64 arena_default_commit_size = KB(64);
global ArenaFlags arena_default_flags = 0;
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt);
//- rjf: arena creation/destruction
internal Arena *arena_alloc_(ArenaParams *params);
#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = arena_default_reserve_size, .commit_size = arena_default_commit_size, .flags = arena_default_flags, .allocation_site_file = __FILE__, .allocation_site_line = __LINE__, __VA_ARGS__})
internal Arena* arena_alloc(void);
internal void arena_release(Arena *arena);
//- rjf: arena push/pop/pos core functions
internal void *arena_push(Arena *arena, U64 size, U64 align, B32 zero);
internal void* arena_push__impl(Arena *arena, U64 size);
internal U64 arena_pos(Arena *arena);
internal void arena_pop_to(Arena *arena, U64 pos);
//- rjf: arena push/pop helpers
internal void arena_absorb(Arena *arena, Arena *sub);
////////////////////////////////
// Wrappers
internal void* arena_push(Arena *arena, U64 size);
internal void* arena_push_contiguous(Arena *arena, U64 size);
internal void arena_clear(Arena *arena);
internal void arena_pop(Arena *arena, U64 amt);
internal void arena_push_align(Arena *arena, U64 align);
internal void arena_put_back(Arena *arena, U64 amt);
//- rjf: temporary arena scopes
internal Temp temp_begin(Arena *arena);
internal void temp_end(Temp temp);
//- rjf: push helper macros
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (0))
#define push_array_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (1))
#define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T)))
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
////////////////////////////////
//~ NOTE(allen): "Mini-Arena" Helper
internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size);
////////////////////////////////
//~ NOTE(allen): Main API Macros
#if !ENABLE_DEV
# define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
#else
# define push_array_no_zero(a,T,c) (tctx_write_this_srcloc(), (T*)arena_push((a), sizeof(T)*(c)))
#endif
#define push_array_no_zero__no_annotation(a,T,c) (T*)arena_push__impl((a), sizeof(T)*(c))
#define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c))
#endif // BASE_ARENA_H
+197
View File
@@ -0,0 +1,197 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): Dev Arena
#if ENABLE_DEV
internal void
arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){
ArenaDev *dev = arena->dev;
if (dev != 0 && ptr != 0){
//- read location
char *file_name = 0;
U64 line_number = 0;
tctx_read_srcloc(&file_name, &line_number);
tctx_write_srcloc(0, 0);
//- profile
ArenaProf *prof = dev->prof;
if (prof != 0){
// c string -> string
String8 file_name_str = str8_lit("(null)");
if (file_name != 0){
file_name_str = str8_cstring(file_name);
}
// record
arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1);
}
}
}
internal void
arena_annotate_absorb__dev(Arena *arena, Arena *sub){
ArenaDev *dev = arena->dev;
ArenaDev *sub_dev = sub->dev;
if (dev != 0 && sub_dev != 0){
//- merge profiles
ArenaProf *prof = dev->prof;
ArenaProf *sub_prof = sub_dev->prof;
if (prof != 0 && sub_prof != 0){
for (ArenaProfNode *sub_node = sub_prof->first;
sub_node != 0;
sub_node = sub_node->next){
arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line,
sub_node->size, sub_node->count);
}
}
}
//- release the sub dev memory
if (sub_dev != 0){
arena_release(sub_dev->arena);
}
}
internal ArenaDev*
arena_equip__dev(Arena *arena){
ArenaDev *result = arena->dev;
if (result == 0){
Arena *dev_arena = arena_alloc();
ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev));
MemoryZeroStruct(dev);
dev->arena = dev_arena;
arena->dev = dev;
result = dev;
}
return(result);
}
internal void
arena_equip_profile__dev(Arena *arena){
ArenaDev *dev = arena_equip__dev(arena);
if (dev->prof == 0){
dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf));
MemoryZeroStruct(dev->prof);
}
}
internal void
arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){
Assert(arena != out_arena);
//- get dev & disable
ArenaDev *dev = arena->dev;
arena->dev = 0;
//- get prof
ArenaProf *prof = (dev != 0)?dev->prof:0;
//- not equipped with prof
if (prof == 0){
str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n"));
}
//- print prof
if (prof != 0){
Temp scratch = temp_begin(dev->arena);
//- make flat array
U64 note_count = prof->count;
ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count);
{
ArenaProfNode **note_ptr = notes;
for (ArenaProfNode *node = prof->first;
node != 0;
node = node->next, note_ptr += 1){
*note_ptr = node;
}
}
//- file name size
U64 max_file_name_size = 0;
{
ArenaProfNode **note_ptr = notes;
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size);
}
}
//- sort (> size, < [address])
for (U64 i = 0; i < note_count; i += 1){
ArenaProfNode **i_note = notes + i;
ArenaProfNode **min_note = i_note;
for (U64 j = i + 1; j < note_count; j += 1){
ArenaProfNode **j_note = notes + j;
if ((**j_note).size > (**min_note).size ||
((**j_note).size == (**min_note).size && *j_note < *min_note)){
min_note = j_note;
}
}
if (min_note != i_note){
ArenaProfNode *t = *i_note;
*i_note = *min_note;
*min_note = t;
}
}
//- total size
U64 total_size = 0;
{
ArenaProfNode **note_ptr = notes;
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
ArenaProfNode *note = *note_ptr;
total_size += note->size;
}
}
//- print
{
str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size);
ArenaProfNode **note_ptr = notes;
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
ArenaProfNode *note = *note_ptr;
String8 location = push_str8f(scratch.arena, "%S:%5llu:",
note->file_name, note->line);
F32 percent = 100.f*((F32)note->size)/total_size;
str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n",
max_file_name_size + 7, str8_varg(location),
note->size, percent, note->count);
}
}
temp_end(scratch);
}
//- restore dev
arena->dev = dev;
}
internal void
arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line,
U64 size, U64 count){
// find existing profile node
ArenaProfNode *prof_node = 0;
for (ArenaProfNode *node = prof->first;
node != 0;
node = node->next){
if (node->line == line && str8_match(file_name, node->file_name, 0)){
prof_node = node;
break;
}
}
// make new histogram node if necessary
if (prof_node == 0){
prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node));
SLLQueuePush(prof->first, prof->last, prof_node);
prof->count += 1;
prof_node->file_name = file_name;
prof_node->line = line;
}
// record this allocation
prof_node->size += size;
prof_node->count += count;
}
#endif
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_ARENA_DEV_H
#define BASE_ARENA_DEV_H
////////////////////////////////
//~ NOTE(allen): Dev Arena Types
typedef struct ArenaDev ArenaDev;
struct ArenaDev
{
Arena *arena;
struct ArenaProf *prof;
};
typedef struct ArenaProf ArenaProf;
struct ArenaProf
{
struct ArenaProfNode *first;
struct ArenaProfNode *last;
U64 count;
};
typedef struct ArenaProfNode ArenaProfNode;
struct ArenaProfNode
{
ArenaProfNode *next;
String8 file_name;
U64 line;
U64 size;
U64 count;
};
////////////////////////////////
//~ NOTE(allen): Dev Arena Functions
#if ENABLE_DEV
internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr);
internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub);
internal ArenaDev* arena_equip__dev(Arena *arena);
internal void arena_equip_profile__dev(Arena *arena);
internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out);
internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count);
#endif
#endif // BASE_ARENA_DEV_H
+103
View File
@@ -0,0 +1,103 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
internal U64
count_bits_set16(U16 val)
{
return __popcnt16(val);
}
internal U64
count_bits_set32(U32 val)
{
return __popcnt(val);
}
internal U64
count_bits_set64(U64 val)
{
return __popcnt64(val);
}
internal U64
ctz32(U32 mask)
{
unsigned long idx;
_BitScanForward(&idx, mask);
return idx;
}
internal U64
ctz64(U64 mask)
{
unsigned long idx;
_BitScanForward64(&idx, mask);
return idx;
}
internal U64
clz32(U32 mask)
{
unsigned long idx;
_BitScanReverse(&idx, mask);
return 31 - idx;
}
internal U64
clz64(U64 mask)
{
unsigned long idx;
_BitScanReverse64(&idx, mask);
return 63 - idx;
}
#elif COMPILER_CLANG || COMPILER_GCC
internal U64
count_bits_set16(U16 val)
{
NotImplemented;
return 0;
}
internal U64
count_bits_set32(U32 val)
{
NotImplemented;
return 0;
}
internal U64
count_bits_set64(U64 val)
{
NotImplemented;
return 0;
}
internal U64
ctz32(U32 val)
{
NotImplemented;
return 0;
}
internal U64
clz32(U32 val)
{
NotImplemented;
return 0;
}
internal U64
clz64(U64 val)
{
NotImplemented;
return 0;
}
#else
# error "bits not defined for this target"
#endif
+18
View File
@@ -0,0 +1,18 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_BITS_H
#define BASE_BITS_H
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
internal U64 count_bits_set16(U16 val);
internal U64 count_bits_set32(U32 val);
internal U64 count_bits_set64(U64 val);
internal U64 ctz32(U32 val);
internal U64 ctz64(U64 val);
internal U64 clz32(U32 val);
internal U64 clz64(U64 val);
#endif // BASE_BITS_H
+60 -59
View File
@@ -1,8 +1,19 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Command Line Parsing Functions
//~ 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)
@@ -10,7 +21,7 @@ cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
CmdLineOpt **slot = 0;
if(cmd_line->option_table_size != 0)
{
U64 hash = u64_hash_from_str8(string);
U64 hash = cmd_line_hash_from_string(string);
U64 bucket = hash % cmd_line->option_table_size;
slot = &cmd_line->option_table[bucket];
}
@@ -53,7 +64,7 @@ cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List
{
var = push_array(arena, CmdLineOpt, 1);
var->hash_next = *slot;
var->hash = u64_hash_from_str8(string);
var->hash = cmd_line_hash_from_string(string);
var->string = push_str8_copy(arena, string);
var->value_strings = values;
StringJoin join = {0};
@@ -71,26 +82,26 @@ internal CmdLine
cmd_line_from_string_list(Arena *arena, String8List command_line)
{
CmdLine parsed = {0};
parsed.exe_name = command_line.first->string;
parsed.option_table_size = 64;
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
//- rjf: parse options / inputs
// 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;
//- rjf: look at --, -, or / (only on Windows) at the start of an
// argument to determine if it's a flag option. all arguments after a
// single "--" (with no trailing string on the command line will be
// considered as passthrough input strings.
B32 is_option = 0;
String8 option_name = node->string;
if(!after_passthrough_option)
// 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)
{
is_option = 1;
if(str8_match(node->string, str8_lit("--"), 0))
{
after_passthrough_option = 1;
@@ -104,79 +115,69 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
{
option_name = str8_skip(option_name, 1);
}
else if(OperatingSystem_CURRENT == OperatingSystem_Windows &&
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;
}
//- rjf: string is an option
// NOTE(rjf): This string is an option.
if(is_option)
{
// rjf: unpack option prefix
B32 has_values = 0;
U64 value_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
U64 value_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
U64 value_signifier_position = Min(value_signifier_position1, value_signifier_position2);
String8 value_portion_this_string = str8_skip(option_name, value_signifier_position+1);
if(value_signifier_position < option_name.size)
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_values = 1;
has_arguments = 1;
}
option_name = str8_prefix(option_name, value_signifier_position);
option_name = str8_prefix(option_name, arg_signifier_position);
// rjf: parse option's values
String8List values = {0};
if(has_values)
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 = value_portion_this_string;
string = arg_portion_this_string;
}
U8 splits[] = { ',' };
String8List values_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
for(String8Node *sub_val = values_in_this_string.first; sub_val; sub_val = sub_val->next)
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, &values, sub_val->string);
str8_list_push(arena, &arguments, sub_arg->string);
}
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
(n != node || value_portion_this_string.size != 0))
(n != node || arg_portion_this_string.size != 0))
{
break;
}
}
}
// rjf: store
cmd_line_insert_opt(arena, &parsed, option_name, values);
// NOTE(rjf): Register config variable.
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
}
//- rjf: default path - treat as a passthrough input
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
// 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))
{
str8_list_push(arena, &parsed.inputs, node->string);
first_passthrough = 0;
}
}
//- rjf: fill argc/argv
parsed.argc = command_line.node_count;
parsed.argv = push_array(arena, char *, parsed.argc);
{
U64 idx = 0;
for(String8Node *n = command_line.first; n != 0; n = n->next)
{
parsed.argv[idx] = (char *)push_str8_copy(arena, n->string).str;
idx += 1;
after_passthrough_option = 1;
}
}
@@ -217,12 +218,12 @@ internal B32
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
{
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
return (var != 0);
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);
return(var != 0 && var->value_strings.node_count > 0);
}
+3 -5
View File
@@ -1,4 +1,4 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_COMMAND_LINE_H
@@ -29,18 +29,16 @@ struct CmdLineOptList
typedef struct CmdLine CmdLine;
struct CmdLine
{
String8 exe_name;
CmdLineOptList options;
String8List inputs;
U64 option_table_size;
CmdLineOpt **option_table;
U64 argc;
char **argv;
};
////////////////////////////////
//~ rjf: Command Line Parsing Functions
//~ 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);
+16 -119
View File
@@ -1,12 +1,9 @@
// Copyright (c) Epic Games Tools
// 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
@@ -18,7 +15,7 @@
# elif defined(__APPLE__) && defined(__MACH__)
# define OS_MAC 1
# else
# error This compiler/OS combo is not supported.
# error This compiler/platform combo is not supported yet
# endif
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
@@ -30,40 +27,17 @@
# elif defined(__arm__)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# error architecture not supported yet
# 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
# define COMPILER_CL 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# else
# error This compiler/OS combo is not supported.
# error This compiler/platform combo is not supported yet
# endif
# if defined(_M_AMD64)
@@ -75,12 +49,9 @@
# elif defined(_M_ARM)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# error architecture not supported yet
# endif
////////////////////////////////
//~ rjf: GCC OS/Arch Cracking
#elif defined(__GNUC__) || defined(__GNUG__)
# define COMPILER_GCC 1
@@ -88,7 +59,7 @@
# if defined(__gnu_linux__) || defined(__linux__)
# define OS_LINUX 1
# else
# error This compiler/OS combo is not supported.
# error This compiler/platform combo is not supported yet
# endif
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
@@ -100,96 +71,26 @@
# elif defined(__arm__)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# error architecture not supported yet
# endif
#else
# error Compiler not supported.
# error This compiler is not supported yet
#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 9
#endif
#if !defined(BUILD_VERSION_PATCH)
# define BUILD_VERSION_PATCH 24
#endif
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
#if BUILD_DEBUG
# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]"
#else
# define BUILD_MODE_STRING_LITERAL_APPEND ""
#endif
#if defined(BUILD_GIT_HASH)
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]"
#else
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND ""
#endif
#if !defined(BUILD_TITLE)
# define BUILD_TITLE "Untitled"
#endif
#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL)
# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
#endif
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGamesExt/raddebugger/issues"
#endif
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
////////////////////////////////
//~ rjf: Zero All Undefined Options
// zeroify
#if !defined(ARCH_32BIT)
# define ARCH_32BIT 0
@@ -209,8 +110,8 @@
#if !defined(ARCH_ARM32)
# define ARCH_ARM32 0
#endif
#if !defined(COMPILER_MSVC)
# define COMPILER_MSVC 0
#if !defined(COMPILER_CL)
# define COMPILER_CL 0
#endif
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 0
@@ -234,14 +135,10 @@
# 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.
#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
#endif // BASE_CONTEXT_CRACKING_H
-1026
View File
File diff suppressed because it is too large Load Diff
-234
View File
@@ -1,234 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
global U64 global_update_tick_idx = 0;
global U64 async_threads_count = 0;
global CondVar async_tick_start_cond_var = {0};
global Mutex async_tick_start_mutex = {0};
global Mutex async_tick_stop_mutex = {0};
global B32 async_loop_again = 0;
global B32 async_loop_again_high_priority = 0;
global B32 global_async_exit = 0;
thread_static B32 is_async_thread = 0;
internal void
main_thread_base_entry_point(int arguments_count, char **arguments)
{
ThreadNameF("main_thread");
Temp scratch = scratch_begin(0, 0);
//- rjf: set up async thread group info
async_tick_start_cond_var = cond_var_alloc();
async_tick_start_mutex = mutex_alloc();
async_tick_stop_mutex = mutex_alloc();
//- rjf: set up telemetry
#if PROFILE_TELEMETRY
local_persist char tm_data[MB(64)];
tmLoadLibrary(TM_RELEASE);
tmSetMaxThreadCount(256);
tmInitialize(sizeof(tm_data), tm_data);
#endif
//- rjf: set up spall
#if PROFILE_SPALL
spall_profile = spall_init_file_ex("spall_capture", 1, 0);
#endif
//- rjf: parse command line
String8List command_line_argument_strings = {0};
{
for EachIndex(idx, arguments_count)
{
str8_list_push(scratch.arena, &command_line_argument_strings, str8_cstring(arguments[idx]));
}
}
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
//- rjf: begin captures
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
if(capture)
{
ProfBeginCapture(arguments[0]);
ProfMsg(BUILD_TITLE);
}
//- rjf: initialize all included layers
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
ac_init();
#endif
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
async_init(&cmdline);
#endif
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
c_init();
#endif
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
fs_init();
#endif
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
mtx_init();
#endif
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
di_init(&cmdline);
#endif
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
dmn_init();
#endif
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
ctrl_init();
#endif
#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL)
os_gfx_init();
#endif
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
fp_init();
#endif
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
r_init(&cmdline);
#endif
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
fnt_init();
#endif
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
d_init();
#endif
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
rd_init(&cmdline);
#endif
//- rjf: launch async threads
Thread *async_threads = 0;
U64 lane_broadcast_val = 0;
{
U64 num_main_threads = 1;
#if defined(CTRL_CORE_H)
num_main_threads += 1;
#endif
U64 num_async_threads = os_get_system_info()->logical_processor_count;
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
num_async_threads -= num_main_threads_clamped;
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
if(num_async_threads_string.size != 0)
{
try_u64_from_str8_c_rules(num_async_threads_string, &num_async_threads);
}
num_async_threads = Max(1, num_async_threads);
Barrier barrier = barrier_alloc(num_async_threads);
LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads);
async_threads_count = num_async_threads;
async_threads = push_array(scratch.arena, Thread, async_threads_count);
for EachIndex(idx, num_async_threads)
{
lane_ctxs[idx].lane_idx = idx;
lane_ctxs[idx].lane_count = async_threads_count;
lane_ctxs[idx].barrier = barrier;
lane_ctxs[idx].broadcast_memory = &lane_broadcast_val;
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
}
}
//- rjf: call into entry point
entry_point(&cmdline);
//- rjf: join async threads
ins_atomic_u32_inc_eval(&global_async_exit);
cond_var_broadcast(async_tick_start_cond_var);
for EachIndex(idx, async_threads_count)
{
thread_join(async_threads[idx], max_U64);
}
//- rjf: end captures
if(capture)
{
ProfEndCapture();
}
scratch_end(scratch);
}
internal void
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
{
TCTX *tctx = tctx_alloc();
tctx_select(tctx);
entry_point(params);
tctx_release(tctx);
}
internal U64
update_tick_idx(void)
{
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
return result;
}
internal B32
update(void)
{
ProfTick(0);
ins_atomic_u64_inc_eval(&global_update_tick_idx);
#if defined(FONT_CACHE_H)
fnt_frame();
#endif
#if OS_FEATURE_GRAPHICAL
B32 result = frame();
#else
B32 result = 0;
#endif
return result;
}
internal void
async_thread_entry_point(void *params)
{
LaneCtx lctx = *(LaneCtx *)params;
lane_ctx(lctx);
is_async_thread = 1;
ThreadNameF("async_thread_%I64u", lane_idx());
for(;;)
{
// rjf: wait for signal if we need, otherwise reset loop signal & continue
if(lane_idx() == 0)
{
if(!ins_atomic_u32_eval(&async_loop_again))
{
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+1000000);
}
ins_atomic_u32_eval_assign(&async_loop_again, 0);
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
}
lane_sync();
// rjf: do all ticks for all layers
ProfScope("async tick")
{
#if defined(ARTIFACT_CACHE_H)
ac_async_tick();
#endif
#if defined(CONTENT_H)
c_async_tick();
#endif
#if defined(FILE_STREAM_H)
fs_async_tick();
#endif
#if defined(DBG_INFO_H)
di_async_tick();
#endif
}
// rjf: take exit signal; break if set
lane_sync();
B32 need_exit = 0;
if(lane_idx() == 0)
{
need_exit = ins_atomic_u32_eval(&global_async_exit);
}
lane_sync_u64(&need_exit, 0);
if(need_exit)
{
break;
}
}
}
-13
View File
@@ -1,13 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_ENTRY_POINT_H
#define BASE_ENTRY_POINT_H
internal void main_thread_base_entry_point(int argc, char **argv);
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
internal U64 update_tick_idx(void);
internal B32 update(void);
internal void async_thread_entry_point(void *params);
#endif // BASE_ENTRY_POINT_H
-50
View File
@@ -1,50 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: MD5
#include "third_party/martins_hash/md5.h"
internal MD5
md5_from_data(String8 data)
{
md5_ctx ctx = {0};
md5_init(&ctx);
md5_update(&ctx, (void*)data.str, data.size);
MD5 result = {0};
md5_finish(&ctx, result.u8);
return result;
}
////////////////////////////////
//~ rjf: SHA
#include "third_party/martins_hash/sha1.h"
#include "third_party/martins_hash/sha256.h"
internal SHA1
sha1_from_data(String8 data)
{
SHA1 result = {0};
{
sha1_ctx ctx = {0};
sha1_init(&ctx);
sha1_update(&ctx, data.str, data.size);
sha1_finish(&ctx, result.u8);
}
return result;
}
internal SHA256
sha256_from_data(String8 data)
{
SHA256 result = {0};
{
sha256_ctx ctx = {0};
sha256_init(&ctx);
sha256_update(&ctx, data.str, data.size);
sha256_finish(&ctx, result.u8);
}
return result;
}
-48
View File
@@ -1,48 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_HASH_H
#define BASE_HASH_H
////////////////////////////////
//~ rjf: Hash Result Types
typedef union MD5 MD5;
union MD5
{
U8 u8[16];
U16 u16[8];
U32 u32[4];
U64 u64[2];
U128 u128;
};
typedef union SHA1 SHA1;
union SHA1
{
U8 u8[20];
};
typedef union SHA256 SHA256;
union SHA256
{
U8 u8[32];
U16 u16[16];
U32 u32[8];
U64 u64[4];
U128 u128[2];
U256 u256;
};
////////////////////////////////
//~ rjf: MD5
internal MD5 md5_from_data(String8 data);
////////////////////////////////
//~ rjf: SHA
internal SHA1 sha1_from_data(String8 data);
internal SHA256 sha256_from_data(String8 data);
#endif // BASE_HASH_H
+8 -12
View File
@@ -1,22 +1,18 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Base Includes
#undef LAYER_COLOR
#define LAYER_COLOR 0x3399ccff
#undef RADDBG_LAYER_COLOR
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
#include "base_core.c"
#include "base_profile.c"
#include "base_types.c"
#include "base_markup.c"
#include "base_arena.c"
#include "base_math.c"
#include "base_strings.c"
#include "base_hash.c"
#include "base_threads.c"
#include "base_string.c"
#include "base_thread_context.c"
#include "base_command_line.c"
#include "base_markup.c"
#include "base_meta.c"
#include "base_log.c"
#include "base_entry_point.c"
#include "base_arena_dev.c"
#include "base_bits.c"
+8 -11
View File
@@ -1,4 +1,4 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_INC_H
@@ -8,19 +8,16 @@
//~ rjf: Base Includes
#include "base_context_cracking.h"
#include "base_core.h"
#include "base_profile.h"
#include "base_types.h"
#include "base_markup.h"
#include "base_ins.h"
#include "base_linked_lists.h"
#include "base_arena.h"
#include "base_math.h"
#include "base_strings.h"
#include "base_hash.h"
#include "base_threads.h"
#include "base_string.h"
#include "base_thread_context.h"
#include "base_command_line.h"
#include "base_markup.h"
#include "base_meta.h"
#include "base_log.h"
#include "base_entry_point.h"
#include "base_arena_dev.h"
#include "base_bits.h"
#endif // BASE_INC_H
+52
View File
@@ -0,0 +1,52 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_INS_H
#define BASE_INS_H
////////////////////////////////
// NOTE(allen): Implementations of Intrinsics
#if OS_WINDOWS
# include <windows.h>
# include <tmmintrin.h>
# include <wmmintrin.h>
# include <intrin.h>
# if ARCH_X64
# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(x), 0)
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
# endif
#elif OS_LINUX
# if ARCH_X64
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
# endif
#else
// TODO(allen):
#endif
////////////////////////////////
// NOTE(allen): Intrinsic Checks
#if ARCH_X64
# if !defined(ins_atomic_u64_inc_eval)
# error missing: ins_atomic_u64_inc_eval
# endif
#else
# error the intrinsic set for this arch is not developed
#endif
#endif //BASE_INS_H
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_LINKED_LIST_H
#define BASE_LINKED_LIST_H
////////////////////////////////
//~ rjf: Helpers
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
#define SetNil(nil,p) ((p) = nil)
////////////////////////////////
//~ rjf: Base Macros
//- rjf: Base Doubly-Linked-List Macros
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
CheckNil(nil,p) ? \
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
((p)==(l)) ? \
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
((n) == (l) ? (l) = (l)->prev : (0)),\
(CheckNil(nil,(n)->prev) ? (0) :\
((n)->prev->next = (n)->next)),\
(CheckNil(nil,(n)->next) ? (0) :\
((n)->next->prev = (n)->prev)))
//- rjf: Base Singly-Linked-List Queue Macros
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((n)->next=(f),(f)=(n)))
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
(SetNil(nil,f),SetNil(nil,l)):\
((f)=(f)->next))
//- rjf: Base Singly-Linked-List Stack Macros
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
#define SLLStackPop_N(f,next) ((f)=(f)->next)
////////////////////////////////
//~ rjf: Convenience Wrappers
//- rjf: Doubly-Linked-List Wrappers
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
//- rjf: Singly-Linked-List Queue Wrappers
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
//- rjf: Singly-Linked-List Stack Wrappers
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
#define SLLStackPop(f) SLLStackPop_N(f,next)
#endif //BASE_LINKED_LIST_H
-103
View File
@@ -1,103 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Globals/Thread-Locals
C_LINKAGE thread_static Log *log_active;
#if !BUILD_SUPPLEMENTARY_UNIT
C_LINKAGE thread_static Log *log_active = 0;
#endif
////////////////////////////////
//~ rjf: Log Creation/Selection
internal Log *
log_alloc(void)
{
Arena *arena = arena_alloc();
Log *log = push_array(arena, Log, 1);
log->arena = arena;
return log;
}
internal void
log_release(Log *log)
{
arena_release(log->arena);
}
internal void
log_select(Log *log)
{
log_active = log;
}
////////////////////////////////
//~ rjf: Log Building/Clearing
internal void
log_msg(LogMsgKind kind, String8 string)
{
if(log_active != 0 && log_active->top_scope != 0)
{
String8 string_copy = push_str8_copy(log_active->arena, string);
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
}
}
internal void
log_msgf(LogMsgKind kind, char *fmt, ...)
{
if(log_active != 0)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
log_msg(kind, string);
va_end(args);
scratch_end(scratch);
}
}
////////////////////////////////
//~ rjf: Log Scopes
internal void
log_scope_begin(void)
{
if(log_active != 0)
{
U64 pos = arena_pos(log_active->arena);
LogScope *scope = push_array(log_active->arena, LogScope, 1);
scope->pos = pos;
SLLStackPush(log_active->top_scope, scope);
}
}
internal LogScopeResult
log_scope_end(Arena *arena)
{
LogScopeResult result = {0};
if(log_active != 0)
{
LogScope *scope = log_active->top_scope;
if(scope != 0)
{
SLLStackPop(log_active->top_scope);
if(arena != 0)
{
for EachEnumVal(LogMsgKind, kind)
{
Temp scratch = scratch_begin(&arena, 1);
String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
result.strings[kind] = indented_from_string(arena, result_unindented);
scratch_end(scratch);
}
}
arena_pop_to(log_active->arena, scope->pos);
}
}
return result;
}
-65
View File
@@ -1,65 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_LOG_H
#define BASE_LOG_H
////////////////////////////////
//~ rjf: Log Types
typedef enum LogMsgKind
{
LogMsgKind_Info,
LogMsgKind_UserError,
LogMsgKind_COUNT
}
LogMsgKind;
typedef struct LogScope LogScope;
struct LogScope
{
LogScope *next;
U64 pos;
String8List strings[LogMsgKind_COUNT];
};
typedef struct LogScopeResult LogScopeResult;
struct LogScopeResult
{
String8 strings[LogMsgKind_COUNT];
};
typedef struct Log Log;
struct Log
{
Arena *arena;
LogScope *top_scope;
};
////////////////////////////////
//~ rjf: Log Creation/Selection
internal Log *log_alloc(void);
internal void log_release(Log *log);
internal void log_select(Log *log);
////////////////////////////////
//~ rjf: Log Building
internal void log_msg(LogMsgKind kind, String8 string);
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
#define log_info(s) log_msg(LogMsgKind_Info, (s))
#define log_infof(...) log_msgf(LogMsgKind_Info, __VA_ARGS__)
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
#define log_user_errorf(...) log_msgf(LogMsgKind_UserError, __VA_ARGS__)
#define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
#define LogInfoNamedBlockF(...) DeferLoop((log_infof(__VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
////////////////////////////////
//~ rjf: Log Scopes
internal void log_scope_begin(void);
internal LogScopeResult log_scope_end(Arena *arena);
#endif // BASE_LOG_H
+1 -20
View File
@@ -1,21 +1,2 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
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);
}
+69 -12
View File
@@ -1,22 +1,79 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_MARKUP_H
#define BASE_MARKUP_H
#define RADDBG_MARKUP_IMPLEMENTATION
#define RADDBG_MARKUP_VSNPRINTF raddbg_vsnprintf
#if OS_LINUX
# define RADDBG_MARKUP_STUBS
#endif
#include "lib_raddbg_markup/raddbg_markup.h"
////////////////////////////////
//~ rjf: Zero Settings
#if !defined(LAYER_COLOR)
# define LAYER_COLOR 0x404040ff
#if !defined(PROFILE_TELEMETRY)
# define PROFILE_TELEMETRY 0
#endif
internal void set_thread_name(String8 string);
internal void set_thread_namef(char *fmt, ...);
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
#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())
////////////////////////////////
//~ rjf: General Markup
#define ThreadName(...) (ProfThreadName(__VA_ARGS__))
#endif // BASE_MARKUP_H
+22 -236
View File
@@ -1,8 +1,8 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Scalar Math Ops
//~ rjf: Scalar Ops
internal F32
mix_1f32(F32 a, F32 b, F32 t)
@@ -42,6 +42,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s) {Vec2S64 c = {v.
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;}
internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;}
internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;}
internal Vec2S64 normalize_2s64(Vec2S64 v) {v = scale_2s64(v, (S64)(1.f/length_2s64(v))); return v;}
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;}
@@ -53,6 +54,7 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s) {Vec2S32 c = {v.
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;}
internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;}
internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;}
internal Vec2S32 normalize_2s32(Vec2S32 v) {v = scale_2s32(v, (S32)(1.f/length_2s32(v))); return v;}
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;}
@@ -64,6 +66,7 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s) {Vec2S16 c = {(S
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;}
internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;}
internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;}
internal Vec2S16 normalize_2s16(Vec2S16 v) {v = scale_2s16(v, (S16)(1.f/length_2s16(v))); return v;}
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;}
@@ -78,14 +81,6 @@ internal F32 length_3f32(Vec3F32 v) {F32 c = sqrt_f3
internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;}
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;}
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m)
{
Vec3F32 result;
result.x = v.x*m.v[0][0] + v.y*m.v[1][0] + v.z*m.v[2][0];
result.y = v.x*m.v[0][1] + v.y*m.v[1][1] + v.z*m.v[2][1];
result.z = v.x*m.v[0][2] + v.y*m.v[1][2] + v.z*m.v[2][2];
return result;
}
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;}
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
@@ -96,6 +91,7 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s) {Vec3S32 c = {v.
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;}
internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;}
internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;}
internal Vec3S32 normalize_3s32(Vec3S32 v) {v = scale_3s32(v, (S32)(1.f/length_3s32(v))); return v;}
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;}
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
@@ -120,6 +116,7 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s) {Vec4S32 c = {v.
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;}
internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;}
internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;}
internal Vec4S32 normalize_4s32(Vec4S32 v) {v = scale_4s32(v, (S32)(1.f/length_4s32(v))); return v;}
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;}
////////////////////////////////
@@ -389,21 +386,6 @@ derotate_4x4f32(Mat4x4F32 mat)
return mat;
}
internal Mat4x4F32
transpose_4x4f32(Mat4x4F32 mat)
{
Mat4x4F32 result =
{
{
mat.v[0][0], mat.v[1][0], mat.v[2][0], mat.v[3][0],
mat.v[0][1], mat.v[1][1], mat.v[2][1], mat.v[3][1],
mat.v[0][2], mat.v[1][2], mat.v[2][2], mat.v[3][2],
mat.v[0][3], mat.v[1][3], mat.v[2][3], mat.v[3][3],
}
};
return result;
}
////////////////////////////////
//~ rjf: Range Ops
@@ -412,7 +394,7 @@ internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.m
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;}
internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal U32 dim_1u32(Rng1U32 r) {U32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal U32 dim_1u32(Rng1U32 r) {U32 c = r.max-r.min; return c;}
internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;}
@@ -422,7 +404,7 @@ internal Rng1S32 shift_1s32(Rng1S32 r, S32 x) {r.min += x; r.m
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;}
internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;}
internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal S32 dim_1s32(Rng1S32 r) {S32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal S32 dim_1s32(Rng1S32 r) {S32 c = r.max-r.min; return c;}
internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;}
@@ -432,7 +414,7 @@ internal Rng1U64 shift_1u64(Rng1U64 r, U64 x) {r.min += x; r.m
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;}
internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;}
internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal U64 dim_1u64(Rng1U64 r) {U64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal U64 dim_1u64(Rng1U64 r) {U64 c = r.max-r.min; return c;}
internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;}
@@ -442,7 +424,7 @@ internal Rng1S64 shift_1s64(Rng1S64 r, S64 x) {r.min += x; r.m
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;}
internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;}
internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal S64 dim_1s64(Rng1S64 r) {S64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal S64 dim_1s64(Rng1S64 r) {S64 c = r.max-r.min; return c;}
internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;}
@@ -452,7 +434,7 @@ internal Rng1F32 shift_1f32(Rng1F32 r, F32 x) {r.min += x; r.m
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;}
internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;}
internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal F32 dim_1f32(Rng1F32 r) {F32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal F32 dim_1f32(Rng1F32 r) {F32 c = r.max-r.min; return c;}
internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;}
@@ -462,7 +444,7 @@ internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x) {r.min = add_2s1
internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;}
internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;}
internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0)), (S16)(((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0))}; return dim;}
internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(r.max.x-r.min.x), (S16)(r.max.y-r.min.y)}; return dim;}
internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
@@ -472,7 +454,7 @@ internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x) {r.min = add_2s3
internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;}
internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
@@ -482,7 +464,7 @@ internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x) {r.min = add_2s6
internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;}
internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
@@ -492,15 +474,13 @@ internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x) {r.min = add_2f3
internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;}
internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
////////////////////////////////
//~ rjf: Color Operations
//- rjf: hsv <-> rgb
//~ rjf: Miscellaneous Ops
internal Vec3F32
hsv_from_rgb(Vec3F32 rgb)
@@ -587,102 +567,16 @@ rgba_from_hsva(Vec4F32 hsva)
return rgba;
}
//- rjf: srgb <-> linear
internal Vec3F32
linear_from_srgb(Vec3F32 srgb)
{
Vec3F32 result;
for EachElement(idx, srgb.v)
{
result.v[idx] = (srgb.v[idx] < 0.0404482362771082f ? srgb.v[idx] / 12.92f : pow_f32((srgb.v[idx] + 0.055f) / 1.055f, 2.4f));
}
return result;
}
internal Vec3F32
srgb_from_linear(Vec3F32 linear)
{
Vec3F32 result;
for EachElement(idx, linear.v)
{
result.v[idx] = (0 <= linear.v[idx] && linear.v[idx] < 0.00313066844250063) ? linear.v[idx]*12.92f : 1.05f * pow_f32(linear.v[idx], 1.f/2.4f) - 0.055f;
}
return result;
}
internal Vec4F32
linear_from_srgba(Vec4F32 srgba)
rgba_from_u32(U32 hex)
{
Vec4F32 result;
result.xyz = linear_from_srgb(srgba.xyz);
result.w = srgba.w;
Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f,
((hex&0x00ff0000)>>16)/255.f,
((hex&0x0000ff00)>> 8)/255.f,
((hex&0x000000ff)>> 0)/255.f);
return result;
}
internal Vec4F32
srgba_from_linear(Vec4F32 linear)
{
Vec4F32 result;
result.xyz = srgb_from_linear(linear.xyz);
result.w = linear.w;
return result;
}
//- rjf: oklab <-> linear
internal Vec3F32
oklab_from_linear(Vec3F32 linear)
{
F32 l = (0.4122214708f * linear.x + 0.5363325363f * linear.y + 0.0514459929f * linear.z);
F32 m = (0.2119034982f * linear.x + 0.6806995451f * linear.y + 0.1073969566f * linear.z);
F32 s = (0.0883024619f * linear.x + 0.2817188376f * linear.y + 0.6299787005f * linear.z);
F32 l_ = cbrt_f32(l);
F32 m_ = cbrt_f32(m);
F32 s_ = cbrt_f32(s);
Vec3F32 result;
result.x = 0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_;
result.y = 1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_;
result.z = 0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_;
return result;
}
internal Vec3F32
linear_from_oklab(Vec3F32 oklab)
{
F32 l_ = oklab.x + 0.3963377774f * oklab.y + 0.2158037573f * oklab.z;
F32 m_ = oklab.x - 0.1055613458f * oklab.y - 0.0638541728f * oklab.z;
F32 s_ = oklab.x - 0.0894841775f * oklab.y - 1.2914855480f * oklab.z;
F32 l = l_*l_*l_;
F32 m = m_*m_*m_;
F32 s = s_*s_*s_;
Vec3F32 result;
result.x = +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s;
result.y = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s;
result.z = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s;
return result;
}
internal Vec4F32
oklab_from_lineara(Vec4F32 lineara)
{
Vec4F32 result;
result.xyz = oklab_from_linear(lineara.xyz);
result.w = lineara.w;
return result;
}
internal Vec4F32
lineara_from_oklab(Vec4F32 oklab)
{
Vec4F32 result;
result.xyz = linear_from_oklab(oklab.xyz);
result.w = oklab.w;
return result;
}
//- rjf: rgba <-> u32
internal U32
u32_from_rgba(Vec4F32 rgba)
{
@@ -694,100 +588,9 @@ u32_from_rgba(Vec4F32 rgba)
return result;
}
internal Vec4F32
rgba_from_u32(U32 hex)
{
Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f,
((hex&0x00ff0000)>>16)/255.f,
((hex&0x0000ff00)>> 8)/255.f,
((hex&0x000000ff)>> 0)/255.f);
return result;
}
////////////////////////////////
//~ rjf: List Type Functions
internal void
rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n)
{
SLLQueuePush(list->first, list->last, n);
list->count += 1;
}
internal Rng1U64Node *
rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng)
{
Rng1U64Node *n = push_array(arena, Rng1U64Node, 1);
MemoryCopyStruct(&n->v, &rng);
rng1u64_list_push_node(list, n);
return n;
}
internal void
rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat)
{
if(to_concat->first)
{
if(list->first)
{
list->last->next = to_concat->first;
list->last = to_concat->last;
}
else
{
list->first = to_concat->first;
list->last = to_concat->last;
}
MemoryZeroStruct(to_concat);
}
}
internal Rng1U64Array
rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
{
Rng1U64Array arr = {0};
arr.count = list->count;
arr.v = push_array_no_zero(arena, Rng1U64, arr.count);
U64 idx = 0;
for(Rng1U64Node *n = list->first; n != 0; n = n->next)
{
arr.v[idx] = n->v;
idx += 1;
}
return arr;
}
internal U64
rng_1u64_array_bsearch(Rng1U64Array arr, U64 value)
{
if(arr.count > 0 && arr.v[0].min < value && value < arr.v[arr.count-1].max)
{
U64 l = 0;
U64 r = arr.count - 1;
for(; l <= r; )
{
U64 m = l + (r - l) / 2;
if(contains_1u64(arr.v[m], value))
{
return m;
}
else if(arr.v[m].min < value)
{
l = m + 1;
}
else
{
r = m - 1;
}
}
}
else if(arr.count == 1 && contains_1u64(arr.v[0], value))
{
return 0;
}
return max_U64;
}
internal void
rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng)
{
@@ -811,20 +614,3 @@ rng1s64_array_from_list(Arena *arena, Rng1S64List *list)
}
return arr;
}
////////////////////////////////
//~ rjf: N -> M Element Subdivision
internal Rng1U64
m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count)
{
U64 main_idxes_per_lane = m_count/n_count;
U64 leftover_idxes_count = m_count - main_idxes_per_lane*n_count;
U64 leftover_idxes_before_this_lane_count = Min(n_idx, leftover_idxes_count);
U64 lane_base_idx = n_idx*main_idxes_per_lane + leftover_idxes_before_this_lane_count;
U64 lane_base_idx__clamped = Min(lane_base_idx, m_count);
U64 lane_opl_idx = lane_base_idx__clamped + main_idxes_per_lane + ((n_idx < leftover_idxes_count) ? 1 : 0);
U64 lane_opl_idx__clamped = Min(lane_opl_idx, m_count);
Rng1U64 result = r1u64(lane_base_idx__clamped, lane_opl_idx__clamped);
return result;
}
+16 -62
View File
@@ -1,4 +1,4 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_MATH_H
@@ -327,29 +327,7 @@ union Rng2S64
};
////////////////////////////////
//~ rjf: Range List Types
typedef struct Rng1U64Node Rng1U64Node;
struct Rng1U64Node
{
Rng1U64Node *next;
Rng1U64 v;
};
typedef struct Rng1U64List Rng1U64List;
struct Rng1U64List
{
U64 count;
Rng1U64Node *first;
Rng1U64Node *last;
};
typedef struct Rng1U64Array Rng1U64Array;
struct Rng1U64Array
{
Rng1U64 *v;
U64 count;
};
//~ rjf: List Types
typedef struct Rng1S64Node Rng1S64Node;
struct Rng1S64Node
@@ -374,20 +352,19 @@ struct Rng1S64Array
};
////////////////////////////////
//~ rjf: Scalar Math Ops
//~ rjf: Scalar Ops
#define abs_s64(v) (S64)llabs(v)
#define sqrt_f32(v) sqrtf(v)
#define cbrt_f32(v) cbrtf(v)
#define mod_f32(a, b) fmodf((a), (b))
#define pow_f32(b, e) powf((b), (e))
#define ceil_f32(v) ceilf(v)
#define floor_f32(v) floorf(v)
#define round_f32(v) roundf(v)
#define abs_f32(v) fabsf(v)
#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f))
#define turns_from_radians_f32(v) ((v)/(2*3.1415926535897f))
#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f)
#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f)
#define degrees_from_turns_f32(v) ((v)*360.f)
#define turns_from_degrees_f32(v) ((v)/360.f)
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
@@ -397,15 +374,14 @@ struct Rng1S64Array
#define tan_f32(v) tanf(radians_from_turns_f32(v))
#define sqrt_f64(v) sqrt(v)
#define cbrt_f64(v) cbrt(v)
#define mod_f64(a, b) fmod((a), (b))
#define pow_f64(b, e) pow((b), (e))
#define ceil_f64(v) ceil(v)
#define floor_f64(v) floor(v)
#define round_f64(v) round(v)
#define abs_f64(v) fabs(v)
#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897))
#define turns_from_radians_f64(v) ((v)/(2*3.1415926535897))
#define radians_from_turns_f64(v) ((v)*2*3.1415926535897)
#define turns_from_radians_f64(v) ((v)/2*3.1415926535897)
#define degrees_from_turns_f64(v) ((v)*360.0)
#define turns_from_degrees_f64(v) ((v)/360.0)
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
@@ -443,6 +419,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s);
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
internal S64 length_squared_2s64(Vec2S64 v);
internal S64 length_2s64(Vec2S64 v);
internal Vec2S64 normalize_2s64(Vec2S64 v);
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
#define v2s32(x, y) vec_2s32((x), (y))
@@ -455,6 +432,7 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s);
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
internal S32 length_squared_2s32(Vec2S32 v);
internal S32 length_2s32(Vec2S32 v);
internal Vec2S32 normalize_2s32(Vec2S32 v);
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
#define v2s16(x, y) vec_2s16((x), (y))
@@ -467,6 +445,7 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s);
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
internal S16 length_squared_2s16(Vec2S16 v);
internal S16 length_2s16(Vec2S16 v);
internal Vec2S16 normalize_2s16(Vec2S16 v);
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
@@ -482,7 +461,6 @@ internal F32 length_3f32(Vec3F32 v);
internal Vec3F32 normalize_3f32(Vec3F32 v);
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m);
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
@@ -494,6 +472,7 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s);
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
internal S32 length_squared_3s32(Vec3S32 v);
internal S32 length_3s32(Vec3S32 v);
internal Vec3S32 normalize_3s32(Vec3S32 v);
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
@@ -520,6 +499,7 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s);
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
internal S32 length_squared_4s32(Vec4S32 v);
internal S32 length_4s32(Vec4S32 v);
internal Vec4S32 normalize_4s32(Vec4S32 v);
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
////////////////////////////////
@@ -541,7 +521,6 @@ internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b);
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
////////////////////////////////
//~ rjf: Range Ops
@@ -650,46 +629,21 @@ internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b);
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
////////////////////////////////
//~ rjf: Color Operations
//~ rjf: Miscellaneous Ops
//- rjf: hsv <-> rgb
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
//- rjf: srgb <-> linear
internal Vec3F32 linear_from_srgb(Vec3F32 srgb);
internal Vec3F32 srgb_from_linear(Vec3F32 linear);
internal Vec4F32 linear_from_srgba(Vec4F32 srgba);
internal Vec4F32 srgba_from_linear(Vec4F32 linear);
//- rjf: oklab <-> linear
internal Vec3F32 oklab_from_linear(Vec3F32 linear);
internal Vec3F32 linear_from_oklab(Vec3F32 oklab);
internal Vec4F32 oklab_from_lineara(Vec4F32 lineara);
internal Vec4F32 lineara_from_oklab(Vec4F32 oklab);
//- rjf: rgba <-> u32
internal U32 u32_from_rgba(Vec4F32 rgba);
internal Vec4F32 rgba_from_u32(U32 hex);
internal U32 u32_from_rgba(Vec4F32 rgba);
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
////////////////////////////////
//~ rjf: List Type Functions
internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value);
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
////////////////////////////////
//~ rjf: N -> M Element Subdivision
internal Rng1U64 m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count);
#endif //BASE_MATH_H
#endif // BASE_MATH_H
-421
View File
@@ -1,421 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Type Info Lookups
internal Member *
member_from_name(Type *type, String8 name)
{
Member *member = &member_nil;
if(type->members != 0 && name.size != 0)
{
for(U64 idx = 0; idx < type->count; idx += 1)
{
if(str8_match(type->members[idx].name, name, 0))
{
member = &type->members[idx];
break;
}
}
}
return member;
}
////////////////////////////////
//~ rjf: Type Info * Instance Operations
internal void
typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr)
{
Temp scratch = scratch_begin(0, 0);
typedef struct RebaseTypeTask RebaseTypeTask;
struct RebaseTypeTask
{
RebaseTypeTask *next;
Type *type;
U8 *ptr;
};
RebaseTypeTask start_task = {0, type, data.str};
RebaseTypeTask *first_task = &start_task;
RebaseTypeTask *last_task = first_task;
for(RebaseTypeTask *t = first_task; t != 0; t = t->next)
{
switch(t->type->kind)
{
default:{}break;
case TypeKind_Ptr:
{
*(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr));
}break;
case TypeKind_Array:
{
for(U64 idx = 0; idx < t->type->count; idx += 1)
{
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
task->type = t->type->direct;
task->ptr = t->ptr + t->type->direct->size * idx;
SLLQueuePush(first_task, last_task, task);
}
}break;
case TypeKind_Struct:
{
for(U64 idx = 0; idx < t->type->count; idx += 1)
{
Member *member = &t->type->members[idx];
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
task->type = member->type;
task->ptr = t->ptr + member->value;
SLLQueuePush(first_task, last_task, task);
}
}break;
}
}
scratch_end(scratch);
}
internal String8
serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
{
Temp scratch = scratch_begin(&arena, 1);
String8List strings = {0};
str8_serial_begin(scratch.arena, &strings);
{
typedef struct SerializeTypeTask SerializeTypeTask;
struct SerializeTypeTask
{
SerializeTypeTask *next;
Type *type;
U64 count;
U8 *src;
Type *containing_type;
U8 *containing_ptr;
B32 is_post_header;
};
SerializeTypeTask start_task = {0, type, 1, data.str};
SerializeTypeTask *first_task = &start_task;
SerializeTypeTask *last_task = first_task;
for(SerializeTypeTask *t = first_task; t != 0; t = t->next)
{
switch(t->type->kind)
{
//- rjf: leaf -> just copy the data directly
default:
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
{
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
}break;
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise just write as plain data
case TypeKind_Ptr:
{
// rjf: unpack info about this pointer
TypeSerializePtrRefInfo *ptr_ref_info = 0;
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
{
if(params->ptr_ref_infos[idx].type == t->type->direct)
{
ptr_ref_info = &params->ptr_ref_infos[idx];
break;
}
}
// rjf: indexification -> subtract base, divide direct size, write index
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
{
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size);
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
}
// rjf: offsetification -> subtract base, write offsets
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
{
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base);
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
}
// rjf: size-by-member (pre-header): still potentially dependent on other members which
// delimit our size, so push a new post-header task for pointer.
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
{
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
task->type = t->type;
task->count = t->count;
task->src = t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
task->is_post_header = 1;
SLLQueuePush(first_task, last_task, task);
}
// rjf: size-by-member (post-header): all flat parts of containing struct have been
// iterated, so now we can read the size, & descend to new task to read pointer
// destination contents
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
{
// rjf: determine count of this pointer
U64 count = 0;
{
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
}
// rjf: push task
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
task->type = t->type->direct;
task->count = count;
task->src = *(void **)t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}
// rjf: catch-all: write pointer value
else
{
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
}
}break;
//- rjf: arrays -> descend to underlying type, + count
case TypeKind_Array:
{
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
task->type = t->type->direct;
task->count = t->type->count;
task->src = t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}break;
//- rjf: struct -> descend to members
case TypeKind_Struct:
{
U64 off = 0;
for(U64 idx = 0; idx < t->count; idx += 1)
{
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
{
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
{
continue;
}
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
task->type = t->type->members[member_idx].type;
task->count = 1;
task->src = t->src + idx*t->type->size + t->type->members[member_idx].value;
task->containing_type = t->type;
task->containing_ptr = t->src;
SLLQueuePush(first_task, last_task, task);
}
}
}break;
//- rjf: enum -> descend to basic type interpretation
case TypeKind_Enum:
{
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
task->type = t->type->direct;
task->count = t->count;
task->src = t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}break;
}
}
}
String8 result = str8_serial_end(arena, &strings);
scratch_end(scratch);
return result;
}
internal String8
deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
{
String8 result = {0};
result.size = type->size;
result.str = push_array(arena, U8, result.size);
{
Temp scratch = scratch_begin(&arena, 1);
typedef struct DeserializeTypeTask DeserializeTypeTask;
struct DeserializeTypeTask
{
DeserializeTypeTask *next;
Type *type;
U64 count;
U8 *dst;
Type *containing_type;
U8 *containing_ptr;
B32 is_post_header;
};
U64 read_off = 0;
DeserializeTypeTask start_task = {0, type, 1, result.str};
DeserializeTypeTask *first_task = &start_task;
DeserializeTypeTask *last_task = first_task;
for(DeserializeTypeTask *t = first_task; t != 0; t = t->next)
{
U8 *t_src = data.str + read_off;
switch(t->type->kind)
{
//- rjf: leaf -> copy the data directly
default:
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
{
MemoryCopy(t->dst, t_src, t->type->size*t->count);
read_off += t->type->size*t->count;
}break;
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
case TypeKind_Ptr:
{
// rjf: unpack info about this pointer
TypeSerializePtrRefInfo *ptr_ref_info = 0;
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
{
if(params->ptr_ref_infos[idx].type == t->type->direct)
{
ptr_ref_info = &params->ptr_ref_infos[idx];
break;
}
}
// rjf: indexification -> add base, multiply direct size
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
{
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size;
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
read_off += sizeof(ptr_value);
}
// rjf: offsetification -> subtract base, write offsets
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
{
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base;
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
read_off += sizeof(ptr_value);
}
// rjf: size-by-member (pre-header): still potentially dependent on other members which
// delimit our size, so push a new post-header task for pointer.
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
{
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
task->type = t->type;
task->count = t->count;
task->dst = t->dst;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
task->is_post_header = 1;
SLLQueuePush(first_task, last_task, task);
}
// rjf: size-by-member (post-header): all flat parts of containing struct have been
// iterated, so now we can read the size, & descend to new task to read pointer
// destination contents
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
{
// rjf: determine count of this pointer
U64 count = 0;
{
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
}
// rjf: allocate buffer for pointer destination; write address into pointer value slot
U64 ptr_dest_buffer_size = (count+1)*t->type->direct->size;
U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size);
MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer));
// rjf: push task
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
task->type = t->type->direct;
task->count = count;
task->dst = ptr_dest_buffer;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}
// rjf: catch-all: read pointer value
else
{
MemoryCopy(t->dst, t_src, t->type->size*t->count);
read_off += t->type->size*t->count;
}
}break;
//- rjf: arrays -> descend to underlying type, + count
case TypeKind_Array:
{
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
task->type = t->type->direct;
task->count = t->type->count;
task->dst = t->dst;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}break;
//- rjf: struct -> descend to members
case TypeKind_Struct:
{
for(U64 idx = 0; idx < t->count; idx += 1)
{
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
{
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
{
continue;
}
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
task->type = t->type->members[member_idx].type;
task->count = 1;
task->dst = t->dst + idx*t->type->size + t->type->members[member_idx].value;
task->containing_type = t->type;
task->containing_ptr = t->dst;
SLLQueuePush(first_task, last_task, task);
}
}
}break;
//- rjf: enum -> descend to basic type interpretation
case TypeKind_Enum:
{
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
task->type = t->type->direct;
task->count = t->count;
task->dst = t->dst;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}break;
}
}
if(params->advance_out != 0)
{
params->advance_out[0] = read_off;
}
scratch_end(scratch);
}
return result;
}
internal String8
deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
{
Temp scratch = scratch_begin(&arena, 1);
String8 data_srlz = serialized_from_typed_data(scratch.arena, type, data, params);
String8 data_copy = deserialized_from_typed_data(arena, type, data_srlz, params);
scratch_end(scratch);
return data_copy;
}
-297
View File
@@ -1,297 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_META_H
#define BASE_META_H
////////////////////////////////
//~ rjf: Meta Markup Features
#define EmbedFile(name, path)
#define TweakB32(name, default) (TWEAK_##name)
#define TweakF32(name, default, min, max) (TWEAK_##name)
////////////////////////////////
//~ rjf: Tweak Info Tables
typedef struct TweakB32Info TweakB32Info;
struct TweakB32Info
{
String8 name;
B32 default_value;
B32 *value_ptr;
};
typedef struct TweakF32Info TweakF32Info;
struct TweakF32Info
{
String8 name;
F32 default_value;
Rng1F32 value_range;
F32 *value_ptr;
};
typedef struct TweakB32InfoTable TweakB32InfoTable;
struct TweakB32InfoTable
{
TweakB32Info *v;
U64 count;
};
typedef struct TweakF32InfoTable TweakF32InfoTable;
struct TweakF32InfoTable
{
TweakF32Info *v;
U64 count;
};
typedef struct EmbedInfo EmbedInfo;
struct EmbedInfo
{
String8 name;
String8 *data;
U128 *hash;
};
typedef struct EmbedInfoTable EmbedInfoTable;
struct EmbedInfoTable
{
EmbedInfo *v;
U64 count;
};
////////////////////////////////
//~ rjf: Type Info Types
typedef enum TypeKind
{
TypeKind_Null,
// rjf: leaves
TypeKind_Void, TypeKind_FirstLeaf = TypeKind_Void,
TypeKind_U8,
TypeKind_U16,
TypeKind_U32,
TypeKind_U64,
TypeKind_S8,
TypeKind_S16,
TypeKind_S32,
TypeKind_S64,
TypeKind_B8,
TypeKind_B16,
TypeKind_B32,
TypeKind_B64,
TypeKind_F32,
TypeKind_F64, TypeKind_LastLeaf = TypeKind_F64,
// rjf: operators
TypeKind_Ptr,
TypeKind_Array,
// rjf: user-defined-types
TypeKind_Struct,
TypeKind_Union,
TypeKind_Enum,
TypeKind_COUNT
}
TypeKind;
typedef U32 TypeFlags;
enum
{
TypeFlag_IsPlainText = (1<<0),
TypeFlag_IsCodeText = (1<<1),
TypeFlag_IsPathText = (1<<2),
};
typedef U32 MemberFlags;
enum
{
MemberFlag_DoNotSerialize = (1<<0),
};
typedef struct Type Type;
typedef struct Member Member;
struct Member
{
String8 name;
String8 pretty_name;
Type *type;
U64 value;
MemberFlags flags;
};
typedef struct Type Type;
struct Type
{
TypeKind kind;
TypeFlags flags;
U64 size;
Type *direct;
String8 name;
String8 count_delimiter_name; // gathered from surrounding members, turns *->[1] into *->[N]
U64 count;
Member *members;
};
////////////////////////////////
//~ rjf: Type Serialization Parameters
typedef struct TypeSerializePtrRefInfo TypeSerializePtrRefInfo;
struct TypeSerializePtrRefInfo
{
Type *type; // pointers to this
void *indexify_base; // can be indexified using this
void *offsetify_base; // can be offsetified using this
void *nil_ptr; // is terminal if matching 0 or this
};
typedef struct TypeSerializeParams TypeSerializeParams;
struct TypeSerializeParams
{
U64 *advance_out;
TypeSerializePtrRefInfo *ptr_ref_infos;
U64 ptr_ref_infos_count;
};
////////////////////////////////
//~ rjf: Type Name -> Type Info
#define type(T) (&T##__type)
////////////////////////////////
//~ rjf: Type Info Table Initializer Helpers
#define member_lit_comp(S, ti, m, ...) {str8_lit_comp(#m), {0}, (ti), OffsetOf(S, m), __VA_ARGS__}
#define struct_members(S) read_only global Member S##__members[] =
#define struct_type(S, ...) read_only global Type S##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#S), {0}, ArrayCount(S##__members), S##__members, __VA_ARGS__}
#define named_struct_type(name, S, ...) read_only global Type name##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#name), {0}, ArrayCount(name##__members), name##__members, __VA_ARGS__}
#define ptr_type(name, ti, ...) read_only global Type name = {TypeKind_Ptr, 0, sizeof(void *), (ti), __VA_ARGS__}
////////////////////////////////
//~ rjf: Globals
read_only global Type type_nil = {TypeKind_Null, 0, 0, &type_nil};
read_only global Member member_nil = {{0}, {0}, &type_nil};
////////////////////////////////
//~ rjf: Built-In Types
//- rjf: leaves
read_only global Type void__type = {TypeKind_Void, 0, 0, &type_nil, str8_lit_comp("void")};
read_only global Type U8__type = {TypeKind_U8, 0, sizeof(U8), &type_nil, str8_lit_comp("U8")};
read_only global Type U16__type = {TypeKind_U16, 0, sizeof(U16), &type_nil, str8_lit_comp("U16")};
read_only global Type U32__type = {TypeKind_U32, 0, sizeof(U32), &type_nil, str8_lit_comp("U32")};
read_only global Type U64__type = {TypeKind_U64, 0, sizeof(U64), &type_nil, str8_lit_comp("U64")};
read_only global Type S8__type = {TypeKind_S8, 0, sizeof(S8), &type_nil, str8_lit_comp("S8")};
read_only global Type S16__type = {TypeKind_S16, 0, sizeof(S16), &type_nil, str8_lit_comp("S16")};
read_only global Type S32__type = {TypeKind_S32, 0, sizeof(S32), &type_nil, str8_lit_comp("S32")};
read_only global Type S64__type = {TypeKind_S64, 0, sizeof(S64), &type_nil, str8_lit_comp("S64")};
read_only global Type B8__type = {TypeKind_B8, 0, sizeof(B8), &type_nil, str8_lit_comp("B8")};
read_only global Type B16__type = {TypeKind_B16, 0, sizeof(B16), &type_nil, str8_lit_comp("B16")};
read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, str8_lit_comp("B32")};
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")};
read_only global Type F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
read_only global Type *type_kind_type_table[] =
{
&type_nil,
type(void),
type(U8),
type(U16),
type(U32),
type(U64),
type(S8),
type(S16),
type(S32),
type(S64),
type(B8),
type(B16),
type(B32),
type(B64),
type(F32),
type(F64),
&type_nil,
&type_nil,
&type_nil,
&type_nil,
&type_nil,
};
//- rjf: Rng1U64
struct_members(Rng1U64)
{
member_lit_comp(Rng1U64, type(U64), min),
member_lit_comp(Rng1U64, type(U64), max),
};
struct_type(Rng1U64);
//- rjf: String8
ptr_type(String8__str_ptr_type, type(U8), str8_lit_comp("size"));
struct_members(String8)
{
member_lit_comp(String8, &String8__str_ptr_type, str),
member_lit_comp(String8, type(U64), size),
};
struct_type(String8);
//- rjf: String8Node
extern Type String8Node__type;
Type String8Node__ptr_type = {TypeKind_Ptr, 0, sizeof(void *), &String8Node__type};
Member String8Node__members[] =
{
{str8_lit_comp("next"), {0}, &String8Node__ptr_type, OffsetOf(String8Node, next)},
{str8_lit_comp("string"), {0}, type(String8), OffsetOf(String8Node, string)},
};
Type String8Node__type =
{
TypeKind_Struct,
0,
sizeof(String8Node),
&type_nil,
str8_lit_comp("String8Node"),
{0},
ArrayCount(String8Node__members),
String8Node__members,
};
//- rjf: String8List
Member String8List__members[] =
{
{str8_lit_comp("first"), {0}, &String8Node__ptr_type, OffsetOf(String8List, first)},
{str8_lit_comp("last"), {0}, &String8Node__ptr_type, OffsetOf(String8List, last), MemberFlag_DoNotSerialize},
{str8_lit_comp("node_count"), {0}, type(U64), OffsetOf(String8List, node_count)},
{str8_lit_comp("total_size"), {0}, type(U64), OffsetOf(String8List, total_size)},
};
Type String8List__type =
{
TypeKind_Struct,
0,
sizeof(String8List),
&type_nil,
str8_lit_comp("String8List"),
{0},
ArrayCount(String8List__members),
String8List__members,
};
////////////////////////////////
//~ rjf: Type Info Lookups
internal Member *member_from_name(Type *type, String8 name);
#define EachMember(T, it) (Member *it = (type(T))->members; it != 0 && it < (type(T))->members + (type(T))->count; it += 1)
////////////////////////////////
//~ rjf: Type Info * Instance Operations
internal void typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr);
internal String8 serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
internal String8 deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
internal String8 deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
#define struct_rebase_ptrs(T, ptr, base) typed_data_rebase_ptrs(type(T), str8_struct(ptr), (base))
#define serialized_from_struct(arena, T, ptr, ...) serialized_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__})
#define struct_from_serialized(arena, T, string, ...) (T *)deserialized_from_typed_data((arena), type(T), (string), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
#define deep_copy_from_struct(arena, T, ptr, ...) (T *)deep_copy_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
#endif // BASE_META_H
-31
View File
@@ -1,31 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if PROFILE_SPALL
internal inline void
spall_begin(char *fmt, ...)
{
if(spall_buffer.data == 0)
{
spall_buffer.length = MB(1);
spall_buffer.data = os_reserve(spall_buffer.length);
os_commit(spall_buffer.data, spall_buffer.length);
spall_buffer_init(&spall_profile, &spall_buffer);
}
if(spall_pid == 0)
{
spall_pid = os_get_process_info()->pid;
}
if(spall_tid == 0)
{
spall_tid = os_tid();
}
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, os_now_microseconds(), spall_tid, spall_pid);
va_end(args);
scratch_end(scratch);
}
#endif
-126
View File
@@ -1,126 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_PROFILE_H
#define BASE_PROFILE_H
////////////////////////////////
//~ rjf: Zero Settings
#if !defined(PROFILE_TELEMETRY)
# define PROFILE_TELEMETRY 0
#endif
#if !defined(PROFILE_SPALL)
# define PROFILE_SPALL 0
#endif
////////////////////////////////
//~ rjf: Third Party Includes
#if PROFILE_TELEMETRY
# include "rad_tm.h"
# if OS_WINDOWS
# pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "rad_tm_win64.lib")
# endif
#elif PROFILE_SPALL
# include "spall.h"
#endif
////////////////////////////////
//~ rjf: Telemetry Profile Defines
#if PROFILE_TELEMETRY
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
# define ProfTick(...) tmTick(0)
# define ProfIsCapturing(...) tmRunning()
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
# define ProfEndCapture(...) tmClose(0)
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
# define ProfEndLockWait(...) tmEndWaitForLock(0)
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
# define ProfColor(color) tmZoneColor((((color) & 0xff000000) >> 24) / 255.f, (((color) & 0x00ff0000) >> 16) / 255.f, (((color) & 0x0000ff00) >> 8) / 255.f)
# define ProfBeginV(...) \
if (TM_API_PTR) { \
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
Temp scratch = scratch_begin(0,0); \
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
scratch_end(scratch); \
}
# define ProfNoteV(...) \
if (TM_API_PTR) { \
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
Temp scratch = scratch_begin(0,0); \
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
scratch_end(scratch); \
}
#endif
////////////////////////////////
//~ rjf: Spall Profile Defines
#if PROFILE_SPALL
global U64 spall_capturing = 0;
global SpallProfile spall_profile = {0};
thread_static SpallBuffer spall_buffer = {0};
thread_static U32 spall_tid = 0;
thread_static U32 spall_pid = 0;
internal inline void spall_begin(char *fmt, ...);
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
# define ProfBeginDynamic(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, os_now_microseconds(), spall_tid, spall_pid)), 0 : 0)
# define ProfTick(...)
# define ProfIsCapturing(...) (!!spall_capturing)
# define ProfBeginCapture(...) (spall_capturing = 1)
# define ProfEndCapture(...) (spall_capturing = 0, spall_flush(&spall_profile))
# define ProfThreadName(...)
# define ProfMsg(...)
# define ProfBeginLockWait(...)
# define ProfEndLockWait(...)
# define ProfLockTake(...)
# define ProfLockDrop(...)
# define ProfColor(color)
# define ProfBeginV(...)
# define ProfNoteV(...)
#endif
////////////////////////////////
//~ rjf: Zeroify Undefined Defines
#if !defined(ProfBegin)
# define ProfBegin(...) (0)
# define ProfBeginDynamic(...) (0)
# define ProfEnd(...) (0)
# define ProfTick(...) (0)
# define ProfIsCapturing(...) (0)
# define ProfBeginCapture(...) (0)
# define ProfEndCapture(...) (0)
# define ProfThreadName(...) (0)
# define ProfMsg(...) (0)
# define ProfBeginLockWait(...) (0)
# define ProfEndLockWait(...) (0)
# define ProfLockTake(...) (0)
# define ProfLockDrop(...) (0)
# define ProfColor(...) (0)
# define ProfBeginV(...) (0)
# define ProfNoteV(...) (0)
#endif
////////////////////////////////
//~ rjf: Helper Wrappers
#define ProfBeginFunction(...) ProfBegin(this_function_name)
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
#endif // BASE_PROFILE_H
@@ -4,7 +4,7 @@
////////////////////////////////
//~ rjf: Third Party Includes
#if !BUILD_SUPPLEMENTARY_UNIT
#if !SUPPLEMENT_UNIT
# define STB_SPRINTF_IMPLEMENTATION
# define STB_SPRINTF_STATIC
# include "third_party/stb/stb_sprintf.h"
@@ -215,42 +215,12 @@ str32_cstring(U32 *c){
internal String8
str8_cstring_capped(void *cstr, void *cap)
{
char *ptr = (char *)cstr;
char *opl = (char *)cap;
char *ptr = (char*)cstr;
char *opl = (char*)cap;
for (;ptr < opl && *ptr != 0; ptr += 1);
U64 size = (U64)(ptr - (char *)cstr);
String8 result = str8((U8*)cstr, size);
return result;
}
internal String16
str16_cstring_capped(void *cstr, void *cap)
{
U16 *ptr = (U16 *)cstr;
U16 *opl = (U16 *)cap;
for (;ptr < opl && *ptr != 0; ptr += 1);
U64 size = (U64)(ptr - (U16 *)cstr);
String16 result = str16(cstr, size);
return result;
}
internal String8
str8_cstring_capped_reverse(void *raw_start, void *raw_cap)
{
U8 *start = raw_start;
U8 *ptr = raw_cap;
for(; ptr > start; )
{
ptr -= 1;
if (*ptr == '\0')
{
break;
}
}
U64 size = (U64)(ptr - start);
String8 result = str8(start, size);
return result;
String8 result = {(U8*)cstr, size};
return(result);
}
////////////////////////////////
@@ -293,41 +263,31 @@ backslashed_from_str8(Arena *arena, String8 string)
//~ rjf: String Matching
internal B32
str8_match(String8 a, String8 b, StringMatchFlags flags)
{
str8_match(String8 a, String8 b, StringMatchFlags flags){
B32 result = 0;
if(a.size == b.size && flags == 0)
{
result = MemoryMatch(a.str, b.str, b.size);
}
else if(a.size == b.size || (flags & StringMatchFlag_RightSideSloppy))
{
if (a.size == b.size || (flags & StringMatchFlag_RightSideSloppy)){
B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
B32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive);
U64 size = Min(a.size, b.size);
result = 1;
for(U64 i = 0; i < size; i += 1)
{
for (U64 i = 0; i < size; i += 1){
U8 at = a.str[i];
U8 bt = b.str[i];
if(case_insensitive)
{
if (case_insensitive){
at = char_to_upper(at);
bt = char_to_upper(bt);
}
if(slash_insensitive)
{
if (slash_insensitive){
at = char_to_correct_slash(at);
bt = char_to_correct_slash(bt);
}
if(at != bt)
{
if (at != bt){
result = 0;
break;
}
}
}
return result;
return(result);
}
internal U64
@@ -362,22 +322,6 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
return(result);
}
internal U64
str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
{
U64 result = 0;
for(S64 i = string.size - start_pos - needle.size; i >= 0; --i)
{
String8 haystack = str8_substr(string, rng_1u64(i, i + needle.size));
if(str8_match(haystack, needle, flags))
{
result = (U64)i + needle.size;
break;
}
}
return result;
}
internal B32
str8_ends_with(String8 string, String8 end, StringMatchFlags flags){
String8 postfix = str8_postfix(string, end.size);
@@ -556,22 +500,6 @@ s64_from_str8(String8 string, U32 radix){
return(x);
}
internal U32
u32_from_str8(String8 string, U32 radix)
{
U64 x64 = u64_from_str8(string, radix);
U32 x32 = safe_cast_u32(x64);
return x32;
}
internal S32
s32_from_str8(String8 string, U32 radix)
{
S64 x64 = s64_from_str8(string, radix);
S32 x32 = safe_cast_s32(x64);
return x32;
}
internal B32
try_u64_from_str8_c_rules(String8 string, U64 *x){
B32 is_integer = 0;
@@ -616,121 +544,21 @@ try_s64_from_str8_c_rules(String8 string, S64 *x){
//- rjf: integer -> string
internal String8
str8_from_memory_size(Arena *arena, U64 size)
{
String8 result;
if(size < KB(1))
{
result = push_str8f(arena, "%llu Bytes", size);
str8_from_memory_size(Arena *arena, U64 z){
String8 result = {0};
if (z < KB(1)){
result = push_str8f(arena, "%llu b", z);
}
else if(size < MB(1))
{
result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100);
else if (z < MB(1)){
result = push_str8f(arena, "%llu.%02llu Kb", z/KB(1), ((100*z)/KB(1))%100);
}
else if(size < GB(1))
{
result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100);
else if (z < GB(1)){
result = push_str8f(arena, "%llu.%02llu Mb", z/MB(1), ((100*z)/MB(1))%100);
}
else if(size < TB(1))
{
result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100);
else{
result = push_str8f(arena, "%llu.%02llu Gb", z/GB(1), ((100*z)/GB(1))%100);
}
else
{
result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100);
}
return result;
}
internal String8
str8_from_count(Arena *arena, U64 count)
{
String8 result;
if(count < 1 * 1000)
{
result = push_str8f(arena, "%llu", count);
}
else if(count < 1000000)
{
U64 frac = ((count * 100) / 1000) % 100;
if(frac > 0)
{
result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac);
}
else
{
result = push_str8f(arena, "%lluK", count / 1000);
}
}
else if(count < 1000000000)
{
U64 frac = ((count * 100) / 1000000) % 100;
if(frac > 0)
{
result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac);
}
else
{
result = push_str8f(arena, "%lluM", count / 1000000);
}
}
else
{
U64 frac = ((count * 100) * 1000000000) % 100;
if(frac > 0)
{
result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac);
}
else
{
result = push_str8f(arena, "%lluB", count / 1000000000, frac);
}
}
return result;
}
internal String8
str8_from_bits_u32(Arena *arena, U32 x)
{
U8 c0 = 'a' + ((x >> 28) & 0xf);
U8 c1 = 'a' + ((x >> 24) & 0xf);
U8 c2 = 'a' + ((x >> 20) & 0xf);
U8 c3 = 'a' + ((x >> 16) & 0xf);
U8 c4 = 'a' + ((x >> 12) & 0xf);
U8 c5 = 'a' + ((x >> 8) & 0xf);
U8 c6 = 'a' + ((x >> 4) & 0xf);
U8 c7 = 'a' + ((x >> 0) & 0xf);
String8 result = push_str8f(arena, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
return result;
}
internal String8
str8_from_bits_u64(Arena *arena, U64 x)
{
U8 c0 = 'a' + ((x >> 60) & 0xf);
U8 c1 = 'a' + ((x >> 56) & 0xf);
U8 c2 = 'a' + ((x >> 52) & 0xf);
U8 c3 = 'a' + ((x >> 48) & 0xf);
U8 c4 = 'a' + ((x >> 44) & 0xf);
U8 c5 = 'a' + ((x >> 40) & 0xf);
U8 c6 = 'a' + ((x >> 36) & 0xf);
U8 c7 = 'a' + ((x >> 32) & 0xf);
U8 c8 = 'a' + ((x >> 28) & 0xf);
U8 c9 = 'a' + ((x >> 24) & 0xf);
U8 ca = 'a' + ((x >> 20) & 0xf);
U8 cb = 'a' + ((x >> 16) & 0xf);
U8 cc = 'a' + ((x >> 12) & 0xf);
U8 cd = 'a' + ((x >> 8) & 0xf);
U8 ce = 'a' + ((x >> 4) & 0xf);
U8 cf = 'a' + ((x >> 0) & 0xf);
String8 result = push_str8f(arena,
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf);
return result;
return(result);
}
internal String8
@@ -857,28 +685,27 @@ f64_from_str8(String8 string)
{
// rjf: find starting pos of numeric string, as well as sign
F64 sign = +1.0;
//U64 first_numeric = 0;
if(string.str[0] == '-')
{
//first_numeric = 1;
sign = -1.0;
}
else if(string.str[0] == '+')
{
//first_numeric = 1;
sign = 1.0;
}
// rjf: gather numerics
U64 num_valid_chars = 0;
char buffer[64];
B32 exp = 0;
for(U64 idx = 0; idx < string.size && num_valid_chars < sizeof(buffer)-1; idx += 1)
{
if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.' || string.str[idx] == 'e' ||
(exp && (string.str[idx] == '+' || string.str[idx] == '-')))
if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.')
{
buffer[num_valid_chars] = string.str[idx];
num_valid_chars += 1;
exp = 0;
exp = (string.str[idx] == 'e');
}
}
@@ -1119,11 +946,11 @@ str8_array_from_list(Arena *arena, String8List *list)
{
String8Array array;
array.count = list->node_count;
array.v = push_array_no_zero(arena, String8, array.count);
array.strings = push_array_no_zero(arena, String8, array.count);
U64 idx = 0;
for(String8Node *n = list->first; n != 0; n = n->next, idx += 1)
{
array.v[idx] = n->string;
array.strings[idx] = n->string;
}
return array;
}
@@ -1133,7 +960,7 @@ str8_array_reserve(Arena *arena, U64 count)
{
String8Array arr;
arr.count = 0;
arr.v = push_array(arena, String8, count);
arr.strings = push_array(arena, String8, count);
return arr;
}
@@ -1311,9 +1138,7 @@ 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){
StringJoin params = {0};
switch(style)
{
case PathStyle_Null:{}break;
switch (style){
case PathStyle_Relative:
case PathStyle_WindowsAbsolute:
{
@@ -1326,8 +1151,9 @@ str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){
params.sep = str8_lit("/");
}break;
}
String8 result = str8_list_join(arena, path, &params);
return result;
return(result);
}
internal String8TxtPtPair
@@ -1455,7 +1281,7 @@ utf16_decode(U16 *str, U64 max){
result.codepoint = str[0];
result.inc = 1;
if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000){
result.codepoint = ((str[0] - 0xD800) << 10) | ((str[1] - 0xDC00) + 0x10000);
result.codepoint = ((str[0] - 0xD800) << 10) | (str[1] - 0xDC00) + 0x10000;
result.inc = 2;
}
return(result);
@@ -1480,7 +1306,7 @@ utf8_encode(U8 *str, U32 codepoint){
inc = 3;
}
else if (codepoint <= 0x10FFFF){
str[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3);
str[0] = (bitmask4 << 3) | ((codepoint >> 18) & bitmask3);
str[1] = bit8 | ((codepoint >> 12) & bitmask6);
str[2] = bit8 | ((codepoint >> 6) & bitmask6);
str[3] = bit8 | ( codepoint & bitmask6);
@@ -1520,127 +1346,70 @@ utf8_from_utf32_single(U8 *buffer, U32 character){
//~ rjf: Unicode String Conversions
internal String8
str8_from_16(Arena *arena, String16 in)
{
String8 result = str8_zero();
if(in.size)
{
str8_from_16(Arena *arena, String16 in){
U64 cap = in.size*3;
U8 *str = push_array_no_zero(arena, U8, cap + 1);
U16 *ptr = in.str;
U16 *opl = ptr + in.size;
U64 size = 0;
UnicodeDecode consume;
for(;ptr < opl; ptr += consume.inc)
{
for (;ptr < opl; ptr += consume.inc){
consume = utf16_decode(ptr, opl - ptr);
size += utf8_encode(str + size, consume.codepoint);
}
str[size] = 0;
arena_pop(arena, (cap - size));
result = str8(str, size);
}
return result;
arena_put_back(arena, (cap - size));
return(str8(str, size));
}
internal String16
str16_from_8(Arena *arena, String8 in)
{
String16 result = str16_zero();
if(in.size)
{
str16_from_8(Arena *arena, String8 in){
U64 cap = in.size*2;
U16 *str = push_array_no_zero(arena, U16, cap + 1);
U8 *ptr = in.str;
U8 *opl = ptr + in.size;
U64 size = 0;
UnicodeDecode consume;
for(;ptr < opl; ptr += consume.inc)
{
for (;ptr < opl; ptr += consume.inc){
consume = utf8_decode(ptr, opl - ptr);
size += utf16_encode(str + size, consume.codepoint);
}
str[size] = 0;
arena_pop(arena, (cap - size)*2);
result = str16(str, size);
}
return result;
arena_put_back(arena, (cap - size)*2);
return(str16(str, size));
}
internal String8
str8_from_32(Arena *arena, String32 in)
{
String8 result = str8_zero();
if(in.size)
{
str8_from_32(Arena *arena, String32 in){
U64 cap = in.size*4;
U8 *str = push_array_no_zero(arena, U8, cap + 1);
U32 *ptr = in.str;
U32 *opl = ptr + in.size;
U64 size = 0;
for(;ptr < opl; ptr += 1)
{
for (;ptr < opl; ptr += 1){
size += utf8_encode(str + size, *ptr);
}
str[size] = 0;
arena_pop(arena, (cap - size));
result = str8(str, size);
}
return result;
arena_put_back(arena, (cap - size));
return(str8(str, size));
}
internal String32
str32_from_8(Arena *arena, String8 in)
{
String32 result = str32_zero();
if(in.size)
{
str32_from_8(Arena *arena, String8 in){
U64 cap = in.size;
U32 *str = push_array_no_zero(arena, U32, cap + 1);
U8 *ptr = in.str;
U8 *opl = ptr + in.size;
U64 size = 0;
UnicodeDecode consume;
for(;ptr < opl; ptr += consume.inc)
{
for (;ptr < opl; ptr += consume.inc){
consume = utf8_decode(ptr, opl - ptr);
str[size] = consume.codepoint;
size += 1;
}
str[size] = 0;
arena_pop(arena, (cap - size)*4);
result = str32(str, size);
}
return result;
}
////////////////////////////////
//~ String -> Enum Conversions
read_only global struct
{
String8 string;
OperatingSystem os;
} g_os_enum_map[] =
{
{ str8_lit_comp(""), OperatingSystem_Null },
{ str8_lit_comp("Windows"), OperatingSystem_Windows, },
{ str8_lit_comp("Linux"), OperatingSystem_Linux, },
{ str8_lit_comp("Mac"), OperatingSystem_Mac, },
};
StaticAssert(ArrayCount(g_os_enum_map) == OperatingSystem_COUNT, g_os_enum_map_count_check);
internal OperatingSystem
operating_system_from_string(String8 string)
{
for(U64 i = 0; i < ArrayCount(g_os_enum_map); ++i)
{
if(str8_match(g_os_enum_map[i].string, string, StringMatchFlag_CaseInsensitive))
{
return g_os_enum_map[i].os;
}
}
return OperatingSystem_Null;
arena_put_back(arena, (cap - size)*4);
return(str32(str, size));
}
////////////////////////////////
@@ -1675,18 +1444,22 @@ string_from_side(Side side){
}
internal String8
string_from_operating_system(OperatingSystem os)
{
String8 result = g_os_enum_map[OperatingSystem_Null].string;
if(os < ArrayCount(g_os_enum_map))
{
result = g_os_enum_map[os].string;
string_from_operating_system(OperatingSystem os){
local_persist String8 strings[] = {
str8_lit_comp("Null"),
str8_lit_comp("Windows"),
str8_lit_comp("Linux"),
str8_lit_comp("Mac"),
};
String8 result = str8_lit("error");
if (os < OperatingSystem_COUNT){
result = strings[os];
}
return result;
return(result);
}
internal String8
string_from_arch(Arch arch){
string_from_architecture(Architecture arch){
local_persist String8 strings[] = {
str8_lit_comp("Null"),
str8_lit_comp("x64"),
@@ -1695,7 +1468,7 @@ string_from_arch(Arch arch){
str8_lit_comp("arm32"),
};
String8 result = str8_lit("error");
if (arch < Arch_COUNT){
if (arch < Architecture_COUNT){
result = strings[arch];
}
return(result);
@@ -1792,272 +1565,6 @@ string_from_elapsed_time(Arena *arena, DateTime dt){
return(result);
}
////////////////////////////////
//~ Globally UNique Ids
internal String8
string_from_guid(Arena *arena, Guid guid)
{
String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.data1,
guid.data2,
guid.data3,
guid.data4[0],
guid.data4[1],
guid.data4[2],
guid.data4[3],
guid.data4[4],
guid.data4[5],
guid.data4[6],
guid.data4[7]);
return result;
}
internal B32
try_guid_from_string(String8 string, Guid *guid_out)
{
Temp scratch = scratch_begin(0,0);
B32 is_parsed = 0;
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("-"), StringSplitFlag_KeepEmpties);
if(list.node_count == 5)
{
String8 data1_str = list.first->string;
String8 data2_str = list.first->next->string;
String8 data3_str = list.first->next->next->string;
String8 data4_hi_str = list.first->next->next->next->string;
String8 data4_lo_str = list.first->next->next->next->next->string;
if(str8_is_integer(data1_str, 16) &&
str8_is_integer(data2_str, 16) &&
str8_is_integer(data3_str, 16) &&
str8_is_integer(data4_hi_str, 16) &&
str8_is_integer(data4_lo_str, 16))
{
U64 data1 = u64_from_str8(data1_str, 16);
U64 data2 = u64_from_str8(data2_str, 16);
U64 data3 = u64_from_str8(data3_str, 16);
U64 data4_hi = u64_from_str8(data4_hi_str, 16);
U64 data4_lo = u64_from_str8(data4_lo_str, 16);
if(data1 <= max_U32 &&
data2 <= max_U16 &&
data3 <= max_U16 &&
data4_hi <= max_U16 &&
data4_lo <= 0xffffffffffff)
{
guid_out->data1 = (U32)data1;
guid_out->data2 = (U16)data2;
guid_out->data3 = (U16)data3;
U64 data4 = (data4_hi << 48) | data4_lo;
MemoryCopy(&guid_out->data4[0], &data4, sizeof(data4));
is_parsed = 1;
}
}
}
scratch_end(scratch);
return is_parsed;
}
internal Guid
guid_from_string(String8 string)
{
Guid guid = {0};
try_guid_from_string(string, &guid);
return guid;
}
////////////////////////////////
//~ rjf: Basic Text Indentation
internal String8
indented_from_string(Arena *arena, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
read_only local_persist U8 indentation_bytes[] = " ";
String8List indented_strings = {0};
S64 depth = 0;
S64 next_depth = 0;
U64 line_begin_off = 0;
for(U64 off = 0; off <= string.size; off += 1)
{
U8 byte = off<string.size ? string.str[off] : 0;
switch(byte)
{
default:{}break;
case '{':case '[':case '(':{next_depth += 1; next_depth = Max(0, next_depth);}break;
case '}':case ']':case ')':{next_depth -= 1; next_depth = Max(0, next_depth); depth = next_depth;}break;
case '\n':
case 0:
{
String8 line = str8_skip_chop_whitespace(str8_substr(string, r1u64(line_begin_off, off)));
if(line.size != 0)
{
str8_list_pushf(scratch.arena, &indented_strings, "%.*s%S\n", (int)depth*2, indentation_bytes, line);
}
if(line.size == 0 && indented_strings.node_count != 0 && off < string.size)
{
str8_list_pushf(scratch.arena, &indented_strings, "\n");
}
line_begin_off = off+1;
depth = next_depth;
}break;
}
}
String8 result = str8_list_join(arena, &indented_strings, 0);
scratch_end(scratch);
return result;
}
////////////////////////////////
//~ rjf: Text Escaping
internal String8
escaped_from_raw_str8(Arena *arena, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String8List parts = {0};
U64 start_split_idx = 0;
for(U64 idx = 0; idx <= string.size; idx += 1)
{
U8 byte = (idx < string.size) ? string.str[idx] : 0;
B32 split = 1;
String8 separator_replace = {0};
switch(byte)
{
default:{split = 0;}break;
case 0: {}break;
case '\a': {separator_replace = str8_lit("\\a");}break;
case '\b': {separator_replace = str8_lit("\\b");}break;
case '\f': {separator_replace = str8_lit("\\f");}break;
case '\n': {separator_replace = str8_lit("\\n");}break;
case '\r': {separator_replace = str8_lit("\\r");}break;
case '\t': {separator_replace = str8_lit("\\t");}break;
case '\v': {separator_replace = str8_lit("\\v");}break;
case '\\': {separator_replace = str8_lit("\\\\");}break;
case '"': {separator_replace = str8_lit("\\\"");}break;
case '?': {separator_replace = str8_lit("\\?");}break;
}
if(split)
{
String8 substr = str8_substr(string, r1u64(start_split_idx, idx));
start_split_idx = idx+1;
str8_list_push(scratch.arena, &parts, substr);
if(separator_replace.size != 0)
{
str8_list_push(scratch.arena, &parts, separator_replace);
}
}
}
StringJoin join = {0};
String8 result = str8_list_join(arena, &parts, &join);
scratch_end(scratch);
return result;
}
internal String8
raw_from_escaped_str8(Arena *arena, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String8List strs = {0};
U64 start = 0;
for(U64 idx = 0; idx <= string.size; idx += 1)
{
if(idx == string.size || string.str[idx] == '\\' || string.str[idx] == '\r')
{
String8 str = str8_substr(string, r1u64(start, idx));
if(str.size != 0)
{
str8_list_push(scratch.arena, &strs, str);
}
start = idx+1;
}
if(idx < string.size && string.str[idx] == '\\')
{
U8 next_char = string.str[idx+1];
U8 replace_byte = 0;
switch(next_char)
{
default:{}break;
case 'a': replace_byte = 0x07; break;
case 'b': replace_byte = 0x08; break;
case 'e': replace_byte = 0x1b; break;
case 'f': replace_byte = 0x0c; break;
case 'n': replace_byte = 0x0a; break;
case 'r': replace_byte = 0x0d; break;
case 't': replace_byte = 0x09; break;
case 'v': replace_byte = 0x0b; break;
case '\\':replace_byte = '\\'; break;
case '\'':replace_byte = '\''; break;
case '"': replace_byte = '"'; break;
case '?': replace_byte = '?'; break;
}
String8 replace_string = push_str8_copy(scratch.arena, str8(&replace_byte, 1));
str8_list_push(scratch.arena, &strs, replace_string);
idx += 1;
start += 1;
}
}
String8 result = str8_list_join(arena, &strs, 0);
scratch_end(scratch);
return result;
}
////////////////////////////////
//~ rjf: Text Wrapping
internal String8List
wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent)
{
String8List list = {0};
Rng1U64 line_range = r1u64(0, 0);
U64 wrapped_indent_level = 0;
static char *spaces = " ";
for (U64 idx = 0; idx <= string.size; idx += 1){
U8 chr = idx < string.size ? string.str[idx] : 0;
if (chr == '\n'){
Rng1U64 candidate_line_range = line_range;
candidate_line_range.max = idx;
// NOTE(nick): when wrapping is interrupted with \n we emit a string without including \n
// because later tool_fprint_list inserts separator after each node
// except for last node, so don't strip last \n.
if (idx + 1 == string.size){
candidate_line_range.max += 1;
}
String8 substr = str8_substr(string, candidate_line_range);
str8_list_push(arena, &list, substr);
line_range = r1u64(idx+1,idx+1);
}
else
if (char_is_space(chr) || chr == 0){
Rng1U64 candidate_line_range = line_range;
candidate_line_range.max = idx;
String8 substr = str8_substr(string, candidate_line_range);
U64 width_this_line = max_width-wrapped_indent_level;
if (list.node_count == 0){
width_this_line = first_line_max_width;
}
if (substr.size > width_this_line){
String8 line = str8_substr(string, line_range);
if (wrapped_indent_level > 0){
line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line);
}
str8_list_push(arena, &list, line);
line_range = r1u64(line_range.max+1, candidate_line_range.max);
wrapped_indent_level = ClampTop(64, wrap_indent);
}
else{
line_range = candidate_line_range;
}
}
}
if (line_range.min < string.size && line_range.max > line_range.min){
String8 line = str8_substr(string, line_range);
if (wrapped_indent_level > 0){
line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line);
}
str8_list_push(arena, &list, line);
}
return list;
}
////////////////////////////////
//~ rjf: String <-> Color
@@ -2370,77 +1877,3 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out)
*block_out = str8_substr(string, range);
return block_out->size;
}
internal U64
str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte = 0;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
internal U64
str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
{
value |= -(S64)(1ull << shift);
}
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_STRINGS_H
#define BASE_STRINGS_H
#ifndef BASE_STRING_H
#define BASE_STRING_H
////////////////////////////////
//~ rjf: Third Party Includes
@@ -63,7 +63,7 @@ struct String8List
typedef struct String8Array String8Array;
struct String8Array
{
String8 *v;
String8 *strings;
U64 count;
};
@@ -86,7 +86,6 @@ enum
typedef enum PathStyle
{
PathStyle_Null,
PathStyle_Relative,
PathStyle_WindowsAbsolute,
PathStyle_UnixAbsolute,
@@ -193,8 +192,6 @@ 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);
internal String16 str16_cstring_capped(void *cstr, void *cap);
internal String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
////////////////////////////////
//~ rjf: String Stylization
@@ -208,7 +205,6 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
////////////////////////////////
@@ -235,19 +231,13 @@ internal String8 push_str8f(Arena *arena, char *fmt, ...);
//- 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 U32 u32_from_str8(String8 string, U32 radix);
internal S32 s32_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 size);
internal String8 str8_from_count(Arena *arena, U64 count);
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
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);
@@ -319,18 +309,13 @@ 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);
////////////////////////////////
//~ String -> Enum Conversions
internal OperatingSystem operating_system_from_string(String8 string);
////////////////////////////////
//~ 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_arch(Arch arch);
internal String8 string_from_architecture(Architecture arch);
////////////////////////////////
//~ rjf: Time Types -> String
@@ -341,29 +326,6 @@ 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);
////////////////////////////////
//~ Globally Unique Ids
internal String8 string_from_guid(Arena *arena, Guid guid);
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
internal Guid guid_from_string(String8 string);
////////////////////////////////
//~ rjf: Basic Text Indentation
internal String8 indented_from_string(Arena *arena, String8 string);
////////////////////////////////
//~ rjf: Text Escaping
internal String8 escaped_from_raw_str8(Arena *arena, String8 string);
internal String8 raw_from_escaped_str8(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
@@ -400,13 +362,10 @@ internal void str8_serial_push_string(Arena *arena, String8List *srl, String8
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 void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
#endif // BASE_STRINGS_H
#endif // BASE_STRING_H
File diff suppressed because it is too large Load Diff
+31 -178
View File
@@ -1,225 +1,78 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Globals
// 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;
C_LINKAGE thread_static TCTX* tctx_thread_local;
#if !SUPPLEMENT_UNIT
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
#endif
////////////////////////////////
//~ rjf: Thread Context Functions
//- rjf: thread-context allocation & selection
internal TCTX *
tctx_alloc(void)
{
Arena *arena = arena_alloc();
TCTX *tctx = push_array(arena, TCTX, 1);
tctx->arenas[0] = arena;
tctx->arenas[1] = arena_alloc();
tctx->lane_ctx.lane_count = 1;
return tctx;
}
internal void
tctx_release(TCTX *tctx)
{
arena_release(tctx->arenas[1]);
arena_release(tctx->arenas[0]);
}
internal void
tctx_select(TCTX *tctx)
{
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 TCTX *
tctx_selected(void)
{
return tctx_thread_local;
internal TCTX*
tctx_get_equipped(void){
return(tctx_thread_local);
}
//- rjf: scratch arenas
internal Arena*
tctx_get_scratch(Arena **conflicts, U64 count){
TCTX *tctx = tctx_get_equipped();
internal Arena *
tctx_get_scratch(Arena **conflicts, U64 count)
{
TCTX *tctx = tctx_selected();
Arena *result = 0;
Arena **arena_ptr = tctx->arenas;
for(U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1)
{
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)
{
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
if (*arena_ptr == *conflict_ptr){
has_conflict = 1;
break;
}
}
if(!has_conflict)
{
if (!has_conflict){
result = *arena_ptr;
break;
}
}
return result;
}
//- rjf: lane metadata
internal LaneCtx
tctx_set_lane_ctx(LaneCtx lane_ctx)
{
TCTX *tctx = tctx_selected();
LaneCtx restore = tctx->lane_ctx;
tctx->lane_ctx = lane_ctx;
return restore;
return(result);
}
internal void
tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx)
{
ProfBeginFunction();
ProfColor(0x00000ff);
TCTX *tctx = tctx_selected();
// rjf: doing broadcast -> copy to broadcast memory on source lane
U64 broadcast_size_clamped = ClampTop(broadcast_size, sizeof(tctx->lane_ctx.broadcast_memory[0]));
if(broadcast_ptr != 0 && lane_idx() == broadcast_src_lane_idx)
{
MemoryCopy(tctx->lane_ctx.broadcast_memory, broadcast_ptr, broadcast_size_clamped);
}
// rjf: all cases: barrier
os_barrier_wait(tctx->lane_ctx.barrier);
// rjf: doing broadcast -> copy from broadcast memory on destination lanes
if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx)
{
MemoryCopy(broadcast_ptr, tctx->lane_ctx.broadcast_memory, broadcast_size_clamped);
}
// rjf: doing broadcast -> barrier on all lanes
if(broadcast_ptr != 0)
{
os_barrier_wait(tctx->lane_ctx.barrier);
}
ProfEnd();
}
//- rjf: thread names
internal void
tctx_set_thread_name(String8 string)
{
TCTX *tctx = tctx_selected();
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_selected();
tctx_get_thread_name(void){
TCTX *tctx = tctx_get_equipped();
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
return result;
return(result);
}
//- rjf: thread source-locations
internal void
tctx_write_srcloc(char *file_name, U64 line_number)
{
TCTX *tctx = tctx_selected();
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_selected();
tctx_read_srcloc(char **file_name, U64 *line_number){
TCTX *tctx = tctx_get_equipped();
*file_name = tctx->file_name;
*line_number = tctx->line_number;
}
////////////////////////////////
//~ rjf: Touch Scope Functions
internal Access *
access_open(void)
{
if(tctx_thread_local->access_arena == 0)
{
tctx_thread_local->access_arena = arena_alloc();
}
Access *access = tctx_thread_local->free_access;
if(access != 0)
{
SLLStackPop(tctx_thread_local->free_access);
}
else
{
access = push_array_no_zero(tctx_thread_local->access_arena, Access, 1);
}
MemoryZeroStruct(access);
return access;
}
internal void
access_close(Access *access)
{
for(Touch *touch = access->top_touch, *next = 0; touch != 0; touch = next)
{
next = touch->next;
ins_atomic_u64_dec_eval(&touch->pt->access_refcount);
if(touch->cv.u64[0] != 0) { cond_var_broadcast(touch->cv); }
SLLStackPush(tctx_thread_local->free_touch, touch);
}
SLLStackPush(tctx_thread_local->free_access, access);
}
internal void
access_touch(Access *access, AccessPt *pt, CondVar cv)
{
ins_atomic_u64_inc_eval(&pt->access_refcount);
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, os_now_microseconds());
ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx());
Touch *touch = tctx_thread_local->free_touch;
if(touch != 0)
{
SLLStackPop(tctx_thread_local->free_touch);
}
else
{
touch = push_array_no_zero(tctx_thread_local->access_arena, Touch, 1);
}
MemoryZeroStruct(touch);
SLLStackPush(access->top_touch, touch);
touch->cv = cv;
touch->pt = pt;
}
//- rjf: access points
internal B32
access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params)
{
U64 access_refcount = ins_atomic_u64_eval(&pt->access_refcount);
U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us);
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
B32 result = (access_refcount == 0 &&
last_time_touched_us + params->time <= os_now_microseconds() &&
last_update_idx_touched + params->update_idxs <= update_tick_idx());
return result;
}
+9 -101
View File
@@ -1,132 +1,40 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_THREAD_CONTEXT_H
#define BASE_THREAD_CONTEXT_H
////////////////////////////////
//~ rjf: Lane Context
typedef struct LaneCtx LaneCtx;
struct LaneCtx
{
U64 lane_idx;
U64 lane_count;
Barrier barrier;
U64 *broadcast_memory;
};
////////////////////////////////
//~ rjf: Access Scopes
typedef struct AccessPt AccessPt;
struct AccessPt
{
U64 access_refcount;
U64 last_time_touched_us;
U64 last_update_idx_touched;
};
typedef struct AccessPtExpireParams AccessPtExpireParams;
struct AccessPtExpireParams
{
U64 time;
U64 update_idxs;
};
typedef struct Touch Touch;
struct Touch
{
Touch *next;
AccessPt *pt;
CondVar cv;
};
typedef struct Access Access;
struct Access
{
Access *next;
Touch *top_touch;
};
////////////////////////////////
//~ rjf: Base Per-Thread State Bundle
// NOTE(allen): Thread Context
typedef struct TCTX TCTX;
struct TCTX
{
// rjf: scratch arenas
Arena *arenas[2];
// rjf: thread name
U8 thread_name[32];
U64 thread_name_size;
// rjf: lane context
LaneCtx lane_ctx;
// rjf: source location info
char *file_name;
U64 line_number;
// rjf: accesses
Arena *access_arena;
Access *free_access;
Touch *free_touch;
// rjf: progress
U64 *progress_counter_ptr;
U64 *progress_target_ptr;
};
////////////////////////////////
//~ rjf: Thread Context Functions
// NOTE(allen): Thread Context Functions
//- rjf: thread-context allocation & selection
internal TCTX *tctx_alloc(void);
internal void tctx_release(TCTX *tctx);
internal void tctx_select(TCTX *tctx);
internal TCTX *tctx_selected(void);
internal void tctx_init_and_equip(TCTX *tctx);
internal TCTX* tctx_get_equipped(void);
//- rjf: scratch arenas
internal Arena *tctx_get_scratch(Arena **conflicts, U64 count);
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
#define scratch_end(scratch) temp_end(scratch)
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
//- rjf: lane metadata
internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx);
internal void tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx);
#define lane_idx() (tctx_selected()->lane_ctx.lane_idx)
#define lane_count() (tctx_selected()->lane_ctx.lane_count)
#define lane_from_task_idx(idx) ((idx)%lane_count())
#define lane_ctx(ctx) tctx_set_lane_ctx((ctx))
#define lane_sync() tctx_lane_barrier_wait(0, 0, 0)
#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(*(ptr)), (src_lane_idx))
#define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count))
//- rjf: thread names
internal void tctx_set_thread_name(String8 name);
internal String8 tctx_get_thread_name(void);
//- rjf: thread source-locations
internal void tctx_write_srcloc(char *file_name, U64 line_number);
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
//- rjf: access scopes
internal Access *access_open(void);
internal void access_close(Access *access);
internal void access_touch(Access *access, AccessPt *pt, CondVar cv);
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
#define scratch_end(scratch) temp_end(scratch)
//- rjf: access points
internal B32 access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params);
#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 2, __VA_ARGS__})
//- rjf: progress counters
#define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr))
#define set_progress_target_ptr(ptr) (tctx_selected()->progress_target_ptr = (ptr))
#define set_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
#define add_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_add_eval(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
#define set_progress_target(val) (tctx_selected()->progress_target_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_target_ptr, (val)) : (void)0)
#endif // BASE_THREAD_CONTEXT_H
#endif //BASE_THREAD_CONTEXT_H
-102
View File
@@ -1,102 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Thread Functions
internal Thread
thread_launch(ThreadEntryPointFunctionType *f, void *p)
{
Thread thread = os_thread_launch(f, p);
return thread;
}
internal B32
thread_join(Thread thread, U64 endt_us)
{
B32 result = os_thread_join(thread, endt_us);
return result;
}
internal void
thread_detach(Thread thread)
{
os_thread_detach(thread);
}
////////////////////////////////
//~ rjf: Synchronization Primitive Functions
//- rjf: recursive mutexes
internal Mutex mutex_alloc(void) {return os_mutex_alloc();}
internal void mutex_release(Mutex mutex) {os_mutex_release(mutex);}
internal void mutex_take(Mutex mutex) {os_mutex_take(mutex);}
internal void mutex_drop(Mutex mutex) {os_mutex_drop(mutex);}
//- rjf: reader/writer mutexes
internal RWMutex rw_mutex_alloc(void) {return os_rw_mutex_alloc();}
internal void rw_mutex_release(RWMutex mutex) {os_rw_mutex_release(mutex);}
internal void rw_mutex_take(RWMutex mutex, B32 write_mode) {os_rw_mutex_take(mutex, write_mode);}
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode) {os_rw_mutex_drop(mutex, write_mode);}
//- rjf: condition variables
internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();}
internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);}
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);}
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) {return os_cond_var_wait_rw(cv, mutex_rw, write_mode, endt_us);}
internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);}
internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);}
//- rjf: cross-process semaphores
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name) {return os_semaphore_alloc(initial_count, max_count, name);}
internal void semaphore_release(Semaphore semaphore) {os_semaphore_release(semaphore);}
internal Semaphore semaphore_open(String8 name) {return os_semaphore_open(name);}
internal void semaphore_close(Semaphore semaphore) {os_semaphore_close(semaphore);}
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us) {return os_semaphore_take(semaphore, endt_us);}
internal void semaphore_drop(Semaphore semaphore) {os_semaphore_drop(semaphore);}
//- rjf: barriers
internal Barrier barrier_alloc(U64 count) {return os_barrier_alloc(count);}
internal void barrier_release(Barrier barrier) {os_barrier_release(barrier);}
internal void barrier_wait(Barrier barrier) {os_barrier_wait(barrier);}
////////////////////////////////
//~ rjf: Table Stripe Functions
internal StripeArray
stripe_array_alloc(Arena *arena)
{
StripeArray array = {0};
array.count = os_get_system_info()->logical_processor_count;
array.v = push_array(arena, Stripe, array.count);
for EachIndex(idx, array.count)
{
array.v[idx].arena = arena_alloc();
array.v[idx].rw_mutex = rw_mutex_alloc();
array.v[idx].cv = cond_var_alloc();
}
return array;
}
internal void
stripe_array_release(StripeArray *stripes)
{
for EachIndex(idx, stripes->count)
{
arena_release(stripes->v[idx].arena);
rw_mutex_release(stripes->v[idx].rw_mutex);
cond_var_release(stripes->v[idx].cv);
}
}
internal Stripe *
stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx)
{
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
return stripe;
}
-133
View File
@@ -1,133 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_THREADS_H
#define BASE_THREADS_H
////////////////////////////////
//~ rjf: Thread Types
typedef struct Thread Thread;
struct Thread
{
U64 u64[1];
};
typedef void ThreadEntryPointFunctionType(void *p);
////////////////////////////////
//~ rjf: Synchronization Primitive Types
typedef struct Mutex Mutex;
struct Mutex
{
U64 u64[1];
};
typedef struct RWMutex RWMutex;
struct RWMutex
{
U64 u64[1];
};
typedef struct CondVar CondVar;
struct CondVar
{
U64 u64[1];
};
typedef struct Semaphore Semaphore;
struct Semaphore
{
U64 u64[1];
};
typedef struct Barrier Barrier;
struct Barrier
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: Table Stripes
typedef struct Stripe Stripe;
struct Stripe
{
Arena *arena;
RWMutex rw_mutex;
CondVar cv;
void *free;
};
typedef struct StripeArray StripeArray;
struct StripeArray
{
Stripe *v;
U64 count;
};
////////////////////////////////
//~ rjf: Thread Functions
internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
internal B32 thread_join(Thread thread, U64 endt_us);
internal void thread_detach(Thread thread);
////////////////////////////////
//~ rjf: Synchronization Primitive Functions
//- rjf: recursive mutexes
internal Mutex mutex_alloc(void);
internal void mutex_release(Mutex mutex);
internal void mutex_take(Mutex mutex);
internal void mutex_drop(Mutex mutex);
//- rjf: reader/writer mutexes
internal RWMutex rw_mutex_alloc(void);
internal void rw_mutex_release(RWMutex mutex);
internal void rw_mutex_take(RWMutex mutex, B32 write_mode);
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode);
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
//- rjf: condition variables
internal CondVar cond_var_alloc(void);
internal void cond_var_release(CondVar cv);
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us);
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us);
#define cond_var_wait_rw_r(cv, m, endt) cond_var_wait_rw((cv), (m), (0), (endt))
#define cond_var_wait_rw_w(cv, m, endt) cond_var_wait_rw((cv), (m), (1), (endt))
internal void cond_var_signal(CondVar cv);
internal void cond_var_broadcast(CondVar cv);
//- rjf: cross-process semaphores
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
internal void semaphore_release(Semaphore semaphore);
internal Semaphore semaphore_open(String8 name);
internal void semaphore_close(Semaphore semaphore);
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
internal void semaphore_drop(Semaphore semaphore);
//- rjf: barriers
internal Barrier barrier_alloc(U64 count);
internal void barrier_release(Barrier barrier);
internal void barrier_wait(Barrier barrier);
//- rjf: scope macros
#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex))
#define RWMutexScope(mutex, write_mode) DeferLoop(rw_mutex_take((mutex), (write_mode)), rw_mutex_drop((mutex), (write_mode)))
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
////////////////////////////////
//~ rjf: Table Stripe Functions
internal StripeArray stripe_array_alloc(Arena *arena);
internal void stripe_array_release(StripeArray *stripes);
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
#endif // BASE_THREADS_H
@@ -2,7 +2,7 @@
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Safe Casts
//~ Safe Casts
internal U16
safe_cast_u16(U32 x)
@@ -141,94 +141,6 @@ bswap_u64(U64 x)
return result;
}
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
internal U64
count_bits_set32(U32 val)
{
return __popcnt(val);
}
internal U64
count_bits_set64(U64 val)
{
return __popcnt64(val);
}
internal U64
ctz32(U32 mask)
{
unsigned long idx;
_BitScanForward(&idx, mask);
return idx;
}
internal U64
ctz64(U64 mask)
{
unsigned long idx;
_BitScanForward64(&idx, mask);
return idx;
}
internal U64
clz32(U32 mask)
{
unsigned long idx;
_BitScanReverse(&idx, mask);
return 31 - idx;
}
internal U64
clz64(U64 mask)
{
unsigned long idx;
_BitScanReverse64(&idx, mask);
return 63 - idx;
}
#elif COMPILER_CLANG || COMPILER_GCC
internal U64
count_bits_set32(U32 val)
{
return __builtin_popcount(val);
}
internal U64
count_bits_set64(U64 val)
{
return __builtin_popcountll(val);
}
internal U64
ctz32(U32 val)
{
return __builtin_ctz(val);
}
internal U64
clz32(U32 val)
{
return __builtin_clz(val);
}
internal U64
ctz64(U64 val)
{
return __builtin_ctzll(val);
}
internal U64
clz64(U64 val)
{
return __builtin_clzll(val);
}
#else
# error "Bit intrinsic functions not defined for this compiler."
#endif
////////////////////////////////
//~ rjf: Enum -> Sign
@@ -375,35 +287,27 @@ txt_rng_union(TxtRng a, TxtRng b)
return result;
}
internal B32
txt_rng_contains(TxtRng r, TxtPt pt)
{
B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) &&
txt_pt_less_than(pt, r.max));
return result;
}
////////////////////////////////
//~ rjf: Toolchain/Environment Enum Functions
internal U64
bit_size_from_arch(Arch arch)
bit_size_from_arch(Architecture arch)
{
// TODO(rjf): metacode
U64 arch_bitsize = 0;
switch(arch)
{
case Arch_x64: arch_bitsize = 64; break;
case Arch_x86: arch_bitsize = 32; break;
case Arch_arm64: arch_bitsize = 64; break;
case Arch_arm32: arch_bitsize = 32; break;
case Architecture_x64: arch_bitsize = 64; break;
case Architecture_x86: arch_bitsize = 32; break;
case Architecture_arm64: arch_bitsize = 64; break;
case Architecture_arm32: arch_bitsize = 32; break;
default: break;
}
return arch_bitsize;
}
internal U64
max_instruction_size_from_arch(Arch arch)
max_instruction_size_from_arch(Architecture arch)
{
// TODO(rjf): make this real
return 64;
@@ -422,17 +326,17 @@ operating_system_from_context(void){
return os;
}
internal Arch
arch_from_context(void){
Arch arch = Arch_Null;
internal Architecture
architecture_from_context(void){
Architecture arch = Architecture_Null;
#if ARCH_X64
arch = Arch_x64;
arch = Architecture_x64;
#elif ARCH_X86
arch = Arch_x86;
arch = Architecture_x86;
#elif ARCH_ARM64
arch = Arch_arm64;
arch = Architecture_arm64;
#elif ARCH_ARM32
arch = Arch_arm32;
arch = Architecture_arm32;
#endif
return arch;
}
@@ -440,8 +344,8 @@ arch_from_context(void){
internal Compiler
compiler_from_context(void){
Compiler compiler = Compiler_Null;
#if COMPILER_MSVC
compiler = Compiler_msvc;
#if COMPILER_CL
compiler = Compiler_cl;
#elif COMPILER_GCC
compiler = Compiler_gcc;
#elif COMPILER_CLANG
@@ -514,60 +418,6 @@ date_time_from_micro_seconds(U64 time){
return(result);
}
internal DateTime
date_time_from_unix_time(U64 unix_time)
{
DateTime date = {0};
date.year = 1970;
date.day = 1 + (unix_time / 86400);
date.sec = (U32)unix_time % 60;
date.min = (U32)(unix_time / 60) % 60;
date.hour = (U32)(unix_time / 3600) % 24;
for(;;)
{
for(date.month = 0; date.month < 12; ++date.month)
{
U64 c = 0;
switch(date.month)
{
case Month_Jan: c = 31; break;
case Month_Feb:
{
if((date.year % 4 == 0) && ((date.year % 100) != 0 || (date.year % 400) == 0))
{
c = 29;
}
else
{
c = 28;
}
} break;
case Month_Mar: c = 31; break;
case Month_Apr: c = 30; break;
case Month_May: c = 31; break;
case Month_Jun: c = 30; break;
case Month_Jul: c = 31; break;
case Month_Aug: c = 31; break;
case Month_Sep: c = 30; break;
case Month_Oct: c = 31; break;
case Month_Nov: c = 30; break;
case Month_Dec: c = 31; break;
default: InvalidPath;
}
if(date.day <= c)
{
goto exit;
}
date.day -= c;
}
++date.year;
}
exit:;
return date;
}
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_CORE_H
#define BASE_CORE_H
#ifndef BASE_TYPES_H
#define BASE_TYPES_H
////////////////////////////////
//~ rjf: Foreign Includes
@@ -13,6 +13,17 @@
#include <string.h>
#include <stdint.h>
////////////////////////////////
//~ rjf: Build Configuration
#if !defined(ENABLE_DEV)
# define ENABLE_DEV 0
#endif
#if !defined(SUPPLEMENT_UNIT)
# define SUPPLEMENT_UNIT 0
#endif
////////////////////////////////
//~ rjf: Codebase Keywords
@@ -20,7 +31,7 @@
#define global static
#define local_persist static
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
# pragma section(".rdata$", read)
# define read_only __declspec(allocate(".rdata$"))
#elif (COMPILER_CLANG && OS_LINUX)
@@ -34,101 +45,6 @@
# define read_only
#endif
#if COMPILER_MSVC
# define thread_static __declspec(thread)
#elif COMPILER_CLANG || COMPILER_GCC
# define thread_static __thread
#endif
#if COMPILER_MSVC
# define force_inline __forceinline
#elif COMPILER_CLANG || COMPILER_GCC
# define force_inline __attribute__((always_inline))
#endif
////////////////////////////////
//~ rjf: Linkage Keyword Macros
#if OS_WINDOWS
# define shared_function C_LINKAGE __declspec(dllexport)
#else
# define shared_function C_LINKAGE
#endif
#if LANG_CPP
# define C_LINKAGE_BEGIN extern "C"{
# define C_LINKAGE_END }
# define C_LINKAGE extern "C"
#else
# define C_LINKAGE_BEGIN
# define C_LINKAGE_END
# define C_LINKAGE
#endif
////////////////////////////////
//~ rjf: Units
#define KB(n) (((U64)(n)) << 10)
#define MB(n) (((U64)(n)) << 20)
#define GB(n) (((U64)(n)) << 30)
#define TB(n) (((U64)(n)) << 40)
#define Thousand(n) ((n)*1000)
#define Million(n) ((n)*1000000)
#define Billion(n) ((n)*1000000000)
////////////////////////////////
//~ rjf: Branch Predictor Hints
#if defined(__clang__)
# define Expect(expr, val) __builtin_expect((expr), (val))
#else
# define Expect(expr, val) (expr)
#endif
#define Likely(expr) Expect(expr,1)
#define Unlikely(expr) Expect(expr,0)
////////////////////////////////
//~ rjf: Clamps, Mins, Maxes
#define Min(A,B) (((A)<(B))?(A):(B))
#define Max(A,B) (((A)>(B))?(A):(B))
#define ClampTop(A,X) Min(A,X)
#define ClampBot(X,B) Max(X,B)
#define Clamp(A,X,B) (((X)<(A))?(A):((X)>(B))?(B):(X))
////////////////////////////////
//~ rjf: Type -> Alignment
#if COMPILER_MSVC
# define AlignOf(T) __alignof(T)
#elif COMPILER_CLANG
# define AlignOf(T) __alignof(T)
#elif COMPILER_GCC
# define AlignOf(T) __alignof__(T)
#else
# error AlignOf not defined for this compiler.
#endif
////////////////////////////////
//~ rjf: Member Offsets
#define Member(T,m) (((T*)0)->m)
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
////////////////////////////////
//~ rjf: For-Loop Construct Macros
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
#define EachIndex(it, count) (U64 it = 0; it < (count); it += 1)
#define EachElement(it, array) (U64 it = 0; it < ArrayCount(array); it += 1)
#define EachEnumVal(type, it) (type it = (type)0; it < type##_COUNT; it = (type)(it+1))
#define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1))
////////////////////////////////
//~ rjf: Memory Operation Macros
@@ -151,143 +67,147 @@
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
#define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
#define MemoryConsume(T,p,e) \
( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
////////////////////////////////
//~ rjf: Units
#define KB(n) (((U64)(n)) << 10)
#define MB(n) (((U64)(n)) << 20)
#define GB(n) (((U64)(n)) << 30)
#define TB(n) (((U64)(n)) << 40)
#define Thousand(n) ((n)*1000)
#define Million(n) ((n)*1000000)
#define Billion(n) ((n)*1000000000)
////////////////////////////////
//~ rjf: Asserts
#if COMPILER_MSVC
#if COMPILER_CL
# define Trap() __debugbreak()
#elif COMPILER_CLANG || COMPILER_GCC
# define Trap() __builtin_trap()
#else
# error Unknown trap intrinsic for this compiler.
# else
# error "undefined trap"
#endif
#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0)
#if BUILD_DEBUG
#if !defined(NDEBUG)
# define Assert(x) AssertAlways(x)
#else
# define Assert(x) (void)(x)
#endif
#define AssertImplies(a,b) Assert(!(a) || b)
#define AssertIff(a,b) Assert(!!(a) == !!(b))
#define InvalidPath Assert(!"Invalid Path!")
#define NotImplemented Assert(!"Not Implemented!")
#define NoOp ((void)0)
#define StaticAssert(C, ID) global U8 Glue(ID, __LINE__)[(C)?1:-1]
#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1]
////////////////////////////////
//~ rjf: Atomic Operations
//~ rjf: Branch Predictor Hints
#if COMPILER_MSVC
# include <intrin.h>
# if ARCH_X64
# define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c))
# define ins_atomic_u32_eval(x) *((volatile U32 *)(x))
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x)
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
# else
# error Atomic intrinsics not defined for this compiler / architecture combination.
# endif
#elif COMPILER_CLANG || COMPILER_GCC
# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((volatile U64 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((volatile U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((volatile U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((volatile U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
#if defined(__clang__)
# define Expect(expr, val) __builtin_expect((expr), (val))
#else
# error Atomic intrinsics not defined for this compiler / architecture.
# define Expect(expr, val) (expr)
#endif
#define Likely(expr) Expect(expr,1)
#define Unlikely(expr) Expect(expr,0)
////////////////////////////////
//~ rjf: Misc. Helper Macros
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
#define Stmnt(S) do{ S }while(0)
#define Stringify_(S) #S
#define Stringify(S) Stringify_(S)
#define Glue_(A,B) A##B
#define Glue(A,B) Glue_(A,B)
#define Min(A,B) ( ((A)<(B))?(A):(B) )
#define Max(A,B) ( ((A)>(B))?(A):(B) )
#define ClampTop(A,X) Min(A,X)
#define ClampBot(X,B) Max(X,B)
#define Clamp(A,X,B) ( ((X)<(A))?(A):((X)>(B))?(B):(X) )
#define PtrClampTop(A,X) ClampTop(A,X)
#define PtrClampBot(X,B) ClampBot(X,B)
#define PtrClamp(A,X,B) Clamp(A,X,B)
#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b))
#define Swap(T,a,b) Stmnt( T t__ = a; a = b; b = t__; )
#if ARCH_64BIT
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u64_eval_cond_assign((volatile U64 *)(x), (U64)(k), (U64)(c))
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u64_eval((volatile U64 *)x)
# define IntFromPtr(ptr) ((U64)(ptr))
#elif ARCH_32BIT
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u32_eval_cond_assign((volatile U32 *)(x), (U32)(k), (U32)(c))
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u32_eval_assign((volatile U32 *)(x), (U32)(c))
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u32_eval((volatile U32 *)x)
# define IntFromPtr(ptr) ((U32)(ptr))
#else
# error Atomic intrinsics for pointers not defined for this architecture.
# error missing ptr cast for this architecture
#endif
#define PtrFromInt(i) (void*)((U8*)0 + (i))
#define Member(T,m) (((T*)0)->m)
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0)
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
#if LANG_CPP
# define zero_struct {}
#else
# define zero_struct {0}
#endif
#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
# define this_function_name "unknown"
#else
# define this_function_name __func__
#endif
#if LANG_CPP
# define C_LINKAGE_BEGIN extern "C"{
# define C_LINKAGE_END }
# define C_LINKAGE extern "C"
#else
# define C_LINKAGE_BEGIN
# define C_LINKAGE_END
# define C_LINKAGE
#endif
#if COMPILER_CL
# define thread_static __declspec(thread)
#elif COMPILER_CLANG || COMPILER_GCC
# define thread_static __thread
#endif
#if OS_WINDOWS
# define shared_function C_LINKAGE __declspec(dllexport)
#else
# define shared_function C_LINKAGE
#endif
////////////////////////////////
//~ rjf: Linked List Building Macros
//~ ASAN
//- rjf: linked list macro helpers
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
#define SetNil(nil,p) ((p) = nil)
//- rjf: doubly-linked-lists
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
CheckNil(nil,p) ? \
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
((p)==(l)) ? \
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
((n) == (l) ? (l) = (l)->prev : (0)),\
(CheckNil(nil,(n)->prev) ? (0) :\
((n)->prev->next = (n)->next)),\
(CheckNil(nil,(n)->next) ? (0) :\
((n)->next->prev = (n)->prev)))
//- rjf: singly-linked, doubly-headed lists (queues)
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((n)->next=(f),(f)=(n)))
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
(SetNil(nil,f),SetNil(nil,l)):\
((f)=(f)->next))
//- rjf: singly-linked, singly-headed lists (stacks)
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
#define SLLStackPop_N(f,next) ((f)=(f)->next)
//- rjf: doubly-linked-list helpers
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
//- rjf: singly-linked, doubly-headed list helpers
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
//- rjf: singly-linked, singly-headed list helpers
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
#define SLLStackPop(f) SLLStackPop_N(f,next)
////////////////////////////////
//~ rjf: Address Sanitizer Markup
#if COMPILER_MSVC
#if COMPILER_CL
# if defined(__SANITIZE_ADDRESS__)
# define ASAN_ENABLED 1
# define NO_ASAN __declspec(no_sanitize_address)
@@ -302,63 +222,24 @@ CheckNil(nil,p) ? \
# endif
# define NO_ASAN __attribute__((no_sanitize("address")))
#else
# define NO_ASAN
# error "NO_ASAN is not defined"
#endif
#if ASAN_ENABLED
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
C_LINKAGE void __asan_poison_memory_region(void const volatile *addr, size_t size);
C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
C_LINKAGE_BEGIN
void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
C_LINKAGE_END
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size))
#else
# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
#endif
////////////////////////////////
//~ rjf: Misc. Helper Macros
#define Stringify_(S) #S
#define Stringify(S) Stringify_(S)
#define Glue_(A,B) A##B
#define Glue(A,B) Glue_(A,B)
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b))
#define Swap(T,a,b) do{T t__ = a; a = b; b = t__;}while(0)
#if ARCH_64BIT
# define IntFromPtr(ptr) ((U64)(ptr))
#elif ARCH_32BIT
# define IntFromPtr(ptr) ((U32)(ptr))
#else
# error Missing pointer-to-integer cast for this architecture.
#endif
#define PtrFromInt(i) (void*)((U8*)0 + (i))
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0)
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
#if LANG_CPP
# define zero_struct {}
#else
# define zero_struct {0}
#endif
#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
# define this_function_name "unknown"
#else
# define this_function_name __func__
#endif
////////////////////////////////
@@ -378,7 +259,10 @@ typedef S32 B32;
typedef S64 B64;
typedef float F32;
typedef double F64;
typedef void VoidProc(void);
////////////////////////////////
//~ rjf: Large Base Types
typedef struct U128 U128;
struct U128
{
@@ -388,6 +272,8 @@ struct U128
////////////////////////////////
//~ rjf: Basic Types & Spaces
typedef void VoidProc(void);
typedef enum Dimension
{
Dimension_X,
@@ -428,19 +314,6 @@ typedef enum Corner
}
Corner;
typedef enum Dir2
{
Dir2_Invalid = -1,
Dir2_Left,
Dir2_Up,
Dir2_Right,
Dir2_Down,
Dir2_COUNT
}
Dir2;
#define axis2_from_dir2(d) (((d) & 1) ? Axis2_Y : Axis2_X)
#define side_from_dir2(d) (((d) < Dir2_Right) ? Side_Min : Side_Max)
////////////////////////////////
//~ rjf: Toolchain/Environment Enums
@@ -454,30 +327,21 @@ typedef enum OperatingSystem
}
OperatingSystem;
typedef enum ImageType
typedef enum Architecture
{
Image_Null,
Image_CoffPe,
Image_Elf32,
Image_Elf64,
Image_Macho
} ImageType;
typedef enum Arch
{
Arch_Null,
Arch_x64,
Arch_x86,
Arch_arm64,
Arch_arm32,
Arch_COUNT,
Architecture_Null,
Architecture_x64,
Architecture_x86,
Architecture_arm64,
Architecture_arm32,
Architecture_COUNT,
}
Arch;
Architecture;
typedef enum Compiler
{
Compiler_Null,
Compiler_msvc,
Compiler_cl,
Compiler_gcc,
Compiler_clang,
Compiler_COUNT,
@@ -501,51 +365,6 @@ struct TxtRng
TxtPt max;
};
////////////////////////////////
//~ Globally Unique Ids
typedef union Guid Guid;
union Guid
{
struct
{
U32 data1;
U16 data2;
U16 data3;
U8 data4[8];
};
U8 v[16];
};
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
////////////////////////////////
//~ Arrays
typedef struct U16Array U16Array;
struct U16Array
{
U64 count;
U16 *v;
};
typedef struct U32Array U32Array;
struct U32Array
{
U64 count;
U32 *v;
};
typedef struct U64Array U64Array;
struct U64Array
{
U64 count;
U64 *v;
};
typedef struct U128Array U128Array;
struct U128Array
{
U64 count;
U128 *v;
};
////////////////////////////////
//~ NOTE(allen): Constants
@@ -750,13 +569,11 @@ struct DateTime
U16 min; // [0,59]
U16 hour; // [0,24]
U16 day; // [0,30]
union
{
union{
WeekDay week_day;
U32 wday;
};
union
{
union{
Month month;
U32 mon;
};
@@ -784,7 +601,7 @@ struct FileProperties
};
////////////////////////////////
//~ rjf: Safe Casts
//~ Safe Casts
internal U16 safe_cast_u16(U32 x);
internal U32 safe_cast_u32(U64 x);
@@ -812,24 +629,6 @@ internal U16 bswap_u16(U16 x);
internal U32 bswap_u32(U32 x);
internal U64 bswap_u64(U64 x);
#if ARCH_LITTLE_ENDIAN
# define from_be_u16(x) bswap_u16(x)
# define from_be_u32(x) bswap_u32(x)
# define from_be_u64(x) bswap_u64(x)
#else
# define from_be_u16(x) (x)
# define from_be_u32(x) (x)
# define from_be_u64(x) (x)
#endif
internal U64 count_bits_set32(U32 val);
internal U64 count_bits_set64(U64 val);
internal U64 ctz32(U32 val);
internal U64 ctz64(U64 val);
internal U64 clz32(U32 val);
internal U64 clz64(U64 val);
////////////////////////////////
//~ rjf: Enum -> Sign
@@ -852,16 +651,15 @@ internal TxtPt txt_pt_max(TxtPt a, TxtPt b);
internal TxtRng txt_rng(TxtPt min, TxtPt max);
internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b);
internal TxtRng txt_rng_union(TxtRng a, TxtRng b);
internal B32 txt_rng_contains(TxtRng r, TxtPt pt);
////////////////////////////////
//~ rjf: Toolchain/Environment Enum Functions
internal U64 bit_size_from_arch(Arch arch);
internal U64 max_instruction_size_from_arch(Arch arch);
internal U64 bit_size_from_arch(Architecture arch);
internal U64 max_instruction_size_from_arch(Architecture arch);
internal OperatingSystem operating_system_from_context(void);
internal Arch arch_from_context(void);
internal Architecture architecture_from_context(void);
internal Compiler compiler_from_context(void);
////////////////////////////////
@@ -870,7 +668,6 @@ internal Compiler compiler_from_context(void);
internal DenseTime dense_time_from_date_time(DateTime date_time);
internal DateTime date_time_from_dense_time(DenseTime time);
internal DateTime date_time_from_micro_seconds(U64 time);
internal DateTime date_time_from_unix_time(U64 unix_time);
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
@@ -880,9 +677,4 @@ internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_dat
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
////////////////////////////////
//~ rjf: Sorts
#define quick_sort(ptr, count, element_size, cmp_function) qsort((ptr), (count), (element_size), (int (*)(const void *, const void *))(cmp_function))
#endif // BASE_CORE_H
#endif // BASE_TYPES_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-630
View File
@@ -1,630 +0,0 @@
////////////////////////////////
//~ rjf: CV Numerics
@table(name val)
CV_NumericKindTable:
{
{CHAR 0x8000}
{SHORT 0x8001}
{USHORT 0x8002}
{LONG 0x8003}
{ULONG 0x8004}
{FLOAT32 0x8005}
{FLOAT64 0x8006}
{FLOAT80 0x8007}
{FLOAT128 0x8008}
{QUADWORD 0x8009}
{UQUADWORD 0x800a}
{FLOAT48 0x800b}
{COMPLEX32 0x800c}
{COMPLEX64 0x800d}
{COMPLEX80 0x800e}
{COMPLEX128 0x800f}
{VARSTRING 0x8010}
{OCTWORD 0x8017}
{UOCTWORD 0x8018}
{DECIMAL 0x8019}
{DATE 0x801a}
{UTF8STRING 0x801b}
{FLOAT16 0x801c}
}
@enum(U16) CV_NumericKind:
{
@expand(CV_NumericKindTable a) `$(a.name) = $(a.val)`
}
@enum2string_switch(CV_NumericKind)
cv_string_from_numeric_kind:
{
@expand(CV_NumericKindTable a) `case CV_NumericKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
////////////////////////////////
//~ rjf: CV Architectures
@table(name val)
CV_ArchTable:
{
{8080 0x00}
{8086 0x01}
{80286 0x02}
{80386 0x03}
{80486 0x04}
{PENTIUM 0x05}
{PENTIUMII 0x06}
{PENTIUMIII 0x07}
{MIPS 0x10}
{MIPS16 0x11}
{MIPS32 0x12}
{MIPS64 0x13}
{MIPSI 0x14}
{MIPSII 0x15}
{MIPSIII 0x16}
{MIPSIV 0x17}
{MIPSV 0x18}
{M68000 0x20}
{M68010 0x21}
{M68020 0x22}
{M68030 0x23}
{M68040 0x24}
{ALPHA 0x30}
{ALPHA_21164 0x31}
{ALPHA_21164A 0x32}
{ALPHA_21264 0x33}
{ALPHA_21364 0x34}
{PPC601 0x40}
{PPC603 0x41}
{PPC604 0x42}
{PPC620 0x43}
{PPCFP 0x44}
{PPCBE 0x45}
{SH3 0x50}
{SH3E 0x51}
{SH3DSP 0x52}
{SH4 0x53}
{SHMEDIA 0x54}
{ARM3 0x60}
{ARM4 0x61}
{ARM4T 0x62}
{ARM5 0x63}
{ARM5T 0x64}
{ARM6 0x65}
{ARM_XMAC 0x66}
{ARM_WMMX 0x67}
{ARM7 0x68}
{OMNI 0x70}
{IA64_1 0x80}
{IA64_2 0x81}
{CEE 0x90}
{AM33 0xA0}
{M32R 0xB0}
{TRICORE 0xC0}
{X64 0xD0}
{EBC 0xE0}
{THUMB 0xF0}
{ARMNT 0xF4}
{ARM64 0xF6}
{D3D11_SHADER 0x100}
}
@enum(U16) CV_Arch:
{
@expand(CV_ArchTable a) `$(a.name) = $(a.val)`,
`IA64 = CV_Arch_IA64_1`,
`PENTIUMPRO = CV_Arch_PENTIUMII`,
`MIPSR4000 = CV_Arch_MIPS`,
`ALPHA_21064 = CV_Arch_ALPHA`,
`AMD64 = CV_Arch_X64`,
}
@enum2string_switch(CV_Arch)
cv_string_from_arch:
{
@expand(CV_ArchTable a) `case CV_Arch_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
////////////////////////////////
//~ rjf: CV Registers
@table(name val) CV_AllRegTable:
{
{ERR 30000}
{TEB 30001}
{TIMER 30002}
{EFAD1 30003}
{EFAD2 30004}
{EFAD3 30005}
{VFRAME 30006}
{HANDLE 30007}
{PARAMS 30008}
{LOCALS 30009}
{TID 30010}
{ENV 30011}
{CMDLN 30012}
}
@enum(U16) CV_AllReg:
{
@expand(CV_AllRegTable a) `$(a.name) = $(a.val)`
}
////////////////////////////////
//~ rjf: CV Sym Kinds
@table(name header_type_name val) CV_SymKindTable:
{
{COMPILE Compile 0x0001}
{REGISTER_16t - 0x0002}
{CONSTANT_16t - 0x0003}
{UDT_16t - 0x0004}
{SSEARCH StartSearch 0x0005}
{END - 0x0006}
{SKIP - 0x0007}
{CVRESERVE - 0x0008}
{OBJNAME_ST - 0x0009}
{ENDARG - 0x000a}
{COBOLUDT_16t - 0x000b}
{MANYREG_16t - 0x000c}
{RETURN Return 0x000d}
{ENTRYTHIS - 0x000e}
{BPREL16 - 0x0100}
{LDATA16 - 0x0101}
{GDATA16 - 0x0102}
{PUB16 - 0x0103}
{LPROC16 - 0x0104}
{GPROC16 - 0x0105}
{THUNK16 - 0x0106}
{BLOCK16 - 0x0107}
{WITH16 - 0x0108}
{LABEL16 - 0x0109}
{CEXMODEL16 - 0x010a}
{VFTABLE16 - 0x010b}
{REGREL16 - 0x010c}
{BPREL32_16t - 0x0200}
{LDATA32_16t - 0x0201}
{GDATA32_16t - 0x0202}
{PUB32_16t - 0x0203}
{LPROC32_16t - 0x0204}
{GPROC32_16t - 0x0205}
{THUNK32_ST - 0x0206}
{BLOCK32_ST - 0x0207}
{WITH32_ST - 0x0208}
{LABEL32_ST - 0x0209}
{CEXMODEL32 - 0x020a}
{VFTABLE32_16t - 0x020b}
{REGREL32_16t - 0x020c}
{LTHREAD32_16t - 0x020d}
{GTHREAD32_16t - 0x020e}
{SLINK32 SLink32 0x020f}
{LPROCMIPS_16t - 0x0300}
{GPROCMIPS_16t - 0x0301}
{PROCREF_ST - 0x0400}
{DATAREF_ST - 0x0401}
{ALIGN - 0x0402}
{LPROCREF_ST - 0x0403}
{OEM OEM 0x0404}
{TI16_MAX - 0x1000}
{CONSTANT_ST - 0x1002}
{UDT_ST - 0x1003}
{COBOLUDT_ST - 0x1004}
{MANYREG_ST - 0x1005}
{BPREL32_ST - 0x1006}
{LDATA32_ST - 0x1007}
{GDATA32_ST - 0x1008}
{PUB32_ST - 0x1009}
{LPROC32_ST - 0x100a}
{GPROC32_ST - 0x100b}
{VFTABLE32 VPath32 0x100c}
{REGREL32_ST - 0x100d}
{LTHREAD32_ST - 0x100e}
{GTHREAD32_ST - 0x100f}
{LPROCMIPS_ST - 0x1010}
{GPROCMIPS_ST - 0x1011}
{FRAMEPROC Frameproc 0x1012}
{COMPILE2_ST - 0x1013}
{MANYREG2_ST - 0x1014}
{LPROCIA64_ST - 0x1015}
{GPROCIA64_ST - 0x1016}
{LOCALSLOT_ST - 0x1017}
{PARAMSLOT_ST - 0x1018}
{ANNOTATION Annotation 0x1019}
{GMANPROC_ST - 0x101a}
{LMANPROC_ST - 0x101b}
{RESERVED1 - 0x101c}
{RESERVED2 - 0x101d}
{RESERVED3 - 0x101e}
{RESERVED4 - 0x101f}
{LMANDATA_ST - 0x1020}
{GMANDATA_ST - 0x1021}
{MANFRAMEREL_ST - 0x1022}
{MANREGISTER_ST - 0x1023}
{MANSLOT_ST - 0x1024}
{MANMANYREG_ST - 0x1025}
{MANREGREL_ST - 0x1026}
{MANMANYREG2_ST - 0x1027}
{MANTYPREF - 0x1028}
{UNAMESPACE_ST - 0x1029}
{ST_MAX - 0x1100}
{OBJNAME ObjName 0x1101}
{THUNK32 Thunk32 0x1102}
{BLOCK32 Block32 0x1103}
{WITH32 - 0x1104}
{LABEL32 Label32 0x1105}
{REGISTER Register 0x1106}
{CONSTANT Constant 0x1107}
{UDT UDT 0x1108}
{COBOLUDT - 0x1109}
{MANYREG Manyreg 0x110a}
{BPREL32 BPRel32 0x110b}
{LDATA32 Data32 0x110c}
{GDATA32 Data32 0x110d}
{PUB32 Pub32 0x110e}
{LPROC32 Proc32 0x110f}
{GPROC32 Proc32 0x1110}
{REGREL32 Regrel32 0x1111}
{LTHREAD32 Thread32 0x1112}
{GTHREAD32 Thread32 0x1113}
{LPROCMIPS - 0x1114}
{GPROCMIPS - 0x1115}
{COMPILE2 Compile2 0x1116}
{MANYREG2 Manyreg2 0x1117}
{LPROCIA64 - 0x1118}
{GPROCIA64 - 0x1119}
{LOCALSLOT Slot 0x111a}
{PARAMSLOT - 0x111b}
{LMANDATA - 0x111c}
{GMANDATA - 0x111d}
{MANFRAMEREL AttrFrameRel 0x111e}
{MANREGISTER AttrReg 0x111f}
{MANSLOT - 0x1120}
{MANMANYREG AttrManyReg 0x1121}
{MANREGREL AttrRegRel 0x1122}
{MANMANYREG2 - 0x1123}
{UNAMESPACE UNamespace 0x1124}
{PROCREF Ref2 0x1125}
{DATAREF Ref2 0x1126}
{LPROCREF Ref2 0x1127}
{ANNOTATIONREF - 0x1128}
{TOKENREF - 0x1129}
{GMANPROC - 0x112a}
{LMANPROC - 0x112b}
{TRAMPOLINE Trampoline 0x112c}
{MANCONSTANT - 0x112d}
{ATTR_FRAMEREL AttrFrameRel 0x112e}
{ATTR_REGISTER AttrReg 0x112f}
{ATTR_REGREL AttrRegRel 0x1130}
{ATTR_MANYREG AttrManyReg 0x1131}
{SEPCODE Sepcode 0x1132}
{DEFRANGE_2005 - 0x1134}
{DEFRANGE2_2005 - 0x1135}
{SECTION Section 0x1136}
{COFFGROUP CoffGroup 0x1137}
{EXPORT Export 0x1138}
{CALLSITEINFO CallSiteInfo 0x1139}
{FRAMECOOKIE FrameCookie 0x113a}
{DISCARDED Discarded 0x113b}
{COMPILE3 Compile3 0x113c}
{ENVBLOCK EnvBlock 0x113d}
{LOCAL Local 0x113e}
{DEFRANGE - 0x113f}
{DEFRANGE_SUBFIELD DefrangeSubfield 0x1140}
{DEFRANGE_REGISTER DefrangeRegister 0x1141}
{DEFRANGE_FRAMEPOINTER_REL DefrangeFramepointerRel 0x1142}
{DEFRANGE_SUBFIELD_REGISTER DefrangeSubfieldRegister 0x1143}
{DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE DefrangeFramepointerRelFullScope 0x1144}
{DEFRANGE_REGISTER_REL DefrangeRegisterRel 0x1145}
{LPROC32_ID - 0x1146}
{GPROC32_ID - 0x1147}
{LPROCMIPS_ID - 0x1148}
{GPROCMIPS_ID - 0x1149}
{LPROCIA64_ID - 0x114a}
{GPROCIA64_ID - 0x114b}
{BUILDINFO BuildInfo 0x114c}
{INLINESITE InlineSite 0x114d}
{INLINESITE_END - 0x114e}
{PROC_ID_END - 0x114f}
{DEFRANGE_HLSL - 0x1150}
{GDATA_HLSL - 0x1151}
{LDATA_HLSL - 0x1152}
{FILESTATIC FileStatic 0x1153}
{LPROC32_DPC - 0x1155}
{LPROC32_DPC_ID - 0x1156}
{DEFRANGE_DPC_PTR_TAG - 0x1157}
{DPC_SYM_TAG_MAP - 0x1158}
{ARMSWITCHTABLE - 0x1159}
{CALLEES FunctionList 0x115a}
{CALLERS FunctionList 0x115b}
{POGODATA PogoInfo 0x115c}
{INLINESITE2 InlineSite2 0x115d}
{HEAPALLOCSITE HeapAllocSite 0x115e}
{MOD_TYPEREF ModTypeRef 0x115f}
{REF_MINIPDB RefMiniPdb 0x1160}
{PDBMAP - 0x1161}
{GDATA_HLSL32 - 0x1162}
{LDATA_HLSL32 - 0x1163}
{GDATA_HLSL32_EX - 0x1164}
{LDATA_HLSL32_EX - 0x1165}
{FASTLINK FastLink 0x1167}
{INLINEES Inlinees 0x1168}
}
@enum(U16) CV_SymKind:
{
@expand(CV_SymKindTable a) `$(a.name) = $(a.val)`
}
@enum2string_switch(CV_SymKind)
cv_string_from_sym_kind:
{
@expand(CV_SymKindTable a) `case CV_SymKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
@gen(functions)
{
`internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);`;
}
@gen(functions) @c_file
{
`internal U64`;
`cv_header_struct_size_from_sym_kind(CV_SymKind v)`;
`{`;
`U64 result = 0;`;
`switch(v)`;
`{`;
`default:{}break;`;
@expand(CV_SymKindTable a) `$(a.header_type_name != "-" -> "case CV_SymKind_"..a.name..":{result = sizeof(CV_Sym"..a.header_type_name..");}break;")`;
`}`;
`return result;`;
`}`;
}
////////////////////////////////
//~ rjf: CV Basic Types
@table(name val type_name)
CV_BasicTypeTable:
{
{NOTYPE 0x00 "" }
{ABS 0x01 "" }
{SEGMENT 0x02 "" }
{VOID 0x03 "void" }
{CURRENCY 0x04 "" }
{NBASICSTR 0x05 "" }
{FBASICSTR 0x06 "" }
{NOTTRANS 0x07 "" }
{HRESULT 0x08 "HRESULT" }
{CHAR 0x10 "CHAR" }
{SHORT 0x11 "SHORT" }
{LONG 0x12 "LONG" }
{QUAD 0x13 "QUAD" }
{OCT 0x14 "OCT" }
{UCHAR 0x20 "UCHAR" }
{USHORT 0x21 "USHORT" }
{ULONG 0x22 "ULONG" }
{UQUAD 0x23 "UQUAD" }
{UOCT 0x24 "UOCT" }
{BOOL8 0x30 "BOOL8" }
{BOOL16 0x31 "BOOL16" }
{BOOL32 0x32 "BOOL32" }
{BOOL64 0x33 "BOOL64" }
{FLOAT32 0x40 "FLOAT32" }
{FLOAT64 0x41 "FLOAT64" }
{FLOAT80 0x42 "FLOAT80" }
{FLOAT128 0x43 "FLOAT128" }
{FLOAT48 0x44 "FLOAT48" }
{FLOAT32PP 0x45 "FLOAT32PP" }
{FLOAT16 0x46 "FLOAT16" }
{COMPLEX32 0x50 "ComplexF32" }
{COMPLEX64 0x51 "ComplexF64" }
{COMPLEX80 0x52 "ComplexF80" }
{COMPLEX128 0x53 "ComplexF128" }
{BIT 0x60 "" }
{PASCHAR 0x61 "" }
{BOOL32FF 0x62 "BOOL32FF" }
{INT8 0x68 "int8" }
{UINT8 0x69 "uint8" }
{RCHAR 0x70 "char" }
{WCHAR 0x71 "WCHAR" }
{INT16 0x72 "int16" }
{UINT16 0x73 "uint16" }
{INT32 0x74 "int32" }
{UINT32 0x75 "uint32" }
{INT64 0x76 "int64" }
{UINT64 0x77 "uint64" }
{INT128 0x78 "int128" }
{UINT128 0x79 "uint128" }
{CHAR16 0x7a "char16" }
{CHAR32 0x7b "char32" }
{CHAR8 0x7c "char" }
{PTR 0xf0 "PTR" }
}
@enum(U8) CV_BasicType:
{
@expand(CV_BasicTypeTable a) `$(a.name) = $(a.val)`
}
@enum2string_switch(CV_BasicType) cv_string_from_basic_type:
{
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.name)");}break`
}
@enum2string_switch(CV_BasicType) cv_type_name_from_basic_type:
{
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.type_name)");}break`
}
////////////////////////////////
//~ rjf: CV Leaf Kinds
@table(name header_type_name val)
CV_LeafKindTable:
{
{NOTYPE - 0x0000}
{MODIFIER_16t - 0x0001}
{POINTER_16t - 0x0002}
{ARRAY_16t - 0x0003}
{CLASS_16t - 0x0004}
{STRUCTURE_16t - 0x0005}
{UNION_16t - 0x0006}
{ENUM_16t - 0x0007}
{PROCEDURE_16t - 0x0008}
{MFUNCTION_16t - 0x0009}
{VTSHAPE VTShape 0x000a}
{COBOL0_16t - 0x000b}
{COBOL1 - 0x000c}
{BARRAY_16t - 0x000d}
{LABEL Label 0x000e}
{NULL - 0x000f}
{NOTTRAN - 0x0010}
{DIMARRAY_16t - 0x0011}
{VFTPATH_16t - 0x0012}
{PRECOMP_16t - 0x0013}
{ENDPRECOMP - 0x0014}
{OEM_16t - 0x0015}
{TYPESERVER_ST - 0x0016}
{SKIP_16t - 0x0200}
{ARGLIST_16t - 0x0201}
{DEFARG_16t - 0x0202}
{LIST - 0x0203}
{FIELDLIST_16t - 0x0204}
{DERIVED_16t - 0x0205}
{BITFIELD_16t - 0x0206}
{METHODLIST_16t - 0x0207}
{DIMCONU_16t - 0x0208}
{DIMCONLU_16t - 0x0209}
{DIMVARU_16t - 0x020a}
{DIMVARLU_16t - 0x020b}
{REFSYM - 0x020c}
{BCLASS_16t - 0x0400}
{VBCLASS_16t - 0x0401}
{IVBCLASS_16t - 0x0402}
{ENUMERATE_ST - 0x0403}
{FRIENDFCN_16t - 0x0404}
{INDEX_16t - 0x0405}
{MEMBER_16t - 0x0406}
{STMEMBER_16t - 0x0407}
{METHOD_16t - 0x0408}
{NESTTYPE_16t - 0x0409}
{VFUNCTAB_16t - 0x040a}
{FRIENDCLS_16t - 0x040b}
{ONEMETHOD_16t - 0x040c}
{VFUNCOFF_16t - 0x040d}
{TI16_MAX - 0x1000}
{MODIFIER Modifier 0x1001}
{POINTER Pointer 0x1002}
{ARRAY_ST - 0x1003}
{CLASS_ST - 0x1004}
{STRUCTURE_ST - 0x1005}
{UNION_ST - 0x1006}
{ENUM_ST - 0x1007}
{PROCEDURE Procedure 0x1008}
{MFUNCTION MFunction 0x1009}
{COBOL0 - 0x100a}
{BARRAY - 0x100b}
{DIMARRAY_ST - 0x100c}
{VFTPATH VFPath 0x100d}
{PRECOMP_ST - 0x100e}
{OEM - 0x100f}
{ALIAS_ST - 0x1010}
{OEM2 - 0x1011}
{SKIP Skip 0x1200}
{ARGLIST ArgList 0x1201}
{DEFARG_ST - 0x1202}
{FIELDLIST - 0x1203}
{DERIVED - 0x1204}
{BITFIELD BitField 0x1205}
{METHODLIST MethodListMember 0x1206}
{DIMCONU - 0x1207}
{DIMCONLU - 0x1208}
{DIMVARU - 0x1209}
{DIMVARLU - 0x120a}
{BCLASS BClass 0x1400}
{VBCLASS VBClass 0x1401}
{IVBCLASS - 0x1402}
{FRIENDFCN_ST - 0x1403}
{INDEX Index 0x1404}
{MEMBER_ST - 0x1405}
{STMEMBER_ST - 0x1406}
{METHOD_ST - 0x1407}
{NESTTYPE_ST - 0x1408}
{VFUNCTAB VFuncTab 0x1409}
{FRIENDCLS - 0x140a}
{ONEMETHOD_ST - 0x140b}
{VFUNCOFF VFuncOff 0x140c}
{NESTTYPEEX_ST - 0x140d}
{MEMBERMODIFY_ST - 0x140e}
{MANAGED_ST - 0x140f}
{ST_MAX - 0x1500}
{TYPESERVER TypeServer 0x1501}
{ENUMERATE Enumerate 0x1502}
{ARRAY Array 0x1503}
{CLASS Struct 0x1504}
{STRUCTURE Struct 0x1505}
{UNION Union 0x1506}
{ENUM Enum 0x1507}
{DIMARRAY - 0x1508}
{PRECOMP PreComp 0x1509}
{ALIAS Alias 0x150a}
{DEFARG - 0x150b}
{FRIENDFCN - 0x150c}
{MEMBER Member 0x150d}
{STMEMBER StMember 0x150e}
{METHOD Method 0x150f}
{NESTTYPE NestType 0x1510}
{ONEMETHOD OneMethod 0x1511}
{NESTTYPEEX NestTypeEx 0x1512}
{MEMBERMODIFY - 0x1513}
{MANAGED - 0x1514}
{TYPESERVER2 TypeServer2 0x1515}
{STRIDED_ARRAY - 0x1516}
{HLSL - 0x1517}
{MODIFIER_EX - 0x1518}
{INTERFACE Struct 0x1519}
{BINTERFACE - 0x151a}
{VECTOR - 0x151b}
{MATRIX - 0x151c}
{VFTABLE - 0x151d}
{FUNC_ID FuncId 0x1601}
{MFUNC_ID MFuncId 0x1602}
{BUILDINFO BuildInfo 0x1603}
{SUBSTR_LIST SubstrList 0x1604}
{STRING_ID StringId 0x1605}
{UDT_SRC_LINE UDTSrcLine 0x1606}
{UDT_MOD_SRC_LINE UDTModSrcLine 0x1607}
{CLASS2 Struct2 0x1608}
{STRUCT2 Struct2 0x1609}
}
@enum(U16) CV_LeafKind:
{
@expand(CV_LeafKindTable a) `$(a.name) = $(a.val)`;
}
@enum2string_switch(CV_LeafKind)
cv_string_from_leaf_kind:
{
@expand(CV_LeafKindTable a) `case CV_LeafKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
@gen(functions)
{
`internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);`;
}
@gen(functions) @c_file
{
`internal U64`;
`cv_header_struct_size_from_leaf_kind(CV_LeafKind v)`;
`{`;
`U64 result = 0;`;
`switch(v)`;
`{`;
`default:{}break;`;
@expand(CV_LeafKindTable a) `$(a.header_type_name != "-" -> "case CV_LeafKind_"..a.name..":{result = sizeof(CV_Leaf"..a.header_type_name..");}break;")`;
`}`;
`return result;`;
`}`;
}
-24
View File
@@ -1,24 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal String8
cv_string_from_numeric(Arena *arena, CV_NumericParsed num)
{
String8 result = str8_zero();
switch (num.kind) {
case CV_NumericKind_FLOAT16: NotImplemented; break; // TODO: format float16
case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break;
case CV_NumericKind_FLOAT48: NotImplemented; break; // TODO: format float48
case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break;
case CV_NumericKind_FLOAT80: NotImplemented; break; // TODO: format float80
case CV_NumericKind_FLOAT128: NotImplemented; break; // TODO: format float128
case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break;
case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break;
case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break;
case CV_NumericKind_QUADWORD: result = push_str8f(arena, "%lld", *(S64*)num.val); break;
case CV_NumericKind_USHORT: result = push_str8f(arena, "%u", *(U16*)num.val); break;
case CV_NumericKind_ULONG: result = push_str8f(arena, "%u", *(U32*)num.val); break;
case CV_NumericKind_UQUADWORD: result = push_str8f(arena, "%llu", *(U64*)num.val); break;
}
return result;
}
-9
View File
@@ -1,9 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CODEVIEW_DUMP_H
#define CODEVIEW_DUMP_H
internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num);
#endif // CODEVIEW_DUMP_H
File diff suppressed because it is too large Load Diff
-305
View File
@@ -1,305 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CODEVIEW_PARSE_H
#define CODEVIEW_PARSE_H
////////////////////////////////
//~ CodeView Common Parser Types
// CV_Numeric layout
// x: U16
// buf: U8[]
// case (x < 0x8000): kind=U16 val=x
// case (x >= 0x8000): kind=x val=buf
typedef struct CV_NumericParsed CV_NumericParsed;
struct CV_NumericParsed
{
CV_NumericKind kind;
U8 *val;
U64 encoded_size;
};
typedef struct CV_RecRange CV_RecRange;
struct CV_RecRange
{
U32 off;
CV_RecHeader hdr;
};
#define CV_REC_RANGE_CHUNK_SIZE 511
typedef struct CV_RecRangeChunk CV_RecRangeChunk;
struct CV_RecRangeChunk
{
struct CV_RecRangeChunk *next;
CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE];
};
typedef struct CV_RecRangeStream CV_RecRangeStream;
struct CV_RecRangeStream
{
CV_RecRangeChunk *first_chunk;
CV_RecRangeChunk *last_chunk;
U64 total_count;
};
typedef struct CV_RecRangeArray CV_RecRangeArray;
struct CV_RecRangeArray
{
CV_RecRange *ranges;
U64 count;
};
////////////////////////////////
//~ CodeView Sym Parser Types
typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo;
struct CV_SymTopLevelInfo
{
CV_Arch arch;
CV_Language language;
String8 compiler_name;
};
typedef struct CV_SymParsed CV_SymParsed;
struct CV_SymParsed
{
// source information
String8 data;
U64 sym_align;
// sym index derived from source
CV_RecRangeArray sym_ranges;
// top-level info derived from the syms
CV_SymTopLevelInfo info;
};
////////////////////////////////
//~ CodeView Leaf Parser Types
typedef struct CV_LeafParsed CV_LeafParsed;
struct CV_LeafParsed
{
// source information
String8 data;
CV_TypeId itype_first;
CV_TypeId itype_opl;
// leaf index derived from source
CV_RecRangeArray leaf_ranges;
};
////////////////////////////////
//~ CodeView C13 Info Parser Types
typedef struct CV_C13InlineSiteDecoder CV_C13InlineSiteDecoder;
struct CV_C13InlineSiteDecoder
{
U64 cursor;
U64 parent_voff;
CV_InlineRangeKind range_kind;
U32 code_length;
U32 code_offset;
U32 file_off;
S32 ln;
S32 cn;
U64 code_offset_lo;
B32 code_offset_changed;
B32 code_offset_lo_changed;
B32 code_length_changed;
B32 ln_changed;
B32 file_off_changed;
Rng1U64 last_range;
U32 file_count;
Rng1U64 file_last_range;
U64 file_line_count;
U64 file_last_ln;
};
typedef U32 CV_C13InlineSiteDecoderStepFlags;
enum
{
CV_C13InlineSiteDecoderStepFlag_EmitRange = (1 << 0),
CV_C13InlineSiteDecoderStepFlag_ExtendLastRange = (1 << 1),
CV_C13InlineSiteDecoderStepFlag_EmitFile = (1 << 2),
CV_C13InlineSiteDecoderStepFlag_EmitLine = (1 << 3),
};
typedef struct CV_C13InlineSiteDecoderStep CV_C13InlineSiteDecoderStep;
struct CV_C13InlineSiteDecoderStep
{
CV_C13InlineSiteDecoderStepFlags flags;
Rng1U64 range;
U64 line_voff;
U64 line_voff_end;
U64 ln;
U64 cn;
U32 file_off;
};
typedef struct CV_C13LinesParsed CV_C13LinesParsed;
struct CV_C13LinesParsed
{
// raw info
U32 sec_idx;
U32 file_off;
U64 secrel_base_off;
// parsed info
String8 file_name;
CV_C13ChecksumKind checksum_kind;
String8 checksum;
U64 *voffs; // [line_count + 1]
U32 *line_nums; // [line_count]
U16 *col_nums; // [2*line_count]
U32 line_count;
};
typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode;
struct CV_C13LinesParsedNode
{
CV_C13LinesParsedNode *next;
CV_C13LinesParsed v;
};
typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed;
struct CV_C13InlineeLinesParsed
{
CV_ItemId inlinee;
U32 file_off;
String8 file_name;
CV_C13ChecksumKind checksum_kind;
String8 checksum;
U32 first_source_ln;
U32 extra_file_count;
U32 *extra_files;
};
typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode;
struct CV_C13InlineeLinesParsedNode
{
CV_C13InlineeLinesParsedNode *next;
CV_C13InlineeLinesParsedNode *hash_next;
CV_C13InlineeLinesParsed v;
};
typedef struct CV_C13SubSectionNode CV_C13SubSectionNode;
struct CV_C13SubSectionNode
{
struct CV_C13SubSectionNode *next;
CV_C13SubSectionKind kind;
U32 off;
U32 size;
CV_C13LinesParsedNode *lines_first;
CV_C13LinesParsedNode *lines_last;
CV_C13InlineeLinesParsedNode *inlinee_lines_first;
CV_C13InlineeLinesParsedNode *inlinee_lines_last;
};
typedef struct CV_C13Parsed CV_C13Parsed;
struct CV_C13Parsed
{
// rjf: source data
String8 data;
// rjf: full sub-section list
CV_C13SubSectionNode *first_sub_section;
CV_C13SubSectionNode *last_sub_section;
U64 sub_section_count;
// rjf: fastpath to file checksums section
CV_C13SubSectionNode *file_chksms_sub_section;
// rjf: fastpath to map inlinee CV_ItemId -> CV_InlineeLinesParsed quickly
CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots;
U64 inlinee_lines_parsed_slots_count;
};
typedef struct CV_UDTInfo CV_UDTInfo;
struct CV_UDTInfo
{
String8 name;
String8 unique_name;
CV_TypeProps props;
};
////////////////////////////////
//~ CodeView Compound Types
typedef struct CV_TypeIdArray CV_TypeIdArray;
struct CV_TypeIdArray
{
CV_TypeId *itypes;
U64 count;
};
////////////////////////////////
//- Hasher
internal U64 cv_hash_from_string(String8 string);
internal U64 cv_hash_from_item_id(CV_ItemId item_id);
//- Numeric Decoder
internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl);
internal U64 cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out);
internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num);
internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num);
internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num);
internal U64 cv_u64_from_numeric(CV_NumericParsed *num);
internal S64 cv_s64_from_numeric(CV_NumericParsed *num);
internal F64 cv_f64_from_numeric(CV_NumericParsed *num);
//- Inlinee Lines Binary Annot Decoder
internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value);
internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value);
internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value);
internal CV_C13InlineSiteDecoder cv_c13_inline_site_decoder_init(U32 file_off, U32 first_source_ln, U32 parent_voff);
internal CV_C13InlineSiteDecoderStep cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots);
//- Symbol/Leaf Helpers
internal B32 cv_is_udt_name_anon(String8 name);
internal B32 cv_is_global_symbol(CV_SymKind kind);
internal B32 cv_is_typedef(CV_SymKind kind);
internal B32 cv_is_scope_symbol(CV_SymKind kind);
internal B32 cv_is_end_symbol(CV_SymKind kind);
internal B32 cv_is_udt(CV_LeafKind kind);
internal B32 cv_is_leaf_type_server(CV_LeafKind kind);
internal B32 cv_is_leaf_pch(CV_LeafKind kind);
internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind);
internal CV_TypeIndexInfoList cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data);
internal CV_TypeIndexInfoList cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data);
internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data);
internal String8Array cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data);
internal U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data);
internal String8 cv_name_from_symbol(CV_SymKind kind, String8 data);
internal CV_UDTInfo cv_get_udt_info(CV_LeafKind kind, String8 data);
internal String8 cv_name_from_udt_info(CV_UDTInfo udt_info);
//- rjf: record range stream parsing
internal CV_RecRangeStream * cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align);
internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream);
//- rjf: sym stream parsing
internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align);
//- rjf: leaf stream parsing
internal CV_LeafParsed * cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first);
internal CV_C13Parsed * cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections);
#endif // CODEVIEW_PARSE_H
-718
View File
@@ -1,718 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
internal String8
cv_string_from_numeric_kind(CV_NumericKind v)
{
String8 result = str8_lit("<Unknown CV_NumericKind>");
switch(v)
{
default:{}break;
case CV_NumericKind_CHAR:{result = str8_lit("CHAR");}break;
case CV_NumericKind_SHORT:{result = str8_lit("SHORT");}break;
case CV_NumericKind_USHORT:{result = str8_lit("USHORT");}break;
case CV_NumericKind_LONG:{result = str8_lit("LONG");}break;
case CV_NumericKind_ULONG:{result = str8_lit("ULONG");}break;
case CV_NumericKind_FLOAT32:{result = str8_lit("FLOAT32");}break;
case CV_NumericKind_FLOAT64:{result = str8_lit("FLOAT64");}break;
case CV_NumericKind_FLOAT80:{result = str8_lit("FLOAT80");}break;
case CV_NumericKind_FLOAT128:{result = str8_lit("FLOAT128");}break;
case CV_NumericKind_QUADWORD:{result = str8_lit("QUADWORD");}break;
case CV_NumericKind_UQUADWORD:{result = str8_lit("UQUADWORD");}break;
case CV_NumericKind_FLOAT48:{result = str8_lit("FLOAT48");}break;
case CV_NumericKind_COMPLEX32:{result = str8_lit("COMPLEX32");}break;
case CV_NumericKind_COMPLEX64:{result = str8_lit("COMPLEX64");}break;
case CV_NumericKind_COMPLEX80:{result = str8_lit("COMPLEX80");}break;
case CV_NumericKind_COMPLEX128:{result = str8_lit("COMPLEX128");}break;
case CV_NumericKind_VARSTRING:{result = str8_lit("VARSTRING");}break;
case CV_NumericKind_OCTWORD:{result = str8_lit("OCTWORD");}break;
case CV_NumericKind_UOCTWORD:{result = str8_lit("UOCTWORD");}break;
case CV_NumericKind_DECIMAL:{result = str8_lit("DECIMAL");}break;
case CV_NumericKind_DATE:{result = str8_lit("DATE");}break;
case CV_NumericKind_UTF8STRING:{result = str8_lit("UTF8STRING");}break;
case CV_NumericKind_FLOAT16:{result = str8_lit("FLOAT16");}break;
}
return result;
}
internal String8
cv_string_from_arch(CV_Arch v)
{
String8 result = str8_lit("<Unknown CV_Arch>");
switch(v)
{
default:{}break;
case CV_Arch_8080:{result = str8_lit("8080");}break;
case CV_Arch_8086:{result = str8_lit("8086");}break;
case CV_Arch_80286:{result = str8_lit("80286");}break;
case CV_Arch_80386:{result = str8_lit("80386");}break;
case CV_Arch_80486:{result = str8_lit("80486");}break;
case CV_Arch_PENTIUM:{result = str8_lit("PENTIUM");}break;
case CV_Arch_PENTIUMII:{result = str8_lit("PENTIUMII");}break;
case CV_Arch_PENTIUMIII:{result = str8_lit("PENTIUMIII");}break;
case CV_Arch_MIPS:{result = str8_lit("MIPS");}break;
case CV_Arch_MIPS16:{result = str8_lit("MIPS16");}break;
case CV_Arch_MIPS32:{result = str8_lit("MIPS32");}break;
case CV_Arch_MIPS64:{result = str8_lit("MIPS64");}break;
case CV_Arch_MIPSI:{result = str8_lit("MIPSI");}break;
case CV_Arch_MIPSII:{result = str8_lit("MIPSII");}break;
case CV_Arch_MIPSIII:{result = str8_lit("MIPSIII");}break;
case CV_Arch_MIPSIV:{result = str8_lit("MIPSIV");}break;
case CV_Arch_MIPSV:{result = str8_lit("MIPSV");}break;
case CV_Arch_M68000:{result = str8_lit("M68000");}break;
case CV_Arch_M68010:{result = str8_lit("M68010");}break;
case CV_Arch_M68020:{result = str8_lit("M68020");}break;
case CV_Arch_M68030:{result = str8_lit("M68030");}break;
case CV_Arch_M68040:{result = str8_lit("M68040");}break;
case CV_Arch_ALPHA:{result = str8_lit("ALPHA");}break;
case CV_Arch_ALPHA_21164:{result = str8_lit("ALPHA_21164");}break;
case CV_Arch_ALPHA_21164A:{result = str8_lit("ALPHA_21164A");}break;
case CV_Arch_ALPHA_21264:{result = str8_lit("ALPHA_21264");}break;
case CV_Arch_ALPHA_21364:{result = str8_lit("ALPHA_21364");}break;
case CV_Arch_PPC601:{result = str8_lit("PPC601");}break;
case CV_Arch_PPC603:{result = str8_lit("PPC603");}break;
case CV_Arch_PPC604:{result = str8_lit("PPC604");}break;
case CV_Arch_PPC620:{result = str8_lit("PPC620");}break;
case CV_Arch_PPCFP:{result = str8_lit("PPCFP");}break;
case CV_Arch_PPCBE:{result = str8_lit("PPCBE");}break;
case CV_Arch_SH3:{result = str8_lit("SH3");}break;
case CV_Arch_SH3E:{result = str8_lit("SH3E");}break;
case CV_Arch_SH3DSP:{result = str8_lit("SH3DSP");}break;
case CV_Arch_SH4:{result = str8_lit("SH4");}break;
case CV_Arch_SHMEDIA:{result = str8_lit("SHMEDIA");}break;
case CV_Arch_ARM3:{result = str8_lit("ARM3");}break;
case CV_Arch_ARM4:{result = str8_lit("ARM4");}break;
case CV_Arch_ARM4T:{result = str8_lit("ARM4T");}break;
case CV_Arch_ARM5:{result = str8_lit("ARM5");}break;
case CV_Arch_ARM5T:{result = str8_lit("ARM5T");}break;
case CV_Arch_ARM6:{result = str8_lit("ARM6");}break;
case CV_Arch_ARM_XMAC:{result = str8_lit("ARM_XMAC");}break;
case CV_Arch_ARM_WMMX:{result = str8_lit("ARM_WMMX");}break;
case CV_Arch_ARM7:{result = str8_lit("ARM7");}break;
case CV_Arch_OMNI:{result = str8_lit("OMNI");}break;
case CV_Arch_IA64_1:{result = str8_lit("IA64_1");}break;
case CV_Arch_IA64_2:{result = str8_lit("IA64_2");}break;
case CV_Arch_CEE:{result = str8_lit("CEE");}break;
case CV_Arch_AM33:{result = str8_lit("AM33");}break;
case CV_Arch_M32R:{result = str8_lit("M32R");}break;
case CV_Arch_TRICORE:{result = str8_lit("TRICORE");}break;
case CV_Arch_X64:{result = str8_lit("X64");}break;
case CV_Arch_EBC:{result = str8_lit("EBC");}break;
case CV_Arch_THUMB:{result = str8_lit("THUMB");}break;
case CV_Arch_ARMNT:{result = str8_lit("ARMNT");}break;
case CV_Arch_ARM64:{result = str8_lit("ARM64");}break;
case CV_Arch_D3D11_SHADER:{result = str8_lit("D3D11_SHADER");}break;
}
return result;
}
internal String8
cv_string_from_sym_kind(CV_SymKind v)
{
String8 result = str8_lit("<Unknown CV_SymKind>");
switch(v)
{
default:{}break;
case CV_SymKind_COMPILE:{result = str8_lit("COMPILE");}break;
case CV_SymKind_REGISTER_16t:{result = str8_lit("REGISTER_16t");}break;
case CV_SymKind_CONSTANT_16t:{result = str8_lit("CONSTANT_16t");}break;
case CV_SymKind_UDT_16t:{result = str8_lit("UDT_16t");}break;
case CV_SymKind_SSEARCH:{result = str8_lit("SSEARCH");}break;
case CV_SymKind_END:{result = str8_lit("END");}break;
case CV_SymKind_SKIP:{result = str8_lit("SKIP");}break;
case CV_SymKind_CVRESERVE:{result = str8_lit("CVRESERVE");}break;
case CV_SymKind_OBJNAME_ST:{result = str8_lit("OBJNAME_ST");}break;
case CV_SymKind_ENDARG:{result = str8_lit("ENDARG");}break;
case CV_SymKind_COBOLUDT_16t:{result = str8_lit("COBOLUDT_16t");}break;
case CV_SymKind_MANYREG_16t:{result = str8_lit("MANYREG_16t");}break;
case CV_SymKind_RETURN:{result = str8_lit("RETURN");}break;
case CV_SymKind_ENTRYTHIS:{result = str8_lit("ENTRYTHIS");}break;
case CV_SymKind_BPREL16:{result = str8_lit("BPREL16");}break;
case CV_SymKind_LDATA16:{result = str8_lit("LDATA16");}break;
case CV_SymKind_GDATA16:{result = str8_lit("GDATA16");}break;
case CV_SymKind_PUB16:{result = str8_lit("PUB16");}break;
case CV_SymKind_LPROC16:{result = str8_lit("LPROC16");}break;
case CV_SymKind_GPROC16:{result = str8_lit("GPROC16");}break;
case CV_SymKind_THUNK16:{result = str8_lit("THUNK16");}break;
case CV_SymKind_BLOCK16:{result = str8_lit("BLOCK16");}break;
case CV_SymKind_WITH16:{result = str8_lit("WITH16");}break;
case CV_SymKind_LABEL16:{result = str8_lit("LABEL16");}break;
case CV_SymKind_CEXMODEL16:{result = str8_lit("CEXMODEL16");}break;
case CV_SymKind_VFTABLE16:{result = str8_lit("VFTABLE16");}break;
case CV_SymKind_REGREL16:{result = str8_lit("REGREL16");}break;
case CV_SymKind_BPREL32_16t:{result = str8_lit("BPREL32_16t");}break;
case CV_SymKind_LDATA32_16t:{result = str8_lit("LDATA32_16t");}break;
case CV_SymKind_GDATA32_16t:{result = str8_lit("GDATA32_16t");}break;
case CV_SymKind_PUB32_16t:{result = str8_lit("PUB32_16t");}break;
case CV_SymKind_LPROC32_16t:{result = str8_lit("LPROC32_16t");}break;
case CV_SymKind_GPROC32_16t:{result = str8_lit("GPROC32_16t");}break;
case CV_SymKind_THUNK32_ST:{result = str8_lit("THUNK32_ST");}break;
case CV_SymKind_BLOCK32_ST:{result = str8_lit("BLOCK32_ST");}break;
case CV_SymKind_WITH32_ST:{result = str8_lit("WITH32_ST");}break;
case CV_SymKind_LABEL32_ST:{result = str8_lit("LABEL32_ST");}break;
case CV_SymKind_CEXMODEL32:{result = str8_lit("CEXMODEL32");}break;
case CV_SymKind_VFTABLE32_16t:{result = str8_lit("VFTABLE32_16t");}break;
case CV_SymKind_REGREL32_16t:{result = str8_lit("REGREL32_16t");}break;
case CV_SymKind_LTHREAD32_16t:{result = str8_lit("LTHREAD32_16t");}break;
case CV_SymKind_GTHREAD32_16t:{result = str8_lit("GTHREAD32_16t");}break;
case CV_SymKind_SLINK32:{result = str8_lit("SLINK32");}break;
case CV_SymKind_LPROCMIPS_16t:{result = str8_lit("LPROCMIPS_16t");}break;
case CV_SymKind_GPROCMIPS_16t:{result = str8_lit("GPROCMIPS_16t");}break;
case CV_SymKind_PROCREF_ST:{result = str8_lit("PROCREF_ST");}break;
case CV_SymKind_DATAREF_ST:{result = str8_lit("DATAREF_ST");}break;
case CV_SymKind_ALIGN:{result = str8_lit("ALIGN");}break;
case CV_SymKind_LPROCREF_ST:{result = str8_lit("LPROCREF_ST");}break;
case CV_SymKind_OEM:{result = str8_lit("OEM");}break;
case CV_SymKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break;
case CV_SymKind_CONSTANT_ST:{result = str8_lit("CONSTANT_ST");}break;
case CV_SymKind_UDT_ST:{result = str8_lit("UDT_ST");}break;
case CV_SymKind_COBOLUDT_ST:{result = str8_lit("COBOLUDT_ST");}break;
case CV_SymKind_MANYREG_ST:{result = str8_lit("MANYREG_ST");}break;
case CV_SymKind_BPREL32_ST:{result = str8_lit("BPREL32_ST");}break;
case CV_SymKind_LDATA32_ST:{result = str8_lit("LDATA32_ST");}break;
case CV_SymKind_GDATA32_ST:{result = str8_lit("GDATA32_ST");}break;
case CV_SymKind_PUB32_ST:{result = str8_lit("PUB32_ST");}break;
case CV_SymKind_LPROC32_ST:{result = str8_lit("LPROC32_ST");}break;
case CV_SymKind_GPROC32_ST:{result = str8_lit("GPROC32_ST");}break;
case CV_SymKind_VFTABLE32:{result = str8_lit("VFTABLE32");}break;
case CV_SymKind_REGREL32_ST:{result = str8_lit("REGREL32_ST");}break;
case CV_SymKind_LTHREAD32_ST:{result = str8_lit("LTHREAD32_ST");}break;
case CV_SymKind_GTHREAD32_ST:{result = str8_lit("GTHREAD32_ST");}break;
case CV_SymKind_LPROCMIPS_ST:{result = str8_lit("LPROCMIPS_ST");}break;
case CV_SymKind_GPROCMIPS_ST:{result = str8_lit("GPROCMIPS_ST");}break;
case CV_SymKind_FRAMEPROC:{result = str8_lit("FRAMEPROC");}break;
case CV_SymKind_COMPILE2_ST:{result = str8_lit("COMPILE2_ST");}break;
case CV_SymKind_MANYREG2_ST:{result = str8_lit("MANYREG2_ST");}break;
case CV_SymKind_LPROCIA64_ST:{result = str8_lit("LPROCIA64_ST");}break;
case CV_SymKind_GPROCIA64_ST:{result = str8_lit("GPROCIA64_ST");}break;
case CV_SymKind_LOCALSLOT_ST:{result = str8_lit("LOCALSLOT_ST");}break;
case CV_SymKind_PARAMSLOT_ST:{result = str8_lit("PARAMSLOT_ST");}break;
case CV_SymKind_ANNOTATION:{result = str8_lit("ANNOTATION");}break;
case CV_SymKind_GMANPROC_ST:{result = str8_lit("GMANPROC_ST");}break;
case CV_SymKind_LMANPROC_ST:{result = str8_lit("LMANPROC_ST");}break;
case CV_SymKind_RESERVED1:{result = str8_lit("RESERVED1");}break;
case CV_SymKind_RESERVED2:{result = str8_lit("RESERVED2");}break;
case CV_SymKind_RESERVED3:{result = str8_lit("RESERVED3");}break;
case CV_SymKind_RESERVED4:{result = str8_lit("RESERVED4");}break;
case CV_SymKind_LMANDATA_ST:{result = str8_lit("LMANDATA_ST");}break;
case CV_SymKind_GMANDATA_ST:{result = str8_lit("GMANDATA_ST");}break;
case CV_SymKind_MANFRAMEREL_ST:{result = str8_lit("MANFRAMEREL_ST");}break;
case CV_SymKind_MANREGISTER_ST:{result = str8_lit("MANREGISTER_ST");}break;
case CV_SymKind_MANSLOT_ST:{result = str8_lit("MANSLOT_ST");}break;
case CV_SymKind_MANMANYREG_ST:{result = str8_lit("MANMANYREG_ST");}break;
case CV_SymKind_MANREGREL_ST:{result = str8_lit("MANREGREL_ST");}break;
case CV_SymKind_MANMANYREG2_ST:{result = str8_lit("MANMANYREG2_ST");}break;
case CV_SymKind_MANTYPREF:{result = str8_lit("MANTYPREF");}break;
case CV_SymKind_UNAMESPACE_ST:{result = str8_lit("UNAMESPACE_ST");}break;
case CV_SymKind_ST_MAX:{result = str8_lit("ST_MAX");}break;
case CV_SymKind_OBJNAME:{result = str8_lit("OBJNAME");}break;
case CV_SymKind_THUNK32:{result = str8_lit("THUNK32");}break;
case CV_SymKind_BLOCK32:{result = str8_lit("BLOCK32");}break;
case CV_SymKind_WITH32:{result = str8_lit("WITH32");}break;
case CV_SymKind_LABEL32:{result = str8_lit("LABEL32");}break;
case CV_SymKind_REGISTER:{result = str8_lit("REGISTER");}break;
case CV_SymKind_CONSTANT:{result = str8_lit("CONSTANT");}break;
case CV_SymKind_UDT:{result = str8_lit("UDT");}break;
case CV_SymKind_COBOLUDT:{result = str8_lit("COBOLUDT");}break;
case CV_SymKind_MANYREG:{result = str8_lit("MANYREG");}break;
case CV_SymKind_BPREL32:{result = str8_lit("BPREL32");}break;
case CV_SymKind_LDATA32:{result = str8_lit("LDATA32");}break;
case CV_SymKind_GDATA32:{result = str8_lit("GDATA32");}break;
case CV_SymKind_PUB32:{result = str8_lit("PUB32");}break;
case CV_SymKind_LPROC32:{result = str8_lit("LPROC32");}break;
case CV_SymKind_GPROC32:{result = str8_lit("GPROC32");}break;
case CV_SymKind_REGREL32:{result = str8_lit("REGREL32");}break;
case CV_SymKind_LTHREAD32:{result = str8_lit("LTHREAD32");}break;
case CV_SymKind_GTHREAD32:{result = str8_lit("GTHREAD32");}break;
case CV_SymKind_LPROCMIPS:{result = str8_lit("LPROCMIPS");}break;
case CV_SymKind_GPROCMIPS:{result = str8_lit("GPROCMIPS");}break;
case CV_SymKind_COMPILE2:{result = str8_lit("COMPILE2");}break;
case CV_SymKind_MANYREG2:{result = str8_lit("MANYREG2");}break;
case CV_SymKind_LPROCIA64:{result = str8_lit("LPROCIA64");}break;
case CV_SymKind_GPROCIA64:{result = str8_lit("GPROCIA64");}break;
case CV_SymKind_LOCALSLOT:{result = str8_lit("LOCALSLOT");}break;
case CV_SymKind_PARAMSLOT:{result = str8_lit("PARAMSLOT");}break;
case CV_SymKind_LMANDATA:{result = str8_lit("LMANDATA");}break;
case CV_SymKind_GMANDATA:{result = str8_lit("GMANDATA");}break;
case CV_SymKind_MANFRAMEREL:{result = str8_lit("MANFRAMEREL");}break;
case CV_SymKind_MANREGISTER:{result = str8_lit("MANREGISTER");}break;
case CV_SymKind_MANSLOT:{result = str8_lit("MANSLOT");}break;
case CV_SymKind_MANMANYREG:{result = str8_lit("MANMANYREG");}break;
case CV_SymKind_MANREGREL:{result = str8_lit("MANREGREL");}break;
case CV_SymKind_MANMANYREG2:{result = str8_lit("MANMANYREG2");}break;
case CV_SymKind_UNAMESPACE:{result = str8_lit("UNAMESPACE");}break;
case CV_SymKind_PROCREF:{result = str8_lit("PROCREF");}break;
case CV_SymKind_DATAREF:{result = str8_lit("DATAREF");}break;
case CV_SymKind_LPROCREF:{result = str8_lit("LPROCREF");}break;
case CV_SymKind_ANNOTATIONREF:{result = str8_lit("ANNOTATIONREF");}break;
case CV_SymKind_TOKENREF:{result = str8_lit("TOKENREF");}break;
case CV_SymKind_GMANPROC:{result = str8_lit("GMANPROC");}break;
case CV_SymKind_LMANPROC:{result = str8_lit("LMANPROC");}break;
case CV_SymKind_TRAMPOLINE:{result = str8_lit("TRAMPOLINE");}break;
case CV_SymKind_MANCONSTANT:{result = str8_lit("MANCONSTANT");}break;
case CV_SymKind_ATTR_FRAMEREL:{result = str8_lit("ATTR_FRAMEREL");}break;
case CV_SymKind_ATTR_REGISTER:{result = str8_lit("ATTR_REGISTER");}break;
case CV_SymKind_ATTR_REGREL:{result = str8_lit("ATTR_REGREL");}break;
case CV_SymKind_ATTR_MANYREG:{result = str8_lit("ATTR_MANYREG");}break;
case CV_SymKind_SEPCODE:{result = str8_lit("SEPCODE");}break;
case CV_SymKind_DEFRANGE_2005:{result = str8_lit("DEFRANGE_2005");}break;
case CV_SymKind_DEFRANGE2_2005:{result = str8_lit("DEFRANGE2_2005");}break;
case CV_SymKind_SECTION:{result = str8_lit("SECTION");}break;
case CV_SymKind_COFFGROUP:{result = str8_lit("COFFGROUP");}break;
case CV_SymKind_EXPORT:{result = str8_lit("EXPORT");}break;
case CV_SymKind_CALLSITEINFO:{result = str8_lit("CALLSITEINFO");}break;
case CV_SymKind_FRAMECOOKIE:{result = str8_lit("FRAMECOOKIE");}break;
case CV_SymKind_DISCARDED:{result = str8_lit("DISCARDED");}break;
case CV_SymKind_COMPILE3:{result = str8_lit("COMPILE3");}break;
case CV_SymKind_ENVBLOCK:{result = str8_lit("ENVBLOCK");}break;
case CV_SymKind_LOCAL:{result = str8_lit("LOCAL");}break;
case CV_SymKind_DEFRANGE:{result = str8_lit("DEFRANGE");}break;
case CV_SymKind_DEFRANGE_SUBFIELD:{result = str8_lit("DEFRANGE_SUBFIELD");}break;
case CV_SymKind_DEFRANGE_REGISTER:{result = str8_lit("DEFRANGE_REGISTER");}break;
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL");}break;
case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = str8_lit("DEFRANGE_SUBFIELD_REGISTER");}break;
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE");}break;
case CV_SymKind_DEFRANGE_REGISTER_REL:{result = str8_lit("DEFRANGE_REGISTER_REL");}break;
case CV_SymKind_LPROC32_ID:{result = str8_lit("LPROC32_ID");}break;
case CV_SymKind_GPROC32_ID:{result = str8_lit("GPROC32_ID");}break;
case CV_SymKind_LPROCMIPS_ID:{result = str8_lit("LPROCMIPS_ID");}break;
case CV_SymKind_GPROCMIPS_ID:{result = str8_lit("GPROCMIPS_ID");}break;
case CV_SymKind_LPROCIA64_ID:{result = str8_lit("LPROCIA64_ID");}break;
case CV_SymKind_GPROCIA64_ID:{result = str8_lit("GPROCIA64_ID");}break;
case CV_SymKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
case CV_SymKind_INLINESITE:{result = str8_lit("INLINESITE");}break;
case CV_SymKind_INLINESITE_END:{result = str8_lit("INLINESITE_END");}break;
case CV_SymKind_PROC_ID_END:{result = str8_lit("PROC_ID_END");}break;
case CV_SymKind_DEFRANGE_HLSL:{result = str8_lit("DEFRANGE_HLSL");}break;
case CV_SymKind_GDATA_HLSL:{result = str8_lit("GDATA_HLSL");}break;
case CV_SymKind_LDATA_HLSL:{result = str8_lit("LDATA_HLSL");}break;
case CV_SymKind_FILESTATIC:{result = str8_lit("FILESTATIC");}break;
case CV_SymKind_LPROC32_DPC:{result = str8_lit("LPROC32_DPC");}break;
case CV_SymKind_LPROC32_DPC_ID:{result = str8_lit("LPROC32_DPC_ID");}break;
case CV_SymKind_DEFRANGE_DPC_PTR_TAG:{result = str8_lit("DEFRANGE_DPC_PTR_TAG");}break;
case CV_SymKind_DPC_SYM_TAG_MAP:{result = str8_lit("DPC_SYM_TAG_MAP");}break;
case CV_SymKind_ARMSWITCHTABLE:{result = str8_lit("ARMSWITCHTABLE");}break;
case CV_SymKind_CALLEES:{result = str8_lit("CALLEES");}break;
case CV_SymKind_CALLERS:{result = str8_lit("CALLERS");}break;
case CV_SymKind_POGODATA:{result = str8_lit("POGODATA");}break;
case CV_SymKind_INLINESITE2:{result = str8_lit("INLINESITE2");}break;
case CV_SymKind_HEAPALLOCSITE:{result = str8_lit("HEAPALLOCSITE");}break;
case CV_SymKind_MOD_TYPEREF:{result = str8_lit("MOD_TYPEREF");}break;
case CV_SymKind_REF_MINIPDB:{result = str8_lit("REF_MINIPDB");}break;
case CV_SymKind_PDBMAP:{result = str8_lit("PDBMAP");}break;
case CV_SymKind_GDATA_HLSL32:{result = str8_lit("GDATA_HLSL32");}break;
case CV_SymKind_LDATA_HLSL32:{result = str8_lit("LDATA_HLSL32");}break;
case CV_SymKind_GDATA_HLSL32_EX:{result = str8_lit("GDATA_HLSL32_EX");}break;
case CV_SymKind_LDATA_HLSL32_EX:{result = str8_lit("LDATA_HLSL32_EX");}break;
case CV_SymKind_FASTLINK:{result = str8_lit("FASTLINK");}break;
case CV_SymKind_INLINEES:{result = str8_lit("INLINEES");}break;
}
return result;
}
internal String8
cv_string_from_basic_type(CV_BasicType v)
{
String8 result = str8_lit("<Unknown CV_BasicType>");
switch(v)
{
default:{}break;
case CV_BasicType_NOTYPE:{result = str8_lit("NOTYPE");}break;
case CV_BasicType_ABS:{result = str8_lit("ABS");}break;
case CV_BasicType_SEGMENT:{result = str8_lit("SEGMENT");}break;
case CV_BasicType_VOID:{result = str8_lit("VOID");}break;
case CV_BasicType_CURRENCY:{result = str8_lit("CURRENCY");}break;
case CV_BasicType_NBASICSTR:{result = str8_lit("NBASICSTR");}break;
case CV_BasicType_FBASICSTR:{result = str8_lit("FBASICSTR");}break;
case CV_BasicType_NOTTRANS:{result = str8_lit("NOTTRANS");}break;
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break;
case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break;
case CV_BasicType_LONG:{result = str8_lit("LONG");}break;
case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break;
case CV_BasicType_OCT:{result = str8_lit("OCT");}break;
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break;
case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break;
case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break;
case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break;
case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break;
case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break;
case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break;
case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break;
case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break;
case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break;
case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break;
case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break;
case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break;
case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break;
case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break;
case CV_BasicType_COMPLEX32:{result = str8_lit("COMPLEX32");}break;
case CV_BasicType_COMPLEX64:{result = str8_lit("COMPLEX64");}break;
case CV_BasicType_COMPLEX80:{result = str8_lit("COMPLEX80");}break;
case CV_BasicType_COMPLEX128:{result = str8_lit("COMPLEX128");}break;
case CV_BasicType_BIT:{result = str8_lit("BIT");}break;
case CV_BasicType_PASCHAR:{result = str8_lit("PASCHAR");}break;
case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break;
case CV_BasicType_INT8:{result = str8_lit("INT8");}break;
case CV_BasicType_UINT8:{result = str8_lit("UINT8");}break;
case CV_BasicType_RCHAR:{result = str8_lit("RCHAR");}break;
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
case CV_BasicType_INT16:{result = str8_lit("INT16");}break;
case CV_BasicType_UINT16:{result = str8_lit("UINT16");}break;
case CV_BasicType_INT32:{result = str8_lit("INT32");}break;
case CV_BasicType_UINT32:{result = str8_lit("UINT32");}break;
case CV_BasicType_INT64:{result = str8_lit("INT64");}break;
case CV_BasicType_UINT64:{result = str8_lit("UINT64");}break;
case CV_BasicType_INT128:{result = str8_lit("INT128");}break;
case CV_BasicType_UINT128:{result = str8_lit("UINT128");}break;
case CV_BasicType_CHAR16:{result = str8_lit("CHAR16");}break;
case CV_BasicType_CHAR32:{result = str8_lit("CHAR32");}break;
case CV_BasicType_CHAR8:{result = str8_lit("CHAR8");}break;
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
}
return result;
}
internal String8
cv_type_name_from_basic_type(CV_BasicType v)
{
String8 result = str8_lit("<Unknown CV_BasicType>");
switch(v)
{
default:{}break;
case CV_BasicType_NOTYPE:{result = str8_lit("");}break;
case CV_BasicType_ABS:{result = str8_lit("");}break;
case CV_BasicType_SEGMENT:{result = str8_lit("");}break;
case CV_BasicType_VOID:{result = str8_lit("void");}break;
case CV_BasicType_CURRENCY:{result = str8_lit("");}break;
case CV_BasicType_NBASICSTR:{result = str8_lit("");}break;
case CV_BasicType_FBASICSTR:{result = str8_lit("");}break;
case CV_BasicType_NOTTRANS:{result = str8_lit("");}break;
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break;
case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break;
case CV_BasicType_LONG:{result = str8_lit("LONG");}break;
case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break;
case CV_BasicType_OCT:{result = str8_lit("OCT");}break;
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break;
case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break;
case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break;
case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break;
case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break;
case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break;
case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break;
case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break;
case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break;
case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break;
case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break;
case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break;
case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break;
case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break;
case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break;
case CV_BasicType_COMPLEX32:{result = str8_lit("ComplexF32");}break;
case CV_BasicType_COMPLEX64:{result = str8_lit("ComplexF64");}break;
case CV_BasicType_COMPLEX80:{result = str8_lit("ComplexF80");}break;
case CV_BasicType_COMPLEX128:{result = str8_lit("ComplexF128");}break;
case CV_BasicType_BIT:{result = str8_lit("");}break;
case CV_BasicType_PASCHAR:{result = str8_lit("");}break;
case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break;
case CV_BasicType_INT8:{result = str8_lit("int8");}break;
case CV_BasicType_UINT8:{result = str8_lit("uint8");}break;
case CV_BasicType_RCHAR:{result = str8_lit("char");}break;
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
case CV_BasicType_INT16:{result = str8_lit("int16");}break;
case CV_BasicType_UINT16:{result = str8_lit("uint16");}break;
case CV_BasicType_INT32:{result = str8_lit("int32");}break;
case CV_BasicType_UINT32:{result = str8_lit("uint32");}break;
case CV_BasicType_INT64:{result = str8_lit("int64");}break;
case CV_BasicType_UINT64:{result = str8_lit("uint64");}break;
case CV_BasicType_INT128:{result = str8_lit("int128");}break;
case CV_BasicType_UINT128:{result = str8_lit("uint128");}break;
case CV_BasicType_CHAR16:{result = str8_lit("char16");}break;
case CV_BasicType_CHAR32:{result = str8_lit("char32");}break;
case CV_BasicType_CHAR8:{result = str8_lit("char");}break;
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
}
return result;
}
internal String8
cv_string_from_leaf_kind(CV_LeafKind v)
{
String8 result = str8_lit("<Unknown CV_LeafKind>");
switch(v)
{
default:{}break;
case CV_LeafKind_NOTYPE:{result = str8_lit("NOTYPE");}break;
case CV_LeafKind_MODIFIER_16t:{result = str8_lit("MODIFIER_16t");}break;
case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break;
case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break;
case CV_LeafKind_CLASS_16t:{result = str8_lit("CLASS_16t");}break;
case CV_LeafKind_STRUCTURE_16t:{result = str8_lit("STRUCTURE_16t");}break;
case CV_LeafKind_UNION_16t:{result = str8_lit("UNION_16t");}break;
case CV_LeafKind_ENUM_16t:{result = str8_lit("ENUM_16t");}break;
case CV_LeafKind_PROCEDURE_16t:{result = str8_lit("PROCEDURE_16t");}break;
case CV_LeafKind_MFUNCTION_16t:{result = str8_lit("MFUNCTION_16t");}break;
case CV_LeafKind_VTSHAPE:{result = str8_lit("VTSHAPE");}break;
case CV_LeafKind_COBOL0_16t:{result = str8_lit("COBOL0_16t");}break;
case CV_LeafKind_COBOL1:{result = str8_lit("COBOL1");}break;
case CV_LeafKind_BARRAY_16t:{result = str8_lit("BARRAY_16t");}break;
case CV_LeafKind_LABEL:{result = str8_lit("LABEL");}break;
case CV_LeafKind_NULL:{result = str8_lit("NULL");}break;
case CV_LeafKind_NOTTRAN:{result = str8_lit("NOTTRAN");}break;
case CV_LeafKind_DIMARRAY_16t:{result = str8_lit("DIMARRAY_16t");}break;
case CV_LeafKind_VFTPATH_16t:{result = str8_lit("VFTPATH_16t");}break;
case CV_LeafKind_PRECOMP_16t:{result = str8_lit("PRECOMP_16t");}break;
case CV_LeafKind_ENDPRECOMP:{result = str8_lit("ENDPRECOMP");}break;
case CV_LeafKind_OEM_16t:{result = str8_lit("OEM_16t");}break;
case CV_LeafKind_TYPESERVER_ST:{result = str8_lit("TYPESERVER_ST");}break;
case CV_LeafKind_SKIP_16t:{result = str8_lit("SKIP_16t");}break;
case CV_LeafKind_ARGLIST_16t:{result = str8_lit("ARGLIST_16t");}break;
case CV_LeafKind_DEFARG_16t:{result = str8_lit("DEFARG_16t");}break;
case CV_LeafKind_LIST:{result = str8_lit("LIST");}break;
case CV_LeafKind_FIELDLIST_16t:{result = str8_lit("FIELDLIST_16t");}break;
case CV_LeafKind_DERIVED_16t:{result = str8_lit("DERIVED_16t");}break;
case CV_LeafKind_BITFIELD_16t:{result = str8_lit("BITFIELD_16t");}break;
case CV_LeafKind_METHODLIST_16t:{result = str8_lit("METHODLIST_16t");}break;
case CV_LeafKind_DIMCONU_16t:{result = str8_lit("DIMCONU_16t");}break;
case CV_LeafKind_DIMCONLU_16t:{result = str8_lit("DIMCONLU_16t");}break;
case CV_LeafKind_DIMVARU_16t:{result = str8_lit("DIMVARU_16t");}break;
case CV_LeafKind_DIMVARLU_16t:{result = str8_lit("DIMVARLU_16t");}break;
case CV_LeafKind_REFSYM:{result = str8_lit("REFSYM");}break;
case CV_LeafKind_BCLASS_16t:{result = str8_lit("BCLASS_16t");}break;
case CV_LeafKind_VBCLASS_16t:{result = str8_lit("VBCLASS_16t");}break;
case CV_LeafKind_IVBCLASS_16t:{result = str8_lit("IVBCLASS_16t");}break;
case CV_LeafKind_ENUMERATE_ST:{result = str8_lit("ENUMERATE_ST");}break;
case CV_LeafKind_FRIENDFCN_16t:{result = str8_lit("FRIENDFCN_16t");}break;
case CV_LeafKind_INDEX_16t:{result = str8_lit("INDEX_16t");}break;
case CV_LeafKind_MEMBER_16t:{result = str8_lit("MEMBER_16t");}break;
case CV_LeafKind_STMEMBER_16t:{result = str8_lit("STMEMBER_16t");}break;
case CV_LeafKind_METHOD_16t:{result = str8_lit("METHOD_16t");}break;
case CV_LeafKind_NESTTYPE_16t:{result = str8_lit("NESTTYPE_16t");}break;
case CV_LeafKind_VFUNCTAB_16t:{result = str8_lit("VFUNCTAB_16t");}break;
case CV_LeafKind_FRIENDCLS_16t:{result = str8_lit("FRIENDCLS_16t");}break;
case CV_LeafKind_ONEMETHOD_16t:{result = str8_lit("ONEMETHOD_16t");}break;
case CV_LeafKind_VFUNCOFF_16t:{result = str8_lit("VFUNCOFF_16t");}break;
case CV_LeafKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break;
case CV_LeafKind_MODIFIER:{result = str8_lit("MODIFIER");}break;
case CV_LeafKind_POINTER:{result = str8_lit("POINTER");}break;
case CV_LeafKind_ARRAY_ST:{result = str8_lit("ARRAY_ST");}break;
case CV_LeafKind_CLASS_ST:{result = str8_lit("CLASS_ST");}break;
case CV_LeafKind_STRUCTURE_ST:{result = str8_lit("STRUCTURE_ST");}break;
case CV_LeafKind_UNION_ST:{result = str8_lit("UNION_ST");}break;
case CV_LeafKind_ENUM_ST:{result = str8_lit("ENUM_ST");}break;
case CV_LeafKind_PROCEDURE:{result = str8_lit("PROCEDURE");}break;
case CV_LeafKind_MFUNCTION:{result = str8_lit("MFUNCTION");}break;
case CV_LeafKind_COBOL0:{result = str8_lit("COBOL0");}break;
case CV_LeafKind_BARRAY:{result = str8_lit("BARRAY");}break;
case CV_LeafKind_DIMARRAY_ST:{result = str8_lit("DIMARRAY_ST");}break;
case CV_LeafKind_VFTPATH:{result = str8_lit("VFTPATH");}break;
case CV_LeafKind_PRECOMP_ST:{result = str8_lit("PRECOMP_ST");}break;
case CV_LeafKind_OEM:{result = str8_lit("OEM");}break;
case CV_LeafKind_ALIAS_ST:{result = str8_lit("ALIAS_ST");}break;
case CV_LeafKind_OEM2:{result = str8_lit("OEM2");}break;
case CV_LeafKind_SKIP:{result = str8_lit("SKIP");}break;
case CV_LeafKind_ARGLIST:{result = str8_lit("ARGLIST");}break;
case CV_LeafKind_DEFARG_ST:{result = str8_lit("DEFARG_ST");}break;
case CV_LeafKind_FIELDLIST:{result = str8_lit("FIELDLIST");}break;
case CV_LeafKind_DERIVED:{result = str8_lit("DERIVED");}break;
case CV_LeafKind_BITFIELD:{result = str8_lit("BITFIELD");}break;
case CV_LeafKind_METHODLIST:{result = str8_lit("METHODLIST");}break;
case CV_LeafKind_DIMCONU:{result = str8_lit("DIMCONU");}break;
case CV_LeafKind_DIMCONLU:{result = str8_lit("DIMCONLU");}break;
case CV_LeafKind_DIMVARU:{result = str8_lit("DIMVARU");}break;
case CV_LeafKind_DIMVARLU:{result = str8_lit("DIMVARLU");}break;
case CV_LeafKind_BCLASS:{result = str8_lit("BCLASS");}break;
case CV_LeafKind_VBCLASS:{result = str8_lit("VBCLASS");}break;
case CV_LeafKind_IVBCLASS:{result = str8_lit("IVBCLASS");}break;
case CV_LeafKind_FRIENDFCN_ST:{result = str8_lit("FRIENDFCN_ST");}break;
case CV_LeafKind_INDEX:{result = str8_lit("INDEX");}break;
case CV_LeafKind_MEMBER_ST:{result = str8_lit("MEMBER_ST");}break;
case CV_LeafKind_STMEMBER_ST:{result = str8_lit("STMEMBER_ST");}break;
case CV_LeafKind_METHOD_ST:{result = str8_lit("METHOD_ST");}break;
case CV_LeafKind_NESTTYPE_ST:{result = str8_lit("NESTTYPE_ST");}break;
case CV_LeafKind_VFUNCTAB:{result = str8_lit("VFUNCTAB");}break;
case CV_LeafKind_FRIENDCLS:{result = str8_lit("FRIENDCLS");}break;
case CV_LeafKind_ONEMETHOD_ST:{result = str8_lit("ONEMETHOD_ST");}break;
case CV_LeafKind_VFUNCOFF:{result = str8_lit("VFUNCOFF");}break;
case CV_LeafKind_NESTTYPEEX_ST:{result = str8_lit("NESTTYPEEX_ST");}break;
case CV_LeafKind_MEMBERMODIFY_ST:{result = str8_lit("MEMBERMODIFY_ST");}break;
case CV_LeafKind_MANAGED_ST:{result = str8_lit("MANAGED_ST");}break;
case CV_LeafKind_ST_MAX:{result = str8_lit("ST_MAX");}break;
case CV_LeafKind_TYPESERVER:{result = str8_lit("TYPESERVER");}break;
case CV_LeafKind_ENUMERATE:{result = str8_lit("ENUMERATE");}break;
case CV_LeafKind_ARRAY:{result = str8_lit("ARRAY");}break;
case CV_LeafKind_CLASS:{result = str8_lit("CLASS");}break;
case CV_LeafKind_STRUCTURE:{result = str8_lit("STRUCTURE");}break;
case CV_LeafKind_UNION:{result = str8_lit("UNION");}break;
case CV_LeafKind_ENUM:{result = str8_lit("ENUM");}break;
case CV_LeafKind_DIMARRAY:{result = str8_lit("DIMARRAY");}break;
case CV_LeafKind_PRECOMP:{result = str8_lit("PRECOMP");}break;
case CV_LeafKind_ALIAS:{result = str8_lit("ALIAS");}break;
case CV_LeafKind_DEFARG:{result = str8_lit("DEFARG");}break;
case CV_LeafKind_FRIENDFCN:{result = str8_lit("FRIENDFCN");}break;
case CV_LeafKind_MEMBER:{result = str8_lit("MEMBER");}break;
case CV_LeafKind_STMEMBER:{result = str8_lit("STMEMBER");}break;
case CV_LeafKind_METHOD:{result = str8_lit("METHOD");}break;
case CV_LeafKind_NESTTYPE:{result = str8_lit("NESTTYPE");}break;
case CV_LeafKind_ONEMETHOD:{result = str8_lit("ONEMETHOD");}break;
case CV_LeafKind_NESTTYPEEX:{result = str8_lit("NESTTYPEEX");}break;
case CV_LeafKind_MEMBERMODIFY:{result = str8_lit("MEMBERMODIFY");}break;
case CV_LeafKind_MANAGED:{result = str8_lit("MANAGED");}break;
case CV_LeafKind_TYPESERVER2:{result = str8_lit("TYPESERVER2");}break;
case CV_LeafKind_STRIDED_ARRAY:{result = str8_lit("STRIDED_ARRAY");}break;
case CV_LeafKind_HLSL:{result = str8_lit("HLSL");}break;
case CV_LeafKind_MODIFIER_EX:{result = str8_lit("MODIFIER_EX");}break;
case CV_LeafKind_INTERFACE:{result = str8_lit("INTERFACE");}break;
case CV_LeafKind_BINTERFACE:{result = str8_lit("BINTERFACE");}break;
case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break;
case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break;
case CV_LeafKind_VFTABLE:{result = str8_lit("VFTABLE");}break;
case CV_LeafKind_FUNC_ID:{result = str8_lit("FUNC_ID");}break;
case CV_LeafKind_MFUNC_ID:{result = str8_lit("MFUNC_ID");}break;
case CV_LeafKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
case CV_LeafKind_SUBSTR_LIST:{result = str8_lit("SUBSTR_LIST");}break;
case CV_LeafKind_STRING_ID:{result = str8_lit("STRING_ID");}break;
case CV_LeafKind_UDT_SRC_LINE:{result = str8_lit("UDT_SRC_LINE");}break;
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = str8_lit("UDT_MOD_SRC_LINE");}break;
case CV_LeafKind_CLASS2:{result = str8_lit("CLASS2");}break;
case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break;
}
return result;
}
internal U64
cv_header_struct_size_from_sym_kind(CV_SymKind v)
{
U64 result = 0;
switch(v)
{
default:{}break;
case CV_SymKind_COMPILE:{result = sizeof(CV_SymCompile);}break;
case CV_SymKind_SSEARCH:{result = sizeof(CV_SymStartSearch);}break;
case CV_SymKind_RETURN:{result = sizeof(CV_SymReturn);}break;
case CV_SymKind_SLINK32:{result = sizeof(CV_SymSLink32);}break;
case CV_SymKind_OEM:{result = sizeof(CV_SymOEM);}break;
case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break;
case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break;
case CV_SymKind_ANNOTATION:{result = sizeof(CV_SymAnnotation);}break;
case CV_SymKind_OBJNAME:{result = sizeof(CV_SymObjName);}break;
case CV_SymKind_THUNK32:{result = sizeof(CV_SymThunk32);}break;
case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break;
case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break;
case CV_SymKind_REGISTER:{result = sizeof(CV_SymRegister);}break;
case CV_SymKind_CONSTANT:{result = sizeof(CV_SymConstant);}break;
case CV_SymKind_UDT:{result = sizeof(CV_SymUDT);}break;
case CV_SymKind_MANYREG:{result = sizeof(CV_SymManyreg);}break;
case CV_SymKind_BPREL32:{result = sizeof(CV_SymBPRel32);}break;
case CV_SymKind_LDATA32:{result = sizeof(CV_SymData32);}break;
case CV_SymKind_GDATA32:{result = sizeof(CV_SymData32);}break;
case CV_SymKind_PUB32:{result = sizeof(CV_SymPub32);}break;
case CV_SymKind_LPROC32:{result = sizeof(CV_SymProc32);}break;
case CV_SymKind_GPROC32:{result = sizeof(CV_SymProc32);}break;
case CV_SymKind_REGREL32:{result = sizeof(CV_SymRegrel32);}break;
case CV_SymKind_LTHREAD32:{result = sizeof(CV_SymThread32);}break;
case CV_SymKind_GTHREAD32:{result = sizeof(CV_SymThread32);}break;
case CV_SymKind_COMPILE2:{result = sizeof(CV_SymCompile2);}break;
case CV_SymKind_MANYREG2:{result = sizeof(CV_SymManyreg2);}break;
case CV_SymKind_LOCALSLOT:{result = sizeof(CV_SymSlot);}break;
case CV_SymKind_MANFRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
case CV_SymKind_MANREGISTER:{result = sizeof(CV_SymAttrReg);}break;
case CV_SymKind_MANMANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
case CV_SymKind_MANREGREL:{result = sizeof(CV_SymAttrRegRel);}break;
case CV_SymKind_UNAMESPACE:{result = sizeof(CV_SymUNamespace);}break;
case CV_SymKind_PROCREF:{result = sizeof(CV_SymRef2);}break;
case CV_SymKind_DATAREF:{result = sizeof(CV_SymRef2);}break;
case CV_SymKind_LPROCREF:{result = sizeof(CV_SymRef2);}break;
case CV_SymKind_TRAMPOLINE:{result = sizeof(CV_SymTrampoline);}break;
case CV_SymKind_ATTR_FRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
case CV_SymKind_ATTR_REGISTER:{result = sizeof(CV_SymAttrReg);}break;
case CV_SymKind_ATTR_REGREL:{result = sizeof(CV_SymAttrRegRel);}break;
case CV_SymKind_ATTR_MANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
case CV_SymKind_SEPCODE:{result = sizeof(CV_SymSepcode);}break;
case CV_SymKind_SECTION:{result = sizeof(CV_SymSection);}break;
case CV_SymKind_COFFGROUP:{result = sizeof(CV_SymCoffGroup);}break;
case CV_SymKind_EXPORT:{result = sizeof(CV_SymExport);}break;
case CV_SymKind_CALLSITEINFO:{result = sizeof(CV_SymCallSiteInfo);}break;
case CV_SymKind_FRAMECOOKIE:{result = sizeof(CV_SymFrameCookie);}break;
case CV_SymKind_DISCARDED:{result = sizeof(CV_SymDiscarded);}break;
case CV_SymKind_COMPILE3:{result = sizeof(CV_SymCompile3);}break;
case CV_SymKind_ENVBLOCK:{result = sizeof(CV_SymEnvBlock);}break;
case CV_SymKind_LOCAL:{result = sizeof(CV_SymLocal);}break;
case CV_SymKind_DEFRANGE_SUBFIELD:{result = sizeof(CV_SymDefrangeSubfield);}break;
case CV_SymKind_DEFRANGE_REGISTER:{result = sizeof(CV_SymDefrangeRegister);}break;
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = sizeof(CV_SymDefrangeFramepointerRel);}break;
case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = sizeof(CV_SymDefrangeSubfieldRegister);}break;
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = sizeof(CV_SymDefrangeFramepointerRelFullScope);}break;
case CV_SymKind_DEFRANGE_REGISTER_REL:{result = sizeof(CV_SymDefrangeRegisterRel);}break;
case CV_SymKind_BUILDINFO:{result = sizeof(CV_SymBuildInfo);}break;
case CV_SymKind_INLINESITE:{result = sizeof(CV_SymInlineSite);}break;
case CV_SymKind_FILESTATIC:{result = sizeof(CV_SymFileStatic);}break;
case CV_SymKind_CALLEES:{result = sizeof(CV_SymFunctionList);}break;
case CV_SymKind_CALLERS:{result = sizeof(CV_SymFunctionList);}break;
case CV_SymKind_POGODATA:{result = sizeof(CV_SymPogoInfo);}break;
case CV_SymKind_INLINESITE2:{result = sizeof(CV_SymInlineSite2);}break;
case CV_SymKind_HEAPALLOCSITE:{result = sizeof(CV_SymHeapAllocSite);}break;
case CV_SymKind_MOD_TYPEREF:{result = sizeof(CV_SymModTypeRef);}break;
case CV_SymKind_REF_MINIPDB:{result = sizeof(CV_SymRefMiniPdb);}break;
case CV_SymKind_FASTLINK:{result = sizeof(CV_SymFastLink);}break;
case CV_SymKind_INLINEES:{result = sizeof(CV_SymInlinees);}break;
}
return result;
}
internal U64
cv_header_struct_size_from_leaf_kind(CV_LeafKind v)
{
U64 result = 0;
switch(v)
{
default:{}break;
case CV_LeafKind_VTSHAPE:{result = sizeof(CV_LeafVTShape);}break;
case CV_LeafKind_LABEL:{result = sizeof(CV_LeafLabel);}break;
case CV_LeafKind_MODIFIER:{result = sizeof(CV_LeafModifier);}break;
case CV_LeafKind_POINTER:{result = sizeof(CV_LeafPointer);}break;
case CV_LeafKind_PROCEDURE:{result = sizeof(CV_LeafProcedure);}break;
case CV_LeafKind_MFUNCTION:{result = sizeof(CV_LeafMFunction);}break;
case CV_LeafKind_VFTPATH:{result = sizeof(CV_LeafVFPath);}break;
case CV_LeafKind_SKIP:{result = sizeof(CV_LeafSkip);}break;
case CV_LeafKind_ARGLIST:{result = sizeof(CV_LeafArgList);}break;
case CV_LeafKind_BITFIELD:{result = sizeof(CV_LeafBitField);}break;
case CV_LeafKind_METHODLIST:{result = sizeof(CV_LeafMethodListMember);}break;
case CV_LeafKind_BCLASS:{result = sizeof(CV_LeafBClass);}break;
case CV_LeafKind_VBCLASS:{result = sizeof(CV_LeafVBClass);}break;
case CV_LeafKind_INDEX:{result = sizeof(CV_LeafIndex);}break;
case CV_LeafKind_VFUNCTAB:{result = sizeof(CV_LeafVFuncTab);}break;
case CV_LeafKind_VFUNCOFF:{result = sizeof(CV_LeafVFuncOff);}break;
case CV_LeafKind_TYPESERVER:{result = sizeof(CV_LeafTypeServer);}break;
case CV_LeafKind_ENUMERATE:{result = sizeof(CV_LeafEnumerate);}break;
case CV_LeafKind_ARRAY:{result = sizeof(CV_LeafArray);}break;
case CV_LeafKind_CLASS:{result = sizeof(CV_LeafStruct);}break;
case CV_LeafKind_STRUCTURE:{result = sizeof(CV_LeafStruct);}break;
case CV_LeafKind_UNION:{result = sizeof(CV_LeafUnion);}break;
case CV_LeafKind_ENUM:{result = sizeof(CV_LeafEnum);}break;
case CV_LeafKind_PRECOMP:{result = sizeof(CV_LeafPreComp);}break;
case CV_LeafKind_ALIAS:{result = sizeof(CV_LeafAlias);}break;
case CV_LeafKind_MEMBER:{result = sizeof(CV_LeafMember);}break;
case CV_LeafKind_STMEMBER:{result = sizeof(CV_LeafStMember);}break;
case CV_LeafKind_METHOD:{result = sizeof(CV_LeafMethod);}break;
case CV_LeafKind_NESTTYPE:{result = sizeof(CV_LeafNestType);}break;
case CV_LeafKind_ONEMETHOD:{result = sizeof(CV_LeafOneMethod);}break;
case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break;
case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break;
case CV_LeafKind_INTERFACE:{result = sizeof(CV_LeafStruct);}break;
case CV_LeafKind_FUNC_ID:{result = sizeof(CV_LeafFuncId);}break;
case CV_LeafKind_MFUNC_ID:{result = sizeof(CV_LeafMFuncId);}break;
case CV_LeafKind_BUILDINFO:{result = sizeof(CV_LeafBuildInfo);}break;
case CV_LeafKind_SUBSTR_LIST:{result = sizeof(CV_LeafSubstrList);}break;
case CV_LeafKind_STRING_ID:{result = sizeof(CV_LeafStringId);}break;
case CV_LeafKind_UDT_SRC_LINE:{result = sizeof(CV_LeafUDTSrcLine);}break;
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = sizeof(CV_LeafUDTModSrcLine);}break;
case CV_LeafKind_CLASS2:{result = sizeof(CV_LeafStruct2);}break;
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
}
return result;
}
-528
View File
@@ -1,528 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
#ifndef CODEVIEW_META_H
#define CODEVIEW_META_H
typedef U16 CV_NumericKind;
typedef enum CV_NumericKindEnum
{
CV_NumericKind_CHAR = 0x8000,
CV_NumericKind_SHORT = 0x8001,
CV_NumericKind_USHORT = 0x8002,
CV_NumericKind_LONG = 0x8003,
CV_NumericKind_ULONG = 0x8004,
CV_NumericKind_FLOAT32 = 0x8005,
CV_NumericKind_FLOAT64 = 0x8006,
CV_NumericKind_FLOAT80 = 0x8007,
CV_NumericKind_FLOAT128 = 0x8008,
CV_NumericKind_QUADWORD = 0x8009,
CV_NumericKind_UQUADWORD = 0x800a,
CV_NumericKind_FLOAT48 = 0x800b,
CV_NumericKind_COMPLEX32 = 0x800c,
CV_NumericKind_COMPLEX64 = 0x800d,
CV_NumericKind_COMPLEX80 = 0x800e,
CV_NumericKind_COMPLEX128 = 0x800f,
CV_NumericKind_VARSTRING = 0x8010,
CV_NumericKind_OCTWORD = 0x8017,
CV_NumericKind_UOCTWORD = 0x8018,
CV_NumericKind_DECIMAL = 0x8019,
CV_NumericKind_DATE = 0x801a,
CV_NumericKind_UTF8STRING = 0x801b,
CV_NumericKind_FLOAT16 = 0x801c,
} CV_NumericKindEnum;
typedef U16 CV_Arch;
typedef enum CV_ArchEnum
{
CV_Arch_8080 = 0x00,
CV_Arch_8086 = 0x01,
CV_Arch_80286 = 0x02,
CV_Arch_80386 = 0x03,
CV_Arch_80486 = 0x04,
CV_Arch_PENTIUM = 0x05,
CV_Arch_PENTIUMII = 0x06,
CV_Arch_PENTIUMIII = 0x07,
CV_Arch_MIPS = 0x10,
CV_Arch_MIPS16 = 0x11,
CV_Arch_MIPS32 = 0x12,
CV_Arch_MIPS64 = 0x13,
CV_Arch_MIPSI = 0x14,
CV_Arch_MIPSII = 0x15,
CV_Arch_MIPSIII = 0x16,
CV_Arch_MIPSIV = 0x17,
CV_Arch_MIPSV = 0x18,
CV_Arch_M68000 = 0x20,
CV_Arch_M68010 = 0x21,
CV_Arch_M68020 = 0x22,
CV_Arch_M68030 = 0x23,
CV_Arch_M68040 = 0x24,
CV_Arch_ALPHA = 0x30,
CV_Arch_ALPHA_21164 = 0x31,
CV_Arch_ALPHA_21164A = 0x32,
CV_Arch_ALPHA_21264 = 0x33,
CV_Arch_ALPHA_21364 = 0x34,
CV_Arch_PPC601 = 0x40,
CV_Arch_PPC603 = 0x41,
CV_Arch_PPC604 = 0x42,
CV_Arch_PPC620 = 0x43,
CV_Arch_PPCFP = 0x44,
CV_Arch_PPCBE = 0x45,
CV_Arch_SH3 = 0x50,
CV_Arch_SH3E = 0x51,
CV_Arch_SH3DSP = 0x52,
CV_Arch_SH4 = 0x53,
CV_Arch_SHMEDIA = 0x54,
CV_Arch_ARM3 = 0x60,
CV_Arch_ARM4 = 0x61,
CV_Arch_ARM4T = 0x62,
CV_Arch_ARM5 = 0x63,
CV_Arch_ARM5T = 0x64,
CV_Arch_ARM6 = 0x65,
CV_Arch_ARM_XMAC = 0x66,
CV_Arch_ARM_WMMX = 0x67,
CV_Arch_ARM7 = 0x68,
CV_Arch_OMNI = 0x70,
CV_Arch_IA64_1 = 0x80,
CV_Arch_IA64_2 = 0x81,
CV_Arch_CEE = 0x90,
CV_Arch_AM33 = 0xA0,
CV_Arch_M32R = 0xB0,
CV_Arch_TRICORE = 0xC0,
CV_Arch_X64 = 0xD0,
CV_Arch_EBC = 0xE0,
CV_Arch_THUMB = 0xF0,
CV_Arch_ARMNT = 0xF4,
CV_Arch_ARM64 = 0xF6,
CV_Arch_D3D11_SHADER = 0x100,
CV_Arch_IA64 = CV_Arch_IA64_1,
CV_Arch_PENTIUMPRO = CV_Arch_PENTIUMII,
CV_Arch_MIPSR4000 = CV_Arch_MIPS,
CV_Arch_ALPHA_21064 = CV_Arch_ALPHA,
CV_Arch_AMD64 = CV_Arch_X64,
} CV_ArchEnum;
typedef U16 CV_AllReg;
typedef enum CV_AllRegEnum
{
CV_AllReg_ERR = 30000,
CV_AllReg_TEB = 30001,
CV_AllReg_TIMER = 30002,
CV_AllReg_EFAD1 = 30003,
CV_AllReg_EFAD2 = 30004,
CV_AllReg_EFAD3 = 30005,
CV_AllReg_VFRAME = 30006,
CV_AllReg_HANDLE = 30007,
CV_AllReg_PARAMS = 30008,
CV_AllReg_LOCALS = 30009,
CV_AllReg_TID = 30010,
CV_AllReg_ENV = 30011,
CV_AllReg_CMDLN = 30012,
} CV_AllRegEnum;
typedef U16 CV_SymKind;
typedef enum CV_SymKindEnum
{
CV_SymKind_COMPILE = 0x0001,
CV_SymKind_REGISTER_16t = 0x0002,
CV_SymKind_CONSTANT_16t = 0x0003,
CV_SymKind_UDT_16t = 0x0004,
CV_SymKind_SSEARCH = 0x0005,
CV_SymKind_END = 0x0006,
CV_SymKind_SKIP = 0x0007,
CV_SymKind_CVRESERVE = 0x0008,
CV_SymKind_OBJNAME_ST = 0x0009,
CV_SymKind_ENDARG = 0x000a,
CV_SymKind_COBOLUDT_16t = 0x000b,
CV_SymKind_MANYREG_16t = 0x000c,
CV_SymKind_RETURN = 0x000d,
CV_SymKind_ENTRYTHIS = 0x000e,
CV_SymKind_BPREL16 = 0x0100,
CV_SymKind_LDATA16 = 0x0101,
CV_SymKind_GDATA16 = 0x0102,
CV_SymKind_PUB16 = 0x0103,
CV_SymKind_LPROC16 = 0x0104,
CV_SymKind_GPROC16 = 0x0105,
CV_SymKind_THUNK16 = 0x0106,
CV_SymKind_BLOCK16 = 0x0107,
CV_SymKind_WITH16 = 0x0108,
CV_SymKind_LABEL16 = 0x0109,
CV_SymKind_CEXMODEL16 = 0x010a,
CV_SymKind_VFTABLE16 = 0x010b,
CV_SymKind_REGREL16 = 0x010c,
CV_SymKind_BPREL32_16t = 0x0200,
CV_SymKind_LDATA32_16t = 0x0201,
CV_SymKind_GDATA32_16t = 0x0202,
CV_SymKind_PUB32_16t = 0x0203,
CV_SymKind_LPROC32_16t = 0x0204,
CV_SymKind_GPROC32_16t = 0x0205,
CV_SymKind_THUNK32_ST = 0x0206,
CV_SymKind_BLOCK32_ST = 0x0207,
CV_SymKind_WITH32_ST = 0x0208,
CV_SymKind_LABEL32_ST = 0x0209,
CV_SymKind_CEXMODEL32 = 0x020a,
CV_SymKind_VFTABLE32_16t = 0x020b,
CV_SymKind_REGREL32_16t = 0x020c,
CV_SymKind_LTHREAD32_16t = 0x020d,
CV_SymKind_GTHREAD32_16t = 0x020e,
CV_SymKind_SLINK32 = 0x020f,
CV_SymKind_LPROCMIPS_16t = 0x0300,
CV_SymKind_GPROCMIPS_16t = 0x0301,
CV_SymKind_PROCREF_ST = 0x0400,
CV_SymKind_DATAREF_ST = 0x0401,
CV_SymKind_ALIGN = 0x0402,
CV_SymKind_LPROCREF_ST = 0x0403,
CV_SymKind_OEM = 0x0404,
CV_SymKind_TI16_MAX = 0x1000,
CV_SymKind_CONSTANT_ST = 0x1002,
CV_SymKind_UDT_ST = 0x1003,
CV_SymKind_COBOLUDT_ST = 0x1004,
CV_SymKind_MANYREG_ST = 0x1005,
CV_SymKind_BPREL32_ST = 0x1006,
CV_SymKind_LDATA32_ST = 0x1007,
CV_SymKind_GDATA32_ST = 0x1008,
CV_SymKind_PUB32_ST = 0x1009,
CV_SymKind_LPROC32_ST = 0x100a,
CV_SymKind_GPROC32_ST = 0x100b,
CV_SymKind_VFTABLE32 = 0x100c,
CV_SymKind_REGREL32_ST = 0x100d,
CV_SymKind_LTHREAD32_ST = 0x100e,
CV_SymKind_GTHREAD32_ST = 0x100f,
CV_SymKind_LPROCMIPS_ST = 0x1010,
CV_SymKind_GPROCMIPS_ST = 0x1011,
CV_SymKind_FRAMEPROC = 0x1012,
CV_SymKind_COMPILE2_ST = 0x1013,
CV_SymKind_MANYREG2_ST = 0x1014,
CV_SymKind_LPROCIA64_ST = 0x1015,
CV_SymKind_GPROCIA64_ST = 0x1016,
CV_SymKind_LOCALSLOT_ST = 0x1017,
CV_SymKind_PARAMSLOT_ST = 0x1018,
CV_SymKind_ANNOTATION = 0x1019,
CV_SymKind_GMANPROC_ST = 0x101a,
CV_SymKind_LMANPROC_ST = 0x101b,
CV_SymKind_RESERVED1 = 0x101c,
CV_SymKind_RESERVED2 = 0x101d,
CV_SymKind_RESERVED3 = 0x101e,
CV_SymKind_RESERVED4 = 0x101f,
CV_SymKind_LMANDATA_ST = 0x1020,
CV_SymKind_GMANDATA_ST = 0x1021,
CV_SymKind_MANFRAMEREL_ST = 0x1022,
CV_SymKind_MANREGISTER_ST = 0x1023,
CV_SymKind_MANSLOT_ST = 0x1024,
CV_SymKind_MANMANYREG_ST = 0x1025,
CV_SymKind_MANREGREL_ST = 0x1026,
CV_SymKind_MANMANYREG2_ST = 0x1027,
CV_SymKind_MANTYPREF = 0x1028,
CV_SymKind_UNAMESPACE_ST = 0x1029,
CV_SymKind_ST_MAX = 0x1100,
CV_SymKind_OBJNAME = 0x1101,
CV_SymKind_THUNK32 = 0x1102,
CV_SymKind_BLOCK32 = 0x1103,
CV_SymKind_WITH32 = 0x1104,
CV_SymKind_LABEL32 = 0x1105,
CV_SymKind_REGISTER = 0x1106,
CV_SymKind_CONSTANT = 0x1107,
CV_SymKind_UDT = 0x1108,
CV_SymKind_COBOLUDT = 0x1109,
CV_SymKind_MANYREG = 0x110a,
CV_SymKind_BPREL32 = 0x110b,
CV_SymKind_LDATA32 = 0x110c,
CV_SymKind_GDATA32 = 0x110d,
CV_SymKind_PUB32 = 0x110e,
CV_SymKind_LPROC32 = 0x110f,
CV_SymKind_GPROC32 = 0x1110,
CV_SymKind_REGREL32 = 0x1111,
CV_SymKind_LTHREAD32 = 0x1112,
CV_SymKind_GTHREAD32 = 0x1113,
CV_SymKind_LPROCMIPS = 0x1114,
CV_SymKind_GPROCMIPS = 0x1115,
CV_SymKind_COMPILE2 = 0x1116,
CV_SymKind_MANYREG2 = 0x1117,
CV_SymKind_LPROCIA64 = 0x1118,
CV_SymKind_GPROCIA64 = 0x1119,
CV_SymKind_LOCALSLOT = 0x111a,
CV_SymKind_PARAMSLOT = 0x111b,
CV_SymKind_LMANDATA = 0x111c,
CV_SymKind_GMANDATA = 0x111d,
CV_SymKind_MANFRAMEREL = 0x111e,
CV_SymKind_MANREGISTER = 0x111f,
CV_SymKind_MANSLOT = 0x1120,
CV_SymKind_MANMANYREG = 0x1121,
CV_SymKind_MANREGREL = 0x1122,
CV_SymKind_MANMANYREG2 = 0x1123,
CV_SymKind_UNAMESPACE = 0x1124,
CV_SymKind_PROCREF = 0x1125,
CV_SymKind_DATAREF = 0x1126,
CV_SymKind_LPROCREF = 0x1127,
CV_SymKind_ANNOTATIONREF = 0x1128,
CV_SymKind_TOKENREF = 0x1129,
CV_SymKind_GMANPROC = 0x112a,
CV_SymKind_LMANPROC = 0x112b,
CV_SymKind_TRAMPOLINE = 0x112c,
CV_SymKind_MANCONSTANT = 0x112d,
CV_SymKind_ATTR_FRAMEREL = 0x112e,
CV_SymKind_ATTR_REGISTER = 0x112f,
CV_SymKind_ATTR_REGREL = 0x1130,
CV_SymKind_ATTR_MANYREG = 0x1131,
CV_SymKind_SEPCODE = 0x1132,
CV_SymKind_DEFRANGE_2005 = 0x1134,
CV_SymKind_DEFRANGE2_2005 = 0x1135,
CV_SymKind_SECTION = 0x1136,
CV_SymKind_COFFGROUP = 0x1137,
CV_SymKind_EXPORT = 0x1138,
CV_SymKind_CALLSITEINFO = 0x1139,
CV_SymKind_FRAMECOOKIE = 0x113a,
CV_SymKind_DISCARDED = 0x113b,
CV_SymKind_COMPILE3 = 0x113c,
CV_SymKind_ENVBLOCK = 0x113d,
CV_SymKind_LOCAL = 0x113e,
CV_SymKind_DEFRANGE = 0x113f,
CV_SymKind_DEFRANGE_SUBFIELD = 0x1140,
CV_SymKind_DEFRANGE_REGISTER = 0x1141,
CV_SymKind_DEFRANGE_FRAMEPOINTER_REL = 0x1142,
CV_SymKind_DEFRANGE_SUBFIELD_REGISTER = 0x1143,
CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 0x1144,
CV_SymKind_DEFRANGE_REGISTER_REL = 0x1145,
CV_SymKind_LPROC32_ID = 0x1146,
CV_SymKind_GPROC32_ID = 0x1147,
CV_SymKind_LPROCMIPS_ID = 0x1148,
CV_SymKind_GPROCMIPS_ID = 0x1149,
CV_SymKind_LPROCIA64_ID = 0x114a,
CV_SymKind_GPROCIA64_ID = 0x114b,
CV_SymKind_BUILDINFO = 0x114c,
CV_SymKind_INLINESITE = 0x114d,
CV_SymKind_INLINESITE_END = 0x114e,
CV_SymKind_PROC_ID_END = 0x114f,
CV_SymKind_DEFRANGE_HLSL = 0x1150,
CV_SymKind_GDATA_HLSL = 0x1151,
CV_SymKind_LDATA_HLSL = 0x1152,
CV_SymKind_FILESTATIC = 0x1153,
CV_SymKind_LPROC32_DPC = 0x1155,
CV_SymKind_LPROC32_DPC_ID = 0x1156,
CV_SymKind_DEFRANGE_DPC_PTR_TAG = 0x1157,
CV_SymKind_DPC_SYM_TAG_MAP = 0x1158,
CV_SymKind_ARMSWITCHTABLE = 0x1159,
CV_SymKind_CALLEES = 0x115a,
CV_SymKind_CALLERS = 0x115b,
CV_SymKind_POGODATA = 0x115c,
CV_SymKind_INLINESITE2 = 0x115d,
CV_SymKind_HEAPALLOCSITE = 0x115e,
CV_SymKind_MOD_TYPEREF = 0x115f,
CV_SymKind_REF_MINIPDB = 0x1160,
CV_SymKind_PDBMAP = 0x1161,
CV_SymKind_GDATA_HLSL32 = 0x1162,
CV_SymKind_LDATA_HLSL32 = 0x1163,
CV_SymKind_GDATA_HLSL32_EX = 0x1164,
CV_SymKind_LDATA_HLSL32_EX = 0x1165,
CV_SymKind_FASTLINK = 0x1167,
CV_SymKind_INLINEES = 0x1168,
} CV_SymKindEnum;
typedef U8 CV_BasicType;
typedef enum CV_BasicTypeEnum
{
CV_BasicType_NOTYPE = 0x00,
CV_BasicType_ABS = 0x01,
CV_BasicType_SEGMENT = 0x02,
CV_BasicType_VOID = 0x03,
CV_BasicType_CURRENCY = 0x04,
CV_BasicType_NBASICSTR = 0x05,
CV_BasicType_FBASICSTR = 0x06,
CV_BasicType_NOTTRANS = 0x07,
CV_BasicType_HRESULT = 0x08,
CV_BasicType_CHAR = 0x10,
CV_BasicType_SHORT = 0x11,
CV_BasicType_LONG = 0x12,
CV_BasicType_QUAD = 0x13,
CV_BasicType_OCT = 0x14,
CV_BasicType_UCHAR = 0x20,
CV_BasicType_USHORT = 0x21,
CV_BasicType_ULONG = 0x22,
CV_BasicType_UQUAD = 0x23,
CV_BasicType_UOCT = 0x24,
CV_BasicType_BOOL8 = 0x30,
CV_BasicType_BOOL16 = 0x31,
CV_BasicType_BOOL32 = 0x32,
CV_BasicType_BOOL64 = 0x33,
CV_BasicType_FLOAT32 = 0x40,
CV_BasicType_FLOAT64 = 0x41,
CV_BasicType_FLOAT80 = 0x42,
CV_BasicType_FLOAT128 = 0x43,
CV_BasicType_FLOAT48 = 0x44,
CV_BasicType_FLOAT32PP = 0x45,
CV_BasicType_FLOAT16 = 0x46,
CV_BasicType_COMPLEX32 = 0x50,
CV_BasicType_COMPLEX64 = 0x51,
CV_BasicType_COMPLEX80 = 0x52,
CV_BasicType_COMPLEX128 = 0x53,
CV_BasicType_BIT = 0x60,
CV_BasicType_PASCHAR = 0x61,
CV_BasicType_BOOL32FF = 0x62,
CV_BasicType_INT8 = 0x68,
CV_BasicType_UINT8 = 0x69,
CV_BasicType_RCHAR = 0x70,
CV_BasicType_WCHAR = 0x71,
CV_BasicType_INT16 = 0x72,
CV_BasicType_UINT16 = 0x73,
CV_BasicType_INT32 = 0x74,
CV_BasicType_UINT32 = 0x75,
CV_BasicType_INT64 = 0x76,
CV_BasicType_UINT64 = 0x77,
CV_BasicType_INT128 = 0x78,
CV_BasicType_UINT128 = 0x79,
CV_BasicType_CHAR16 = 0x7a,
CV_BasicType_CHAR32 = 0x7b,
CV_BasicType_CHAR8 = 0x7c,
CV_BasicType_PTR = 0xf0,
} CV_BasicTypeEnum;
typedef U16 CV_LeafKind;
typedef enum CV_LeafKindEnum
{
CV_LeafKind_NOTYPE = 0x0000,
CV_LeafKind_MODIFIER_16t = 0x0001,
CV_LeafKind_POINTER_16t = 0x0002,
CV_LeafKind_ARRAY_16t = 0x0003,
CV_LeafKind_CLASS_16t = 0x0004,
CV_LeafKind_STRUCTURE_16t = 0x0005,
CV_LeafKind_UNION_16t = 0x0006,
CV_LeafKind_ENUM_16t = 0x0007,
CV_LeafKind_PROCEDURE_16t = 0x0008,
CV_LeafKind_MFUNCTION_16t = 0x0009,
CV_LeafKind_VTSHAPE = 0x000a,
CV_LeafKind_COBOL0_16t = 0x000b,
CV_LeafKind_COBOL1 = 0x000c,
CV_LeafKind_BARRAY_16t = 0x000d,
CV_LeafKind_LABEL = 0x000e,
CV_LeafKind_NULL = 0x000f,
CV_LeafKind_NOTTRAN = 0x0010,
CV_LeafKind_DIMARRAY_16t = 0x0011,
CV_LeafKind_VFTPATH_16t = 0x0012,
CV_LeafKind_PRECOMP_16t = 0x0013,
CV_LeafKind_ENDPRECOMP = 0x0014,
CV_LeafKind_OEM_16t = 0x0015,
CV_LeafKind_TYPESERVER_ST = 0x0016,
CV_LeafKind_SKIP_16t = 0x0200,
CV_LeafKind_ARGLIST_16t = 0x0201,
CV_LeafKind_DEFARG_16t = 0x0202,
CV_LeafKind_LIST = 0x0203,
CV_LeafKind_FIELDLIST_16t = 0x0204,
CV_LeafKind_DERIVED_16t = 0x0205,
CV_LeafKind_BITFIELD_16t = 0x0206,
CV_LeafKind_METHODLIST_16t = 0x0207,
CV_LeafKind_DIMCONU_16t = 0x0208,
CV_LeafKind_DIMCONLU_16t = 0x0209,
CV_LeafKind_DIMVARU_16t = 0x020a,
CV_LeafKind_DIMVARLU_16t = 0x020b,
CV_LeafKind_REFSYM = 0x020c,
CV_LeafKind_BCLASS_16t = 0x0400,
CV_LeafKind_VBCLASS_16t = 0x0401,
CV_LeafKind_IVBCLASS_16t = 0x0402,
CV_LeafKind_ENUMERATE_ST = 0x0403,
CV_LeafKind_FRIENDFCN_16t = 0x0404,
CV_LeafKind_INDEX_16t = 0x0405,
CV_LeafKind_MEMBER_16t = 0x0406,
CV_LeafKind_STMEMBER_16t = 0x0407,
CV_LeafKind_METHOD_16t = 0x0408,
CV_LeafKind_NESTTYPE_16t = 0x0409,
CV_LeafKind_VFUNCTAB_16t = 0x040a,
CV_LeafKind_FRIENDCLS_16t = 0x040b,
CV_LeafKind_ONEMETHOD_16t = 0x040c,
CV_LeafKind_VFUNCOFF_16t = 0x040d,
CV_LeafKind_TI16_MAX = 0x1000,
CV_LeafKind_MODIFIER = 0x1001,
CV_LeafKind_POINTER = 0x1002,
CV_LeafKind_ARRAY_ST = 0x1003,
CV_LeafKind_CLASS_ST = 0x1004,
CV_LeafKind_STRUCTURE_ST = 0x1005,
CV_LeafKind_UNION_ST = 0x1006,
CV_LeafKind_ENUM_ST = 0x1007,
CV_LeafKind_PROCEDURE = 0x1008,
CV_LeafKind_MFUNCTION = 0x1009,
CV_LeafKind_COBOL0 = 0x100a,
CV_LeafKind_BARRAY = 0x100b,
CV_LeafKind_DIMARRAY_ST = 0x100c,
CV_LeafKind_VFTPATH = 0x100d,
CV_LeafKind_PRECOMP_ST = 0x100e,
CV_LeafKind_OEM = 0x100f,
CV_LeafKind_ALIAS_ST = 0x1010,
CV_LeafKind_OEM2 = 0x1011,
CV_LeafKind_SKIP = 0x1200,
CV_LeafKind_ARGLIST = 0x1201,
CV_LeafKind_DEFARG_ST = 0x1202,
CV_LeafKind_FIELDLIST = 0x1203,
CV_LeafKind_DERIVED = 0x1204,
CV_LeafKind_BITFIELD = 0x1205,
CV_LeafKind_METHODLIST = 0x1206,
CV_LeafKind_DIMCONU = 0x1207,
CV_LeafKind_DIMCONLU = 0x1208,
CV_LeafKind_DIMVARU = 0x1209,
CV_LeafKind_DIMVARLU = 0x120a,
CV_LeafKind_BCLASS = 0x1400,
CV_LeafKind_VBCLASS = 0x1401,
CV_LeafKind_IVBCLASS = 0x1402,
CV_LeafKind_FRIENDFCN_ST = 0x1403,
CV_LeafKind_INDEX = 0x1404,
CV_LeafKind_MEMBER_ST = 0x1405,
CV_LeafKind_STMEMBER_ST = 0x1406,
CV_LeafKind_METHOD_ST = 0x1407,
CV_LeafKind_NESTTYPE_ST = 0x1408,
CV_LeafKind_VFUNCTAB = 0x1409,
CV_LeafKind_FRIENDCLS = 0x140a,
CV_LeafKind_ONEMETHOD_ST = 0x140b,
CV_LeafKind_VFUNCOFF = 0x140c,
CV_LeafKind_NESTTYPEEX_ST = 0x140d,
CV_LeafKind_MEMBERMODIFY_ST = 0x140e,
CV_LeafKind_MANAGED_ST = 0x140f,
CV_LeafKind_ST_MAX = 0x1500,
CV_LeafKind_TYPESERVER = 0x1501,
CV_LeafKind_ENUMERATE = 0x1502,
CV_LeafKind_ARRAY = 0x1503,
CV_LeafKind_CLASS = 0x1504,
CV_LeafKind_STRUCTURE = 0x1505,
CV_LeafKind_UNION = 0x1506,
CV_LeafKind_ENUM = 0x1507,
CV_LeafKind_DIMARRAY = 0x1508,
CV_LeafKind_PRECOMP = 0x1509,
CV_LeafKind_ALIAS = 0x150a,
CV_LeafKind_DEFARG = 0x150b,
CV_LeafKind_FRIENDFCN = 0x150c,
CV_LeafKind_MEMBER = 0x150d,
CV_LeafKind_STMEMBER = 0x150e,
CV_LeafKind_METHOD = 0x150f,
CV_LeafKind_NESTTYPE = 0x1510,
CV_LeafKind_ONEMETHOD = 0x1511,
CV_LeafKind_NESTTYPEEX = 0x1512,
CV_LeafKind_MEMBERMODIFY = 0x1513,
CV_LeafKind_MANAGED = 0x1514,
CV_LeafKind_TYPESERVER2 = 0x1515,
CV_LeafKind_STRIDED_ARRAY = 0x1516,
CV_LeafKind_HLSL = 0x1517,
CV_LeafKind_MODIFIER_EX = 0x1518,
CV_LeafKind_INTERFACE = 0x1519,
CV_LeafKind_BINTERFACE = 0x151a,
CV_LeafKind_VECTOR = 0x151b,
CV_LeafKind_MATRIX = 0x151c,
CV_LeafKind_VFTABLE = 0x151d,
CV_LeafKind_FUNC_ID = 0x1601,
CV_LeafKind_MFUNC_ID = 0x1602,
CV_LeafKind_BUILDINFO = 0x1603,
CV_LeafKind_SUBSTR_LIST = 0x1604,
CV_LeafKind_STRING_ID = 0x1605,
CV_LeafKind_UDT_SRC_LINE = 0x1606,
CV_LeafKind_UDT_MOD_SRC_LINE = 0x1607,
CV_LeafKind_CLASS2 = 0x1608,
CV_LeafKind_STRUCT2 = 0x1609,
} CV_LeafKindEnum;
internal String8 cv_string_from_numeric_kind(CV_NumericKind v);
internal String8 cv_string_from_arch(CV_Arch v);
internal String8 cv_string_from_sym_kind(CV_SymKind v);
internal String8 cv_string_from_basic_type(CV_BasicType v);
internal String8 cv_type_name_from_basic_type(CV_BasicType v);
internal String8 cv_string_from_leaf_kind(CV_LeafKind v);
internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);
internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);
#endif // CODEVIEW_META_H
+928 -763
View File
File diff suppressed because it is too large Load Diff
+678 -463
View File
File diff suppressed because it is too large Load Diff
-819
View File
@@ -1,819 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if 0
internal void
coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names)
{
Temp scratch = scratch_begin(&arena, 1);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp);
rd_printf("Name : %S" , header.name );
rd_printf("Time Stamp: (%#x) %S" , header.time_stamp, time_stamp );
rd_printf("User ID : %u" , header.user_id );
rd_printf("Group ID : %u" , header.group_id);
rd_printf("Mode : %S" , header.mode );
rd_printf("Data : [%#llx-%#llx)", header.data_range.min, header.data_range.max);
scratch_end(scratch);
}
internal void
coff_print_section_table(Arena *arena,
String8List *out,
String8 indent,
String8 string_table,
COFF_Symbol32Array symbol_table,
U64 section_count,
COFF_SectionHeader *section_table)
{
Temp scratch = scratch_begin(&arena, 1);
String8 *symlinks = push_array(scratch.arena, String8, section_count);
for (U64 i = 0; i < symbol_table.count; ++i) {
COFF_Symbol32 *symbol = symbol_table.v+i;
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class);
if (interp == COFF_SymbolValueInterp_Regular &&
symbol->aux_symbol_count == 0 &&
(symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) {
if (symbol->section_number > 0 && symbol->section_number <= symbol_table.count) {
COFF_SectionHeader *header = section_table+(symbol->section_number-1);
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
symlinks[symbol->section_number-1] = coff_read_symbol_name(string_table, &symbol->name);
}
}
}
i += symbol->aux_symbol_count;
}
if (section_count) {
rd_printf("# Section Table");
rd_indent();
rd_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s",
"No.",
"Name",
"VirtSize",
"VirtOff",
"FileSize",
"FileOff",
"RelocOff",
"LinesOff",
"RelocCnt",
"LineCnt",
"Align",
"Flags",
"Symlink");
for (U64 i = 0; i < section_count; ++i) {
COFF_SectionHeader *header = section_table+i;
String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name));
String8 full_name = coff_name_from_section_header(string_table, header);
String8 align;
{
U64 align_size = coff_align_size_from_section_flags(header->flags);
align = push_str8f(scratch.arena, "%u", align_size);
}
String8 flags;
{
String8List mem_flags = {0};
if (header->flags & COFF_SectionFlag_MemRead) {
str8_list_pushf(scratch.arena, &mem_flags, "r");
}
if (header->flags & COFF_SectionFlag_MemWrite) {
str8_list_pushf(scratch.arena, &mem_flags, "w");
}
if (header->flags & COFF_SectionFlag_MemExecute) {
str8_list_pushf(scratch.arena, &mem_flags, "x");
}
String8List cnt_flags = {0};
if (header->flags & COFF_SectionFlag_CntCode) {
str8_list_pushf(scratch.arena, &cnt_flags, "c");
}
if (header->flags & COFF_SectionFlag_CntInitializedData) {
str8_list_pushf(scratch.arena, &cnt_flags, "d");
}
if (header->flags & COFF_SectionFlag_CntUninitializedData) {
str8_list_pushf(scratch.arena, &cnt_flags, "u");
}
String8List mem_extra_flags = {0};
if (header->flags & COFF_SectionFlag_MemShared) {
str8_list_pushf(scratch.arena, &mem_flags, "s");
}
if (header->flags & COFF_SectionFlag_Mem16Bit) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "h");
}
if (header->flags & COFF_SectionFlag_MemLocked) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "l");
}
if (header->flags & COFF_SectionFlag_MemDiscardable) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "d");
}
if (header->flags & COFF_SectionFlag_MemNotCached) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "c");
}
if (header->flags & COFF_SectionFlag_MemNotPaged) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "p");
}
String8List lnk_flags = {0};
if (header->flags & COFF_SectionFlag_LnkRemove) {
str8_list_pushf(scratch.arena, &lnk_flags, "r");
}
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
str8_list_pushf(scratch.arena, &lnk_flags, "c");
}
if (header->flags & COFF_SectionFlag_LnkOther) {
str8_list_pushf(scratch.arena, &lnk_flags, "o");
}
if (header->flags & COFF_SectionFlag_LnkInfo) {
str8_list_pushf(scratch.arena, &lnk_flags, "i");
}
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl) {
str8_list_pushf(scratch.arena, &lnk_flags, "f");
}
String8List other_flags = {0};
if (header->flags & COFF_SectionFlag_TypeNoPad) {
str8_list_pushf(scratch.arena, &other_flags, "n");
}
if (header->flags & COFF_SectionFlag_GpRel) {
str8_list_pushf(scratch.arena, &other_flags, "g");
}
String8 mem = str8_list_join(scratch.arena, &mem_flags, 0);
String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0);
String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0);
String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0);
String8 oth = str8_list_join(scratch.arena, &other_flags, 0);
String8List f = {0};
str8_list_push(scratch.arena, &f, mem);
str8_list_push(scratch.arena, &f, cnt);
str8_list_push(scratch.arena, &f, ext);
str8_list_push(scratch.arena, &f, lnk);
str8_list_push(scratch.arena, &f, oth);
flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") });
if (!flags.size) {
flags = str8_lit("none");
}
}
String8List l = {0};
str8_list_pushf(scratch.arena, &l, "%-4x", i+1 );
str8_list_pushf(scratch.arena, &l, "%-8S", name );
str8_list_pushf(scratch.arena, &l, "%08x", header->vsize );
str8_list_pushf(scratch.arena, &l, "%08x", header->voff );
str8_list_pushf(scratch.arena, &l, "%08x", header->fsize );
str8_list_pushf(scratch.arena, &l, "%08x", header->foff );
str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff);
str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff );
str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count);
str8_list_pushf(scratch.arena, &l, "%08x", header->line_count );
str8_list_pushf(scratch.arena, &l, "%-5S", align );
str8_list_pushf(scratch.arena, &l, "%-10S", flags );
if (symlinks[i].size > 0) {
str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]);
} else {
str8_list_pushf(scratch.arena, &l, "[no symlink]");
}
String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), });
rd_printf("%S", line);
if (full_name.size != name.size) {
rd_indent();
rd_printf("Full Name: %S", full_name);
rd_unindent();
}
}
rd_newline();
rd_printf("Flags:");
rd_indent();
rd_printf("r = MemRead w = MemWrite x = MemExecute");
rd_printf("c = CntCode d = InitializedData u = UninitializedData");
rd_printf("s = MemShared h = Mem16bit l = MemLocked d = MemDiscardable c = MemNotCached p = MemNotPaged");
rd_printf("r = LnkRemove c = LnkComdat o = LnkOther i = LnkInfo f = LnkNRelocOvfl");
rd_printf("g = GpRel n = TypeNoPad");
rd_unindent();
rd_unindent();
rd_newline();
}
scratch_end(scratch);
}
internal void
coff_disasm_sections(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
COFF_MachineType machine,
U64 image_base,
B32 is_obj,
RD_MarkerArray *section_markers,
U64 section_count,
COFF_SectionHeader *sections)
{
if (section_count) {
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
COFF_SectionHeader *sect = sections+sect_idx;
if (sect->flags & COFF_SectionFlag_CntCode) {
U64 sect_off = is_obj ? sect->foff : sect->voff;
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
U64 sect_number = sect_idx+1;
RD_MarkerArray markers = section_markers[sect_number];
rd_printf("# Disassembly [Section No. %#llx]", sect_number);
rd_indent();
rd_print_disasm(arena, out, indent, arch_from_coff_machine(machine), image_base, sect_off, markers.count, markers.v, raw_code);
rd_unindent();
}
}
}
}
internal void
coff_raw_data_sections(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
B32 is_obj,
RD_MarkerArray *section_markers,
U64 section_count,
COFF_SectionHeader *section_table)
{
if (section_count) {
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
COFF_SectionHeader *sect = section_table+sect_idx;
if (sect->fsize > 0) {
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
RD_MarkerArray markers = section_markers[sect_idx];
rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1));
rd_indent();
rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect);
rd_unindent();
rd_newline();
}
}
}
}
internal void
coff_print_relocs(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
String8 string_table,
COFF_MachineType machine,
U64 sect_count,
COFF_SectionHeader *sect_headers,
COFF_Symbol32Array symbols)
{
Temp scratch = scratch_begin(&arena, 1);
B32 print_header = 1;
for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) {
COFF_SectionHeader *sect_header = sect_headers+sect_idx;
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header);
if (reloc_info.count) {
if (print_header) {
print_header = 0;
rd_printf("# Relocations");
rd_indent();
}
rd_printf("## Section %llx", sect_idx);
rd_indent();
rd_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName");
for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) {
COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx;
String8 type = coff_string_from_reloc(machine, reloc->type);
U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type);
U64 apply_foff = sect_header->foff + reloc->apply_off;
if (apply_foff + apply_size > raw_data.size) {
rd_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx);
break;
}
U64 raw_apply;
AssertAlways(apply_size <= sizeof(raw_apply));
MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size);
S64 apply = extend_sign64(raw_apply, apply_size);
if (reloc->isymbol > symbols.count) {
rd_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx);
break;
}
COFF_Symbol32 *symbol = symbols.v+reloc->isymbol;
String8 symbol_name = coff_read_symbol_name(string_table, &symbol->name);
String8List line = {0};
str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx );
str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off);
str8_list_pushf(scratch.arena, &line, "%-16S", type );
str8_list_pushf(scratch.arena, &line, "%016x", apply );
str8_list_pushf(scratch.arena, &line, "%S", symbol_name );
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")});
rd_printf("%S", l);
}
rd_unindent();
}
}
if (!print_header) {
rd_unindent();
}
rd_newline();
scratch_end(scratch);
}
internal void
coff_print_symbol_table(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
B32 is_big_obj,
String8 string_table,
COFF_Symbol32Array symbols)
{
Temp scratch = scratch_begin(&arena, 1);
if (symbols.count) {
rd_printf("# Symbol Table");
rd_indent();
rd_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s",
"No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name");
for (U64 i = 0; i < symbols.count; ++i) {
COFF_Symbol32 *symbol = &symbols.v[i];
String8 name = coff_read_symbol_name(string_table, &symbol->name);
String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb);
String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb);
String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class);
String8 section_number;
switch (symbol->section_number) {
case COFF_Symbol_UndefinedSection: section_number = str8_lit("Undef"); break;
case COFF_Symbol_AbsSection32: section_number = str8_lit("Abs"); break;
case COFF_Symbol_DebugSection32: section_number = str8_lit("Debug"); break;
default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break;
}
String8List line = {0};
str8_list_pushf(scratch.arena, &line, "%-4x", i );
str8_list_pushf(scratch.arena, &line, "%08x", symbol->value );
str8_list_pushf(scratch.arena, &line, "%-10S", section_number );
str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count);
str8_list_pushf(scratch.arena, &line, "%-4S", msb );
str8_list_pushf(scratch.arena, &line, "%-4S", lsb );
str8_list_pushf(scratch.arena, &line, "%-16S", storage_class );
str8_list_pushf(scratch.arena, &line, "%S", name );
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")});
rd_printf("%S", l);
rd_indent();
for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) {
void *raw_aux = &symbols.v[k];
switch (symbol->storage_class) {
case COFF_SymStorageClass_External: {
COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k];
rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x",
func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func);
} break;
case COFF_SymStorageClass_Function: {
COFF_SymbolFunc *func = raw_aux;
rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func);
} break;
case COFF_SymStorageClass_WeakExternal: {
COFF_SymbolWeakExt *weak = raw_aux;
String8 type = coff_string_from_weak_ext_type(weak->characteristics);
rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type);
} break;
case COFF_SymStorageClass_File: {
COFF_SymbolFile *file = raw_aux;
String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name));
rd_printf("Name %S", name);
} break;
case COFF_SymStorageClass_Static: {
COFF_SymbolSecDef *sd = raw_aux;
String8 selection = coff_string_from_comdat_select_type(sd->selection);
U32 number = sd->number_lo;
if (is_big_obj) {
number |= (U32)sd->number_hi << 16;
}
if (number) {
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S",
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection);
} else {
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x",
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum);
}
} break;
default: {
rd_printf("???");
} break;
}
}
i += symbol->aux_symbol_count;
rd_unindent();
}
rd_unindent();
rd_newline();
}
scratch_end(scratch);
}
internal void
coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header)
{
Temp scratch = scratch_begin(&arena, 1);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
String8 machine = coff_string_from_machine_type(header->machine);
rd_printf("# Big Obj");
rd_indent();
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp);
rd_printf("Machine : %#x (%S)", header->machine, machine );
rd_printf("Section Count: %u", header->section_count );
rd_printf("Symbol Table : %#x", header->symbol_table_foff);
rd_printf("Symbol Count : %u", header->symbol_count );
rd_unindent();
scratch_end(scratch);
}
internal void
coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header)
{
Temp scratch = scratch_begin(&arena, 1);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
String8 machine = coff_string_from_machine_type(header->machine);
String8 flags = coff_string_from_flags(scratch.arena, header->flags);
rd_printf("# COFF File Header");
rd_indent();
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp );
rd_printf("Machine : %#x %S", header->machine, machine );
rd_printf("Section Count : %u", header->section_count );
rd_printf("Symbol Table : %#x", header->symbol_table_foff );
rd_printf("Symbol Count : %u", header->symbol_count );
rd_printf("Optional Header Size: %#x (%m)", header->optional_header_size, header->optional_header_size);
rd_printf("Flags : %#x (%S)", header->flags, flags );
rd_unindent();
scratch_end(scratch);
}
internal void
coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header)
{
Temp scratch = scratch_begin(&arena, 1);
String8 machine = coff_string_from_machine_type(header->machine);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
rd_printf("# Import");
rd_indent();
rd_printf("Version : %u", header->version );
rd_printf("Machine : %S", machine );
rd_printf("Time Stamp: %#x (%S)", header->time_stamp, time_stamp );
rd_printf("Data Size : %#x (%m)", header->data_size, header->data_size);
rd_printf("Hint : %u", header->hint_or_ordinal);
rd_printf("Type : %u", header->type );
rd_printf("Import By : %u", header->import_by );
rd_printf("Function : %S", header->func_name );
rd_printf("DLL : %S", header->dll_name );
rd_unindent();
scratch_end(scratch);
}
internal void
coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
String8 raw_header = str8_substr(raw_data, header_info.header_range);
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
COFF_BigObjHeader *big_obj = (COFF_BigObjHeader *)raw_header.str;
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_32(scratch.arena, raw_data, header_info.symbol_table_range.min, big_obj->symbol_count);
if (opts & RD_Option_Headers) {
coff_print_big_obj_header(arena, out, indent, big_obj);
rd_newline();
}
if (opts & RD_Option_Sections) {
Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count);
Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count);
if (sect_headers_range.max > raw_data.size) {
rd_errorf("not enough bytes to read big obj section headers");
goto exit;
}
if (big_obj->symbol_count) {
if (symbols_range.max > raw_data.size) {
rd_errorf("not enough bytes to read big obj symbol table");
goto exit;
}
if (contains_1u64(symbols_range, sect_headers_range.min) ||
contains_1u64(symbols_range, sect_headers_range.max)) {
rd_errorf("section headers and symbol table ranges overlap");
goto exit;
}
}
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, big_obj->section_count, section_table);
rd_newline();
}
if (opts & RD_Option_Relocs) {
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, big_obj->machine, big_obj->section_count, section_table, symbol_table);
rd_newline();
}
if (opts & RD_Option_Symbols) {
coff_print_symbol_table(arena, out, indent, raw_data, 1, raw_string_table, symbol_table);
rd_newline();
}
exit:;
scratch_end(scratch);
}
internal void
coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
String8 raw_header = str8_substr(raw_data, header_info.header_range);
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
COFF_FileHeader *header = (COFF_FileHeader *)raw_header.str;
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_16(scratch.arena, raw_data, header_info.symbol_table_range.min, header->symbol_count);
Arch arch = arch_from_coff_machine(header->machine);
if (opts & RD_Option_Headers) {
coff_print_file_header(arena, out, indent, header);
rd_newline();
}
if (opts & RD_Option_Sections) {
Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count);
Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count);
if (sect_headers_range.max > raw_data.size) {
rd_errorf("not enough bytes to read obj section headers");
goto exit;
}
if (header->symbol_count) {
if (symbols_range.max > raw_data.size) {
rd_errorf("not enough bytes to read obj symbol table");
goto exit;
}
if (contains_1u64(symbols_range, sect_headers_range.min) ||
contains_1u64(symbols_range, sect_headers_range.max)) {
rd_errorf("section headers and symbol table ranges overlap");
goto exit;
}
}
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, header->section_count, section_table);
rd_newline();
}
if (opts & RD_Option_Relocs) {
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, header->machine, header->section_count, section_table, symbol_table);
rd_newline();
}
if (opts & RD_Option_Symbols) {
coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbol_table);
rd_newline();
}
RD_MarkerArray *section_markers = 0;
if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) {
section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, header->section_count, symbol_table);
}
if (opts & RD_Option_Rawdata) {
coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, section_table);
}
if (opts & RD_Option_Disasm) {
coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, section_table);
rd_newline();
}
if (opts & RD_Option_Codeview) {
cv_format_debug_sections(arena, out, indent, raw_data, raw_string_table, header->section_count, section_table);
}
if (opts & RD_Option_Dwarf) {
DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
dw_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
}
exit:;
scratch_end(scratch);
}
internal void
coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive);
if (archive_parse.error.size) {
rd_errorf("%S", archive_parse.error);
return;
}
COFF_ArchiveFirstMember first_member = archive_parse.first_member;
{
rd_printf("# First Header");
rd_indent();
rd_printf("Symbol Count : %u", first_member.symbol_count);
rd_printf("String Table Size: %#llx (%M)", first_member.string_table.size, first_member.string_table.size);
rd_printf("Members:");
rd_indent();
String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0);
if (string_table.node_count == first_member.member_offset_count) {
String8Node *string_n = string_table.first;
for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) {
U32 offset = from_be_u32(first_member.member_offsets[i]);
rd_printf("[%4u] %#08x %S", i, offset, string_n->string);
}
} else {
rd_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count);
}
rd_unindent();
rd_unindent();
rd_newline();
}
if (archive_parse.has_second_header) {
COFF_ArchiveSecondMember second_member = archive_parse.second_member;
rd_printf("# Second Header");
rd_indent();
rd_printf("Member Count : %u", second_member.member_count);
rd_printf("Symbol Count : %u", second_member.symbol_count);
rd_printf("String Table Size: %#llx (%M)", second_member.string_table.size, second_member.string_table.size);
String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0);
rd_printf("Members:");
rd_indent();
if (second_member.symbol_index_count == second_member.symbol_count) {
String8Node *string_n = string_table.first;
for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) {
U16 symbol_number = second_member.symbol_indices[i];
if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) {
U16 symbol_idx = symbol_number - 1;
U32 member_offset = second_member.member_offsets[i];
rd_printf("[%4u] %#08x %S", i, member_offset, string_n->string);
} else {
rd_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number);
break;
}
}
} else {
rd_errorf("Symbol index count %u doesn't match symbol count %u",
second_member.symbol_index_count, second_member.symbol_count);
}
rd_unindent();
rd_unindent();
rd_newline();
}
if (archive_parse.has_long_names && opts & RD_Option_LongNames) {
rd_printf("# Long Names");
rd_indent();
String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0);
U64 name_idx = 0;
for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) {
U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str);
rd_printf("[%-4u] %#08x %S", name_idx, offset, name_n->string);
}
rd_unindent();
rd_newline();
}
U64 member_offset_count = 0;
U32 *member_offsets = 0;
if (archive_parse.has_second_header) {
member_offset_count = archive_parse.second_member.member_offset_count;
member_offsets = archive_parse.second_member.member_offsets;
} else {
HashTable *ht = hash_table_init(scratch.arena, 0x1000);
for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) {
U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]);
if (!hash_table_search_u32(ht, member_offset)) {
hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0);
}
}
member_offset_count = ht->count;
member_offsets = keys_from_hash_table_u32(scratch.arena, ht);
radsort(member_offsets, member_offset_count, u32_is_before);
}
rd_printf("# Members");
rd_indent();
for (U64 i = 0; i < member_offset_count; ++i) {
U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size;
U64 member_offset = member_offsets[i];
String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset));
COFF_ArchiveMember member = coff_archive_member_from_data(raw_member);
COFF_DataType member_type = coff_data_type_from_data(member.data);
rd_printf("Member @ %#llx", member_offset);
rd_indent();
if (opts & RD_Option_Headers) {
coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names);
rd_newline();
}
switch (member_type) {
case COFF_DataType_Obj: {
coff_print_obj(arena, out, indent, member.data, opts);
} break;
case COFF_DataType_BigObj: {
coff_print_big_obj(arena, out, indent, member.data, opts);
} break;
case COFF_DataType_Import: {
if (opts & RD_Option_Headers) {
COFF_ParsedArchiveImportHeader header = {0};
U64 parse_size = coff_parse_import(member.data, 0, &header);
if (parse_size) {
coff_print_import(arena, out, indent, &header);
} else {
rd_errorf("not enough bytes to parse import header");
}
}
} break;
case COFF_DataType_Null: {
rd_errorf("unknown member format", member_offset);
} break;
}
rd_unindent();
rd_newline();
}
rd_unindent();
scratch_end(scratch);
}
#endif
-22
View File
@@ -1,22 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_DUMP_H
#define COFF_DUMP_H
#if 0
internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names);
internal void coff_print_section_table (Arena *arena, String8List *out, String8 indent, String8 string_table, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers);
internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 string_table, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols);
internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, String8 string_table, COFF_Symbol32Array symbols);
internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header);
internal void coff_print_file_header (Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header);
internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header);
internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts);
#endif
#endif // COFF_DUMP_H
-1
View File
@@ -1 +0,0 @@
-6
View File
@@ -1,6 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "coff/coff.c"
#include "coff/coff_parse.c"
#include "coff/coff_dump.c"
-11
View File
@@ -1,11 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_INC_H
#define COFF_INC_H
#include "coff/coff.h"
#include "coff/coff_parse.h"
#include "coff/coff_dump.h"
#endif // COFF_INC_H
-387
View File
@@ -1,387 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal COFF_LibWriterSymbolNode *
coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol)
{
COFF_LibWriterSymbolNode *node = push_array_no_zero(arena, COFF_LibWriterSymbolNode, 1);
node->next = 0;
node->data = symbol;
SLLQueuePush(list->first, list->last, node);
list->count += 1;
return node;
}
internal COFF_LibWriterMemberNode *
coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member)
{
COFF_LibWriterMemberNode *node = push_array_no_zero(arena, COFF_LibWriterMemberNode, 1);
node->next = 0;
node->data = member;
SLLQueuePush(list->first, list->last, node);
list->count += 1;
return node;
}
internal COFF_LibWriterSymbol *
coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list)
{
COFF_LibWriterSymbol *arr = push_array_no_zero(arena, COFF_LibWriterSymbol, list.count + 2);
COFF_LibWriterSymbol *ptr = arr + 1;
for (COFF_LibWriterSymbolNode *i = list.first; i != 0; i = i->next, ptr += 1) {
*ptr = i->data;
}
MemoryZeroStruct(&arr[0]);
MemoryZeroStruct(&arr[list.count+1]);
return arr;
}
internal COFF_LibWriterMember *
coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list)
{
COFF_LibWriterMember *arr = push_array_no_zero(arena, COFF_LibWriterMember, list.count);
COFF_LibWriterMember *ptr = arr;
for (COFF_LibWriterMemberNode *i = list.first; i != 0; i = i->next, ptr += 1) {
ptr->name = push_str8_copy(arena, i->data.name);
ptr->data = push_str8_copy(arena, i->data.data);
}
return arr;
}
internal int
coff_lib_writer_symbol_name_compar(const void *raw_a, const void *raw_b)
{
const COFF_LibWriterSymbol *sa = raw_a;
const COFF_LibWriterSymbol *sb = raw_b;
return str8_compar_case_sensitive(&sa->name, &sb->name);
}
internal int
coff_lib_writer_symbol_is_before_name(void *raw_a, void *raw_b)
{
return coff_lib_writer_symbol_name_compar(raw_a, raw_b) < 0;
}
internal int
coff_lib_writer_symbol_is_before_member_idx(void *raw_a, void *raw_b)
{
COFF_LibWriterSymbol *a = raw_a, *b = raw_b;
return a->member_idx < b->member_idx;
}
internal void
coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count)
{
Assert(count >= 2);
radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_name);
}
internal void
coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count)
{
Assert(count >= 2);
radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_member_idx);
}
internal COFF_LibWriter *
coff_lib_writer_alloc(void)
{
Arena *arena = arena_alloc();
COFF_LibWriter *writer = push_array(arena, COFF_LibWriter, 1);
writer->arena = arena;
return writer;
}
internal void
coff_lib_writer_release(COFF_LibWriter **writer_ptr)
{
arena_release((*writer_ptr)->arena);
*writer_ptr = 0;
}
internal U64
coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data)
{
U64 member_idx = writer->member_list.count;
// push obj member
COFF_LibWriterMember member = { .name = obj_path, .data = obj_data };
COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member);
// push external symbols
COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data);
String8 string_table = str8_substr(obj_data, obj_header.string_table_range);
String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range);
COFF_ParsedSymbol symbol;
for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
symbol = coff_parse_symbol(obj_header, string_table, symbol_table, symbol_idx);
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) {
if (symbol.storage_class == COFF_SymStorageClass_External) {
COFF_LibWriterSymbol lib_symbol = { .name = symbol.name, .member_idx = member_idx };
coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol);
}
}
}
return member_idx;
}
internal void
coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type)
{
U64 member_idx = lib_writer->member_list.count;
String8 member_data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type);
COFF_LibWriterMember member = { .name = dll_name, .data = member_data };
COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member);
if (name.size) {
switch (import_type) {
case COFF_ImportHeader_Code: {
COFF_LibWriterSymbol thunk_symbol = {0};
thunk_symbol.name = push_str8_copy(lib_writer->arena, name);
thunk_symbol.member_idx = member_idx;
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, thunk_symbol);
COFF_LibWriterSymbol imp_symbol = {0};
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
imp_symbol.member_idx = member_idx;
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
} break;
case COFF_ImportHeader_Data: {
COFF_LibWriterSymbol imp_symbol = {0};
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
imp_symbol.member_idx = member_idx;
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
} break;
case COFF_ImportHeader_Const: { NotImplemented; } break;
default: { InvalidPath; } break;
}
}
}
internal String8
coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member)
{
Temp scratch = scratch_begin(&arena, 1);
// member lists -> arrays
U64 member_count = lib_writer->member_list.count;
COFF_LibWriterMember *member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list);
// serialize members
U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count);
String8List long_names_list = {0};
String8List member_data_list = {0};
{
HashTable *name_ht = hash_table_init(scratch.arena, 1024);
for EachIndex(member_idx, member_count) {
COFF_LibWriterMember *member = &member_array[member_idx];
// make member name
String8 name;
U64 name_with_slash_size = member->name.size + 1;
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
// have we seen this member name before?
KeyValuePair *is_present = hash_table_search_string(name_ht, member->name);
if (is_present) {
name = is_present->value_string;
} else {
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
}
} else {
name = push_str8f(scratch.arena, "%S/", member->name);
}
member_offsets[member_idx] = member_data_list.total_size;
String8 member_data = member->data;
String8 member_header = coff_make_lib_member_header(scratch.arena, name, time_stamp, 0, 0, mode, member_data.size);
str8_list_push(scratch.arena, &member_data_list, member_header);
str8_list_push(scratch.arena, &member_data_list, member_data);
{
U64 pad_size = AlignPadPow2(member_data_list.total_size, COFF_Archive_MemberAlign);
U8 *pad = push_array(scratch.arena, U8, pad_size);
str8_list_push(scratch.arena, &member_data_list, str8(pad, pad_size));
}
}
}
// write long names member
if (long_names_list.total_size) {
String8 header = coff_make_lib_member_header(scratch.arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size);
String8 data = str8_list_join(scratch.arena, &long_names_list, 0);
U64 member_offset = member_data_list.total_size + data.size + header.size;
{
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
U8 *pad = push_array(scratch.arena, U8, pad_size);
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
}
str8_list_push_front(scratch.arena, &member_data_list, data);
str8_list_push_front(scratch.arena, &member_data_list, header);
}
// compute size for symbol string table
U32 name_buffer_size = 0;
for (COFF_LibWriterSymbolNode *node = lib_writer->symbol_list.first; node != 0; node = node->next) {
name_buffer_size += node->data.name.size;
name_buffer_size += 1; // null
}
// compute members base offset
U64 members_base_offset;
{
U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * lib_writer->symbol_list.count + name_buffer_size;
U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * lib_writer->symbol_list.count + name_buffer_size;
U64 sizeof_long_names = sizeof(COFF_ArchiveMemberHeader) + long_names_list.total_size;
sizeof_first_header = AlignPow2(sizeof_first_header, COFF_Archive_MemberAlign);
sizeof_second_header = AlignPow2(sizeof_second_header, COFF_Archive_MemberAlign);
sizeof_long_names = AlignPow2(sizeof_long_names, COFF_Archive_MemberAlign);
members_base_offset = sizeof(g_coff_archive_sig);
members_base_offset += sizeof_first_header;
if (emit_second_member) {
members_base_offset += sizeof_second_header;
}
if (long_names_list.total_size) {
members_base_offset += sizeof_long_names;
}
}
// write second linker member
if (emit_second_member) {
U64 symbols_count;
COFF_LibWriterSymbol *symbols;
{
U64 symbols_count_with_null = lib_writer->symbol_list.count + 2;
COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list);
coff_lib_writer_symbol_array_sort_on_name(symbols_with_null, symbols_count_with_null);
symbols_count = symbols_count_with_null - 2;
symbols = symbols_with_null + 1;
}
// write symbol name buffer
U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size);
{
U64 name_cursor = 0;
for EachIndex(symbol_idx, symbols_count) {
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size);
name_buffer[name_cursor + symbol->name.size] = '\0';
name_cursor += symbol->name.size + 1;
}
}
U32 member_count32 = safe_cast_u32(member_count);
U32 symbol_count32 = safe_cast_u32(symbols_count);
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, member_count);
U16 *member_idx16_arr = push_array_no_zero(scratch.arena, U16, symbols_count);
// write member offset array
for EachIndex(member_idx, member_count) {
U64 member_offset = members_base_offset + member_offsets[member_idx];
U32 member_off32 = safe_cast_u32(member_offset);
member_off32_arr[member_idx] = member_off32;
}
// write member offset indices for each symbol
for EachIndex(symbol_idx, symbols_count) {
// member offset indices are 1-based
U64 member_idx = symbols[symbol_idx].member_idx + 1;
U16 member_idx16 = safe_cast_u16(member_idx);
member_idx16_arr[symbol_idx] = member_idx16;
}
// layout second member data
String8List second_member_data_list = {0};
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&member_count32));
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_off32_arr, member_count));
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&symbol_count32));
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_idx16_arr, symbols_count));
str8_list_push(scratch.arena, &second_member_data_list, str8(name_buffer, name_buffer_size));
String8 member_data = str8_list_join(scratch.arena, &second_member_data_list, 0);
String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
U64 member_offset = member_data_list.total_size + member_data.size + member_header.size;
{
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
U8 *pad = push_array(scratch.arena, U8, pad_size);
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
}
str8_list_push_front(scratch.arena, &member_data_list, member_data);
str8_list_push_front(scratch.arena, &member_data_list, member_header);
}
// write first linker member (obsolete, but kept for compatability reasons)
{
U64 symbols_count;
COFF_LibWriterSymbol *symbols;
{
U64 symbols_count_with_null = lib_writer->symbol_list.count + 2;
COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list);
coff_lib_writer_symbol_array_sort_on_member_idx(symbols_with_null, symbols_count_with_null);
symbols_count = symbols_count_with_null - 2;
symbols = symbols_with_null + 1;
}
// write symbol name buffer
U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size);
{
U64 name_cursor = 0;
for EachIndex(symbol_idx, symbols_count) {
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size);
name_buffer[name_cursor + symbol->name.size] = '\0';
name_cursor += symbol->name.size + 1;
}
}
U32 symbol_count_be = from_be_u32(symbols_count);
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, symbols_count);
for EachIndex(symbol_idx, symbols_count) {
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
// write big endian member offset
U64 member_offset = members_base_offset + member_offsets[symbol->member_idx];
U32 member_off32 = from_be_u32(safe_cast_u32(member_offset));
member_off32_arr[symbol_idx] = member_off32;
}
// layout first member data
String8List first_member_data_list = {0};
str8_list_push(scratch.arena, &first_member_data_list, str8_struct(&symbol_count_be));
str8_list_push(scratch.arena, &first_member_data_list, str8_array(member_off32_arr, symbols_count));
str8_list_push(scratch.arena, &first_member_data_list, str8(name_buffer, name_buffer_size));
String8 member_data = str8_list_join(scratch.arena, &first_member_data_list, 0);
String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
U64 member_offset = sizeof(g_coff_archive_sig) + member_header.size + member_data.size;
{
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
U8 *pad = push_array(scratch.arena, U8, pad_size);
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
}
str8_list_push_front(scratch.arena, &member_data_list, member_data);
str8_list_push_front(scratch.arena, &member_data_list, member_header);
}
// archive signature
str8_list_push_front(scratch.arena, &member_data_list, str8_struct(&g_coff_archive_sig));
String8 raw_lib = str8_list_join(arena, &member_data_list, 0);
scratch_end(scratch);
return raw_lib;
}
-70
View File
@@ -1,70 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_LIB_WRITER_H
#define COFF_LIB_WRITER_H
typedef struct COFF_LibWriterMember
{
String8 name;
String8 data;
} COFF_LibWriterMember;
typedef struct COFF_LibWriterMemberNode
{
COFF_LibWriterMember data;
struct COFF_LibWriterMemberNode *next;
} COFF_LibWriterMemberNode;
typedef struct COFF_LibWriterMemberList
{
U64 count;
COFF_LibWriterMemberNode *first;
COFF_LibWriterMemberNode *last;
} COFF_LibWriterMemberList;
typedef struct COFF_LibWriterSymbol
{
String8 name;
U64 member_idx;
} COFF_LibWriterSymbol;
typedef struct COFF_LibWriterSymbolNode
{
COFF_LibWriterSymbol data;
struct COFF_LibWriterSymbolNode *next;
} COFF_LibWriterSymbolNode;
typedef struct COFF_LibWriterSymbolList
{
U64 count;
COFF_LibWriterSymbolNode *first;
COFF_LibWriterSymbolNode *last;
} COFF_LibWriterSymbolList;
typedef struct COFF_LibWriter
{
Arena *arena;
COFF_LibWriterMemberList member_list;
COFF_LibWriterSymbolList symbol_list;
} COFF_LibWriter;
////////////////////////////////
internal COFF_LibWriterSymbolNode * coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol);
internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member);
internal COFF_LibWriterSymbol * coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list);
internal COFF_LibWriterMember * coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list);
internal void coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count);
internal void coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count);
internal COFF_LibWriter * coff_lib_writer_alloc(void);
internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr);
internal U64 coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data);
internal void coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type);
internal String8 coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member);
#endif // COFF_LIB_WRITER_H
-500
View File
@@ -1,500 +0,0 @@
internal COFF_ObjWriter*
coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine)
{
Arena *arena = arena_alloc();
COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1);
obj_writer->arena = arena;
obj_writer->time_stamp = time_stamp;
obj_writer->machine = machine;
return obj_writer;
}
internal void
coff_obj_writer_release(COFF_ObjWriter **obj_writer)
{
arena_release((*obj_writer)->arena);
*obj_writer = 0;
}
internal String8
coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer)
{
Temp scratch = scratch_begin(&arena, 1);
String8List srl = {0};
String8List string_table = {0};
U32 *string_table_size = push_array(scratch.arena, U32, 1);
*string_table_size = sizeof(*string_table_size);
str8_list_push(scratch.arena, &string_table, str8_struct(string_table_size));
//
// assing section numbers
//
U64 obj_sections_count;
COFF_ObjSection **obj_sections;
{
obj_sections_count = obj_writer->sect_count;
obj_sections = push_array(scratch.arena, COFF_ObjSection *, obj_writer->sect_count);
U64 sect_idx = 0;
for (COFF_ObjSectionNode *sect_n = obj_writer->sect_first; sect_n != 0; sect_n = sect_n->next, sect_idx += 1) {
COFF_ObjSection *sect = &sect_n->v;
sect->section_number = sect_idx+1;
obj_sections[sect_idx] = sect;
}
}
AssertAlways(obj_sections_count <= max_U16);
//
// serialize symbol table
//
String8List symbol_table = {0};
{
{
U64 symbol_idx = 0;
for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) {
COFF_ObjSymbol *s = &symbol_n->v;
// assign symbol index
s->idx = symbol_idx++;
symbol_idx += s->aux_symbols.node_count;
}
}
U64 symbol_idx = 0;
for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) {
COFF_ObjSymbol *s = &symbol_n->v;
COFF_Symbol16 *d = push_array(scratch.arena, COFF_Symbol16, 1);
str8_list_push(scratch.arena, &symbol_table, str8_struct(d));
COFF_SymbolName name = {0};
// long name
if (s->name.size > sizeof(name.short_name)) {
U64 string_table_offset = string_table.total_size;
str8_list_push(scratch.arena, &string_table, s->name);
str8_list_push(scratch.arena, &string_table, str8_lit("\0"));
name.long_name.zeroes = 0;
name.long_name.string_table_offset = safe_cast_u32(string_table_offset);
}
// short name
else {
MemoryCopyStr8(name.short_name, s->name);
MemoryZeroTyped(name.short_name + s->name.size, sizeof(name.short_name) - s->name.size);
}
// symbol header
AssertAlways(s->aux_symbols.node_count <= max_U8);
d->name = name;
d->value = s->value;
switch (s->loc.type) {
case COFF_SymbolLocation_Null: break;
case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break;
case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break;
case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break;
case COFF_SymbolLocation_Common: d->section_number = COFF_Symbol_UndefinedSection; break;
}
d->type = s->type;
d->storage_class = s->storage_class;
d->aux_symbol_count = 0;
U64 start_symbol_idx = symbol_idx;
if (s->storage_class == COFF_SymStorageClass_WeakExternal) {
if (s->aux_symbols.node_count > 0) {
COFF_ObjSymbolWeak *s_weak = (COFF_ObjSymbolWeak *)s->aux_symbols.first->string.str;
COFF_SymbolWeakExt *d_weak = push_array(scratch.arena, COFF_SymbolWeakExt, 1);
d_weak->tag_index = s_weak->tag ? s_weak->tag->idx : max_U32;
d_weak->characteristics = s_weak->characteristics;
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_weak));
symbol_idx += 1;
}
} else if (s->storage_class == COFF_SymStorageClass_Static) {
if (s->aux_symbols.node_count > 0) {
Assert(s->loc.type == COFF_SymbolLocation_Section);
COFF_ObjSection *sect = s->loc.u.section;
COFF_ObjSymbolSecDef *s_sd = (COFF_ObjSymbolSecDef *)s->aux_symbols.first->string.str;
COFF_SymbolSecDef *d_sd = push_array(scratch.arena, COFF_SymbolSecDef, 1);
d_sd->length = safe_cast_u32(sect->data.total_size);
d_sd->number_of_relocations = (U16)sect->reloc_count;
d_sd->check_sum = 0;
d_sd->number_lo = s_sd->selection == COFF_ComdatSelect_Associative ? safe_cast_u16(s_sd->associate->section_number) : 0;
d_sd->selection = s_sd->selection;
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_sd));
symbol_idx += 1;
}
}
U8 processed_aux_symbol_count = (U8)(symbol_idx - start_symbol_idx);
for (U64 aux_idx = processed_aux_symbol_count; aux_idx < s->aux_symbols.node_count; aux_idx += 1) {
COFF_Symbol16 *a = push_array(scratch.arena, COFF_Symbol16, 1);
str8_list_push(scratch.arena, &symbol_table, str8_struct(a));
}
d->aux_symbol_count = (U8)s->aux_symbols.node_count;
}
}
//
// file header
//
COFF_FileHeader *file_header = push_array(scratch.arena, COFF_FileHeader, 1);
file_header->machine = obj_writer->machine;
file_header->section_count = obj_sections_count;
file_header->time_stamp = obj_writer->time_stamp;
file_header->symbol_table_foff = 0;
file_header->symbol_count = safe_cast_u32(symbol_table.node_count);
file_header->optional_header_size = 0;
file_header->flags = 0;
str8_list_push(scratch.arena, &srl, str8_struct(file_header));
//
// section table
//
COFF_SectionHeader *sectab = push_array(scratch.arena, COFF_SectionHeader, obj_sections_count);
str8_list_push(scratch.arena, &srl, str8_array(sectab, obj_sections_count));
{
for (U64 sect_idx = 0; sect_idx < obj_sections_count; sect_idx += 1) {
COFF_ObjSection *s = obj_sections[sect_idx];
COFF_SectionHeader *d = &sectab[sect_idx];
// section name
String8 sect_name = s->name;
if (sect_name.size > sizeof(d->name)) {
U64 sect_name_off = string_table.total_size;
str8_list_push(scratch.arena, &string_table, push_cstr(scratch.arena, sect_name));
sect_name = push_str8f(scratch.arena, "/%u", sect_name_off);
AssertAlways(sect_name.size <= sizeof(d->name));
}
// alloc zero nodes
for (String8Node *data_n = s->data.first; data_n != 0; data_n = data_n->next) {
if (data_n->string.str == 0 && data_n->string.size > 0) {
data_n->string = str8(push_array(scratch.arena, U8, data_n->string.size), data_n->string.size);
}
}
// section data
U64 data_foff = 0;
U64 data_size = 0;
if (s->data.total_size > 0) {
data_foff = srl.total_size;
data_size = s->data.total_size;
str8_list_concat_in_place(&srl, &s->data);
}
// section relocs
U64 relocs_foff = 0;
if (s->reloc_count) {
AssertAlways(s->reloc_count <= max_U16);
COFF_Reloc *relocs = push_array(scratch.arena, COFF_Reloc, s->reloc_count);
U64 reloc_idx = 0;
for (COFF_ObjRelocNode *reloc_n = s->reloc_first; reloc_n != 0; reloc_n = reloc_n->next, reloc_idx += 1) {
COFF_ObjReloc *rs = &reloc_n->v;
COFF_Reloc *rd = &relocs[reloc_idx];
rd->apply_off = rs->apply_off;
rd->isymbol = rs->symbol->idx;
rd->type = rs->type;
}
relocs_foff = srl.total_size;
str8_list_push(scratch.arena, &srl, str8_array(relocs, s->reloc_count));
}
// section header
MemoryCopyStr8(d->name, sect_name);
MemoryZeroTyped(d->name + sect_name.size, sizeof(d->name) - sect_name.size);
d->vsize = 0;
d->voff = 0;
d->fsize = data_size;
d->foff = data_foff;
d->relocs_foff = relocs_foff;
d->lines_foff = 0;
d->reloc_count = safe_cast_u32(s->reloc_count);
d->line_count = 0;
d->flags = s->flags;
}
}
//
// symbol table
//
if (symbol_table.total_size || string_table.total_size > sizeof(*string_table_size)) {
file_header->symbol_table_foff = srl.total_size;
str8_list_concat_in_place(&srl, &symbol_table);
}
//
// string table
//
if (string_table.total_size) {
*string_table_size = safe_cast_u32(string_table.total_size);
str8_list_concat_in_place(&srl, &string_table);
}
//
// join
//
String8 obj = str8_list_join(arena, &srl, 0);
scratch_end(scratch);
return obj;
}
internal COFF_ObjSection *
coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
{
COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
obj_writer->sect_count += 1;
COFF_ObjSection *sect = &sect_n->v;
sect->name = name;
sect->flags = flags;
if (data.size) {
str8_list_push(obj_writer->arena, &sect->data, data);
}
return sect;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class)
{
COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1);
SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n);
obj_writer->symbol_count += 1;
COFF_ObjSymbol *s = &n->v;
s->name = name;
s->value = value;
s->loc = loc;
s->type = type;
s->storage_class = storage_class;
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
{
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Section;
loc.u.section = section;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_External);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
{
COFF_SymbolType type = { .u.msb = COFF_SymDType_Func };
COFF_SymbolLocation loc = { .type = COFF_SymbolLocation_Section, .u.section = section };
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_External);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section)
{
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Section;
loc.u.section = section;
COFF_SymbolType symtype = {0};
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, loc, symtype, COFF_SymStorageClass_Static);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection)
{
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, section->name, 0, section);
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
sd->selection = selection;
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate)
{
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, head->name, 0, head);
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
sd->selection = COFF_ComdatSelect_Associative;
sd->associate = associate;
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag)
{
COFF_SymbolLocation loc = {0};
COFF_SymbolType symtype = {0};
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, COFF_Symbol_UndefinedSection, loc, symtype, COFF_SymStorageClass_WeakExternal);
COFF_ObjSymbolWeak *weak_ext = push_array(obj_writer->arena, COFF_ObjSymbolWeak, 1);
weak_ext->tag = tag;
weak_ext->characteristics = characteristics;
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(weak_ext));
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class)
{
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Abs;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, storage_class);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name)
{
COFF_SymbolType type = {0};
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Undef;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name)
{
COFF_SymbolType type = {0};
type.u.msb = COFF_SymDType_Func;
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Undef;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value)
{
COFF_SymbolType type = {0};
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Undef;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_Section);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect)
{
COFF_SymbolType type = {0};
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Section;
loc.u.section = sect;
// strip align flags
COFF_SectionFlags expected_flags = sect->flags & ~(COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift);
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, expected_flags, loc, type, COFF_SymStorageClass_Section);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size)
{
COFF_SymbolType type = {0};
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Common;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, size, loc, type, COFF_SymStorageClass_External);
return s;
}
internal void
coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol)
{
AssertAlways(weak_symbol->storage_class == COFF_SymStorageClass_WeakExternal);
COFF_ObjSymbolWeak *w = (COFF_ObjSymbolWeak *)weak_symbol->aux_symbols.first->string.str;
w->tag = default_symbol;
}
internal COFF_ObjReloc*
coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType type)
{
COFF_ObjRelocNode *reloc_n = push_array(obj_writer->arena, COFF_ObjRelocNode, 1);
SLLQueuePush(sect->reloc_first, sect->reloc_last, reloc_n);
sect->reloc_count += 1;
COFF_ObjReloc *reloc = &reloc_n->v;
reloc->apply_off = apply_off;
reloc->symbol = symbol;
reloc->type = type;
return reloc;
}
internal COFF_ObjReloc *
coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
{
COFF_RelocType reloc_type = 0;
switch (obj_writer->machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32; break;
default: { NotImplemented; } break;
}
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
}
internal COFF_ObjReloc *
coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
{
COFF_RelocType reloc_type = 0;
switch (obj_writer->machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr64; break;
default: { NotImplemented; } break;
}
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
}
internal COFF_ObjReloc *
coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
{
COFF_RelocType reloc_type = 0;
switch (obj_writer->machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32Nb; break;
default: { NotImplemented; } break;
}
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
}
internal void
coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive)
{
if (obj_writer->drectve_sect == 0) {
local_persist const U8 bom_sig[] = { ' ', ' ', ' ' };
obj_writer->drectve_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".drectve"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove|COFF_SectionFlag_Align1Bytes, str8_array_fixed(bom_sig));
}
String8List *data = &obj_writer->drectve_sect->data;
str8_list_push(obj_writer->arena, data, directive);
str8_list_pushf(obj_writer->arena, data, " ");
}
internal int
coff_obj_section_is_before(void *raw_a, void *raw_b)
{
COFF_ObjSection **a = raw_a;
COFF_ObjSection **b = raw_b;
return (*a)->section_number < (*b)->section_number;
}
-128
View File
@@ -1,128 +0,0 @@
#ifndef COFF_OBJ_WRITER_H
#define COFF_OBJ_WRITER_H
typedef enum
{
COFF_SymbolLocation_Null,
COFF_SymbolLocation_Section,
COFF_SymbolLocation_Abs,
COFF_SymbolLocation_Undef,
COFF_SymbolLocation_Common,
} COFF_SymbolLocationType;
typedef struct COFF_SymbolLocation
{
COFF_SymbolLocationType type;
union {
struct COFF_ObjSection *section;
} u;
} COFF_SymbolLocation;
typedef struct COFF_ObjSymbolWeak
{
struct COFF_ObjSymbol *tag;
COFF_WeakExtType characteristics;
} COFF_ObjSymbolWeak;
typedef struct COFF_ObjSymbolSecDef
{
COFF_ComdatSelectType selection;
struct COFF_ObjSection *associate;
} COFF_ObjSymbolSecDef;
typedef struct COFF_ObjSymbol
{
String8 name;
U32 value;
COFF_SymbolLocation loc;
COFF_SymbolType type;
COFF_SymStorageClass storage_class;
String8List aux_symbols;
U32 idx;
} COFF_ObjSymbol;
typedef struct COFF_ObjSymbolNode
{
struct COFF_ObjSymbolNode *next;
COFF_ObjSymbol v;
} COFF_ObjSymbolNode;
typedef struct COFF_ObjReloc
{
U32 apply_off;
COFF_ObjSymbol *symbol;
COFF_RelocType type;
} COFF_ObjReloc;
typedef struct COFF_ObjRelocNode
{
struct COFF_ObjRelocNode *next;
COFF_ObjReloc v;
} COFF_ObjRelocNode;
typedef struct COFF_ObjSection
{
String8 name;
String8List data;
COFF_SectionFlags flags;
U64 reloc_count;
COFF_ObjRelocNode *reloc_first;
COFF_ObjRelocNode *reloc_last;
U32 section_number;
} COFF_ObjSection;
typedef struct COFF_ObjSectionNode
{
struct COFF_ObjSectionNode *next;
COFF_ObjSection v;
} COFF_ObjSectionNode;
typedef struct COFF_ObjWriter
{
Arena *arena;
COFF_TimeStamp time_stamp;
COFF_MachineType machine;
U64 symbol_count;
COFF_ObjSymbolNode *symbol_first;
COFF_ObjSymbolNode *symbol_last;
U64 sect_count;
COFF_ObjSectionNode *sect_first;
COFF_ObjSectionNode *sect_last;
COFF_ObjSection *drectve_sect;
} COFF_ObjWriter;
////////////////////////////////
internal COFF_ObjWriter * coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer);
internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size);
internal void coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal void coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive);
#endif // COFF_OBJ_WRITER_H
-991
View File
@@ -1,991 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
coff_is_big_obj(String8 raw_coff)
{
B32 is_big_obj = 0;
if (raw_coff.size >= sizeof(COFF_BigObjHeader)) {
COFF_BigObjHeader *file_header32 = (COFF_BigObjHeader*)(raw_coff.str);
is_big_obj = file_header32->sig1 == COFF_MachineType_Unknown &&
file_header32->sig2 == max_U16 &&
file_header32->version >= 2 &&
MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0;
}
return is_big_obj;
}
internal B32
coff_is_obj(String8 raw_coff)
{
B32 is_obj = 0;
if (raw_coff.size >= sizeof(COFF_FileHeader)) {
COFF_FileHeader *header = (COFF_FileHeader*)(raw_coff.str);
// validate machine
B32 is_machine_type_valid = 0;
switch (header->machine) {
case COFF_MachineType_Unknown:
case COFF_MachineType_X86: case COFF_MachineType_X64:
case COFF_MachineType_Am33: case COFF_MachineType_Arm:
case COFF_MachineType_Arm64: case COFF_MachineType_ArmNt:
case COFF_MachineType_Ebc: case COFF_MachineType_Ia64:
case COFF_MachineType_M32R: case COFF_MachineType_Mips16:
case COFF_MachineType_MipsFpu:case COFF_MachineType_MipsFpu16:
case COFF_MachineType_PowerPc:case COFF_MachineType_PowerPcFp:
case COFF_MachineType_R4000: case COFF_MachineType_RiscV32:
case COFF_MachineType_RiscV64:case COFF_MachineType_RiscV128:
case COFF_MachineType_Sh3: case COFF_MachineType_Sh3Dsp:
case COFF_MachineType_Sh4: case COFF_MachineType_Sh5:
case COFF_MachineType_Thumb: case COFF_MachineType_WceMipsV2:
{
is_machine_type_valid = 1;
}break;
}
if (is_machine_type_valid) {
// validate section count
U64 section_count = header->section_count;
U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader);
if (raw_coff.size >= section_hdr_opl_off) {
COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(raw_coff.str + sizeof(*header));
COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count;
// validate section ranges
B32 is_sect_range_valid = 1;
for (COFF_SectionHeader *sec_hdr = section_hdrs;
sec_hdr < section_hdr_opl;
sec_hdr += 1) {
if (!(sec_hdr->flags & COFF_SectionFlag_CntUninitializedData)) {
U64 min = sec_hdr->foff;
U64 max = min + sec_hdr->fsize;
if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= raw_coff.size)) {
is_sect_range_valid = 0;
break;
}
}
}
if (is_sect_range_valid) {
// validate symbol table
U64 symbol_table_off = header->symbol_table_foff;
U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count;
U64 symbol_table_opl_off = symbol_table_off + symbol_table_size;
// don't validate symbol table when there is none
if (symbol_table_off == 0 && symbol_table_size == 0) {
symbol_table_off = section_hdr_opl_off;
symbol_table_opl_off = section_hdr_opl_off;
}
is_obj = (section_hdr_opl_off <= symbol_table_off &&
symbol_table_off <= symbol_table_opl_off &&
symbol_table_opl_off <= raw_coff.size);
}
}
}
}
return is_obj;
}
internal COFF_FileHeaderInfo
coff_file_header_info_from_data(String8 raw_coff)
{
COFF_FileHeaderInfo info = {0};
if (coff_is_big_obj(raw_coff)) {
COFF_BigObjHeader *header32 = (COFF_BigObjHeader*)raw_coff.str;
info.is_big_obj = 1;
info.machine = header32->machine;
info.section_count_no_null = header32->section_count;
info.symbol_count = header32->symbol_count;
info.symbol_size = sizeof(COFF_Symbol32);
info.header_range = rng_1u64(0, sizeof(COFF_BigObjHeader));
info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header32->section_count);
info.symbol_table_range = rng_1u64(header32->symbol_table_foff, header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count);
info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size);
} else if (coff_is_obj(raw_coff)) {
COFF_FileHeader *header16 = (COFF_FileHeader*)raw_coff.str;
info.is_big_obj = 0;
info.machine = header16->machine;
info.section_count_no_null = header16->section_count;
info.symbol_count = header16->symbol_count;
info.symbol_size = sizeof(COFF_Symbol16);
info.header_range = rng_1u64(0, sizeof(COFF_FileHeader));
info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header16->section_count);
info.symbol_table_range = rng_1u64(header16->symbol_table_foff, header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count);
info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size);
}
return info;
}
internal COFF_SectionHeader **
coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range)
{
U64 section_count = dim_1u64(section_table_range) / sizeof(COFF_SectionHeader);
COFF_SectionHeader **section_table = push_array_no_zero(arena, COFF_SectionHeader *, section_count+1);
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
for (U64 i = 0; i < section_count; ++i) {
section_table[i+1] = str8_deserial_get_raw_ptr(data, section_table_range.min + i*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
}
return section_table;
}
internal COFF_ParsedSymbol
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
{
COFF_ParsedSymbol result = {0};
result.name = coff_read_symbol_name(string_table, &sym32->name);
result.value = sym32->value;
result.section_number = sym32->section_number;
result.type = sym32->type;
result.storage_class = sym32->storage_class;
result.aux_symbol_count = sym32->aux_symbol_count;
result.raw_symbol = sym32;
return result;
}
internal COFF_ParsedSymbol
coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
{
COFF_ParsedSymbol result = {0};
result.name = coff_read_symbol_name(string_table, &sym16->name);
result.value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) {
result.section_number = COFF_Symbol_DebugSection32;
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
result.section_number = COFF_Symbol_AbsSection32;
} else {
result.section_number = (U32)sym16->section_number;
}
result.type = sym16->type;
result.storage_class = sym16->storage_class;
result.aux_symbol_count = sym16->aux_symbol_count;
result.raw_symbol = sym16;
return result;
}
internal COFF_ParsedSymbol
coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx)
{
COFF_ParsedSymbol symbol;
if (header.is_big_obj) {
symbol = coff_parse_symbol32(string_table, (COFF_Symbol32 *)symbol_table.str + symbol_idx);
} else {
symbol = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + symbol_idx);
}
return symbol;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
{
COFF_Symbol32Array result = {0};
result.count = symbol_count;
result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8);
Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count);
String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range);
COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str;
for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) {
COFF_Symbol16 *sym16 = &sym16_arr[isymbol];
COFF_Symbol32 *sym32 = &result.v[isymbol];
sym32->name = sym16->name;
sym32->value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) {
sym32->section_number = COFF_Symbol_DebugSection32;
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
sym32->section_number = COFF_Symbol_AbsSection32;
} else {
sym32->section_number = (U32)sym16->section_number;
}
sym32->type.v = sym16->type.v;
sym32->storage_class = sym16->storage_class;
sym32->aux_symbol_count = sym16->aux_symbol_count;
// copy aux symbols
for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) {
COFF_Symbol16 *aux16 = sym16_arr + iaux;
COFF_Symbol32 *aux32 = result.v + iaux;
// 32bit COFF uses 16bit aux symbols
MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16));
MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16));
}
// take into account aux symbols
isymbol += sym32->aux_symbol_count;
}
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count)
{
COFF_Symbol32Array result;
result.count = symbol_count;
result.v = (COFF_Symbol32 *)(data.str + symbol_array_off);
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size)
{
COFF_Symbol32Array result = {0};
switch (symbol_size) {
case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_array_off, symbol_count); break;
case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_array_off, symbol_count); break;
}
return result;
}
internal COFF_Symbol16Node *
coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol)
{
COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1);
node->next = 0;
node->data = symbol;
SLLQueuePush(list->first, list->last, node);
list->count += 1;
return node;
}
internal COFF_SymbolValueInterpType
coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class)
{
if (storage_class == COFF_SymStorageClass_Section && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Undefined;
}
if (storage_class == COFF_SymStorageClass_External && value == 0 && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Undefined;
}
if (storage_class == COFF_SymStorageClass_External && value != 0 && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Common;
}
if (section_number == COFF_Symbol_AbsSection32) {
return COFF_SymbolValueInterp_Abs;
}
if (section_number == COFF_Symbol_DebugSection32) {
return COFF_SymbolValueInterp_Debug;
}
if (storage_class == COFF_SymStorageClass_WeakExternal) {
return COFF_SymbolValueInterp_Weak;
}
return COFF_SymbolValueInterp_Regular;
}
internal COFF_SymbolValueInterpType
coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol)
{
return coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
}
internal B32
coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol)
{
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
return interp == COFF_SymbolValueInterp_Undefined && symbol.storage_class == COFF_SymStorageClass_External;
}
internal void
coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out)
{
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Regular);
Assert(symbol.aux_symbol_count > 0);
if (is_big_obj) {
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
if (selection_out) *selection_out = sd->selection;
if (length_out) *length_out = sd->length;
if (check_sum_out) *check_sum_out = sd->check_sum;
if (number_out) *number_out = Compose32Bit(sd->number_hi, sd->number_lo);
} else {
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
if (selection_out) *selection_out = sd->selection;
if (length_out) *length_out = sd->length;
if (check_sum_out) *check_sum_out = sd->check_sum;
if (number_out) *number_out = sd->number_lo;
}
}
internal COFF_SymbolWeakExt *
coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj)
{
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Weak);
Assert(symbol.aux_symbol_count > 0);
void *tag;
if (is_big_obj) {
tag = (COFF_SymbolWeakExt *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
} else {
tag = (COFF_SymbolWeakExt *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
}
return tag;
}
internal COFF_RelocNode *
coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc)
{
COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1);
node->data = reloc;
SLLQueuePush(list->first, list->last, node);
++list->count;
return node;
}
internal COFF_RelocInfo
coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header)
{
COFF_RelocInfo result = {0};
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl && header->reloc_count == max_U16) {
COFF_Reloc counter;
U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter);
if (read_size == sizeof(counter) && counter.apply_off > 0) {
result.array_off = header->relocs_foff + sizeof(COFF_Reloc);
result.count = counter.apply_off - 1; // exclude counter entry
}
} else {
result.array_off = header->relocs_foff;
result.count = header->reloc_count;
}
return result;
}
internal String8
coff_resource_string_from_str16(Arena *arena, String16 string)
{
AssertAlways(string.size <= max_U16);
U16 size16 = (U16)string.size;
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
MemoryCopy(buffer + 0, &size16, sizeof(size16));
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
return str8_array(buffer, size16 + 1);
}
internal String8
coff_resource_string_from_str8(Arena *arena, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String16 string16 = str16_from_8(scratch.arena, string);
String8 result = coff_resource_string_from_str16(arena, string16);
scratch_end(scratch);
return result;
}
internal String8
coff_resource_number_from_u16(Arena *arena, U16 number)
{
U16 *buffer = push_array_no_zero(arena, U16, 2);
buffer[0] = max_U16;
buffer[1] = number;
return str8_array(buffer, 2);
}
internal COFF_ResourceID
coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16)
{
COFF_ResourceID id = {0};
id.type = id_16->type;
switch (id_16->type) {
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_Number: {
id.u.number = id_16->u.number;
} break;
case COFF_ResourceIDType_String: {
id.u.string = str8_from_16(arena, id_16->u.string);
} break;
default: InvalidPath;
}
return id;
}
internal U64
coff_read_resource_id_utf16(String8 raw_res, U64 off, COFF_ResourceID16 *id_out)
{
U64 cursor = off;
U16 flag = 0;
str8_deserial_read_struct(raw_res, cursor, &flag);
if (flag == max_U16) {
id_out->type = COFF_ResourceIDType_Number;
cursor += sizeof(flag);
cursor += str8_deserial_read_struct(raw_res, cursor, &id_out->u.number);
} else {
id_out->type = COFF_ResourceIDType_String;
cursor += str8_deserial_read_windows_utf16_string16(raw_res, cursor, &id_out->u.string);
}
U64 read_size = cursor - off;
read_size = AlignPow2(read_size, COFF_ResourceAlign);
return read_size;
}
internal U64
coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out)
{
String8 raw_header = str8_skip(raw_res, off);
U64 header_cursor = 0;
// prefix
COFF_ResourceHeaderPrefix prefix = {0};
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
raw_header = str8_prefix(raw_header, prefix.header_size);
// header
COFF_ResourceID16 type_16 = {0};
COFF_ResourceID16 name_16 = {0};
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
Assert(prefix.header_size == header_cursor);
// convert utf-16 resource ids to utf-8
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
// read data
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
Assert(prefix.data_size == data_read_size);
// compute read size
U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_ResourceAlign);
return read_size;
}
internal COFF_ParsedResourceList
coff_resource_list_from_data(Arena *arena, String8 data)
{
COFF_ParsedResourceList list = {0};
U64 cursor;
for (cursor = 0 ; cursor < data.size; ) {
COFF_ParsedResourceNode *node = push_array(arena, COFF_ParsedResourceNode, 1);
cursor += coff_read_resource(arena, data, cursor, &node->data);
SLLQueuePush(list.first, list.last, node);
++list.count;
}
Assert(cursor == data.size);
return list;
}
internal String8
coff_write_resource_id(Arena *arena, COFF_ResourceID id)
{
String8 result = str8_zero();
switch (id.type) {
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_Number: {
result = coff_resource_number_from_u16(arena, id.u.number);
} break;
case COFF_ResourceIDType_String: {
result = coff_resource_string_from_str8(arena, id.u.string);
} break;
default: InvalidPath;
}
return result;
}
internal String8
coff_write_resource(Arena *arena,
COFF_ResourceID type,
COFF_ResourceID name,
U32 data_version,
COFF_ResourceMemoryFlags memory_flags,
U16 language_id,
U32 version,
U32 characteristics,
String8 data)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
String8 packed_type = coff_write_resource_id(scratch.arena, type);
String8 packed_name = coff_write_resource_id(scratch.arena, name);
// prefix + header
str8_list_push(scratch.arena, &list, str8_struct(prefix));
str8_list_push(scratch.arena, &list, packed_type);
str8_list_push(scratch.arena, &list, packed_name);
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
str8_list_push(scratch.arena, &list, str8_struct(&version));
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
prefix->data_size = safe_cast_u32(data.size);
prefix->header_size = safe_cast_u32(list.total_size);
// data
str8_list_push(scratch.arena, &list, data);
// magic
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
// align
U64 align_size = AlignPow2(list.total_size, COFF_ResourceAlign) - list.total_size;
U8 *align = push_array(scratch.arena, U8, align_size);
str8_list_push(scratch.arena, &list, str8(align, align_size));
// join
String8 res = str8_list_join(arena, &list, 0);
scratch_end(scratch);
return res;
}
internal int
coff_resource_id_compar(void *raw_a, void *raw_b)
{
int cmp;
COFF_ResourceID *a = raw_a;
COFF_ResourceID *b = raw_b;
if (a->type == b->type) {
switch (a->type) {
default:
case COFF_ResourceIDType_Null: cmp = 0; break;
case COFF_ResourceIDType_Number: cmp = MemoryCompare(&a->u.number, &b->u.number, sizeof(a->u.number)); break;
case COFF_ResourceIDType_String: cmp = strncmp((char *)a->u.string.str, (char *)b->u.string.str, Min(a->u.string.size, b->u.string.size)); break;
}
} else {
cmp = a->type < b->type ? -1 : a->type > b->type ? +1 : 0;
}
return cmp;
}
internal B32
coff_is_import(String8 raw_archive_member)
{
B32 is_import = 0;
if (raw_archive_member.size >= sizeof(U16)*2) {
U16 *sig1 = (U16*)raw_archive_member.str;
U16 *sig2 = sig1 + 1;
is_import = *sig1 == COFF_MachineType_Unknown && *sig2 == 0xffff;
}
return is_import;
}
internal COFF_DataType
coff_data_type_from_data(String8 raw_archive_member)
{
B32 is_big_obj = coff_is_big_obj(raw_archive_member);
if (is_big_obj) {
return COFF_DataType_BigObj;
}
B32 is_import = coff_is_import(raw_archive_member);
if (is_import) {
return COFF_DataType_Import;
}
return COFF_DataType_Obj;
}
internal B32
coff_is_regular_archive(String8 raw_archive)
{
B32 is_archive = 0;
U8 sig[sizeof(g_coff_archive_sig)];
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0;
}
return is_archive;
}
internal B32
coff_is_thin_archive(String8 raw_archive)
{
B32 is_archive = 0;
U8 sig[sizeof(g_coff_thin_archive_sig)];
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0;
}
return is_archive;
}
internal COFF_ArchiveType
coff_archive_type_from_data(String8 raw_archive)
{
if (coff_is_regular_archive(raw_archive)) {
return COFF_Archive_Regular;
} else if (coff_is_thin_archive(raw_archive)) {
return COFF_Archive_Thin;
}
return COFF_Archive_Null;
}
internal U64
coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out)
{
COFF_ArchiveMemberHeader *header = str8_deserial_get_raw_ptr(raw_archive, offset, sizeof(*header));
if (header) {
String8 name = str8_skip_chop_whitespace(str8_cstring_capped(header->name, header->name + sizeof(header->name) ));
String8 date = str8_skip_chop_whitespace(str8_cstring_capped(header->date, header->date + sizeof(header->date) ));
String8 user_id = str8_skip_chop_whitespace(str8_cstring_capped(header->user_id, header->user_id + sizeof(header->user_id) ));
String8 group_id = str8_skip_chop_whitespace(str8_cstring_capped(header->group_id, header->group_id + sizeof(header->group_id)));
String8 mode = str8_skip_chop_whitespace(str8_cstring_capped(header->mode, header->mode + sizeof(header->mode) ));
String8 size = str8_skip_chop_whitespace(str8_cstring_capped(header->size, header->size + sizeof(header->size) ));
String8 end = str8_cstring_capped(header->end, header->end + sizeof(header->end));
U32 data_size = u32_from_str8(size, 10);
U64 data_off = offset + sizeof(COFF_ArchiveMemberHeader);
header_out->name = name;
header_out->time_stamp = u32_from_str8(date, 10);
header_out->user_id = u32_from_str8(user_id, 10);
header_out->group_id = u32_from_str8(group_id, 10);
header_out->mode = mode;
header_out->is_end_correct = str8_match_lit("`\n", end, 0);
header_out->data_range = rng_1u64(data_off, data_off + data_size);
return sizeof(*header);
}
return 0;
}
internal COFF_ArchiveFirstMember
coff_parse_first_archive_member(COFF_ArchiveMember *member)
{
Assert(str8_match_lit("/", member->header.name, 0));
U64 cursor = 0;
U32 symbol_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
symbol_count = from_be_u32(symbol_count);
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32));
cursor += dim_1u64(member_offsets_range);
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
cursor += dim_1u64(string_table_range);
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
U32 *member_offsets = (U32 *)raw_member_offsets.str;
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
COFF_ArchiveFirstMember result = {0};
result.symbol_count = symbol_count;
result.member_offset_count = member_offset_count;
result.member_offsets = member_offsets;
result.string_table = str8_substr(member->data, string_table_range);
return result;
}
internal COFF_ArchiveSecondMember
coff_parse_second_archive_member(COFF_ArchiveMember *member)
{
COFF_ArchiveSecondMember result = {0};
if (str8_match_lit("/", member->header.name, 0)) {
U64 cursor = 0;
U32 member_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &member_count);
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32));
cursor += dim_1u64(member_offsets_range);
U32 symbol_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16));
cursor += dim_1u64(symbol_indices_range);
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
String8 raw_indices = str8_substr(member->data, symbol_indices_range);
U32 *member_offsets = (U32 *)raw_member_offsets.str;
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
U16 *symbol_indices = (U16 *)raw_indices.str;
U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]);
result.member_count = member_count;
result.symbol_count = symbol_count;
result.member_offsets = member_offsets;
result.member_offset_count = member_offset_count;
result.symbol_indices = symbol_indices;
result.symbol_index_count = symbol_index_count;
result.string_table = str8_substr(member->data, string_table_range);
}
return result;
}
internal String8
coff_decode_raw_member_name(String8 long_names, String8 name)
{
String8 result = name;
if (name.size > 0 && name.str[0] == '/') {
String8 offset_str = str8(name.str + 1, name.size - 1);
U64 offset = u64_from_str8(offset_str, 10);
if (offset < long_names.size) {
U8 *ptr = long_names.str + offset;
U8 *opl = long_names.str + long_names.size;
for (; ptr < opl; ++ptr) {
if (*ptr == '\0' || *ptr == '\n') {
break;
}
}
result = str8_range(long_names.str + offset, ptr);
}
}
return result;
}
internal String8
coff_decode_member_name(String8 long_names, String8 name)
{
String8 member_name = coff_decode_raw_member_name(long_names, name);
String8 slash = str8_lit("/");
if (str8_ends_with(member_name, slash, 0)) {
member_name = str8_chop(member_name, slash.size);
}
return member_name;
}
internal U64
coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out)
{
COFF_ImportHeader *header = str8_deserial_get_raw_ptr(raw_archive_member, offset, sizeof(*header));
if (header) {
Rng1U64 data_range = rng_1u64(offset + sizeof(*header), offset + sizeof(*header) + header->data_size);
String8 raw_data = str8_substr(raw_archive_member, data_range);
U64 data_cursor = 0;
header_out->version = header->version;
header_out->machine = header->machine;
header_out->time_stamp = header->time_stamp;
header_out->data_size = header->data_size;
header_out->hint_or_ordinal = header->hint_or_ordinal;
header_out->type = COFF_ImportHeader_ExtractType(header->flags);
header_out->import_by = COFF_ImportHeader_ExtractImportBy(header->flags);
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->func_name);
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->dll_name);
Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size);
U64 read_size = sizeof(*header) + header->data_size;
return read_size;
}
return 0;
}
internal COFF_ArchiveMember
coff_archive_member_from_offset(String8 raw_archive, U64 offset)
{
COFF_ArchiveMember member = {0};
coff_regular_archive_member_iter_next(raw_archive, &offset, &member);
return member;
}
internal COFF_ArchiveMember
coff_archive_member_from_data(String8 raw_archive_member)
{
return coff_archive_member_from_offset(raw_archive_member, 0);
}
internal COFF_ParsedArchiveImportHeader
coff_archive_import_from_data(String8 raw_archive_member)
{
COFF_ParsedArchiveImportHeader header = {0};
coff_parse_import(raw_archive_member, 0, &header);
return header;
}
internal U64
coff_regular_archive_member_iter_init(String8 raw_archive)
{
U64 cursor = raw_archive.size;
if (coff_is_regular_archive(raw_archive)) {
cursor = sizeof(g_coff_archive_sig);
}
return cursor;
}
internal B32
coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
{
B32 is_parsed = 0;
member_out->header.is_end_correct = 0;
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
if (member_out->header.is_end_correct) {
member_out->offset = *offset;
member_out->data = str8_substr(raw_archive, member_out->header.data_range);
U64 read_size = AlignPow2(header_size + dim_1u64(member_out->header.data_range), COFF_Archive_MemberAlign);
*offset += read_size;
is_parsed = 1;
}
return is_parsed;
}
internal U64
coff_thin_archive_member_iter_init(String8 raw_archive)
{
U64 cursor = raw_archive.size;
if (coff_is_thin_archive(raw_archive)) {
cursor = sizeof(g_coff_thin_archive_sig);
}
return cursor;
}
internal B32
coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
{
B32 is_parsed = 0;
member_out->header.is_end_correct = 0;
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
if (member_out->header.is_end_correct) {
Rng1U64 data_in_archive_range = {0};
if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) {
data_in_archive_range = member_out->header.data_range;
}
member_out->offset = *offset;
member_out->data = str8_substr(raw_archive, data_in_archive_range);
U64 read_size = AlignPow2(header_size + dim_1u64(data_in_archive_range), COFF_Archive_MemberAlign);
*offset += read_size;
is_parsed = 1;
}
return is_parsed;
}
internal void
coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node)
{
SLLQueuePush(list->first, list->last, node);
list->count += 1;
}
internal COFF_ArchiveParse
coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list)
{
String8 error = str8_zero();
B32 has_second_header = 0;
B32 has_long_names = 0;
COFF_ArchiveMember first_header = {0};
COFF_ArchiveMember second_header = {0};
COFF_ArchiveMember long_names_member = {0};
COFF_ArchiveMemberNode *ptr = member_list.first;
if (ptr) {
if (str8_match_lit("/", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
first_header = ptr->data;
ptr = ptr->next;
} else {
error = str8_lit("first header doesn't have correct end");
}
}
} else {
error = str8_lit("missing first header");
}
if (!error.size && ptr) {
if (str8_match_lit("/", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
second_header = ptr->data;
ptr = ptr->next;
has_second_header = 1;
} else {
error = str8_lit("second header doesn't have correct end");
}
}
}
if (!error.size && ptr) {
if (str8_match_lit("//", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
long_names_member = ptr->data;
ptr = ptr->next;
has_long_names;
} else {
error = str8_lit("long names header doesn't have correct end");
}
}
}
COFF_ArchiveParse parse = {0};
parse.has_second_header = has_second_header;
parse.has_long_names = has_long_names;
parse.first_member = coff_parse_first_archive_member(&first_header);
parse.second_member = coff_parse_second_archive_member(&second_header);
parse.long_names = long_names_member.data;
parse.error = error;
return parse;
}
internal COFF_ArchiveParse
coff_regular_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveMemberList list = {0};
COFF_ArchiveMemberNode node_arr[3] = {0};
U64 cursor = coff_regular_archive_member_iter_init(raw_archive);
for (U64 i = 0; i < ArrayCount(node_arr); ++i) {
COFF_ArchiveMemberNode *node = &node_arr[i];
if (!coff_regular_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
break;
}
coff_archive_member_list_push_node(&list, node);
}
return coff_archive_parse_from_member_list(list);
}
internal COFF_ArchiveParse
coff_thin_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveMemberList list = {0};
COFF_ArchiveMemberNode node_arr[3] = {0};
U64 cursor = coff_thin_archive_member_iter_init(raw_archive);
for (U64 i = 0; i < ArrayCount(node_arr); i += 1) {
COFF_ArchiveMemberNode *node = &node_arr[i];
if (!coff_thin_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
break;
}
coff_archive_member_list_push_node(&list, node);
}
return coff_archive_parse_from_member_list(list);
}
internal COFF_ArchiveParse
coff_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveType type = coff_archive_type_from_data(raw_archive);
switch (type) {
case COFF_Archive_Null: break;
case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive);
case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive);
}
COFF_ArchiveParse null_parse = {0};
return null_parse;
}
-329
View File
@@ -1,329 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_PARSE_H
#define COFF_PARSE_H
typedef struct COFF_FileHeaderInfo
{
B32 is_big_obj;
COFF_MachineType machine;
U64 header_size;
U64 section_count_no_null;
U64 symbol_size;
U64 symbol_count;
Rng1U64 header_range;
Rng1U64 section_table_range;
Rng1U64 symbol_table_range;
Rng1U64 string_table_range;
} COFF_FileHeaderInfo;
////////////////////////////////
typedef struct COFF_SectionHeaderArray
{
U64 count;
COFF_SectionHeader *v;
} COFF_SectionHeaderArray;
////////////////////////////////
typedef struct COFF_Symbol16Node
{
struct COFF_Symbol16Node *next;
COFF_Symbol16 data;
} COFF_Symbol16Node;
typedef struct COFF_Symbol16List
{
U64 count;
COFF_Symbol16Node *first;
COFF_Symbol16Node *last;
} COFF_Symbol16List;
typedef struct COFF_Symbol32Array
{
U64 count;
COFF_Symbol32 *v;
} COFF_Symbol32Array;
typedef struct COFF_ParsedSymbol
{
String8 name;
U64 value;
U32 section_number;
COFF_SymbolType type;
COFF_SymStorageClass storage_class;
U8 aux_symbol_count;
void *raw_symbol;
} COFF_ParsedSymbol;
typedef U32 COFF_SymbolValueInterpType;
enum
{
COFF_SymbolValueInterp_Regular, // symbol has section and offset.
COFF_SymbolValueInterp_Weak, // symbol is overridable.
COFF_SymbolValueInterp_Undefined, // symbol doesn't have a reference section.
COFF_SymbolValueInterp_Common, // symbol has no section but still has size.
COFF_SymbolValueInterp_Abs, // symbol has an absolute (non-relocatable) value and is not an address.
COFF_SymbolValueInterp_Debug // symbol is used to provide general type of debugging information.
};
////////////////////////////////
typedef struct COFF_RelocNode
{
struct COFF_RelocNode *next;
COFF_Reloc data;
} COFF_RelocNode;
typedef struct COFF_RelocList
{
U64 count;
COFF_RelocNode *first;
COFF_RelocNode *last;
} COFF_RelocList;
typedef struct COFF_RelocArray
{
U64 count;
COFF_Reloc *v;
} COFF_RelocArray;
typedef struct COFF_RelocInfo
{
U64 array_off;
U64 count;
} COFF_RelocInfo;
////////////////////////////////
typedef U32 COFF_ResourceIDType;
enum COFF_ResourceIDTypeEnum
{
COFF_ResourceIDType_Null,
COFF_ResourceIDType_Number,
COFF_ResourceIDType_String,
COFF_ResourceIDType_Count
};
typedef struct COFF_ResourceID16
{
COFF_ResourceIDType type;
union {
U16 number;
String16 string;
} u;
} COFF_ResourceID16;
typedef struct COFF_ResourceID
{
COFF_ResourceIDType type;
union {
U16 number;
String8 string;
} u;
} COFF_ResourceID;
typedef struct COFF_ParsedResource
{
COFF_ResourceID type;
COFF_ResourceID name;
U32 data_version;
COFF_ResourceMemoryFlags memory_flags;
U16 language_id;
U32 version;
U32 characteristics;
String8 data;
} COFF_ParsedResource;
typedef struct COFF_ParsedResourceNode
{
struct COFF_ParsedResourceNode *next;
COFF_ParsedResource data;
} COFF_ParsedResourceNode;
typedef struct COFF_ParsedResourceList
{
U64 count;
COFF_ParsedResourceNode *first;
COFF_ParsedResourceNode *last;
} COFF_ParsedResourceList;
////////////////////////////////
typedef enum
{
COFF_DataType_Null,
COFF_DataType_Obj,
COFF_DataType_BigObj,
COFF_DataType_Import
} COFF_DataType;
typedef enum
{
COFF_Archive_Null,
COFF_Archive_Regular,
COFF_Archive_Thin
} COFF_ArchiveType;
typedef struct COFF_ParsedArchiveMemberHeader
{
String8 name; // padded to 16 bytes with spaces
COFF_TimeStamp time_stamp;
U32 user_id; // unix artifact that does not have meaning on windows
U32 group_id; // unix artifact that does not have meaning on windows
String8 mode; // octal representation the members file mode
B32 is_end_correct; // set to true if found correct signature after header
Rng1U64 data_range;
} COFF_ParsedArchiveMemberHeader;
typedef struct COFF_ParsedArchiveImportHeader
{
B32 is_sig_correct;
U16 version;
COFF_MachineType machine;
COFF_TimeStamp time_stamp;
U32 data_size;
U16 hint_or_ordinal;
COFF_ImportType type;
COFF_ImportByType import_by;
String8 func_name;
String8 dll_name;
} COFF_ParsedArchiveImportHeader;
typedef struct COFF_ArchiveMember
{
COFF_ParsedArchiveMemberHeader header;
U64 offset;
String8 data;
} COFF_ArchiveMember;
typedef struct COFF_ArchiveFirstMember
{
U32 symbol_count;
U64 member_offset_count;
U32 *member_offsets;
String8 string_table;
} COFF_ArchiveFirstMember;
typedef struct COFF_ArchiveSecondMember
{
U32 member_count;
U32 symbol_count;
U64 member_offset_count;
U32 *member_offsets;
U64 symbol_index_count;
U16 *symbol_indices;
String8 string_table;
} COFF_ArchiveSecondMember;
typedef struct COFF_ArchiveMemberNode
{
struct COFF_ArchiveMemberNode *next;
COFF_ArchiveMember data;
} COFF_ArchiveMemberNode;
typedef struct COFF_ArchiveMemberList
{
U64 count;
COFF_ArchiveMemberNode *first;
COFF_ArchiveMemberNode *last;
} COFF_ArchiveMemberList;
typedef struct COFF_ArchiveParse
{
B32 has_second_header;
B32 has_long_names;
COFF_ArchiveFirstMember first_member;
COFF_ArchiveSecondMember second_member;
String8 long_names;
String8 error;
} COFF_ArchiveParse;
////////////////////////////////
// Obj Header
internal B32 coff_is_big_obj(String8 raw_coff);
internal B32 coff_is_obj (String8 raw_coff);
internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff);
////////////////////////////////
// Section
internal COFF_SectionHeader ** coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range);
////////////////////////////////
// Symbol
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16);
internal COFF_ParsedSymbol coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data (Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size);
internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol);
internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class);
internal COFF_SymbolValueInterpType coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol);
internal B32 coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol);
internal void coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out);
internal COFF_SymbolWeakExt * coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj);
////////////////////////////////
// Reloc
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
////////////////////////////////
// Resource
internal String8 coff_resource_string_from_str16 (Arena *arena, String16 string);
internal String8 coff_resource_string_from_str8 (Arena *arena, String8 string);
internal String8 coff_resource_number_from_u16 (Arena *arena, U16 number);
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16);
internal U64 coff_read_resource_id_utf16 (String8 raw_res, U64 off, COFF_ResourceID16 *id_out);
internal U64 coff_read_resource (Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out);
internal COFF_ParsedResourceList coff_resource_list_from_data(Arena *arena, String8 data);
internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
internal String8 coff_write_resource (Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
internal int coff_resource_id_compar(void *raw_a, void *raw_b); // COFF_ResourceID
////////////////////////////////
// Archive
internal B32 coff_is_import (String8 raw_archive_member);
internal COFF_DataType coff_data_type_from_data (String8 raw_archive_member);
internal B32 coff_is_regular_archive (String8 raw_archive);
internal B32 coff_is_thin_archive (String8 raw_archive);
internal COFF_ArchiveType coff_archive_type_from_data(String8 raw_archive);
internal U64 coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out);
internal COFF_ArchiveFirstMember coff_parse_first_archive_member (COFF_ArchiveMember *member);
internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member);
internal String8 coff_decode_raw_member_name (String8 long_names, String8 name);
internal String8 coff_decode_member_name (String8 long_names, String8 name);
internal U64 coff_parse_import (String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out);
internal COFF_ArchiveMember coff_archive_member_from_offset(String8 raw_archive, U64 offset);
internal COFF_ArchiveMember coff_archive_member_from_data (String8 raw_archive_member);
internal COFF_ParsedArchiveImportHeader coff_archive_import_from_data (String8 raw_archive_member);
internal U64 coff_regular_archive_member_iter_init(String8 raw_archive);
internal B32 coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
internal U64 coff_thin_archive_member_iter_init(String8 raw_archive);
internal B32 coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
internal COFF_ArchiveParse coff_regular_archive_parse_from_member_list(COFF_ArchiveMemberList list);
internal COFF_ArchiveParse coff_thin_archive_parse_from_data (String8 raw_archive);
internal COFF_ArchiveParse coff_regular_archive_parse_from_data (String8 raw_archive);
internal COFF_ArchiveParse coff_archive_parse_from_data (String8 raw_archive);
#endif // COFF_PARSE_H
-111
View File
@@ -1,111 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal CFG_KeyMap *
cfg_key_map_from_cfg(Arena *arena)
{
Temp scratch = scratch_begin(&arena, 1);
CFG_KeyMap *key_map = push_array(arena, CFG_KeyMap, 1);
{
key_map->name_slots_count = 4096;
key_map->name_slots = push_array(arena, CFG_KeyMapSlot, key_map->name_slots_count);
key_map->binding_slots_count = 4096;
key_map->binding_slots = push_array(arena, CFG_KeyMapSlot, key_map->binding_slots_count);
//- rjf: gather & parse all explicitly stored keybinding sets
CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings"));
for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next)
{
CFG_Node *keybindings_root = n->v;
for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next)
{
String8 name = {0};
CFG_Binding binding = {0};
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
{
if(0){}
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
else
{
OS_Key key = OS_Key_Null;
for EachEnumVal(OS_Key, k)
{
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
{
key = k;
break;
}
}
if(key != OS_Key_Null)
{
binding.key = key;
}
else
{
name = child->string;
}
}
}
if(name.size != 0)
{
U64 name_hash = d_hash_from_string(name);
U64 binding_hash = d_hash_from_string(str8_struct(&binding));
U64 name_slot_idx = name_hash%key_map->name_slots_count;
U64 binding_slot_idx = binding_hash%key_map->binding_slots_count;
CFG_KeyMapNode *n = push_array(arena, CFG_KeyMapNode, 1);
n->cfg_id = keybinding->id;
n->name = push_str8_copy(arena, name);
n->binding = binding;
SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next);
SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next);
}
}
}
}
scratch_end(scratch);
return key_map;
}
internal CFG_KeyMapNodePtrList
cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string)
{
CFG_KeyMapNodePtrList list = {0};
{
U64 hash = d_hash_from_string(string);
U64 slot_idx = hash%key_map->name_slots_count;
for(CFG_KeyMapNode *n = key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next)
{
if(str8_match(n->name, string, 0))
{
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
ptr->v = n;
SLLQueuePush(list.first, list.last, ptr);
list.count += 1;
}
}
}
return list;
}
internal CFG_KeyMapNodePtrList
cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding)
{
CFG_KeyMapNodePtrList list = {0};
{
U64 hash = d_hash_from_string(str8_struct(&binding));
U64 slot_idx = hash%key_map->binding_slots_count;
for(CFG_KeyMapNode *n = key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next)
{
if(MemoryMatchStruct(&binding, &n->binding))
{
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
ptr->v = n;
SLLQueuePush(list.first, list.last, ptr);
list.count += 1;
}
}
}
return list;
}
-59
View File
@@ -1,59 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONFIG_BINDINGS_H
#define CONFIG_BINDINGS_H
typedef struct CFG_Binding CFG_Binding;
struct CFG_Binding
{
OS_Key key;
OS_Modifiers modifiers;
};
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
struct CFG_KeyMapNode
{
CFG_KeyMapNode *name_hash_next;
CFG_KeyMapNode *binding_hash_next;
CFG_ID cfg_id;
String8 name;
CFG_Binding binding;
};
typedef struct CFG_KeyMapNodePtr CFG_KeyMapNodePtr;
struct CFG_KeyMapNodePtr
{
CFG_KeyMapNodePtr *next;
CFG_KeyMapNode *v;
};
typedef struct CFG_KeyMapNodePtrList CFG_KeyMapNodePtrList;
struct CFG_KeyMapNodePtrList
{
CFG_KeyMapNodePtr *first;
CFG_KeyMapNodePtr *last;
U64 count;
};
typedef struct CFG_KeyMapSlot CFG_KeyMapSlot;
struct CFG_KeyMapSlot
{
CFG_KeyMapNode *first;
CFG_KeyMapNode *last;
};
typedef struct CFG_KeyMap CFG_KeyMap;
struct CFG_KeyMap
{
U64 name_slots_count;
CFG_KeyMapSlot *name_slots;
U64 binding_slots_count;
CFG_KeyMapSlot *binding_slots;
};
internal CFG_KeyMap *cfg_key_map_from_cfg(Arena *arena);
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string);
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding);
#endif // CONFIG_BINDINGS_H
-896
View File
@@ -1,896 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: ID Functions
internal void
cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id)
{
CFG_IDNode *n = push_array(arena, CFG_IDNode, 1);
SLLQueuePush(list->first, list->last, n);
list->count += 1;
n->v = id;
}
internal CFG_IDList
cfg_id_list_copy(Arena *arena, CFG_IDList *src)
{
CFG_IDList dst = {0};
for EachNode(n, CFG_IDNode, src->first)
{
cfg_id_list_push(arena, &dst, n->v);
}
return dst;
}
////////////////////////////////
//~ rjf: Node Pointer Data Structure Functions
internal void
cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
{
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
DLLPushBack(list->first, list->last, n);
list->count += 1;
n->v = node;
}
internal void
cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
{
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
DLLPushFront(list->first, list->last, n);
list->count += 1;
n->v = node;
}
internal CFG_NodePtrArray
cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list)
{
CFG_NodePtrArray array = {0};
array.count = list->count;
array.v = push_array_no_zero(arena, CFG_Node *, array.count);
{
U64 idx = 0;
for EachNode(n, CFG_NodePtrNode, list->first)
{
array.v[idx] = n->v;
idx += 1;
}
}
return array;
}
////////////////////////////////
//~ rjf: Schema Data Structure Functions
internal void
cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema)
{
U64 hash = u64_hash_from_str8(name);
U64 slot_idx = hash%table->slots_count;
CFG_SchemaNode *node = 0;
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
{
if(str8_match(n->name, name, 0))
{
node = n;
break;
}
}
if(node == 0)
{
node = push_array(arena, CFG_SchemaNode, 1);
node->name = str8_copy(arena, name);
node->schema = schema;
SLLStackPush(table->slots[slot_idx], node);
}
}
internal MD_Node *
cfg_schema_from_name(CFG_SchemaTable *table, String8 name)
{
MD_Node *result = &md_nil_node;
{
U64 hash = u64_hash_from_str8(name);
U64 slot_idx = hash%table->slots_count;
CFG_SchemaNode *node = 0;
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
{
if(str8_match(n->name, name, 0))
{
result = n->schema;
break;
}
}
}
return result;
}
internal MD_NodePtrList
cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name)
{
MD_NodePtrList result = {0};
{
Temp scratch = scratch_begin(&arena, 1);
String8List tasks = {0};
String8Node seed_task = {0, name};
str8_list_push_node(&tasks, &seed_task);
for EachNode(task, String8Node, tasks.first)
{
MD_Node *schema = cfg_schema_from_name(table, task->string);
if(!md_node_is_nil(schema))
{
md_node_ptr_list_push_front(arena, &result, schema);
for MD_EachNode(tag, schema->first_tag)
{
if(str8_match(tag->string, str8_lit("inherit"), 0))
{
str8_list_push(scratch.arena, &tasks, tag->first->string);
}
}
}
}
scratch_end(scratch);
}
return result;
}
////////////////////////////////
//~ rjf: Config Reading Functions
//- rjf: context selection
internal void
cfg_ctx_select(CFG_Ctx *ctx)
{
cfg_ctx = ctx;
}
//- rjf: tree navigations
internal U64
cfg_change_gen(void)
{
U64 result = 0;
if(cfg_ctx != 0)
{
result = cfg_ctx->change_gen;
}
return result;
}
internal CFG_Node *
cfg_node_root(void)
{
CFG_Node *result = &cfg_nil_node;
if(cfg_ctx != 0)
{
result = cfg_ctx->root;
}
return result;
}
internal CFG_Node *
cfg_node_from_id(CFG_ID id)
{
CFG_Node *result = &cfg_nil_node;
if(id != 0 &&
id == cfg_ctx->last_accessed_id &&
id == cfg_ctx->last_accessed->id)
{
result = cfg_ctx->last_accessed;
}
else
{
U64 hash = u64_hash_from_str8(str8_struct(&id));
U64 slot_idx = hash%cfg_ctx->id_slots_count;
for(CFG_NodePtrNode *n = cfg_ctx->id_slots[slot_idx].first; n != 0; n = n->next)
{
if(n->v->id == id)
{
result = n->v;
break;
}
}
}
cfg_ctx->last_accessed_id = id;
cfg_ctx->last_accessed = result;
return result;
}
internal CFG_Node *
cfg_node_child_from_string(CFG_Node *parent, String8 string)
{
CFG_Node *child = &cfg_nil_node;
if(string.size != 0)
{
for(CFG_Node *c = parent->first; c != &cfg_nil_node; c = c->next)
{
if(str8_match(c->string, string, 0))
{
child = c;
break;
}
}
}
return child;
}
internal CFG_Node *
cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string)
{
CFG_Node *result = cfg_node_child_from_string(parent, string);
if(result == &cfg_nil_node)
{
result = parent;
}
return result;
}
internal CFG_NodePtrList
cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string)
{
CFG_NodePtrList result = {0};
for(CFG_Node *child = parent->first; child != &cfg_nil_node; child = child->next)
{
if(str8_match(child->string, string, 0))
{
cfg_node_ptr_list_push(arena, &result, child);
}
}
return result;
}
internal CFG_NodePtrList
cfg_node_top_level_list_from_string(Arena *arena, String8 string)
{
CFG_NodePtrList result = {0};
for(CFG_Node *bucket = cfg_ctx->root->first; bucket != &cfg_nil_node; bucket = bucket->next)
{
for(CFG_Node *tln = bucket->first; tln != &cfg_nil_node; tln = tln->next)
{
if(str8_match(tln->string, string, 0))
{
cfg_node_ptr_list_push(arena, &result, tln);
}
}
}
return result;
}
internal CFG_NodeRec
cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node)
{
CFG_NodeRec rec = {&cfg_nil_node};
if(node->first != &cfg_nil_node)
{
rec.next = node->first;
rec.push_count = 1;
}
else for(CFG_Node *p = node; p != root; p = p->parent, rec.pop_count += 1)
{
if(p->next != &cfg_nil_node)
{
rec.next = p->next;
break;
}
}
return rec;
}
//- rjf: serialization
internal String8
cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root)
{
Temp scratch = scratch_begin(&arena, 1);
String8List strings = {0};
{
typedef struct NestTask NestTask;
struct NestTask
{
NestTask *next;
CFG_Node *cfg;
MD_Node *schema;
B32 is_simple;
};
NestTask *top_nest_task = 0;
CFG_NodeRec rec = {0};
for(CFG_Node *c = root; c != &cfg_nil_node; c = rec.next)
{
// rjf: look up parent's schemas
MD_NodePtrList schemas = {0};
if(top_nest_task != 0)
{
CFG_Node *parent = top_nest_task->cfg;
schemas = cfg_schemas_from_name(scratch.arena, schema_table, parent->string);
}
// rjf: look up child schema
MD_Node *c_schema = &md_nil_node;
for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next)
{
c_schema = md_child_from_string(n->v, c->string, 0);
}
// rjf: push name of this node
if(c->string.size != 0 || c->first == &cfg_nil_node)
{
// rjf: extract the textualized form for this string (we may need to escape / relativize)
String8 c_serialized_string = c->string;
{
MD_Node *c_schema = &md_nil_node;
if(top_nest_task != 0)
{
c_schema = top_nest_task->schema;
}
// rjf: paths -> relativize
if(!md_node_has_tag(c_schema->first, str8_lit("no_relativize"), 0))
{
if(str8_match(c_schema->first->string, str8_lit("path"), 0))
{
String8 path_absolute = c->string;
String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path);
c_serialized_string = path_relative;
}
else if(str8_match(c_schema->first->string, str8_lit("path_pt"), 0))
{
String8 value = c->string;
String8TxtPtPair parts = str8_txt_pt_pair_from_string(value);
String8 path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, parts.string, root_path);
c_serialized_string = push_str8f(arena, "%S:%I64d:%I64d", path_relative, parts.pt.line, parts.pt.column);
}
}
// rjf: all strings -> escape
c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string);
}
// rjf: generate all strings for this node's string
String8List c_name_strings = {0};
{
B32 name_can_be_pushed_standalone = 0;
{
Temp temp = temp_begin(scratch.arena);
MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string);
name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier|
MD_TokenFlag_Numeric|
MD_TokenFlag_StringLiteral|
MD_TokenFlag_Symbol));
temp_end(temp);
}
if(name_can_be_pushed_standalone)
{
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
}
else
{
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
}
}
// rjf: if we're in a simple nesting task, then just break children by space
if(top_nest_task != 0 && top_nest_task->is_simple)
{
str8_list_push(scratch.arena, &strings, str8_lit(" "));
}
// rjf: join c's strings with main string list
str8_list_concat_in_place(&strings, &c_name_strings);
}
// rjf: grab next recursion
rec = cfg_node_rec__depth_first(root, c);
// rjf: push a new nesting task before descending to children
if(c->first != &cfg_nil_node)
{
B32 is_simple_children_list = 1;
for(CFG_Node *child = c->first; child != &cfg_nil_node; child = child->next)
{
if(child->first != &cfg_nil_node && child != c->last)
{
is_simple_children_list = 0;
break;
}
}
NestTask *task = push_array(scratch.arena, NestTask, 1);
task->cfg = c;
task->schema = c_schema;
task->is_simple = is_simple_children_list;
SLLStackPush(top_nest_task, task);
}
// rjf: tree navigations -> encode hierarchy
if(rec.push_count > 0)
{
if(top_nest_task->is_simple && c->string.size != 0)
{
str8_list_push(scratch.arena, &strings, str8_lit(":"));
}
else
{
if(c->string.size != 0)
{
str8_list_push(scratch.arena, &strings, str8_lit(":\n"));
}
str8_list_push(scratch.arena, &strings, str8_lit("{"));
}
}
else
{
for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task))
{
if(top_nest_task->is_simple)
{
if(top_nest_task->cfg->string.size == 0)
{
str8_list_push(scratch.arena, &strings, str8_lit(" }"));
}
}
else
{
str8_list_push(scratch.arena, &strings, str8_lit("\n}"));
}
}
}
if(!top_nest_task || top_nest_task->is_simple == 0)
{
str8_list_push(scratch.arena, &strings, str8_lit("\n"));
}
}
}
String8 result_unindented = str8_list_join(scratch.arena, &strings, 0);
String8 result = indented_from_string(arena, result_unindented);
scratch_end(scratch);
return result;
}
////////////////////////////////
//~ rjf: Config Writing Functions
//- rjf: state creation / destroying
internal CFG_State *
cfg_state_alloc(void)
{
Arena *arena = arena_alloc();
CFG_State *state = push_array(arena, CFG_State, 1);
state->arena = arena;
state->ctx.id_slots_count = 4096;
state->ctx.id_slots = push_array(arena, CFG_NodePtrSlot, state->ctx.id_slots_count);
state->ctx.root = cfg_node_alloc(state);
return state;
}
internal void
cfg_state_release(CFG_State *state)
{
arena_release(state->arena);
}
//- rjf: state -> ctx
internal CFG_Ctx *
cfg_state_ctx(CFG_State *state)
{
CFG_Ctx *ctx = &state->ctx;
return ctx;
}
//- rjf: string allocations
internal U64
cfg_string_bucket_num_from_size(U64 size)
{
U64 bucket_num = 0;
if(size > 0)
{
for EachElement(idx, cfg_string_bucket_chunk_sizes)
{
if(size <= cfg_string_bucket_chunk_sizes[idx])
{
bucket_num = idx+1;
break;
}
}
}
return bucket_num;
}
internal String8
cfg_string_alloc(CFG_State *state, String8 string)
{
//- rjf: allocate node
CFG_StringChunkNode *node = 0;
{
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
if(bucket_num == ArrayCount(cfg_string_bucket_chunk_sizes))
{
CFG_StringChunkNode *best_node = 0;
CFG_StringChunkNode *best_node_prev = 0;
U64 best_node_size = max_U64;
{
for(CFG_StringChunkNode *n = state->free_string_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next))
{
if(n->size >= string.size && n->size < best_node_size)
{
best_node = n;
best_node_prev = prev;
best_node_size = n->size;
}
}
}
if(best_node != 0)
{
node = best_node;
if(best_node_prev)
{
best_node_prev->next = best_node->next;
}
else
{
state->free_string_chunks[bucket_num-1] = best_node->next;
}
}
else
{
U64 chunk_size = u64_up_to_pow2(string.size);
node = (CFG_StringChunkNode *)push_array(state->arena, U8, chunk_size);
}
}
else if(bucket_num != 0)
{
node = state->free_string_chunks[bucket_num-1];
if(node != 0)
{
SLLStackPop(state->free_string_chunks[bucket_num-1]);
}
else
{
node = (CFG_StringChunkNode *)push_array(state->arena, U8, cfg_string_bucket_chunk_sizes[bucket_num-1]);
}
}
}
//- rjf: fill node
String8 result = {0};
if(node != 0)
{
result.str = (U8 *)node;
result.size = string.size;
MemoryCopy(result.str, string.str, result.size);
}
return result;
}
internal void
cfg_string_release(CFG_State *state, String8 string)
{
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
if(1 <= bucket_num && bucket_num <= ArrayCount(cfg_string_bucket_chunk_sizes))
{
U64 bucket_idx = bucket_num-1;
CFG_StringChunkNode *node = (CFG_StringChunkNode *)string.str;
SLLStackPush(state->free_string_chunks[bucket_idx], node);
node->size = u64_up_to_pow2(string.size);
}
}
//- rjf: tree building
internal CFG_Node *
cfg_node_alloc(CFG_State *state)
{
state->ctx.change_gen += 1;
// rjf: allocate
CFG_Node *result = state->free;
{
if(result)
{
SLLStackPop(state->free);
}
else
{
result = push_array_no_zero(state->arena, CFG_Node, 1);
}
}
// rjf: generate ID & fill
state->id_gen += 1;
MemoryZeroStruct(result);
result->first = result->last = result->next = result->prev = result->parent = &cfg_nil_node;
result->id = state->id_gen;
// rjf: store to ID -> cfg map
{
CFG_NodePtrNode *cfg_id_node = state->free_id_node;
if(cfg_id_node != 0)
{
SLLStackPop(state->free_id_node);
}
else
{
cfg_id_node = push_array(state->arena, CFG_NodePtrNode, 1);
}
U64 hash = u64_hash_from_str8(str8_struct(&result->id));
U64 slot_idx = hash%state->ctx.id_slots_count;
DLLPushBack(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, cfg_id_node);
cfg_id_node->v = result;
}
return result;
}
internal void
cfg_node_release(CFG_State *state, CFG_Node *node)
{
state->ctx.change_gen += 1;
Temp scratch = scratch_begin(0, 0);
// rjf: unhook from context
cfg_node_unhook(state, node->parent, node);
// rjf: gather root & all descendants
CFG_NodePtrList nodes = {0};
for(CFG_Node *c = node; c != &cfg_nil_node; c = cfg_node_rec__depth_first(node, c).next)
{
cfg_node_ptr_list_push(scratch.arena, &nodes, c);
}
// rjf: release all nodes
for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next)
{
CFG_Node *c = n->v;
cfg_string_release(state, c->string);
SLLStackPush(state->free, c);
c->first = c->last = c->prev = c->parent = 0;
c->id = 0;
c->string = str8_zero();
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
U64 slot_idx = hash%state->ctx.id_slots_count;
for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next)
{
if(n->v == c)
{
DLLRemove(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, n);
SLLStackPush(state->free_id_node, n);
break;
}
}
}
scratch_end(scratch);
}
internal void
cfg_node_release_all_children(CFG_State *state, CFG_Node *node)
{
for(CFG_Node *child = node->first, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
{
next = child->next;
cfg_node_release(state, child);
}
}
internal CFG_Node *
cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string)
{
CFG_Node *node = cfg_node_alloc(state);
cfg_node_insert_child(state, parent, parent->last, node);
cfg_node_equip_string(state, node, string);
return node;
}
internal CFG_Node *
cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
CFG_Node *result = cfg_node_new(state, parent, string);
va_end(args);
scratch_end(scratch);
return result;
}
internal CFG_Node *
cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string)
{
Temp scratch = scratch_begin(0, 0);
string = push_str8_copy(scratch.arena, string);
for(CFG_Node *child = parent->first->next, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
{
next = child->next;
cfg_node_release(state, child);
}
if(parent->first == &cfg_nil_node)
{
cfg_node_new(state, parent, str8_zero());
}
CFG_Node *child = parent->first;
cfg_node_equip_string(state, child, string);
scratch_end(scratch);
return child;
}
internal CFG_Node *
cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
CFG_Node *result = cfg_node_new_replace(state, parent, string);
va_end(args);
scratch_end(scratch);
return result;
}
internal CFG_Node *
cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root)
{
CFG_NodeRec rec = {0};
CFG_Node *dst_root = &cfg_nil_node;
CFG_Node *dst_parent = &cfg_nil_node;
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
{
CFG_Node *dst = cfg_node_new(state, dst_parent, src->string);
if(dst_root == &cfg_nil_node)
{
dst_root = dst;
}
rec = cfg_node_rec__depth_first(src_root, src);
if(rec.push_count > 0)
{
dst_parent = dst;
}
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
{
dst_parent = dst_parent->parent;
}
}
return dst_root;
}
internal void
cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string)
{
cfg_string_release(state, node->string);
node->string = cfg_string_alloc(state, string);
state->ctx.change_gen += 1;
}
internal void
cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
cfg_node_equip_string(state, node, string);
va_end(args);
scratch_end(scratch);
}
internal void
cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child)
{
if(parent != &cfg_nil_node)
{
if(new_child->parent != &cfg_nil_node)
{
cfg_node_unhook(state, new_child->parent, new_child);
}
DLLInsert_NPZ(&cfg_nil_node, parent->first, parent->last, prev_child, new_child, next, prev);
new_child->parent = parent;
}
}
internal void
cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child)
{
if(child != &cfg_nil_node && parent == child->parent && parent != &cfg_nil_node)
{
DLLRemove_NPZ(&cfg_nil_node, parent->first, parent->last, child, next, prev);
child->parent = &cfg_nil_node;
}
}
internal CFG_Node *
cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string)
{
CFG_Node *node = cfg_node_child_from_string(parent, string);
if(node == &cfg_nil_node)
{
node = cfg_node_new(state, parent, string);
}
return node;
}
//- rjf: deserialization
internal CFG_NodePtrList
cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string)
{
CFG_NodePtrList result = {0};
Temp scratch = scratch_begin(&arena, 1);
//- rjf: parse the string as metadesk
MD_Node *root = md_tree_from_string(scratch.arena, string);
//- rjf: iterate the top-level metadesk trees, generate new cfg trees for each
for MD_EachNode(tln, root->first)
{
CFG_Node *dst_root_n = &cfg_nil_node;
CFG_Node *dst_active_parent_n = &cfg_nil_node;
MD_NodeRec rec = {0};
for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next)
{
// rjf: lookup schema for this string
MD_Node *schema = &md_nil_node;
{
MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, schema_table, dst_active_parent_n->parent->string);
for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next)
{
schema = md_child_from_string(n->v, dst_active_parent_n->string, 0);
}
}
// rjf: extract & transform metadesk node's string (it is raw textual data, so we need to
// go escaped -> raw, and derelativize paths)
String8 dst_n_string = {0};
{
String8 src_n_string = src_n->string;
String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string);
if(!md_node_has_tag(schema->first, str8_lit("no_relativize"), 0))
{
if(str8_match(schema->first->string, str8_lit("path"), 0))
{
src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path);
}
else if(str8_match(schema->first->string, str8_lit("path_pt"), 0))
{
String8TxtPtPair parts = str8_txt_pt_pair_from_string(src_n_string__raw);
src_n_string__raw = push_str8f(scratch.arena, "%S:%I64d:%I64d", path_absolute_dst_from_relative_dst_src(scratch.arena, parts.string, root_path), parts.pt.line, parts.pt.column);
}
}
dst_n_string = src_n_string__raw;
}
// rjf: allocate, fill, & insert new cfg for this metadesk node
CFG_Node *dst_n = cfg_node_alloc(state);
cfg_node_equip_string(state, dst_n, dst_n_string);
if(dst_active_parent_n != &cfg_nil_node)
{
cfg_node_insert_child(state, dst_active_parent_n, dst_active_parent_n->last, dst_n);
}
// rjf: recurse
rec = md_node_rec_depth_first_pre(src_n, tln);
if(dst_active_parent_n == &cfg_nil_node)
{
dst_root_n = dst_n;
}
if(rec.push_count > 0)
{
dst_active_parent_n = dst_n;
}
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
{
dst_active_parent_n = dst_active_parent_n->parent;
}
}
cfg_node_ptr_list_push(arena, &result, dst_root_n);
}
scratch_end(scratch);
return result;
}
-233
View File
@@ -1,233 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONFIG_CORE_H
#define CONFIG_CORE_H
////////////////////////////////
//~ rjf: IDs
typedef U64 CFG_ID;
typedef struct CFG_IDNode CFG_IDNode;
struct CFG_IDNode
{
CFG_IDNode *next;
CFG_ID v;
};
typedef struct CFG_IDList CFG_IDList;
struct CFG_IDList
{
CFG_IDNode *first;
CFG_IDNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Tree Types
typedef struct CFG_Node CFG_Node;
struct CFG_Node
{
CFG_Node *first;
CFG_Node *last;
CFG_Node *next;
CFG_Node *prev;
CFG_Node *parent;
CFG_ID id;
String8 string;
};
typedef struct CFG_NodePtrNode CFG_NodePtrNode;
struct CFG_NodePtrNode
{
CFG_NodePtrNode *next;
CFG_NodePtrNode *prev;
CFG_Node *v;
};
typedef struct CFG_NodePtrSlot CFG_NodePtrSlot;
struct CFG_NodePtrSlot
{
CFG_NodePtrNode *first;
CFG_NodePtrNode *last;
};
typedef struct CFG_NodePtrList CFG_NodePtrList;
struct CFG_NodePtrList
{
CFG_NodePtrNode *first;
CFG_NodePtrNode *last;
U64 count;
};
typedef struct CFG_NodePtrArray CFG_NodePtrArray;
struct CFG_NodePtrArray
{
CFG_Node **v;
U64 count;
};
typedef struct CFG_NodeRec CFG_NodeRec;
struct CFG_NodeRec
{
CFG_Node *next;
S32 push_count;
S32 pop_count;
};
////////////////////////////////
//~ rjf: String Allocator
read_only global U64 cfg_string_bucket_chunk_sizes[] =
{
16,
64,
256,
1024,
4096,
16384,
65536,
0xffffffffffffffffull,
};
typedef struct CFG_StringChunkNode CFG_StringChunkNode;
struct CFG_StringChunkNode
{
CFG_StringChunkNode *next;
U64 size;
};
////////////////////////////////
//~ rjf: Config State Bundles
typedef struct CFG_Ctx CFG_Ctx;
struct CFG_Ctx
{
CFG_Node *root;
U64 id_slots_count;
CFG_NodePtrSlot *id_slots;
U64 change_gen;
CFG_ID last_accessed_id;
CFG_Node *last_accessed;
};
typedef struct CFG_State CFG_State;
struct CFG_State
{
Arena *arena;
CFG_Node *free;
CFG_NodePtrNode *free_id_node;
CFG_StringChunkNode *free_string_chunks[ArrayCount(cfg_string_bucket_chunk_sizes)];
U64 id_gen;
CFG_Ctx ctx;
};
////////////////////////////////
//~ rjf: Schema Table
typedef struct CFG_SchemaNode CFG_SchemaNode;
struct CFG_SchemaNode
{
CFG_SchemaNode *next;
String8 name;
MD_Node *schema;
};
typedef struct CFG_SchemaTable CFG_SchemaTable;
struct CFG_SchemaTable
{
CFG_SchemaNode **slots;
U64 slots_count;
};
////////////////////////////////
//~ rjf: Globals
read_only global CFG_Node cfg_nil_node =
{
&cfg_nil_node,
&cfg_nil_node,
&cfg_nil_node,
&cfg_nil_node,
&cfg_nil_node,
};
thread_static CFG_Ctx *cfg_ctx = 0;
////////////////////////////////
//~ rjf: ID Functions
internal void cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id);
internal CFG_IDList cfg_id_list_copy(Arena *arena, CFG_IDList *src);
////////////////////////////////
//~ rjf: Node Pointer Data Structure Functions
internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
#define cfg_node_ptr_list_first(list) ((list)->count ? (list)->first->v : &cfg_nil_node)
#define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node)
internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list);
////////////////////////////////
//~ rjf: Schema Data Structure Functions
internal void cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema);
internal MD_Node *cfg_schema_from_name(CFG_SchemaTable *table, String8 name);
internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name);
////////////////////////////////
//~ rjf: Config Reading Functions
//- rjf: context selection
internal void cfg_ctx_select(CFG_Ctx *ctx);
//- rjf: tree navigations
internal U64 cfg_change_gen(void);
internal CFG_Node *cfg_node_root(void);
internal CFG_Node *cfg_node_from_id(CFG_ID id);
internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string);
internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string);
internal CFG_NodePtrList cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string);
internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, String8 string);
internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node);
//- rjf: serialization
internal String8 cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root);
////////////////////////////////
//~ rjf: Config Writing Functions
//- rjf: state creation / destroying
internal CFG_State *cfg_state_alloc(void);
internal void cfg_state_release(CFG_State *state);
//- rjf: state -> ctx
internal CFG_Ctx *cfg_state_ctx(CFG_State *state);
//- rjf: string allocations
internal U64 cfg_string_bucket_num_from_size(U64 size);
internal String8 cfg_string_alloc(CFG_State *state, String8 string);
internal void cfg_string_release(CFG_State *state, String8 string);
//- rjf: tree building
internal CFG_Node *cfg_node_alloc(CFG_State *state);
internal void cfg_node_release(CFG_State *state, CFG_Node *node);
internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node);
internal CFG_Node *cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string);
internal CFG_Node *cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...);
internal CFG_Node *cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string);
internal CFG_Node *cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...);
internal CFG_Node *cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root);
internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string);
internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...);
internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child);
internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child);
internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string);
//- rjf: deserialization
internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string);
#endif // CONFIG_CORE_H
-8
View File
@@ -1,8 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "config_core.c"
#include "config_panels.c"
#if defined(OS_GFX_H)
# include "config_bindings.c"
#endif
-13
View File
@@ -1,13 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONFIG_INC_H
#define CONFIG_INC_H
#include "config_core.h"
#include "config_panels.h"
#if defined(OS_GFX_H)
# include "config_bindings.h"
#endif
#endif // CONFIG_INC_H
-217
View File
@@ -1,217 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal CFG_Node *
cfg_window_from_cfg(CFG_Node *cfg)
{
CFG_Node *result = &cfg_nil_node;
for(CFG_Node *c = cfg; c != &cfg_nil_node; c = c->parent)
{
if(c->parent->parent == cfg_node_root() && str8_match(c->string, str8_lit("window"), 0))
{
result = c;
break;
}
}
return result;
}
internal CFG_PanelTree
cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root)
{
Temp scratch = scratch_begin(&arena, 1);
CFG_Node *wcfg = cfg_window_from_cfg(cfg_root);
CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels"));
CFG_PanelNode *dst_root = &cfg_nil_panel_node;
CFG_PanelNode *dst_focused = &cfg_nil_panel_node;
{
Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y;
CFG_NodeRec rec = {0};
CFG_PanelNode *dst_active_parent = &cfg_nil_panel_node;
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
{
// rjf: build a panel node
CFG_PanelNode *dst = push_array(arena, CFG_PanelNode, 1);
MemoryCopyStruct(dst, &cfg_nil_panel_node);
dst->parent = dst_active_parent;
if(dst_active_parent != &cfg_nil_panel_node)
{
DLLPushBack_NPZ(&cfg_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev);
dst_active_parent->child_count += 1;
}
if(dst_root == &cfg_nil_panel_node)
{
dst_root = dst;
}
// rjf: extract cfg info
B32 panel_has_children = 0;
dst->cfg = src;
dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string));
dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min);
dst->split_axis = active_split_axis;
for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next)
{
MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string);
if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric)
{
panel_has_children = 1;
}
else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0))
{
// NOTE(rjf): skip - this is a panel option.
}
else if(str8_match(src_child->string, str8_lit("selected"), 0))
{
dst_focused = dst;
}
else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier)
{
cfg_node_ptr_list_push(arena, &dst->tabs, src_child);
if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node)
{
dst->selected_tab = src_child;
}
}
}
// rjf: recurse
rec = cfg_node_rec__depth_first(src_root, src);
if(!panel_has_children)
{
MemoryZeroStruct(&rec);
rec.next = &cfg_nil_node;
for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1)
{
if(p->next != &cfg_nil_node)
{
rec.next = p->next;
break;
}
}
}
if(rec.push_count > 0)
{
dst_active_parent = dst;
active_split_axis = axis2_flip(active_split_axis);
}
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
{
dst_active_parent = dst_active_parent->parent;
active_split_axis = axis2_flip(active_split_axis);
}
}
}
scratch_end(scratch);
CFG_PanelTree tree = {dst_root, dst_focused};
return tree;
}
internal CFG_PanelNodeRec
cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off)
{
CFG_PanelNodeRec rec = {&cfg_nil_panel_node};
if(*MemberFromOffset(CFG_PanelNode **, panel, child_off) != &cfg_nil_panel_node)
{
rec.next = *MemberFromOffset(CFG_PanelNode **, panel, child_off);
rec.push_count += 1;
}
else for(CFG_PanelNode *p = panel; p != &cfg_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1)
{
if(*MemberFromOffset(CFG_PanelNode **, p, sib_off) != &cfg_nil_panel_node)
{
rec.next = *MemberFromOffset(CFG_PanelNode **, p, sib_off);
break;
}
}
return rec;
}
internal CFG_PanelNode *
cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg)
{
CFG_PanelNode *result = &cfg_nil_panel_node;
for(CFG_PanelNode *p = root;
p != &cfg_nil_panel_node;
p = cfg_panel_node_rec__depth_first_pre(root, p).next)
{
if(p->cfg == cfg)
{
result = p;
break;
}
}
return result;
}
internal Rng2F32
cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel)
{
Rng2F32 rect = parent_rect;
if(parent != &cfg_nil_panel_node)
{
Vec2F32 parent_rect_size = dim_2f32(parent_rect);
Axis2 axis = parent->split_axis;
rect.p1.v[axis] = rect.p0.v[axis];
for(CFG_PanelNode *child = parent->first; child != &cfg_nil_panel_node; child = child->next)
{
rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent;
if(child == panel)
{
break;
}
rect.p0.v[axis] = rect.p1.v[axis];
}
//rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis];
//rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)];
}
rect.x0 = round_f32(rect.x0);
rect.x1 = round_f32(rect.x1);
rect.y0 = round_f32(rect.y0);
rect.y1 = round_f32(rect.y1);
return rect;
}
internal Rng2F32
cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel)
{
Temp scratch = scratch_begin(0, 0);
// rjf: count ancestors
U64 ancestor_count = 0;
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
{
ancestor_count += 1;
}
// rjf: gather ancestors
CFG_PanelNode **ancestors = push_array(scratch.arena, CFG_PanelNode *, ancestor_count);
{
U64 ancestor_idx = 0;
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
{
ancestors[ancestor_idx] = p;
ancestor_idx += 1;
}
}
// rjf: go from highest ancestor => panel and calculate rect
Rng2F32 parent_rect = root_rect;
for(S64 ancestor_idx = (S64)ancestor_count-1;
0 <= ancestor_idx && ancestor_idx < ancestor_count;
ancestor_idx -= 1)
{
CFG_PanelNode *ancestor = ancestors[ancestor_idx];
CFG_PanelNode *parent = ancestor->parent;
if(parent != &cfg_nil_panel_node)
{
parent_rect = cfg_target_rect_from_panel_node_child(parent_rect, parent, ancestor);
}
}
// rjf: calculate final rect
Rng2F32 rect = cfg_target_rect_from_panel_node_child(parent_rect, panel->parent, panel);
scratch_end(scratch);
return rect;
}
-67
View File
@@ -1,67 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONFIG_PANELS_H
#define CONFIG_PANELS_H
typedef struct CFG_PanelNode CFG_PanelNode;
struct CFG_PanelNode
{
// rjf: links data
CFG_PanelNode *first;
CFG_PanelNode *last;
CFG_PanelNode *next;
CFG_PanelNode *prev;
CFG_PanelNode *parent;
U64 child_count;
CFG_Node *cfg;
// rjf: split data
Axis2 split_axis;
F32 pct_of_parent;
// rjf: tab params
Side tab_side;
// rjf: which tabs are attached
CFG_NodePtrList tabs;
CFG_Node *selected_tab;
};
typedef struct CFG_PanelTree CFG_PanelTree;
struct CFG_PanelTree
{
CFG_PanelNode *root;
CFG_PanelNode *focused;
};
typedef struct CFG_PanelNodeRec CFG_PanelNodeRec;
struct CFG_PanelNodeRec
{
CFG_PanelNode *next;
S32 push_count;
S32 pop_count;
};
read_only global CFG_PanelNode cfg_nil_panel_node =
{
&cfg_nil_panel_node,
&cfg_nil_panel_node,
&cfg_nil_panel_node,
&cfg_nil_panel_node,
&cfg_nil_panel_node,
0,
&cfg_nil_node,
.selected_tab = &cfg_nil_node,
};
internal CFG_Node *cfg_window_from_cfg(CFG_Node *cfg);
internal CFG_PanelTree cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root);
internal CFG_PanelNodeRec cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off);
#define cfg_panel_node_rec__depth_first_pre(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, next), OffsetOf(CFG_PanelNode, first))
#define cfg_panel_node_rec__depth_first_pre_rev(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, prev), OffsetOf(CFG_PanelNode, last))
internal CFG_PanelNode *cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg);
internal Rng2F32 cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel);
internal Rng2F32 cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel);
#endif // CONFIG_PANELS_H
-522
View File
@@ -1,522 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#undef LAYER_COLOR
#define LAYER_COLOR 0x684123ff
////////////////////////////////
//~ rjf: Basic Helpers
internal C_ID
c_id_make(U64 u64_0, U64 u64_1)
{
C_ID id;
id.u128[0].u64[0] = u64_0;
id.u128[0].u64[1] = u64_1;
return id;
}
internal B32
c_id_match(C_ID a, C_ID b)
{
B32 result = MemoryMatchStruct(&a, &b);
return result;
}
internal C_Key
c_key_make(C_Root root, C_ID id)
{
C_Key key = {root, 0, id};
return key;
}
internal B32
c_key_match(C_Key a, C_Key b)
{
return (MemoryMatchStruct(&a.root, &b.root) && c_id_match(a.id, b.id));
}
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void
c_init(void)
{
Arena *arena = arena_alloc();
c_shared = push_array(arena, C_Shared, 1);
c_shared->arena = arena;
c_shared->blob_slots_count = 16384;
c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, os_get_system_info()->logical_processor_count);
c_shared->blob_slots = push_array(arena, C_BlobSlot, c_shared->blob_slots_count);
c_shared->blob_stripes = push_array(arena, C_Stripe, c_shared->blob_stripes_count);
c_shared->blob_stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->blob_stripes_count);
for(U64 idx = 0; idx < c_shared->blob_stripes_count; idx += 1)
{
C_Stripe *stripe = &c_shared->blob_stripes[idx];
stripe->arena = arena_alloc();
stripe->rw_mutex = rw_mutex_alloc();
stripe->cv = cond_var_alloc();
}
c_shared->key_slots_count = 4096;
c_shared->key_stripes_count = Min(c_shared->key_slots_count, os_get_system_info()->logical_processor_count);
c_shared->key_slots = push_array(arena, C_KeySlot, c_shared->key_slots_count);
c_shared->key_stripes = push_array(arena, C_Stripe, c_shared->key_stripes_count);
c_shared->key_stripes_free_nodes = push_array(arena, C_KeyNode *, c_shared->key_stripes_count);
for(U64 idx = 0; idx < c_shared->key_stripes_count; idx += 1)
{
C_Stripe *stripe = &c_shared->key_stripes[idx];
stripe->arena = arena_alloc();
stripe->rw_mutex = rw_mutex_alloc();
stripe->cv = cond_var_alloc();
}
c_shared->root_slots_count = 4096;
c_shared->root_stripes_count = Min(c_shared->root_slots_count, os_get_system_info()->logical_processor_count);
c_shared->root_slots = push_array(arena, C_RootSlot, c_shared->root_slots_count);
c_shared->root_stripes = push_array(arena, C_Stripe, c_shared->root_stripes_count);
c_shared->root_stripes_free_nodes = push_array(arena, C_RootNode *, c_shared->root_stripes_count);
for(U64 idx = 0; idx < c_shared->root_stripes_count; idx += 1)
{
C_Stripe *stripe = &c_shared->root_stripes[idx];
stripe->arena = arena_alloc();
stripe->rw_mutex = rw_mutex_alloc();
stripe->cv = cond_var_alloc();
}
}
////////////////////////////////
//~ rjf: Root Allocation/Deallocation
internal C_Root
c_root_alloc(void)
{
C_Root root = {0};
root.u64[0] = ins_atomic_u64_inc_eval(&c_shared->root_id_gen);
U64 slot_idx = root.u64[0]%c_shared->root_slots_count;
U64 stripe_idx = slot_idx%c_shared->root_stripes_count;
C_RootSlot *slot = &c_shared->root_slots[slot_idx];
C_Stripe *stripe = &c_shared->root_stripes[stripe_idx];
MutexScopeW(stripe->rw_mutex)
{
C_RootNode *node = c_shared->root_stripes_free_nodes[stripe_idx];
if(node != 0)
{
SLLStackPop(c_shared->root_stripes_free_nodes[stripe_idx]);
}
else
{
node = push_array(stripe->arena, C_RootNode, 1);
}
DLLPushBack(slot->first, slot->last, node);
node->root = root;
node->arena = arena_alloc();
}
return root;
}
internal void
c_root_release(C_Root root)
{
//- rjf: unpack root
U64 slot_idx = root.u64[0]%c_shared->root_slots_count;
U64 stripe_idx = slot_idx%c_shared->root_stripes_count;
C_RootSlot *slot = &c_shared->root_slots[slot_idx];
C_Stripe *stripe = &c_shared->root_stripes[stripe_idx];
//- rjf: release root node, grab its arena / ID list
Arena *root_arena = 0;
C_RootIDChunkList root_ids = {0};
MutexScopeW(stripe->rw_mutex)
{
for(C_RootNode *n = slot->first; n != 0; n = n->next)
{
if(MemoryMatchStruct(&root, &n->root))
{
DLLRemove(slot->first, slot->last, n);
root_arena = n->arena;
root_ids = n->ids;
SLLStackPush(c_shared->root_stripes_free_nodes[stripe_idx], n);
break;
}
}
}
//- rjf: release all IDs
for(C_RootIDChunkNode *id_chunk_n = root_ids.first; id_chunk_n != 0; id_chunk_n = id_chunk_n->next)
{
for EachIndex(chunk_idx, id_chunk_n->count)
{
C_ID id = id_chunk_n->v[chunk_idx];
C_Key key = c_key_make(root, id);
c_close_key(key);
}
}
}
////////////////////////////////
//~ rjf: Cache Submission
internal U128
c_submit_data(C_Key key, Arena **data_arena, String8 data)
{
//- rjf: unpack key
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
//- rjf: hash data, unpack hash
U128 hash = u128_hash_from_str8(data);
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
//- rjf: commit to (hash -> data) cache
ProfScope("commit to (hash -> data) cache") RWMutexScope(stripe->rw_mutex, 1)
{
// rjf: find existing node
C_BlobNode *node = 0;
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash))
{
node = n;
break;
}
}
// rjf: release duplicate data if node already exists
if(node != 0 && data_arena != 0 && *data_arena != 0)
{
arena_release(*data_arena);
}
// rjf: allocate node if needed
if(node == 0)
{
node = c_shared->blob_stripes_free_nodes[stripe_idx];
if(node)
{
SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]);
}
else
{
node = push_array_no_zero(stripe->arena, C_BlobNode, 1);
}
MemoryZeroStruct(node);
node->hash = hash;
if(data_arena != 0)
{
node->arena = *data_arena;
}
node->data = data;
DLLPushBack(slot->first, slot->last, node);
}
// rjf: bump key ref count
node->key_ref_count += 1;
// rjf "steal" arena from caller
if(data_arena != 0)
{
*data_arena = 0;
}
}
//- rjf: commit to (key -> list(hash)) cache
U128 key_expired_hash = {0};
ProfScope("commit to (key -> list(hash)) cache") RWMutexScope(key_stripe->rw_mutex, 1)
{
// rjf: find existing key
C_KeyNode *key_node = 0;
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
{
if(c_key_match(n->key, key))
{
key_node = n;
break;
}
}
// rjf: create key node if it doesn't exist
B32 key_is_new = 0;
if(!key_node)
{
key_is_new = 1;
key_node = c_shared->key_stripes_free_nodes[key_stripe_idx];
if(key_node)
{
SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]);
}
else
{
key_node = push_array_no_zero(key_stripe->arena, C_KeyNode, 1);
}
MemoryZeroStruct(key_node);
key_node->key = key;
DLLPushBack(key_slot->first, key_slot->last, key_node);
}
// rjf: push hash into key's history
if(key_node)
{
if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT)
{
key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)];
}
key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash;
key_node->hash_history_gen += 1;
}
// rjf: key is new -> add this key to the associated root
if(key_is_new)
{
U64 root_hash = u64_hash_from_str8(str8_struct(&key.root));
U64 root_slot_idx = root_hash%c_shared->root_slots_count;
U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count;
C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx];
C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx];
RWMutexScope(root_stripe->rw_mutex, 1)
{
for(C_RootNode *n = root_slot->first; n != 0; n = n->next)
{
if(MemoryMatchStruct(&n->root, &key.root))
{
C_RootIDChunkNode *chunk = n->ids.last;
if(chunk == 0 || chunk->count >= chunk->cap)
{
chunk = push_array(n->arena, C_RootIDChunkNode, 1);
SLLQueuePush(n->ids.first, n->ids.last, chunk);
n->ids.chunk_count += 1;
chunk->cap = 1024;
chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap);
}
chunk->v[chunk->count] = key.id;
chunk->count += 1;
n->ids.total_count += 1;
break;
}
}
}
}
}
//- rjf: decrement key ref count of expired hash
if(!u128_match(key_expired_hash, u128_zero())) ProfScope("decrement key ref count of expired hash")
{
U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->blob_slots_count;
U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->blob_stripes_count;
C_BlobSlot *old_hash_slot = &c_shared->blob_slots[old_hash_slot_idx];
C_Stripe *old_hash_stripe = &c_shared->blob_stripes[old_hash_stripe_idx];
RWMutexScope(old_hash_stripe->rw_mutex, 0)
{
for(C_BlobNode *n = old_hash_slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, key_expired_hash))
{
ins_atomic_u64_dec_eval(&n->key_ref_count);
break;
}
}
}
}
return hash;
}
////////////////////////////////
//~ rjf: Key Closing
internal void
c_close_key(C_Key key)
{
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
RWMutexScope(key_stripe->rw_mutex, 1)
{
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
{
if(c_key_match(n->key, key))
{
for(U64 history_idx = 0;
history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen;
history_idx += 1)
{
U128 hash = n->hash_history[(n->hash_history_gen-1-history_idx) % ArrayCount(n->hash_history)];
U64 hash_slot_idx = hash.u64[1]%c_shared->blob_slots_count;
U64 hash_stripe_idx = hash_slot_idx%c_shared->blob_stripes_count;
C_BlobSlot *hash_slot = &c_shared->blob_slots[hash_slot_idx];
C_Stripe *hash_stripe = &c_shared->blob_stripes[hash_stripe_idx];
MutexScopeR(hash_stripe->rw_mutex)
{
for(C_BlobNode *n = hash_slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash))
{
ins_atomic_u64_dec_eval(&n->key_ref_count);
break;
}
}
}
}
DLLRemove(key_slot->first, key_slot->last, n);
SLLStackPush(c_shared->key_stripes_free_nodes[key_stripe_idx], n);
break;
}
}
}
}
////////////////////////////////
//~ rjf: Downstream Accesses
internal void
c_hash_downstream_inc(U128 hash)
{
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex)
{
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
{
if(u128_match(hash, n->hash))
{
ins_atomic_u64_inc_eval(&n->downstream_ref_count);
break;
}
}
}
}
internal void
c_hash_downstream_dec(U128 hash)
{
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex)
{
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
{
if(u128_match(hash, n->hash))
{
ins_atomic_u64_dec_eval(&n->downstream_ref_count);
break;
}
}
}
}
////////////////////////////////
//~ rjf: Cache Lookup
internal U128
c_hash_from_key(C_Key key, U64 rewind_count)
{
U128 result = {0};
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
RWMutexScope(key_stripe->rw_mutex, 0)
{
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
{
if(c_key_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count)
{
result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)];
break;
}
}
}
return result;
}
internal String8
c_data_from_hash(Access *access, U128 hash)
{
ProfBeginFunction();
String8 result = {0};
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex)
{
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash))
{
result = n->data;
access_touch(access, &n->access_pt, stripe->cv);
break;
}
}
}
ProfEnd();
return result;
}
////////////////////////////////
//~ rjf: Asynchronous Tick
internal void
c_async_tick(void)
{
ProfBeginFunction();
//- rjf: garbage collect blobs
{
Rng1U64 range = lane_range(c_shared->blob_slots_count);
for EachInRange(slot_idx, range)
{
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
{
B32 slot_has_work = 0;
RWMutexScope(stripe->rw_mutex, write_mode)
{
for(C_BlobNode *n = slot->first, *next = 0; n != 0; n = next)
{
next = n->next;
U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count);
U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count);
if(access_pt_is_expired(&n->access_pt, .time = 5000000) && key_ref_count == 0 && downstream_ref_count == 0)
{
slot_has_work = 1;
if(!write_mode)
{
break;
}
else
{
DLLRemove(slot->first, slot->last, n);
SLLStackPush(c_shared->blob_stripes_free_nodes[stripe_idx], n);
if(n->arena != 0)
{
arena_release(n->arena);
}
}
}
}
}
if(!slot_has_work)
{
break;
}
}
}
}
ProfEnd();
}
-243
View File
@@ -1,243 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONTENT_H
#define CONTENT_H
////////////////////////////////
//~ NOTE(rjf): Hash Store Notes (2025/05/18)
//
// The hash store is a general-purpose data cache. It offers three layers of
// caching: (a) content (hash of data), (b) key (unique identity correllated
// with history of hashes), and (c) root (bucket for many keys, manually
// allocated / deallocated).
//
// (a) The "content" level of cache access is a simply hash(data) -> data
// mapping. This bypasses all identity/key/root mechanisms and provides a
// way to just talk about unique (and deduplicated) blobs of data.
//
// (b) The "key" level of cache access is used to encode a history of hashes
// for some unique "identity", where the "identity" is a concept managed
// by the user. One example of an identity would be a particular address
// range inside of some process to which the debugger is attached. Another
// might be a range inside of some file.
//
// (c) The "root" level is to provide a top-level allocation/deallocation
// mechanism for a large set of keys. It also provides an extra level of
// key uniqueness. For instance, each process to which the debugger is
// attached might have its own root, and each key might correspond to a
// particular address range within that process. This way, when the
// process ends, all of its keys can be easily destroyed using a single
// deallocation of the root.
//
// The way this might be generally used inside of the debugger would be that
// some evaluation - let's say it's some variable `x` - is mapped (via debug
// info) to some address range. If `x` is a `char[4096]`, then it might map
// to some address range [&x, &x + 4096). This, together with the process
// within which `x` is evaluated, forms both a `root` (for the process) and
// a `key` (for the address range). Some asynchronous memory streaming system
// can then, together with the root and key, read memory for that range, then
// submit that data to the hash store, correllating with the root and key
// combo.
////////////////////////////////
//~ rjf: Key Types
typedef struct C_Root C_Root;
struct C_Root
{
U64 u64[1];
};
typedef struct C_ID C_ID;
struct C_ID
{
U128 u128[1];
};
typedef struct C_Key C_Key;
struct C_Key
{
C_Root root;
U64 _padding_;
C_ID id;
};
////////////////////////////////
//~ rjf: Cache Stripe Type
typedef struct C_Stripe C_Stripe;
struct C_Stripe
{
Arena *arena;
RWMutex rw_mutex;
CondVar cv;
};
////////////////////////////////
//~ rjf: Root Cache Types
typedef struct C_RootIDChunkNode C_RootIDChunkNode;
struct C_RootIDChunkNode
{
C_RootIDChunkNode *next;
C_ID *v;
U64 count;
U64 cap;
};
typedef struct C_RootIDChunkList C_RootIDChunkList;
struct C_RootIDChunkList
{
C_RootIDChunkNode *first;
C_RootIDChunkNode *last;
U64 chunk_count;
U64 total_count;
};
typedef struct C_RootNode C_RootNode;
struct C_RootNode
{
C_RootNode *next;
C_RootNode *prev;
Arena *arena;
C_Root root;
C_RootIDChunkList ids;
};
typedef struct C_RootSlot C_RootSlot;
struct C_RootSlot
{
C_RootNode *first;
C_RootNode *last;
};
////////////////////////////////
//~ rjf: Key Cache Types
#define C_KEY_HASH_HISTORY_COUNT 64
#define C_KEY_HASH_HISTORY_STRONG_REF_COUNT 2
typedef struct C_KeyNode C_KeyNode;
struct C_KeyNode
{
C_KeyNode *next;
C_KeyNode *prev;
C_Key key;
U128 hash_history[C_KEY_HASH_HISTORY_COUNT];
U64 hash_history_gen;
};
typedef struct C_KeySlot C_KeySlot;
struct C_KeySlot
{
C_KeyNode *first;
C_KeyNode *last;
};
////////////////////////////////
//~ rjf: Content Blob Cache Types
typedef struct C_BlobNode C_BlobNode;
struct C_BlobNode
{
C_BlobNode *next;
C_BlobNode *prev;
U128 hash;
Arena *arena;
String8 data;
AccessPt access_pt;
U64 key_ref_count;
U64 downstream_ref_count;
};
typedef struct C_BlobSlot C_BlobSlot;
struct C_BlobSlot
{
C_BlobNode *first;
C_BlobNode *last;
};
////////////////////////////////
//~ rjf: Shared State
typedef struct C_Shared C_Shared;
struct C_Shared
{
Arena *arena;
// rjf: main data blob cache
U64 blob_slots_count;
U64 blob_stripes_count;
C_BlobSlot *blob_slots;
C_Stripe *blob_stripes;
C_BlobNode **blob_stripes_free_nodes;
// rjf: key cache
U64 key_slots_count;
U64 key_stripes_count;
C_KeySlot *key_slots;
C_Stripe *key_stripes;
C_KeyNode **key_stripes_free_nodes;
// rjf: root cache
U64 root_slots_count;
U64 root_stripes_count;
C_RootSlot *root_slots;
C_Stripe *root_stripes;
C_RootNode **root_stripes_free_nodes;
U64 root_id_gen;
};
////////////////////////////////
//~ rjf: Globals
global C_Shared *c_shared = 0;
////////////////////////////////
//~ rjf: Basic Helpers
internal C_ID c_id_make(U64 u64_0, U64 u64_1);
internal B32 c_id_match(C_ID a, C_ID b);
internal C_Key c_key_make(C_Root root, C_ID id);
internal B32 c_key_match(C_Key a, C_Key b);
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void c_init(void);
////////////////////////////////
//~ rjf: Root Allocation/Deallocation
internal C_Root c_root_alloc(void);
internal void c_root_release(C_Root root);
////////////////////////////////
//~ rjf: Cache Submission
internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data);
////////////////////////////////
//~ rjf: Key Closing
internal void c_close_key(C_Key key);
////////////////////////////////
//~ rjf: Downstream Accesses
internal void c_hash_downstream_inc(U128 hash);
internal void c_hash_downstream_dec(U128 hash);
////////////////////////////////
//~ rjf: Cache Lookups
internal U128 c_hash_from_key(C_Key key, U64 rewind_count);
internal String8 c_data_from_hash(Access *access, U128 hash);
////////////////////////////////
//~ rjf: Asynchronous Tick
internal void c_async_tick(void);
#endif // CONTENT_H
+35 -142
View File
@@ -1,46 +1,8 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Entity Kinds
@table(name code_name display_string)
CTRL_EntityKindTable:
{
{Root root "Root" }
{Machine machine "Machine" }
{Process process "Process" }
{Thread thread "Thread" }
{Module module "Module" }
{EntryPoint entry_point "Entry Point" }
{DebugInfoPath debug_info_path "Debug Info Path" }
{PendingThreadName pending_thread_name "Pending Thread Name" }
{PendingThreadColor pending_thread_color "Pending Thread Color" }
{Breakpoint breakpoint "Breakpoint" }
{AddressRangeAnnotation address_range_annotation "Address Range Annotation" }
}
@enum CTRL_EntityKind:
{
Null,
@expand(CTRL_EntityKindTable a) `$(a.name)`,
COUNT,
}
@data(String8) ctrl_entity_kind_code_name_table:
{
`{0}`,
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.code_name)")`
}
@data(String8) ctrl_entity_kind_display_string_table:
{
`{0}`,
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.display_name)")`
}
////////////////////////////////
//~ rjf: Exception Codes
//~ rjf: Tables
@table(name lower_name code default display_string)
CTRL_ExceptionCodeKindTable:
@@ -84,109 +46,40 @@ CTRL_ExceptionCodeKindTable:
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
}
@enum CTRL_ExceptionCodeKind:
{
Null,
@expand(CTRL_ExceptionCodeKindTable a) `$(a.name)`,
COUNT,
}
@data(U32) ctrl_exception_code_kind_code_table:
{
`0`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code)`;
}
@data(String8) ctrl_exception_code_kind_display_string_table:
{
`{0}`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`;
}
@data(String8) ctrl_exception_code_kind_lowercase_code_string_table:
{
`{0}`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`;
}
@data(B8) ctrl_exception_code_kind_default_enable_table:
{
`0`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default)`;
}
////////////////////////////////
//~ rjf: Exception Sub-Codes
//~ rjf: Generators
@table(name, value)
CTRL_ExceptionSubCodeKindTable:
@table_gen_enum CTRL_ExceptionCodeKind:
{
{ W32_FAST_FAIL_LEGACY_GS_VIOLATION 0 }
{ W32_FAST_FAIL_VTGUARD_CHECK_FAILURE 1 }
{ W32_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2 }
{ W32_FAST_FAIL_CORRUPT_LIST_ENTRY 3 }
{ W32_FAST_FAIL_INCORRECT_STACK 4 }
{ W32_FAST_FAIL_INVALID_ARG 5 }
{ W32_FAST_FAIL_GS_COOKIE_INIT 6 }
{ W32_FAST_FAIL_FATAL_APP_EXIT 7 }
{ W32_FAST_FAIL_RANGE_CHECK_FAILURE 8 }
{ W32_FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10 }
{ W32_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11 }
{ W32_FAST_FAIL_INVALID_FIBER_SWITCH 12 }
{ W32_FAST_FAIL_INVALID_SET_OF_CONTEXT 13 }
{ W32_FAST_FAIL_INVALID_REFERENCE_COUNT 14 }
{ W32_FAST_FAIL_INVALID_JUMP_BUFFER 18 }
{ W32_FAST_FAIL_MRDATA_MODIFIED 19 }
{ W32_FAST_FAIL_CERTIFICATION_FAILURE 20 }
{ W32_FAST_FAIL_INVALID_EXCEPTION_CHAIN 21 }
{ W32_FAST_FAIL_CRYPTO_LIBRARY 22 }
{ W32_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23 }
{ W32_FAST_FAIL_INVALID_IMAGE_BASE 24 }
{ W32_FAST_FAIL_DLOAD_PROTECTION_FAILURE 25 }
{ W32_FAST_FAIL_UNSAFE_EXTENSION_CALL 26 }
{ W32_FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27 }
{ W32_FAST_FAIL_INVALID_BUFFER_ACCESS 28 }
{ W32_FAST_FAIL_INVALID_BALANCED_TREE 29 }
{ W32_FAST_FAIL_INVALID_NEXT_THREAD 30 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 }
{ W32_FAST_FAIL_APCS_DISABLED 32 }
{ W32_FAST_FAIL_INVALID_IDLE_STATE 33 }
{ W32_FAST_FAIL_MRDATA_PROTECTION_FAILURE 34 }
{ W32_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35 }
{ W32_FAST_FAIL_INVALID_LOCK_STATE 36 }
{ W32_FAST_FAIL_GUARD_JUMPTABLE 37 }
{ W32_FAST_FAIL_INVALID_LONGJUMP_TARGET 38 }
{ W32_FAST_FAIL_INVALID_DISPATCH_CONTEXT 39 }
{ W32_FAST_FAIL_INVALID_THREAD 40 }
{ W32_FAST_FAIL_INVALID_SYSCALL_NUMBER 41 }
{ W32_FAST_FAIL_INVALID_FILE_OPERATION 42 }
{ W32_FAST_FAIL_LPAC_ACCESS_DENIED 43 }
{ W32_FAST_FAIL_GUARD_SS_FAILURE 44 }
{ W32_FAST_FAIL_LOADER_CONTINUITY_FAILURE 45 }
{ W32_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE 46 }
{ W32_FAST_FAIL_INVALID_CONTROL_STACK 47 }
{ W32_FAST_FAIL_SET_CONTEXT_DENIED 48 }
{ W32_FAST_FAIL_INVALID_IAT 49 }
{ W32_FAST_FAIL_HEAP_METADATA_CORRUPTION 50 }
{ W32_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION 51 }
{ W32_FAST_FAIL_LOW_LABEL_ACCESS_DENIED 52 }
{ W32_FAST_FAIL_ENCLAVE_CALL_FAILURE 53 }
{ W32_FAST_FAIL_UNHANDLED_LSS_EXCEPTON 54 }
{ W32_FAST_FAIL_ADMINLESS_ACCESS_DENIED 55 }
{ W32_FAST_FAIL_UNEXPECTED_CALL 56 }
{ W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS 57 }
{ W32_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR 58 }
{ W32_FAST_FAIL_FLAGS_CORRUPTION 59 }
{ W32_FAST_FAIL_VEH_CORRUPTION 60 }
{ W32_FAST_FAIL_ETW_CORRUPTION 61 }
{ W32_FAST_FAIL_RIO_ABORT 62 }
{ W32_FAST_FAIL_INVALID_PFN 63 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG 64 }
{ W32_FAST_FAIL_CAST_GUARD 65 }
{ W32_FAST_FAIL_HOST_VISIBILITY_CHANGE 66 }
{ W32_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST 67 }
{ W32_FAST_FAIL_PATCH_CALLBACK_FAILED 68 }
{ W32_FAST_FAIL_NTDLL_PATCH_FAILED 69 }
{ W32_FAST_FAIL_INVALID_FLS_DATA 70 }
`CTRL_ExceptionCodeKind_Null,`;
@expand(CTRL_ExceptionCodeKindTable a) `CTRL_ExceptionCodeKind_$(a.name),`;
`CTRL_ExceptionCodeKind_COUNT`;
}
@table_gen_data(type:U32, fallback:0)
ctrl_exception_code_kind_code_table:
{
`0,`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code),`;
}
@table_gen_data(type:String8, fallback:`{0}`)
ctrl_exception_code_kind_display_string_table:
{
`{0},`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)"),`;
}
@table_gen_data(type:String8, fallback:`{0}`)
ctrl_exception_code_kind_lowercase_code_string_table:
{
`{0},`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)"),`;
}
@table_gen_data(type:B8, fallback:0)
ctrl_exception_code_kind_default_enable_table:
{
`0,`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default),`;
}
+1882 -5215
View File
File diff suppressed because it is too large Load Diff
+247 -676
View File
File diff suppressed because it is too large Load Diff
+1 -4
View File
@@ -1,7 +1,4 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#undef LAYER_COLOR
#define LAYER_COLOR 0x969696ff
#include "ctrl_core.c"
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CTRL_INC_H
@@ -74,4 +74,4 @@
#include "ctrl_core.h"
#endif // CTRL_INC_H
#endif //CTRL_INC_H
+1 -204
View File
@@ -1,208 +1,5 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
C_LINKAGE_BEGIN
String8 ctrl_entity_kind_code_name_table[12] =
{
{0},
str8_lit_comp("root"),
str8_lit_comp("machine"),
str8_lit_comp("process"),
str8_lit_comp("thread"),
str8_lit_comp("module"),
str8_lit_comp("entry_point"),
str8_lit_comp("debug_info_path"),
str8_lit_comp("pending_thread_name"),
str8_lit_comp("pending_thread_color"),
str8_lit_comp("breakpoint"),
str8_lit_comp("address_range_annotation"),
};
String8 ctrl_entity_kind_display_string_table[12] =
{
{0},
str8_lit_comp("Root"),
str8_lit_comp("Machine"),
str8_lit_comp("Process"),
str8_lit_comp("Thread"),
str8_lit_comp("Module"),
str8_lit_comp("EntryPoint"),
str8_lit_comp("DebugInfoPath"),
str8_lit_comp("PendingThreadName"),
str8_lit_comp("PendingThreadColor"),
str8_lit_comp("Breakpoint"),
str8_lit_comp("AddressRangeAnnotation"),
};
U32 ctrl_exception_code_kind_code_table[38] =
{
0,
0x40010005,
0x40010008,
0x40080201,
0x40080202,
0x0000071a,
0x80000002,
0xc0000005,
0xc0000006,
0xc0000008,
0xc0000017,
0xc000001d,
0xc0000025,
0xc0000026,
0xc000008c,
0xc000008d,
0xc000008e,
0xc000008f,
0xc0000090,
0xc0000091,
0xc0000092,
0xc0000093,
0xc0000094,
0xc0000095,
0xc0000096,
0xc00000fd,
0xc0000135,
0xc0000138,
0xc0000139,
0xc0000142,
0xc00002b4,
0xc00002b5,
0xc0000420,
0xc06d007e,
0xc06d007f,
0xe073616e,
0xe0736171,
0x0000087a,
};
String8 ctrl_exception_code_kind_display_string_table[38] =
{
{0},
str8_lit_comp("(Win32) Control-C"),
str8_lit_comp("(Win32) Control-Break"),
str8_lit_comp("(Win32) WinRT Originate Error"),
str8_lit_comp("(Win32) WinRT Transform Error"),
str8_lit_comp("(Win32) RPC Call Cancelled"),
str8_lit_comp("(Win32) Data Type Misalignment"),
str8_lit_comp("(Win32) Access Violation"),
str8_lit_comp("(Win32) In Page Error"),
str8_lit_comp("(Win32) Invalid Handle Specified"),
str8_lit_comp("(Win32) Not Enough Quota"),
str8_lit_comp("(Win32) Illegal Instruction"),
str8_lit_comp("(Win32) Cannot Continue From Exception"),
str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"),
str8_lit_comp("(Win32) Array Bounds Exceeded"),
str8_lit_comp("(Win32) Floating-Point Denormal Operand"),
str8_lit_comp("(Win32) Floating-Point Division By Zero"),
str8_lit_comp("(Win32) Floating-Point Inexact Result"),
str8_lit_comp("(Win32) Floating-Point Invalid Operation"),
str8_lit_comp("(Win32) Floating-Point Overflow"),
str8_lit_comp("(Win32) Floating-Point Stack Check"),
str8_lit_comp("(Win32) Floating-Point Underflow"),
str8_lit_comp("(Win32) Integer Division By Zero"),
str8_lit_comp("(Win32) Integer Overflow"),
str8_lit_comp("(Win32) Privileged Instruction"),
str8_lit_comp("(Win32) Stack Overflow"),
str8_lit_comp("(Win32) Unable To Locate DLL"),
str8_lit_comp("(Win32) Ordinal Not Found"),
str8_lit_comp("(Win32) Entry Point Not Found"),
str8_lit_comp("(Win32) DLL Initialization Failed"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"),
str8_lit_comp("(Win32) Assertion Failed"),
str8_lit_comp("(Win32) Module Not Found"),
str8_lit_comp("(Win32) Procedure Not Found"),
str8_lit_comp("(Win32) Sanitizer Error Detected"),
str8_lit_comp("(Win32) Sanitizer Raw Access Violation"),
str8_lit_comp("(Win32) DirectX Debug Layer"),
};
String8 ctrl_exception_code_kind_lowercase_code_string_table[38] =
{
{0},
str8_lit_comp("win32_ctrl_c"),
str8_lit_comp("win32_ctrl_break"),
str8_lit_comp("win32_win_rt_originate_error"),
str8_lit_comp("win32_win_rt_transform_error"),
str8_lit_comp("win32_rpc_call_cancelled"),
str8_lit_comp("win32_datatype_misalignment"),
str8_lit_comp("win32_access_violation"),
str8_lit_comp("win32_in_page_error"),
str8_lit_comp("win32_invalid_handle"),
str8_lit_comp("win32_not_enough_quota"),
str8_lit_comp("win32_illegal_instruction"),
str8_lit_comp("win32_cannot_continue_exception"),
str8_lit_comp("win32_invalid_exception_disposition"),
str8_lit_comp("win32_array_bounds_exceeded"),
str8_lit_comp("win32_floating_point_denormal_operand"),
str8_lit_comp("win32_floating_point_division_by_zero"),
str8_lit_comp("win32_floating_point_inexact_result"),
str8_lit_comp("win32_floating_point_invalid_operation"),
str8_lit_comp("win32_floating_point_overflow"),
str8_lit_comp("win32_floating_point_stack_check"),
str8_lit_comp("win32_floating_point_underflow"),
str8_lit_comp("win32_integer_division_by_zero"),
str8_lit_comp("win32_integer_overflow"),
str8_lit_comp("win32_privileged_instruction"),
str8_lit_comp("win32_stack_overflow"),
str8_lit_comp("win32_unable_to_locate_dll"),
str8_lit_comp("win32_ordinal_not_found"),
str8_lit_comp("win32_entry_point_not_found"),
str8_lit_comp("win32_dll_initialization_failed"),
str8_lit_comp("win32_floating_point_sse_multiple_faults"),
str8_lit_comp("win32_floating_point_sse_multiple_traps"),
str8_lit_comp("win32_assertion_failed"),
str8_lit_comp("win32_module_not_found"),
str8_lit_comp("win32_procedure_not_found"),
str8_lit_comp("win32_sanitizer_error_detected"),
str8_lit_comp("win32_sanitizer_raw_access_violation"),
str8_lit_comp("win32_directx_debug_layer"),
};
B8 ctrl_exception_code_kind_default_enable_table[38] =
{
0,
1,
1,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
1,
};
C_LINKAGE_END
+169 -27
View File
@@ -1,4 +1,4 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
@@ -6,23 +6,6 @@
#ifndef CTRL_META_H
#define CTRL_META_H
typedef enum CTRL_EntityKind
{
CTRL_EntityKind_Null,
CTRL_EntityKind_Root,
CTRL_EntityKind_Machine,
CTRL_EntityKind_Process,
CTRL_EntityKind_Thread,
CTRL_EntityKind_Module,
CTRL_EntityKind_EntryPoint,
CTRL_EntityKind_DebugInfoPath,
CTRL_EntityKind_PendingThreadName,
CTRL_EntityKind_PendingThreadColor,
CTRL_EntityKind_Breakpoint,
CTRL_EntityKind_AddressRangeAnnotation,
CTRL_EntityKind_COUNT,
} CTRL_EntityKind;
typedef enum CTRL_ExceptionCodeKind
{
CTRL_ExceptionCodeKind_Null,
@@ -63,17 +46,176 @@ CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
CTRL_ExceptionCodeKind_COUNT,
CTRL_ExceptionCodeKind_COUNT
} CTRL_ExceptionCodeKind;
C_LINKAGE_BEGIN
extern String8 ctrl_entity_kind_code_name_table[12];
extern String8 ctrl_entity_kind_display_string_table[12];
extern U32 ctrl_exception_code_kind_code_table[38];
extern String8 ctrl_exception_code_kind_display_string_table[38];
extern String8 ctrl_exception_code_kind_lowercase_code_string_table[38];
extern B8 ctrl_exception_code_kind_default_enable_table[38];
U32 ctrl_exception_code_kind_code_table[] =
{
0,
0x40010005,
0x40010008,
0x40080201,
0x40080202,
0x0000071a,
0x80000002,
0xc0000005,
0xc0000006,
0xc0000008,
0xc0000017,
0xc000001d,
0xc0000025,
0xc0000026,
0xc000008c,
0xc000008d,
0xc000008e,
0xc000008f,
0xc0000090,
0xc0000091,
0xc0000092,
0xc0000093,
0xc0000094,
0xc0000095,
0xc0000096,
0xc00000fd,
0xc0000135,
0xc0000138,
0xc0000139,
0xc0000142,
0xc00002b4,
0xc00002b5,
0xc0000420,
0xc06d007e,
0xc06d007f,
0xe073616e,
0xe0736171,
0x0000087a,
};
String8 ctrl_exception_code_kind_display_string_table[] =
{
{0},
str8_lit_comp("(Win32) Control-C"),
str8_lit_comp("(Win32) Control-Break"),
str8_lit_comp("(Win32) WinRT Originate Error"),
str8_lit_comp("(Win32) WinRT Transform Error"),
str8_lit_comp("(Win32) RPC Call Cancelled"),
str8_lit_comp("(Win32) Data Type Misalignment"),
str8_lit_comp("(Win32) Access Violation"),
str8_lit_comp("(Win32) In Page Error"),
str8_lit_comp("(Win32) Invalid Handle Specified"),
str8_lit_comp("(Win32) Not Enough Quota"),
str8_lit_comp("(Win32) Illegal Instruction"),
str8_lit_comp("(Win32) Cannot Continue From Exception"),
str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"),
str8_lit_comp("(Win32) Array Bounds Exceeded"),
str8_lit_comp("(Win32) Floating-Point Denormal Operand"),
str8_lit_comp("(Win32) Floating-Point Division By Zero"),
str8_lit_comp("(Win32) Floating-Point Inexact Result"),
str8_lit_comp("(Win32) Floating-Point Invalid Operation"),
str8_lit_comp("(Win32) Floating-Point Overflow"),
str8_lit_comp("(Win32) Floating-Point Stack Check"),
str8_lit_comp("(Win32) Floating-Point Underflow"),
str8_lit_comp("(Win32) Integer Division By Zero"),
str8_lit_comp("(Win32) Integer Overflow"),
str8_lit_comp("(Win32) Privileged Instruction"),
str8_lit_comp("(Win32) Stack Overflow"),
str8_lit_comp("(Win32) Unable To Locate DLL"),
str8_lit_comp("(Win32) Ordinal Not Found"),
str8_lit_comp("(Win32) Entry Point Not Found"),
str8_lit_comp("(Win32) DLL Initialization Failed"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"),
str8_lit_comp("(Win32) Assertion Failed"),
str8_lit_comp("(Win32) Module Not Found"),
str8_lit_comp("(Win32) Procedure Not Found"),
str8_lit_comp("(Win32) Sanitizer Error Detected"),
str8_lit_comp("(Win32) Sanitizer Raw Access Violation"),
str8_lit_comp("(Win32) DirectX Debug Layer"),
};
String8 ctrl_exception_code_kind_lowercase_code_string_table[] =
{
{0},
str8_lit_comp("win32_ctrl_c"),
str8_lit_comp("win32_ctrl_break"),
str8_lit_comp("win32_win_rt_originate_error"),
str8_lit_comp("win32_win_rt_transform_error"),
str8_lit_comp("win32_rpc_call_cancelled"),
str8_lit_comp("win32_datatype_misalignment"),
str8_lit_comp("win32_access_violation"),
str8_lit_comp("win32_in_page_error"),
str8_lit_comp("win32_invalid_handle"),
str8_lit_comp("win32_not_enough_quota"),
str8_lit_comp("win32_illegal_instruction"),
str8_lit_comp("win32_cannot_continue_exception"),
str8_lit_comp("win32_invalid_exception_disposition"),
str8_lit_comp("win32_array_bounds_exceeded"),
str8_lit_comp("win32_floating_point_denormal_operand"),
str8_lit_comp("win32_floating_point_division_by_zero"),
str8_lit_comp("win32_floating_point_inexact_result"),
str8_lit_comp("win32_floating_point_invalid_operation"),
str8_lit_comp("win32_floating_point_overflow"),
str8_lit_comp("win32_floating_point_stack_check"),
str8_lit_comp("win32_floating_point_underflow"),
str8_lit_comp("win32_integer_division_by_zero"),
str8_lit_comp("win32_integer_overflow"),
str8_lit_comp("win32_privileged_instruction"),
str8_lit_comp("win32_stack_overflow"),
str8_lit_comp("win32_unable_to_locate_dll"),
str8_lit_comp("win32_ordinal_not_found"),
str8_lit_comp("win32_entry_point_not_found"),
str8_lit_comp("win32_dll_initialization_failed"),
str8_lit_comp("win32_floating_point_sse_multiple_faults"),
str8_lit_comp("win32_floating_point_sse_multiple_traps"),
str8_lit_comp("win32_assertion_failed"),
str8_lit_comp("win32_module_not_found"),
str8_lit_comp("win32_procedure_not_found"),
str8_lit_comp("win32_sanitizer_error_detected"),
str8_lit_comp("win32_sanitizer_raw_access_violation"),
str8_lit_comp("win32_directx_debug_layer"),
};
B8 ctrl_exception_code_kind_default_enable_table[] =
{
0,
1,
1,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
1,
};
C_LINKAGE_END
#endif // CTRL_META_H
+540
View File
@@ -0,0 +1,540 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void
dasm_init(void)
{
Arena *arena = arena_alloc();
dasm_shared = push_array(arena, DASM_Shared, 1);
dasm_shared->arena = arena;
dasm_shared->entity_map.slots_count = 1024;
dasm_shared->entity_map.slots = push_array(arena, DASM_EntitySlot, dasm_shared->entity_map.slots_count);
dasm_shared->entity_map_stripes.count = 64;
dasm_shared->entity_map_stripes.v = push_array(arena, DASM_Stripe, dasm_shared->entity_map_stripes.count);
for(U64 idx = 0; idx < dasm_shared->entity_map_stripes.count; idx += 1)
{
dasm_shared->entity_map_stripes.v[idx].arena = arena_alloc();
dasm_shared->entity_map_stripes.v[idx].rw_mutex = os_rw_mutex_alloc();
dasm_shared->entity_map_stripes.v[idx].cv = os_condition_variable_alloc();
}
dasm_shared->u2d_ring_mutex = os_mutex_alloc();
dasm_shared->u2d_ring_cv = os_condition_variable_alloc();
dasm_shared->u2d_ring_size = KB(64);
dasm_shared->u2d_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2d_ring_size);
dasm_shared->decode_thread_count = Max(1, os_logical_core_count()-1);
dasm_shared->decode_threads = push_array(arena, OS_Handle, dasm_shared->decode_thread_count);
for(U64 idx = 0; idx < dasm_shared->decode_thread_count; idx += 1)
{
dasm_shared->decode_threads[idx] = os_launch_thread(dasm_decode_thread_entry_point, (void *)idx, 0);
}
}
////////////////////////////////
//~ rjf: Basic Helpers
internal U64
dasm_hash_from_string(String8 string)
{
U64 result = 5381;
for(U64 i = 0; i < string.size; i += 1)
{
result = ((result << 5) + result) + string.str[i];
}
return result;
}
////////////////////////////////
//~ rjf: Instruction Type Functions
internal void
dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst)
{
DASM_InstChunkNode *node = list->last;
if(node == 0 || node->count >= node->cap)
{
node = push_array(arena, DASM_InstChunkNode, 1);
node->v = push_array_no_zero(arena, DASM_Inst, cap);
node->cap = cap;
SLLQueuePush(list->first, list->last, node);
list->node_count += 1;
}
MemoryCopyStruct(&node->v[node->count], inst);
node->count += 1;
list->inst_count += 1;
}
internal DASM_InstArray
dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list)
{
DASM_InstArray array = {0};
array.count = list->inst_count;
array.v = push_array_no_zero(arena, DASM_Inst, array.count);
U64 idx = 0;
for(DASM_InstChunkNode *n = list->first; n != 0; n = n->next)
{
MemoryCopy(array.v+idx, n->v, sizeof(DASM_Inst)*n->count);
idx += n->count;
}
return array;
}
internal U64
dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off)
{
U64 result = 0;
for(U64 idx = 0; idx < array->count; idx += 1)
{
if(array->v[idx].off == off)
{
result = idx;
break;
}
}
return result;
}
internal U64
dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx)
{
U64 off = 0;
if(idx < array->count)
{
off = array->v[idx].off;
}
return off;
}
////////////////////////////////
//~ rjf: Disassembly Functions
#include "third_party/udis86/config.h"
#include "third_party/udis86/udis86.h"
#include "third_party/udis86/libudis86/decode.c"
#include "third_party/udis86/libudis86/itab.c"
#include "third_party/udis86/libudis86/syn-att.c"
#include "third_party/udis86/libudis86/syn-intel.c"
#include "third_party/udis86/libudis86/syn.c"
#include "third_party/udis86/libudis86/udis86.c"
internal DASM_InstChunkList
dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data)
{
DASM_InstChunkList inst_list = {0};
switch(arch)
{
default:{}break;
//- rjf: x86/x64 decoding
case Architecture_x64:
case Architecture_x86:
{
// rjf: grab context
struct ud udc;
ud_init(&udc);
ud_set_mode(&udc, bit_size_from_arch(arch));
ud_set_pc(&udc, addr);
ud_set_input_buffer(&udc, data.str, data.size);
ud_set_vendor(&udc, UD_VENDOR_ANY);
ud_set_syntax(&udc, UD_SYN_INTEL);
// rjf: disassemble
U64 byte_process_start_off = 0;
for(U64 off = 0; off < data.size;)
{
// rjf: disassemble one instruction
U64 size = ud_disassemble(&udc);
if(size == 0)
{
break;
}
// rjf: analyze
struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0);
U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0;
// rjf: push
String8 string = push_str8f(arena, "%s", udc.asm_buf);
DASM_Inst inst = {string, off, rel_voff};
dasm_inst_chunk_list_push(arena, &inst_list, 1024, &inst);
// rjf: increment
off += size;
if(bytes_processed_counter != 0 && (off-byte_process_start_off >= 1000))
{
ins_atomic_u64_add_eval(bytes_processed_counter, (off-byte_process_start_off));
byte_process_start_off = off;
}
}
}break;
}
return inst_list;
}
////////////////////////////////
//~ rjf: Cache Lookups
//- rjf: opening handles & correllation with module
internal DASM_Handle
dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range)
{
DASM_Handle result = {0};
if(machine != 0 && process.u64[0] != 0)
{
U64 hash = dasm_hash_from_string(str8_struct(&process));
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
OS_MutexScopeW(stripe->rw_mutex)
{
DASM_Entity *entity = 0;
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->machine_id == machine &&
ctrl_handle_match(e->process, process) &&
MemoryMatchStruct(&e->vaddr_range, &vaddr_range))
{
entity = e;
break;
}
}
if(entity == 0)
{
entity = push_array(stripe->arena, DASM_Entity, 1);
SLLQueuePush(slot->first, slot->last, entity);
entity->machine_id = machine;
entity->process = process;
entity->vaddr_range= vaddr_range;
entity->id = ins_atomic_u64_inc_eval(&dasm_shared->entity_id_gen);
entity->decode_inst_arena = arena_alloc__sized(MB(256), KB(64));
entity->decode_string_arena = arena_alloc__sized(GB(1), KB(64));
}
result.u64[0] = hash;
result.u64[1] = entity->id;
}
}
return result;
}
//- rjf: asking for top-level info of a handle
internal DASM_BinaryInfo
dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle)
{
DASM_BinaryInfo info = {0};
{
U64 hash = handle.u64[0];
U64 id = handle.u64[1];
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex)
{
DASM_Entity *entity = 0;
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->id == id)
{
entity = e;
break;
}
}
if(entity != 0)
{
info.machine_id = entity->machine_id;
info.process = entity->process;
info.vaddr_range = entity->vaddr_range;
info.bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed);
info.bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
}
}
}
return info;
}
//- rjf: asking for decoded instructions
internal DASM_InstArray
dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us)
{
DASM_InstArray result = {0};
if(handle.u64[0] != 0 || handle.u64[1] != 0)
{
U64 hash = handle.u64[0];
U64 id = handle.u64[1];
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
B32 sent = 0;
OS_MutexScopeR(stripe->rw_mutex) for(;;)
{
DASM_Entity *entity = 0;
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->id == id)
{
entity = e;
break;
}
}
U64 last_time_sent_us = 0;
if(entity != 0)
{
U64 bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed);
U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
last_time_sent_us = ins_atomic_u64_eval(&entity->last_time_sent_us);
if(bytes_processed == bytes_to_process && bytes_processed != 0)
{
result.count = entity->decode_inst_array.count;
result.v = push_array_no_zero(arena, DASM_Inst, result.count);
MemoryCopy(result.v, entity->decode_inst_array.v, sizeof(DASM_Inst)*result.count);
for(U64 idx = 0; idx < result.count; idx += 1)
{
result.v[idx].string = push_str8_copy(arena, result.v[idx].string);
}
break;
}
}
if(!sent && entity != 0 && last_time_sent_us+10000 <= os_now_microseconds())
{
DASM_DecodeRequest req = {handle};
sent = dasm_u2d_enqueue_request(&req, endt_us);
ins_atomic_u64_eval_assign(&entity->last_time_sent_us, os_now_microseconds());
}
if(os_now_microseconds() >= endt_us)
{
break;
}
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
}
}
return result;
}
////////////////////////////////
//~ rjf: Decode Threads
internal B32
dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us)
{
B32 result = 0;
OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;)
{
U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos);
U64 available_size = (dasm_shared->u2d_ring_size-unconsumed_size);
if(available_size >= sizeof(*req))
{
result = 1;
dasm_shared->u2d_ring_write_pos += ring_write_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_write_pos, req);
dasm_shared->u2d_ring_write_pos += 7;
dasm_shared->u2d_ring_write_pos -= dasm_shared->u2d_ring_write_pos%8;
break;
}
if(os_now_microseconds() >= endt_us)
{
break;
}
os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, endt_us);
}
if(result)
{
os_condition_variable_broadcast(dasm_shared->u2d_ring_cv);
}
return result;
}
internal DASM_DecodeRequest
dasm_u2d_dequeue_request(void)
{
DASM_DecodeRequest req = {0};
OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;)
{
U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos);
if(unconsumed_size >= sizeof(DASM_DecodeRequest))
{
dasm_shared->u2d_ring_read_pos += ring_read_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_read_pos, &req);
dasm_shared->u2d_ring_read_pos += 7;
dasm_shared->u2d_ring_read_pos -= dasm_shared->u2d_ring_read_pos%8;
break;
}
os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, max_U64);
}
os_condition_variable_broadcast(dasm_shared->u2d_ring_cv);
return req;
}
internal void
dasm_decode_thread_entry_point(void *p)
{
TCTX tctx_;
tctx_init_and_equip(&tctx_);
for(;;)
{
Temp scratch = scratch_begin(0, 0);
//- rjf: get next request & unpack
DASM_DecodeRequest req = dasm_u2d_dequeue_request();
DASM_Handle handle = req.handle;
U64 hash = handle.u64[0];
U64 id = handle.u64[1];
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
//- rjf: request -> ctrl info
B32 is_first_to_task = 0;
CTRL_MachineID ctrl_machine_id = 0;
CTRL_Handle ctrl_process = {0};
Rng1U64 vaddr_range = {0};
Architecture arch = Architecture_Null;
U64 *bytes_processed_counter = 0;
OS_MutexScopeR(stripe->rw_mutex)
{
DASM_Entity *entity = 0;
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->id == id)
{
entity = e;
break;
}
}
if(entity != 0)
{
U64 initial_working_count = ins_atomic_u32_eval_cond_assign(&entity->working_count, 1, 0);
if(initial_working_count == 0)
{
is_first_to_task = 1;
ctrl_machine_id = entity->machine_id;
ctrl_process = entity->process;
vaddr_range = entity->vaddr_range;
arch = ctrl_arch_from_handle(ctrl_machine_id, ctrl_process);
bytes_processed_counter = &entity->bytes_processed;
U64 bytes_to_process = dim_1u64(vaddr_range);
ins_atomic_u64_eval_assign(&entity->bytes_processed, 0);
ins_atomic_u64_eval_assign(&entity->bytes_to_process, bytes_to_process);
}
}
}
//- rjf: bad handle or machine id -> bad task
B32 good_task = (is_first_to_task && ctrl_process.u64[0] != 0 && ctrl_machine_id != 0 && arch != Architecture_Null && bytes_processed_counter != 0);
//- rjf: good task -> clear entity's info
if(good_task)
{
OS_MutexScopeW(stripe->rw_mutex)
{
DASM_Entity *entity = 0;
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->id == id)
{
entity = e;
break;
}
}
if(entity != 0)
{
arena_clear(entity->decode_inst_arena);
arena_clear(entity->decode_string_arena);
MemoryZeroStruct(&entity->decode_inst_array);
}
}
}
//- rjf: good task -> read process memory & decode instructions - stop each
// 4k and write into cache, so users can read incremental results
if(good_task)
{
U64 chunk_size = KB(4);
for(U64 off = 0; vaddr_range.min+off < vaddr_range.max; off += chunk_size)
{
Rng1U64 chunk_vaddr_range = r1u64(vaddr_range.min+off, vaddr_range.min+off+chunk_size);
chunk_vaddr_range.min = ClampTop(chunk_vaddr_range.min, vaddr_range.max);
chunk_vaddr_range.max = ClampTop(chunk_vaddr_range.max, vaddr_range.max);
//- rjf: read next chunk & decode
String8 data = {0};
DASM_InstChunkList inst_list = {0};
if(good_task)
{
data.str = push_array_no_zero(scratch.arena, U8, dim_1u64(chunk_vaddr_range));
data.size = ctrl_process_read(ctrl_machine_id, ctrl_process, chunk_vaddr_range, data.str);
if(data.size != 0)
{
inst_list = dasm_inst_chunk_list_from_arch_addr_data(scratch.arena, bytes_processed_counter, arch, chunk_vaddr_range.min, data);
}
}
//- rjf: write into cache
{
OS_MutexScopeW(stripe->rw_mutex)
{
DASM_Entity *entity = 0;
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->id == id)
{
entity = e;
break;
}
}
if(entity != 0)
{
DASM_Inst *new_chunk_base = push_array(entity->decode_inst_arena, DASM_Inst, inst_list.inst_count);
U64 off = 0;
for(DASM_InstChunkNode *node = inst_list.first; node != 0; node = node->next)
{
MemoryCopy(new_chunk_base+off, node->v, sizeof(DASM_Inst)*node->count);
off += node->count;
}
for(U64 idx = 0; idx < inst_list.inst_count; idx += 1)
{
new_chunk_base[idx].string = push_str8_copy(entity->decode_string_arena, new_chunk_base[idx].string);
}
entity->decode_inst_array.count += inst_list.inst_count;
if(entity->decode_inst_array.v == 0)
{
entity->decode_inst_array.v = new_chunk_base;
}
}
}
os_condition_variable_broadcast(stripe->cv);
}
}
}
//- rjf: mark task as complete
if(good_task)
{
OS_MutexScopeR(stripe->rw_mutex)
{
DASM_Entity *entity = 0;
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->id == id)
{
entity = e;
break;
}
}
if(entity != 0)
{
U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
ins_atomic_u64_eval_assign(&entity->bytes_processed, bytes_to_process);
ins_atomic_u64_eval_assign(&entity->working_count, 0);
}
}
}
scratch_end(scratch);
}
}
+206
View File
@@ -0,0 +1,206 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DASM_H
#define DASM_H
////////////////////////////////
//~ rjf: Handle Type
typedef struct DASM_Handle DASM_Handle;
struct DASM_Handle
{
U64 u64[2];
};
////////////////////////////////
//~ rjf: Instruction Types
typedef struct DASM_Inst DASM_Inst;
struct DASM_Inst
{
String8 string;
U64 off;
U64 addr;
};
typedef struct DASM_InstChunkNode DASM_InstChunkNode;
struct DASM_InstChunkNode
{
DASM_InstChunkNode *next;
DASM_Inst *v;
U64 cap;
U64 count;
};
typedef struct DASM_InstChunkList DASM_InstChunkList;
struct DASM_InstChunkList
{
DASM_InstChunkNode *first;
DASM_InstChunkNode *last;
U64 node_count;
U64 inst_count;
};
typedef struct DASM_InstArray DASM_InstArray;
struct DASM_InstArray
{
DASM_Inst *v;
U64 count;
};
////////////////////////////////
//~ rjf: Striped Access Types
typedef struct DASM_Stripe DASM_Stripe;
struct DASM_Stripe
{
Arena *arena;
OS_Handle cv;
OS_Handle rw_mutex;
};
typedef struct DASM_StripeTable DASM_StripeTable;
struct DASM_StripeTable
{
U64 count;
DASM_Stripe *v;
};
////////////////////////////////
//~ rjf: Entity Cache Types
typedef struct DASM_Entity DASM_Entity;
struct DASM_Entity
{
DASM_Entity *next;
// rjf: key info
CTRL_MachineID machine_id;
CTRL_Handle process;
Rng1U64 vaddr_range;
U64 id;
// rjf: top-level info
U64 last_time_sent_us;
U64 working_count;
U64 bytes_processed;
U64 bytes_to_process;
// rjf: decoded instruction data
Arena *decode_inst_arena;
Arena *decode_string_arena;
DASM_InstArray decode_inst_array;
};
typedef struct DASM_EntitySlot DASM_EntitySlot;
struct DASM_EntitySlot
{
DASM_Entity *first;
DASM_Entity *last;
};
typedef struct DASM_EntityMap DASM_EntityMap;
struct DASM_EntityMap
{
U64 slots_count;
DASM_EntitySlot *slots;
};
////////////////////////////////
//~ rjf: Introspection Info Types
typedef struct DASM_BinaryInfo DASM_BinaryInfo;
struct DASM_BinaryInfo
{
CTRL_MachineID machine_id;
CTRL_Handle process;
Rng1U64 vaddr_range;
U64 bytes_processed;
U64 bytes_to_process;
};
////////////////////////////////
//~ rjf: Decode Request Types
typedef struct DASM_DecodeRequest DASM_DecodeRequest;
struct DASM_DecodeRequest
{
DASM_Handle handle;
};
////////////////////////////////
//~ rjf: Shared State
typedef struct DASM_Shared DASM_Shared;
struct DASM_Shared
{
Arena *arena;
// rjf: entity table
DASM_EntityMap entity_map;
DASM_StripeTable entity_map_stripes;
U64 entity_id_gen;
// rjf: user -> decode ring
OS_Handle u2d_ring_mutex;
OS_Handle u2d_ring_cv;
U64 u2d_ring_size;
U8 *u2d_ring_base;
U64 u2d_ring_write_pos;
U64 u2d_ring_read_pos;
// rjf: decode threads
U64 decode_thread_count;
OS_Handle *decode_threads;
};
////////////////////////////////
//~ rjf: Globals
global DASM_Shared *dasm_shared = 0;
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void dasm_init(void);
////////////////////////////////
//~ rjf: Basic Helpers
internal U64 dasm_hash_from_string(String8 string);
////////////////////////////////
//~ rjf: Instruction Type Functions
internal void dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst);
internal DASM_InstArray dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list);
internal U64 dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off);
internal U64 dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx);
////////////////////////////////
//~ rjf: Disassembly Functions
internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data);
////////////////////////////////
//~ rjf: Cache Lookups
//- rjf: opening handles & correllation with module
internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range);
//- rjf: asking for top-level info of a handle
internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle);
//- rjf: asking for decoded instructions
internal DASM_InstArray dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us);
////////////////////////////////
//~ rjf: Decode Threads
internal B32 dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us);
internal DASM_DecodeRequest dasm_u2d_dequeue_request(void);
internal void dasm_decode_thread_entry_point(void *p);
#endif //DASM_H
-90
View File
@@ -1,90 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Built-In Command Tables
@table(name ui_vis ipc_docs_vis text_pt_vis text_rng_vis q_expr q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags ctx_filter)
// / | | | | | | \___ _________________________________/ | | | | | |
// / | | | | | | \ / | | | | | |
D_CmdTable: // | | | | | | | | | | | | | |
{
//- rjf: low-level target control operations
{LaunchAndRun 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" }
{LaunchAndStepInto 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" }
{Kill 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" }
{KillAll 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" }
{Detach 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" }
{Continue 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" }
{StepIntoInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" }
{StepOverInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" }
{StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
{StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
{StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" "" }
{Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
{SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
{SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
//- rjf: high-level composite target control operations
{RunToLine 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "$text_pt," }
{Run 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" }
{Restart 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" }
{StepInto 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" }
{StepOver 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" }
//- rjf: debug control context management operations
{FreezeThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" }
{ThawThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" }
{FreezeProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" }
{ThawProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" }
{FreezeMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" }
{ThawMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" }
{FreezeLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" }
{ThawLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" }
{FreezeEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" }
{ThawEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" }
//- rjf: entity decoration
{SetEntityColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
{SetEntityName 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
//- rjf: attaching
{Attach 1 1 0 0 "query:unattached_processes" PID null Nil Null 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" }
}
@enum D_CmdKind:
{
Null,
@expand(D_CmdTable, a) `$(a.name)`,
COUNT,
}
////////////////////////////////
//~ rjf: Developer Toggles
@table(name)
D_DevToggleTable:
{
{always_refresh}
{simulate_lag}
{draw_ui_text_pos}
{draw_ui_focus_debug}
{draw_ui_box_heatmap}
{eval_compiler_tooltips}
{eval_watch_key_tooltips}
{cmd_context_tooltips}
{updating_indicator}
}
@gen
{
@expand(D_DevToggleTable a) `global B32 DEV_$(a.name) = 0;`
}
@gen
{
`struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =`;
`{`;
@expand(D_DevToggleTable a) `{&DEV_$(a.name), str8_lit_comp("$(a.name)")},`
`};`;
}
File diff suppressed because it is too large Load Diff
-438
View File
@@ -1,438 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DBG_ENGINE_CORE_H
#define DBG_ENGINE_CORE_H
////////////////////////////////
//~ rjf: Tick Input Types
typedef struct D_Target D_Target;
struct D_Target
{
String8 exe;
String8 args;
String8 working_directory;
String8 custom_entry_point_name;
String8 stdout_path;
String8 stderr_path;
String8 stdin_path;
B32 debug_subprocesses;
String8List env;
};
typedef struct D_TargetArray D_TargetArray;
struct D_TargetArray
{
D_Target *v;
U64 count;
};
typedef U32 D_BreakpointFlags;
enum
{
D_BreakpointFlag_BreakOnWrite = (1<<0),
D_BreakpointFlag_BreakOnRead = (1<<1),
D_BreakpointFlag_BreakOnExecute = (1<<2),
};
typedef struct D_Breakpoint D_Breakpoint;
struct D_Breakpoint
{
D_BreakpointFlags flags;
U64 id;
String8 file_path;
TxtPt pt;
String8 vaddr_expr;
String8 condition;
U64 size;
};
typedef struct D_BreakpointArray D_BreakpointArray;
struct D_BreakpointArray
{
D_Breakpoint *v;
U64 count;
};
typedef struct D_PathMap D_PathMap;
struct D_PathMap
{
String8 src;
String8 dst;
};
typedef struct D_PathMapArray D_PathMapArray;
struct D_PathMapArray
{
D_PathMap *v;
U64 count;
};
////////////////////////////////
//~ rjf: Trap Nets
typedef struct D_TrapNet D_TrapNet;
struct D_TrapNet
{
CTRL_TrapList traps;
B32 good_line_info;
B32 good_read;
};
////////////////////////////////
//~ rjf: Tick Output Types
typedef enum D_EventKind
{
D_EventKind_Null,
D_EventKind_ModuleLoad,
D_EventKind_ProcessEnd,
D_EventKind_Stop,
D_EventKind_COUNT
}
D_EventKind;
typedef enum D_EventCause
{
D_EventCause_Null,
D_EventCause_UserBreakpoint,
D_EventCause_Halt,
D_EventCause_SoftHalt,
D_EventCause_COUNT
}
D_EventCause;
typedef struct D_Event D_Event;
struct D_Event
{
D_EventKind kind;
D_EventCause cause;
CTRL_Handle module;
CTRL_Handle thread;
U64 vaddr;
U64 code;
U64 id;
};
typedef struct D_EventNode D_EventNode;
struct D_EventNode
{
D_EventNode *next;
D_Event v;
};
typedef struct D_EventList D_EventList;
struct D_EventList
{
D_EventNode *first;
D_EventNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Line Info Types
typedef struct D_Line D_Line;
struct D_Line
{
String8 file_path;
TxtPt pt;
Rng1U64 voff_range;
DI_Key dbgi_key;
};
typedef struct D_LineNode D_LineNode;
struct D_LineNode
{
D_LineNode *next;
D_Line v;
};
typedef struct D_LineList D_LineList;
struct D_LineList
{
D_LineNode *first;
D_LineNode *last;
U64 count;
};
typedef struct D_LineListArray D_LineListArray;
struct D_LineListArray
{
D_LineList *v;
U64 count;
DI_KeyList dbgi_keys;
};
////////////////////////////////
//~ rjf: Debug Engine Control Communication Types
typedef enum D_RunKind
{
D_RunKind_Run,
D_RunKind_SingleStep,
D_RunKind_Step,
D_RunKind_COUNT
}
D_RunKind;
////////////////////////////////
//~ rjf: Generated Code
#include "dbg_engine/generated/dbg_engine.meta.h"
////////////////////////////////
//~ rjf: Command Types
typedef struct D_CmdParams D_CmdParams;
struct D_CmdParams
{
CTRL_Handle machine;
CTRL_Handle process;
CTRL_Handle thread;
CTRL_Handle entity;
String8 string;
String8 file_path;
TxtPt cursor;
U64 vaddr;
B32 prefer_disasm;
U32 pid;
U32 rgba;
D_TargetArray targets;
U64 retry_idx;
};
typedef struct D_Cmd D_Cmd;
struct D_Cmd
{
D_CmdKind kind;
D_CmdParams params;
};
typedef struct D_CmdNode D_CmdNode;
struct D_CmdNode
{
D_CmdNode *next;
D_CmdNode *prev;
D_Cmd cmd;
};
typedef struct D_CmdList D_CmdList;
struct D_CmdList
{
D_CmdNode *first;
D_CmdNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Main State Caches
//- rjf: per-run tls-base-vaddr cache
typedef struct D_RunTLSBaseCacheNode D_RunTLSBaseCacheNode;
struct D_RunTLSBaseCacheNode
{
D_RunTLSBaseCacheNode *hash_next;
CTRL_Handle process;
U64 root_vaddr;
U64 rip_vaddr;
U64 tls_base_vaddr;
};
typedef struct D_RunTLSBaseCacheSlot D_RunTLSBaseCacheSlot;
struct D_RunTLSBaseCacheSlot
{
D_RunTLSBaseCacheNode *first;
D_RunTLSBaseCacheNode *last;
};
typedef struct D_RunTLSBaseCache D_RunTLSBaseCache;
struct D_RunTLSBaseCache
{
Arena *arena;
U64 slots_count;
D_RunTLSBaseCacheSlot *slots;
};
//- rjf: per-run locals cache
typedef struct D_RunLocalsCacheNode D_RunLocalsCacheNode;
struct D_RunLocalsCacheNode
{
D_RunLocalsCacheNode *hash_next;
DI_Key dbgi_key;
U64 voff;
E_String2NumMap *locals_map;
};
typedef struct D_RunLocalsCacheSlot D_RunLocalsCacheSlot;
struct D_RunLocalsCacheSlot
{
D_RunLocalsCacheNode *first;
D_RunLocalsCacheNode *last;
};
typedef struct D_RunLocalsCache D_RunLocalsCache;
struct D_RunLocalsCache
{
Arena *arena;
U64 table_size;
D_RunLocalsCacheSlot *table;
};
////////////////////////////////
//~ rjf: Main State Types
typedef struct D_State D_State;
struct D_State
{
// rjf: top-level state
Arena *arena;
U64 frame_index;
// rjf: commands
Arena *cmds_arena;
D_CmdList cmds;
// rjf: output log key
C_Key output_log_key;
// rjf: per-run caches
U64 tls_base_cache_reggen_idx;
U64 tls_base_cache_memgen_idx;
D_RunTLSBaseCache tls_base_caches[2];
U64 tls_base_cache_gen;
U64 locals_cache_reggen_idx;
D_RunLocalsCache locals_caches[2];
U64 locals_cache_gen;
U64 member_cache_reggen_idx;
D_RunLocalsCache member_caches[2];
U64 member_cache_gen;
// rjf: user -> ctrl driving state
Arena *ctrl_last_run_arena;
D_RunKind ctrl_last_run_kind;
U64 ctrl_last_run_frame_idx;
CTRL_Handle ctrl_last_run_thread_handle;
CTRL_RunFlags ctrl_last_run_flags;
CTRL_TrapList ctrl_last_run_traps;
D_BreakpointArray ctrl_last_run_extra_bps;
U128 ctrl_last_run_param_state_hash;
B32 ctrl_is_running;
B32 ctrl_thread_run_state;
B32 ctrl_soft_halt_issued;
Arena *ctrl_msg_arena;
CTRL_MsgList ctrl_msgs;
// rjf: ctrl -> user reading state
CTRL_EntityCtxRWStore *ctrl_entity_store;
Arena *ctrl_stop_arena;
CTRL_Event ctrl_last_stop_event;
};
////////////////////////////////
//~ rjf: Globals
global D_State *d_state = 0;
////////////////////////////////
//~ rjf: Basic Helpers
internal U64 d_hash_from_seed_string(U64 seed, String8 string);
internal U64 d_hash_from_string(String8 string);
internal U64 d_hash_from_seed_string__case_insensitive(U64 seed, String8 string);
internal U64 d_hash_from_string__case_insensitive(String8 string);
////////////////////////////////
//~ rjf: Breakpoints
internal D_BreakpointArray d_breakpoint_array_copy(Arena *arena, D_BreakpointArray *src);
////////////////////////////////
//~ rjf: Path Map Application
internal String8List d_possible_path_overrides_from_maps_path(Arena *arena, D_PathMapArray *path_maps, String8 file_path);
////////////////////////////////
//~ rjf: Debug Info Extraction Type Pure Functions
internal D_LineList d_line_list_copy(Arena *arena, D_LineList *list);
////////////////////////////////
//~ rjf: Command Type Functions
//- rjf: command parameters
internal D_CmdParams d_cmd_params_copy(Arena *arena, D_CmdParams *src);
//- rjf: command lists
internal void d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, D_CmdParams *params);
////////////////////////////////
//~ rjf: Stepping "Trap Net" Builders
internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread);
internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread);
internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread);
////////////////////////////////
//~ rjf: Debug Info Lookups
//- rjf: voff -> line info
internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key dbgi_key, U64 voff);
//- rjf: file:line -> line info
// TODO(rjf): this depends on file path maps, needs to move
// TODO(rjf): need to clean this up & dedup
internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range);
internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range);
internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num);
internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num);
////////////////////////////////
//~ rjf: Process/Thread/Module Info Lookups
internal U64 d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr);
////////////////////////////////
//~ rjf: Target Controls
//- rjf: stopped info from the control thread
internal CTRL_Event d_ctrl_last_stop_event(void);
////////////////////////////////
//~ rjf: Main State Accessors/Mutators
//- rjf: frame data
internal U64 d_frame_index(void);
//- rjf: control state
internal D_RunKind d_ctrl_last_run_kind(void);
internal U64 d_ctrl_last_run_frame_idx(void);
internal B32 d_ctrl_targets_running(void);
//- rjf: active entity based queries
internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena);
//- rjf: per-run caches
internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread);
internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count);
internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr);
internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
//- rjf: top-level command dispatch
internal void d_push_cmd(D_CmdKind kind, D_CmdParams *params);
#define d_cmd(kind, ...) d_push_cmd((kind), &(D_CmdParams){.thread = {0}, __VA_ARGS__})
//- rjf: command iteration
internal B32 d_next_cmd(D_Cmd **cmd);
////////////////////////////////
//~ rjf: Main Layer Top-Level Calls
internal void d_init(void);
internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]);
#endif // DBG_ENGINE_CORE_H
-4
View File
@@ -1,4 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "dbg_engine_core.c"
-9
View File
@@ -1,9 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DBG_ENGINE_INC_H
#define DBG_ENGINE_INC_H
#include "dbg_engine_core.h"
#endif // DBG_ENGINE_INC_H
@@ -1,5 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE

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