mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-09-22 17:20:05 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76ce8a79c2 | ||
|
|
932db741fa | ||
|
|
0add3ef72c | ||
|
|
e417a96ce4 | ||
|
|
b2262532a7 | ||
|
|
b24326f502 | ||
|
|
66c1fa337c |
@@ -1 +0,0 @@
|
||||
*.sh text=auto eol=lf
|
||||
@@ -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,4 +1,3 @@
|
||||
/build/
|
||||
/local/
|
||||
*~
|
||||
.vscode/settings.json
|
||||
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
# v0.9.24-alpha
|
||||
|
||||
## Debugger Changes
|
||||
|
||||
- Added the ability for the debugger to load, use, and evaluate using debug
|
||||
info, even when not actively debugging. The debugger will now keep a process'
|
||||
debug info loaded, even after the process ends. It stores the set of loaded
|
||||
debug info files in the project configuration file, meaning it will also
|
||||
automatically load the same debug info across many runs. Debug info can also
|
||||
be loaded manually (without ever launching a process) with the
|
||||
`Load Debug Info` command. There is also a new tab, `Debug Info`, which allows
|
||||
viewing and managing the set of loaded debug info files.
|
||||
- Improved the debugger's behavior when used as a drag & drop target, to allow
|
||||
for debug info loading as an option (when relevant), and to better handle the
|
||||
case where many files (potentially of different types) are dropped together.
|
||||
- Improved debug info searching performance and reponsiveness in large projects.
|
||||
- Fixed some crashes and incorrect results with the new `list` view.
|
||||
- Fixed some cases where RDIs did not contain some basic types from their
|
||||
originating PDBs.
|
||||
- Allowed `.` and `->` operators to be used with array types.
|
||||
- Fixed the debugger's treatment of quoted command line arguments when building
|
||||
targets. In previous versions, calling `raddbg main.exe "foo bar baz"` would
|
||||
create a target `main.exe` with arguments `foo bar baz` (dropping the quotes).
|
||||
This is now fixed, such that the target's arguments string will also contain
|
||||
the quotes, and pass them to the target when launched.
|
||||
- Fixed the debugger not correctly responding (through font and UI scale) to DPI
|
||||
changes.
|
||||
- Fixed the debugger incorrectly generating conflicting source line info records
|
||||
in PDB -> RDI conversion, which in some scenarios was preventing source line
|
||||
maps from working (leading to breakpoint resolution failing).
|
||||
- Other small fixes, improvements, and tweaks.
|
||||
|
||||
# v0.9.23-alpha
|
||||
|
||||
## Debugger Changes
|
||||
|
||||
- Further improved PDB -> RDI conversion performance & memory usage.
|
||||
- Adjusted limits for the amount of PDB -> RDI conversion work that the
|
||||
debugger will kick off, to prevent PDB -> RDI conversion interfering with
|
||||
debuggee performance.
|
||||
- Reintroduced the `list` lens, which gathers all nodes in a linked list, and
|
||||
visualizes them as a flat list of pointers (the same as how an array of
|
||||
pointers is visualized).
|
||||
- Fixed a crash when closing empty Geometry 3D views. (#652, #657)
|
||||
- Fixed the debugger not visualizing `enum` types when evaluated through a
|
||||
bitfield type. (#655)
|
||||
- Fixed the PDB -> RDI conversion not correctly generating location information
|
||||
for function parameters, when the EXE/PDB were built to include support for
|
||||
Edit and Continue (`-ZI` switch). (#656)
|
||||
|
||||
## Binary Utility Changes
|
||||
|
||||
- Fixed a crash when using the `--compress` option, when generating RDI files.
|
||||
|
||||
# v0.9.22-alpha
|
||||
|
||||
## Debugger Changes
|
||||
|
||||
- Further improved PDB -> RDI conversion performance.
|
||||
- Capped the number of additional threads / processes spawned for PDB -> RDI
|
||||
conversion.
|
||||
- Prioritize PDB -> RDI conversion based on what is actually found to be
|
||||
necessary by the debugger, rather than converting all PDBs in the order in
|
||||
which they're discovered.
|
||||
- Added preliminary support for DWARF -> RDI conversion on Windows.
|
||||
- The debugger now relies on source file checksums to determine whether or not
|
||||
a source file is out-of-date with respect to what was compiled when debug info
|
||||
was produced, rather than just the modification timestamp.
|
||||
- The debugger now will rely on debug info to detect the language of source code
|
||||
files, if it cannot infer from the source file's extension, or view settings.
|
||||
This will enable features like syntax highlighting and hover evaluation in
|
||||
cases like `.inl` files being included in C++ projects.
|
||||
- The debugger now will restore the last focused window when continuing
|
||||
automatically. (#245, #596)
|
||||
- Watch tables have been simplified in that they no longer have a separate
|
||||
column for evaluation types, since this was usually taking a lot more space
|
||||
than it deserved. The type of evaluations is still displayed in watch table
|
||||
cells, and it can always be evaluated directly via `typeof`.
|
||||
- Type evaluations have been simplified in watch tables as well; they no longer
|
||||
have untitled columns for sizes and offsets, this is instead displayed as
|
||||
an extra note by default. Similar behavior to the original behavior can still
|
||||
be obtained using the `columns` view, if needed.
|
||||
- The debugger no longer uses complex `union` types for most registers, and
|
||||
instead just displays the register value plainly.
|
||||
- The hover evaluation UI has been made larger when needed.
|
||||
- The debugger now prefers matching global, function, and type identifiers to
|
||||
the most relevant debug info and module in context; this fixes evaluation in
|
||||
some multi-process debugging contexts. (#581)
|
||||
- Fixed the debugger unnecessarily stripping `enum` type information when
|
||||
accessed through array operators. (#634)
|
||||
- The debugger now understands a standalone `unsigned` keyword as an
|
||||
`unsigned int` type, to match C rules.
|
||||
- The debugger now uses the current working directory to form the working
|
||||
directory for targets specified on the command line, to match behavior when
|
||||
running a command from the command line without the debugger.
|
||||
- Improved call stack computation performance.
|
||||
- Improved debugger memory usage over long periods of time.
|
||||
- Fixed string-pointer comparison not working with not-equal (`!=`) operations.
|
||||
- Fixed a bug which was causing bad debuggee performance on some threads after
|
||||
some interactions with the debugger controller.
|
||||
- Fixed incorrect results when adding two register values. (#642)
|
||||
- Fixed the interpretation of register expressions in visualizers. (#649)
|
||||
- Fixed "forever loading" states in disassembly views in some cases. (#643)
|
||||
- Fixed jittering on window resizing. (#636)
|
||||
- Fixed the bitmap visualizer crashing in some circumstances relating to
|
||||
unsupported bitmap sizes. (#444, #563)
|
||||
- Fixed a crash when an empty `cast()` expression would be evaluated. (#625)
|
||||
- Fixed a crash when an invalid expression would be visualized using the `text`
|
||||
view. (#647)
|
||||
|
||||
## Linker Changes
|
||||
|
||||
- Changed symbol resolution in libaries to match MSVC behavior.
|
||||
- Optimized image building step to reduce memory usage.
|
||||
- Linker memory maps all input files by default to lower memory usage.
|
||||
(`/RAD_MEMORY_MAP_FILES`)
|
||||
- If debug info is available, linker uses it to show file and line number for
|
||||
unresolved relocations.
|
||||
- Improved base relocation build performance for large images, cutting build
|
||||
time by 70%.
|
||||
- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability
|
||||
with existing response files
|
||||
- Implemented section garbage collection (`/OPT:REF`)
|
||||
- Fixed bug where thread local variables pointed to incorrect types.
|
||||
- Changed rules for weak and undefined symbols, now weak symbol is not allowed
|
||||
to replace an undefined symbol.
|
||||
- Linker no longer creates thunks for imports that don't require them.
|
||||
|
||||
## Binary Utility Changes
|
||||
|
||||
- The binary utility, like the debugger, now can convert DWARF debug info to
|
||||
RDI files. When both DWARF and PDB info is present, it can now convert both,
|
||||
and produce a single final RDI file with all information.
|
||||
- Textual dumping of RDI files is now done in parallel, massively improving
|
||||
dumping performance.
|
||||
- PDB -> Breakpad conversion performance has now been parallelized to a greater
|
||||
degree, improving performance.
|
||||
@@ -1,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
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
# 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.
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# --- Unpack Arguments --------------------------------------------------------
|
||||
for arg in "$@"; do declare $arg='1'; done
|
||||
if [ ! -v gcc ]; then clang=1; fi
|
||||
if [ ! -v release ]; then debug=1; fi
|
||||
if [ -v debug ]; then echo "[debug mode]"; fi
|
||||
if [ -v release ]; then echo "[release mode]"; fi
|
||||
if [ -v clang ]; then compiler="${CC:-clang}"; echo "[clang compile]"; fi
|
||||
if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
|
||||
|
||||
# --- Unpack Command Line Build Arguments -------------------------------------
|
||||
auto_compile_flags=''
|
||||
|
||||
# --- Get Current Git Commit Id -----------------------------------------------
|
||||
git_hash=$(git describe --always --dirty)
|
||||
git_hash_full=$(git rev-parse HEAD)
|
||||
|
||||
# --- Compile/Link Line Definitions -------------------------------------------
|
||||
clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
||||
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
|
||||
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
|
||||
clang_link="-lpthread -lm -lrt -ldl"
|
||||
clang_out="-o"
|
||||
gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
||||
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
|
||||
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
|
||||
gcc_link="-lpthread -lm -lrt -ldl"
|
||||
gcc_out="-o"
|
||||
|
||||
# --- Per-Build Settings ------------------------------------------------------
|
||||
link_dll="-fPIC"
|
||||
link_os_gfx="-lX11 -lXext"
|
||||
link_render="-lGL -lEGL"
|
||||
link_font_provider="-lfreetype"
|
||||
|
||||
# --- Choose Compile/Link Lines -----------------------------------------------
|
||||
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
|
||||
if [ -v gcc ]; then compile_release="$gcc_release"; fi
|
||||
if [ -v gcc ]; then compile_link="$gcc_link"; fi
|
||||
if [ -v gcc ]; then out="$gcc_out"; fi
|
||||
if [ -v clang ]; then compile_debug="$clang_debug"; fi
|
||||
if [ -v clang ]; then compile_release="$clang_release"; fi
|
||||
if [ -v clang ]; then compile_link="$clang_link"; fi
|
||||
if [ -v clang ]; then out="$clang_out"; fi
|
||||
if [ -v debug ]; then compile="$compile_debug"; fi
|
||||
if [ -v release ]; then compile="$compile_release"; fi
|
||||
|
||||
# --- Prep Directories --------------------------------------------------------
|
||||
mkdir -p build
|
||||
mkdir -p local
|
||||
|
||||
# --- Build & Run Metaprogram -------------------------------------------------
|
||||
if [ -v no_meta ]; then echo "[skipping metagen]"; fi
|
||||
if [ ! -v no_meta ]
|
||||
then
|
||||
cd build
|
||||
$compile_debug ../src/metagen/metagen_main.c $compile_link $out metagen
|
||||
./metagen
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# --- Build Everything (@build_targets) ---------------------------------------
|
||||
cd build
|
||||
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $link_font_provider $out raddbg; fi
|
||||
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
|
||||
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
|
||||
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
|
||||
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
|
||||
if [ -v rdi_breakpad_from_pdb ]; then didbuild=1 && $compile ../src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c $compile_link $out rdi_breakpad_from_pdb; fi
|
||||
if [ -v ryan_scratch ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $link_render $link_font_provider $out ryan_scratch; fi
|
||||
cd ..
|
||||
|
||||
# --- Warn On No Builds -------------------------------------------------------
|
||||
if [ ! -v didbuild ]
|
||||
then
|
||||
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh rdi_from_pdb\`."
|
||||
exit 1
|
||||
fi
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+86
-58
@@ -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",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /D "%~dp0"
|
||||
|
||||
echo --- getting test data folder path ---------------------------------------------
|
||||
if not exist .\local\test_data_path.txt (
|
||||
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
|
||||
goto :EOF
|
||||
)
|
||||
set /p test_data_folder=<.\local\test_data_path.txt
|
||||
echo test data path: %test_data_folder%
|
||||
echo:
|
||||
|
||||
echo --- building all testing executables ------------------------------------------
|
||||
call build rdi_from_pdb rdi_dump raddbg radlink tester
|
||||
echo:
|
||||
|
||||
echo --- running tests -------------------------------------------------------------
|
||||
pushd build
|
||||
call tester.exe --test_data:%test_data_folder%
|
||||
popd
|
||||
@@ -4,6 +4,7 @@ $path_root = git rev-parse --show-toplevel
|
||||
|
||||
if ($IsWindows) {
|
||||
$devshell = Join-Path $path_root 'scripts/helpers/devshell.ps1'
|
||||
# This HandmadeHero implementation is only designed for 64-bit systems
|
||||
& $devshell -arch amd64
|
||||
}
|
||||
|
||||
|
||||
@@ -1,654 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Layer Initialization
|
||||
|
||||
internal void
|
||||
ac_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
ac_shared = push_array(arena, AC_Shared, 1);
|
||||
ac_shared->arena = arena;
|
||||
ac_shared->cache_slots_count = 256;
|
||||
ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count);
|
||||
ac_shared->cache_stripes = stripe_array_alloc(arena);
|
||||
for EachElement(idx, ac_shared->req_batches)
|
||||
{
|
||||
ac_shared->req_batches[idx].mutex = mutex_alloc();
|
||||
ac_shared->req_batches[idx].arena = arena_alloc();
|
||||
}
|
||||
ac_shared->cancel_thread = thread_launch(ac_cancel_thread_entry_point, 0);
|
||||
ac_shared->cancel_thread_mutex = mutex_alloc();
|
||||
mutex_take(ac_shared->cancel_thread_mutex);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal AC_Artifact
|
||||
ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
AC_RequestBatch *req_batch = &ac_shared->req_batches[params->flags & AC_Flag_HighPriority ? 0 : 1];
|
||||
|
||||
//- rjf: create function -> cache
|
||||
AC_Cache *cache = 0;
|
||||
{
|
||||
U64 cache_hash = u64_hash_from_str8(str8_struct(¶ms->create));
|
||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
||||
{
|
||||
RWMutexScope(cache_stripe->rw_mutex, write_mode)
|
||||
{
|
||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
||||
{
|
||||
if(c->create == params->create)
|
||||
{
|
||||
cache = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(write_mode && cache == 0)
|
||||
{
|
||||
cache = push_array(cache_stripe->arena, AC_Cache, 1);
|
||||
SLLStackPush(ac_shared->cache_slots[cache_slot_idx], cache);
|
||||
cache->create = params->create;
|
||||
cache->destroy = params->destroy;
|
||||
cache->slots_count = Max(256, params->slots_count);
|
||||
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
||||
cache->stripes = stripe_array_alloc(cache_stripe->arena);
|
||||
}
|
||||
}
|
||||
if(cache != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: unpack key
|
||||
U64 hash = u64_hash_from_str8(key);
|
||||
U64 slot_idx = hash%cache->slots_count;
|
||||
AC_Slot *slot = &cache->slots[slot_idx];
|
||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||
|
||||
//- rjf: cache * key -> existing artifact
|
||||
B32 artifact_is_stale = 1;
|
||||
B32 got_artifact = 0;
|
||||
B32 need_request = 0;
|
||||
AC_Artifact artifact = {0};
|
||||
RWMutexScope(stripe->rw_mutex, 0)
|
||||
{
|
||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->key, key, 0))
|
||||
{
|
||||
ins_atomic_u64_eval_assign(&n->last_requested_gen, params->gen);
|
||||
B32 is_stale = (n->last_completed_gen != params->gen);
|
||||
if(ins_atomic_u64_eval(&n->completion_count) != 0 && (!is_stale || !(params->flags & AC_Flag_WaitForFresh)))
|
||||
{
|
||||
got_artifact = 1;
|
||||
artifact_is_stale = is_stale;
|
||||
artifact = n->val;
|
||||
access_touch(access, &n->access_pt, stripe->cv);
|
||||
}
|
||||
if(is_stale)
|
||||
{
|
||||
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
||||
need_request = got_task;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: didn't get artifact we want? -> fall back to slow path
|
||||
if(!got_artifact || need_request)
|
||||
{
|
||||
RWMutexScope(stripe->rw_mutex, 1) for(;;)
|
||||
{
|
||||
B32 out_of_time = (os_now_microseconds() >= endt_us);
|
||||
|
||||
// rjf: find node in cache
|
||||
AC_Node *node = 0;
|
||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->key, key, 0))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: no node? -> create
|
||||
if(node == 0)
|
||||
{
|
||||
need_request = 1;
|
||||
node = stripe->free;
|
||||
if(node)
|
||||
{
|
||||
stripe->free = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = push_array_no_zero(stripe->arena, AC_Node, 1);
|
||||
}
|
||||
MemoryZeroStruct(node);
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
// TODO(rjf): string allocator for keys
|
||||
node->key = str8_copy(stripe->arena, key);
|
||||
node->working_count = 1;
|
||||
node->evict_threshold_us = params->evict_threshold_us;
|
||||
}
|
||||
node->access_pt.last_time_touched_us = os_now_microseconds();
|
||||
node->access_pt.last_update_idx_touched = update_tick_idx();
|
||||
|
||||
// rjf: request
|
||||
if(need_request)
|
||||
{
|
||||
need_request = 0;
|
||||
MutexScope(req_batch->mutex)
|
||||
{
|
||||
AC_RequestNode *n = push_array(req_batch->arena, AC_RequestNode, 1);
|
||||
if(params->flags & AC_Flag_Wide)
|
||||
{
|
||||
SLLQueuePush(req_batch->first_wide, req_batch->last_wide, n);
|
||||
req_batch->wide_count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SLLQueuePush(req_batch->first_thin, req_batch->last_thin, n);
|
||||
req_batch->thin_count += 1;
|
||||
}
|
||||
n->v.key = str8_copy(req_batch->arena, key);
|
||||
n->v.gen = params->gen;
|
||||
n->v.cancel_signal = &node->cancelled;
|
||||
n->v.create = params->create;
|
||||
}
|
||||
cond_var_broadcast(async_tick_start_cond_var);
|
||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
||||
if(params->flags & AC_Flag_HighPriority)
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: get value from node, if possible
|
||||
if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time))
|
||||
{
|
||||
got_artifact = 1;
|
||||
artifact_is_stale = (node->last_completed_gen == params->gen);
|
||||
artifact = node->val;
|
||||
access_touch(access, &node->access_pt, stripe->cv);
|
||||
}
|
||||
|
||||
// rjf: abort if needed
|
||||
if(out_of_time || got_artifact || is_async_thread)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: wait for results
|
||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, endt_us);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: report staleness
|
||||
if(params->stale_out)
|
||||
{
|
||||
params->stale_out[0] = artifact_is_stale;
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
return artifact;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal void
|
||||
ac_async_tick(void)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: enable cancellation scanning
|
||||
//
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
mutex_drop(ac_shared->cancel_thread_mutex);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: do eviction pass across all caches
|
||||
//
|
||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
||||
{
|
||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
||||
{
|
||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
||||
{
|
||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
||||
for EachInRange(slot_idx, slot_range)
|
||||
{
|
||||
AC_Slot *slot = &cache->slots[slot_idx];
|
||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
||||
{
|
||||
B32 slot_has_work = 0;
|
||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
||||
{
|
||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
||||
{
|
||||
next = n->next;
|
||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) == 0)
|
||||
{
|
||||
slot_has_work = 1;
|
||||
if(!write_mode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLLRemove(slot->first, slot->last, n);
|
||||
n->next = (AC_Node *)stripe->free;
|
||||
stripe->free = n;
|
||||
if(cache->destroy)
|
||||
{
|
||||
cache->destroy(n->val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!slot_has_work)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather requests
|
||||
//
|
||||
typedef struct RequestBatchTask RequestBatchTask;
|
||||
struct RequestBatchTask
|
||||
{
|
||||
AC_Request *wide;
|
||||
U64 wide_count;
|
||||
AC_Request *thin;
|
||||
U64 thin_count;
|
||||
};
|
||||
RequestBatchTask *tasks = 0;
|
||||
U64 tasks_count = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
tasks_count = 2;
|
||||
tasks = push_array(scratch.arena, RequestBatchTask, tasks_count);
|
||||
for EachElement(task_idx, ac_shared->req_batches)
|
||||
{
|
||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
||||
MutexScope(batch->mutex)
|
||||
{
|
||||
tasks[task_idx].wide_count = batch->wide_count;
|
||||
tasks[task_idx].thin_count = batch->thin_count;
|
||||
tasks[task_idx].wide = push_array(scratch.arena, AC_Request, tasks[task_idx].wide_count);
|
||||
tasks[task_idx].thin = push_array(scratch.arena, AC_Request, tasks[task_idx].thin_count);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, AC_RequestNode, batch->first_wide)
|
||||
{
|
||||
MemoryCopyStruct(&tasks[task_idx].wide[idx], &n->v);
|
||||
tasks[task_idx].wide[idx].key = str8_copy(scratch.arena, tasks[task_idx].wide[idx].key);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, AC_RequestNode, batch->first_thin)
|
||||
{
|
||||
MemoryCopyStruct(&tasks[task_idx].thin[idx], &n->v);
|
||||
tasks[task_idx].thin[idx].key = str8_copy(scratch.arena, tasks[task_idx].thin[idx].key);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
arena_clear(batch->arena);
|
||||
batch->first_wide = batch->last_wide = batch->first_thin = batch->last_thin = 0;
|
||||
batch->wide_count = batch->thin_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
lane_sync_u64(&tasks, 0);
|
||||
lane_sync_u64(&tasks_count, 0);
|
||||
lane_sync();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: do all requests
|
||||
//
|
||||
for EachIndex(task_idx, tasks_count)
|
||||
{
|
||||
lane_sync();
|
||||
RequestBatchTask *task = &tasks[task_idx];
|
||||
|
||||
//- rjf: set up cancellation signal
|
||||
U64 cancelled = 0;
|
||||
U64 *cancelled_ptr = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
cancelled_ptr = &cancelled;
|
||||
}
|
||||
lane_sync_u64(&cancelled_ptr, 0);
|
||||
|
||||
//- rjf: do all wide requests for this priority
|
||||
U64 done_wide_count = 0;
|
||||
ProfScope("wide requests (p%I64u)", task_idx)
|
||||
{
|
||||
for EachIndex(idx, task->wide_count)
|
||||
{
|
||||
lane_sync();
|
||||
AC_Request *r = &task->wide[idx];
|
||||
|
||||
// rjf: any new higher priority tasks? -> cancel
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
if(task_idx == 1 && idx != 0 && ins_atomic_u32_eval(&async_loop_again_high_priority))
|
||||
{
|
||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
// rjf: cancelled? -> exit
|
||||
if(ins_atomic_u32_eval(cancelled_ptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: compute val
|
||||
B32 retry = 0;
|
||||
U64 gen = r->gen;
|
||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
||||
|
||||
// rjf: retry? -> resubmit request
|
||||
if(retry && lane_idx() == 0)
|
||||
{
|
||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
||||
MutexScope(batch->mutex)
|
||||
{
|
||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
||||
batch->wide_count += 1;
|
||||
MemoryCopyStruct(&n->v, r);
|
||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
||||
}
|
||||
|
||||
// rjf: create function -> cache
|
||||
AC_Cache *cache = 0;
|
||||
if(!retry && lane_idx() == 0)
|
||||
{
|
||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
||||
{
|
||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
||||
{
|
||||
if(c->create == r->create)
|
||||
{
|
||||
cache = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: write value into cache
|
||||
if(!retry && lane_idx() == 0)
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(r->key);
|
||||
U64 slot_idx = hash%cache->slots_count;
|
||||
AC_Slot *slot = &cache->slots[slot_idx];
|
||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||
RWMutexScope(stripe->rw_mutex, 1)
|
||||
{
|
||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->key, r->key, 0))
|
||||
{
|
||||
n->last_completed_gen = gen;
|
||||
n->val = val;
|
||||
ins_atomic_u64_dec_eval(&n->working_count);
|
||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
cond_var_broadcast(stripe->cv);
|
||||
}
|
||||
|
||||
// rjf: increment count
|
||||
lane_sync();
|
||||
done_wide_count += 1;
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
//- rjf: do all thin requests for this priority
|
||||
U64 done_thin_count = 0;
|
||||
ProfScope("thin requests (p%I64u)", task_idx)
|
||||
{
|
||||
U64 req_take_counter = 0;
|
||||
U64 *req_take_counter_ptr = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
req_take_counter_ptr = &req_take_counter;
|
||||
}
|
||||
lane_sync_u64(&req_take_counter_ptr, 0);
|
||||
for(;;)
|
||||
{
|
||||
// rjf: any new higher priority tasks? -> cancel
|
||||
if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2 &&
|
||||
ins_atomic_u32_eval(&async_loop_again_high_priority))
|
||||
{
|
||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
||||
}
|
||||
|
||||
// rjf: cancelled? -> exit
|
||||
if(ins_atomic_u64_eval(cancelled_ptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: take next task
|
||||
U64 req_idx = ins_atomic_u64_inc_eval(req_take_counter_ptr) - 1;
|
||||
if(req_idx >= task->thin_count) { break; }
|
||||
AC_Request *r = &task->thin[req_idx];
|
||||
|
||||
// rjf: push thin lane ctx
|
||||
U64 thin_lane_ctx_broadcast_memory = 0;
|
||||
LaneCtx thin_lane_ctx = {0, 1, {0}, &thin_lane_ctx_broadcast_memory};
|
||||
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
|
||||
|
||||
// rjf: compute val
|
||||
B32 retry = 0;
|
||||
U64 gen = r->gen;
|
||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
||||
|
||||
// rjf: restore wide lane ctx
|
||||
lane_ctx(lane_ctx_restore);
|
||||
|
||||
// rjf: retry? -> resubmit request
|
||||
if(retry)
|
||||
{
|
||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
||||
MutexScope(batch->mutex)
|
||||
{
|
||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
||||
batch->thin_count += 1;
|
||||
MemoryCopyStruct(&n->v, r);
|
||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
||||
}
|
||||
|
||||
// rjf: create function -> cache
|
||||
AC_Cache *cache = 0;
|
||||
if(!retry)
|
||||
{
|
||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
||||
{
|
||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
||||
{
|
||||
if(c->create == r->create)
|
||||
{
|
||||
cache = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: write value into cache
|
||||
if(!retry)
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(r->key);
|
||||
U64 slot_idx = hash%cache->slots_count;
|
||||
AC_Slot *slot = &cache->slots[slot_idx];
|
||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||
RWMutexScope(stripe->rw_mutex, 1)
|
||||
{
|
||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->key, r->key, 0))
|
||||
{
|
||||
n->last_completed_gen = gen;
|
||||
n->val = val;
|
||||
ins_atomic_u64_dec_eval(&n->working_count);
|
||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
cond_var_broadcast(stripe->cv);
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
done_thin_count = ins_atomic_u64_eval(req_take_counter_ptr);
|
||||
lane_sync();
|
||||
}
|
||||
|
||||
//- rjf: cancelled early, unfinished tasks? -> defer to next tick
|
||||
if(lane_idx() == 0 && task_idx > 0)
|
||||
{
|
||||
B32 need_another_try = (done_wide_count < task->wide_count || done_thin_count < task->thin_count);
|
||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
||||
MutexScope(batch->mutex)
|
||||
{
|
||||
// rjf: push leftover wide tasks
|
||||
for(U64 idx = done_wide_count; idx < task->wide_count; idx += 1)
|
||||
{
|
||||
AC_Request *r = &task->wide[idx];
|
||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
||||
batch->wide_count += 1;
|
||||
MemoryCopyStruct(&n->v, r);
|
||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
||||
}
|
||||
|
||||
// rjf: push leftover thin tasks
|
||||
for(U64 idx = done_thin_count; idx < task->thin_count; idx += 1)
|
||||
{
|
||||
AC_Request *r = &task->thin[idx];
|
||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
||||
batch->thin_count += 1;
|
||||
MemoryCopyStruct(&n->v, r);
|
||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
||||
}
|
||||
}
|
||||
if(need_another_try)
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: disable cancellation scanning
|
||||
//
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
mutex_take(ac_shared->cancel_thread_mutex);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cancel Thread
|
||||
|
||||
internal void
|
||||
ac_cancel_thread_entry_point(void *p)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
os_sleep_milliseconds(50);
|
||||
MutexScope(ac_shared->cancel_thread_mutex)
|
||||
{
|
||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
||||
{
|
||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
||||
{
|
||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
||||
{
|
||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
||||
for EachInRange(slot_idx, slot_range)
|
||||
{
|
||||
AC_Slot *slot = &cache->slots[slot_idx];
|
||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
||||
{
|
||||
B32 slot_has_work = 0;
|
||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
||||
{
|
||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
||||
{
|
||||
next = n->next;
|
||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) > 0)
|
||||
{
|
||||
slot_has_work = 1;
|
||||
if(!write_mode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->cancelled = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!slot_has_work)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef ARTIFACT_CACHE_H
|
||||
#define ARTIFACT_CACHE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Artifact Handle Type
|
||||
|
||||
typedef struct AC_Artifact AC_Artifact;
|
||||
struct AC_Artifact
|
||||
{
|
||||
U64 u64[4];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Artifact Computation Function Types
|
||||
|
||||
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
typedef void AC_DestroyFunctionType(AC_Artifact artifact);
|
||||
|
||||
typedef U32 AC_Flags;
|
||||
typedef enum AC_FlagsEnum
|
||||
{
|
||||
AC_Flag_WaitForFresh = (1<<0),
|
||||
AC_Flag_HighPriority = (1<<1),
|
||||
AC_Flag_Wide = (1<<2),
|
||||
}
|
||||
AC_FlagsEnum;
|
||||
|
||||
typedef struct AC_ArtifactParams AC_ArtifactParams;
|
||||
struct AC_ArtifactParams
|
||||
{
|
||||
AC_CreateFunctionType *create;
|
||||
AC_DestroyFunctionType *destroy;
|
||||
U64 slots_count;
|
||||
U64 gen;
|
||||
U64 evict_threshold_us;
|
||||
B32 *stale_out;
|
||||
AC_Flags flags;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct AC_Request AC_Request;
|
||||
struct AC_Request
|
||||
{
|
||||
String8 key;
|
||||
U64 gen;
|
||||
B32 *cancel_signal;
|
||||
AC_CreateFunctionType *create;
|
||||
};
|
||||
|
||||
typedef struct AC_RequestNode AC_RequestNode;
|
||||
struct AC_RequestNode
|
||||
{
|
||||
AC_RequestNode *next;
|
||||
AC_Request v;
|
||||
};
|
||||
|
||||
typedef struct AC_Node AC_Node;
|
||||
struct AC_Node
|
||||
{
|
||||
AC_Node *next;
|
||||
AC_Node *prev;
|
||||
|
||||
// rjf: key/gen/value
|
||||
String8 key;
|
||||
U64 last_requested_gen;
|
||||
U64 last_completed_gen;
|
||||
AC_Artifact val;
|
||||
|
||||
// rjf: metadata
|
||||
AccessPt access_pt;
|
||||
U64 working_count;
|
||||
U64 completion_count;
|
||||
U64 evict_threshold_us;
|
||||
B32 cancelled;
|
||||
U64 _unused_;
|
||||
};
|
||||
|
||||
typedef struct AC_Slot AC_Slot;
|
||||
struct AC_Slot
|
||||
{
|
||||
AC_Node *first;
|
||||
AC_Node *last;
|
||||
};
|
||||
|
||||
typedef struct AC_Cache AC_Cache;
|
||||
struct AC_Cache
|
||||
{
|
||||
// rjf: link / key for cache-cache
|
||||
AC_Cache *next;
|
||||
AC_CreateFunctionType *create;
|
||||
AC_DestroyFunctionType *destroy;
|
||||
|
||||
// rjf: artifact cache
|
||||
U64 slots_count;
|
||||
AC_Slot *slots;
|
||||
StripeArray stripes;
|
||||
};
|
||||
|
||||
typedef struct AC_RequestBatch AC_RequestBatch;
|
||||
struct AC_RequestBatch
|
||||
{
|
||||
Mutex mutex;
|
||||
Arena *arena;
|
||||
AC_RequestNode *first_wide;
|
||||
AC_RequestNode *last_wide;
|
||||
AC_RequestNode *first_thin;
|
||||
AC_RequestNode *last_thin;
|
||||
U64 wide_count;
|
||||
U64 thin_count;
|
||||
};
|
||||
|
||||
typedef struct AC_Shared AC_Shared;
|
||||
struct AC_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: cache cache
|
||||
U64 cache_slots_count;
|
||||
AC_Cache **cache_slots;
|
||||
StripeArray cache_stripes;
|
||||
|
||||
// rjf: requests
|
||||
AC_RequestBatch req_batches[2]; // 0: high priority, 1: low priority
|
||||
|
||||
// rjf: cancel thread
|
||||
Thread cancel_thread;
|
||||
Mutex cancel_thread_mutex;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global AC_Shared *ac_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Layer Initialization
|
||||
|
||||
internal void ac_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us);
|
||||
#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), .evict_threshold_us = (2000000), __VA_ARGS__}, (endt_us))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal void ac_async_tick(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cancel Thread
|
||||
|
||||
internal void ac_cancel_thread_entry_point(void *p);
|
||||
|
||||
#endif // ARTIFACT_CACHE_H
|
||||
+227
-174
@@ -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
@@ -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
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Dev Arena
|
||||
|
||||
#if ENABLE_DEV
|
||||
|
||||
internal void
|
||||
arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){
|
||||
ArenaDev *dev = arena->dev;
|
||||
if (dev != 0 && ptr != 0){
|
||||
//- read location
|
||||
char *file_name = 0;
|
||||
U64 line_number = 0;
|
||||
tctx_read_srcloc(&file_name, &line_number);
|
||||
tctx_write_srcloc(0, 0);
|
||||
|
||||
//- profile
|
||||
ArenaProf *prof = dev->prof;
|
||||
if (prof != 0){
|
||||
// c string -> string
|
||||
String8 file_name_str = str8_lit("(null)");
|
||||
if (file_name != 0){
|
||||
file_name_str = str8_cstring(file_name);
|
||||
}
|
||||
// record
|
||||
arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_annotate_absorb__dev(Arena *arena, Arena *sub){
|
||||
ArenaDev *dev = arena->dev;
|
||||
ArenaDev *sub_dev = sub->dev;
|
||||
if (dev != 0 && sub_dev != 0){
|
||||
//- merge profiles
|
||||
ArenaProf *prof = dev->prof;
|
||||
ArenaProf *sub_prof = sub_dev->prof;
|
||||
if (prof != 0 && sub_prof != 0){
|
||||
for (ArenaProfNode *sub_node = sub_prof->first;
|
||||
sub_node != 0;
|
||||
sub_node = sub_node->next){
|
||||
arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line,
|
||||
sub_node->size, sub_node->count);
|
||||
}
|
||||
}
|
||||
}
|
||||
//- release the sub dev memory
|
||||
if (sub_dev != 0){
|
||||
arena_release(sub_dev->arena);
|
||||
}
|
||||
}
|
||||
|
||||
internal ArenaDev*
|
||||
arena_equip__dev(Arena *arena){
|
||||
ArenaDev *result = arena->dev;
|
||||
if (result == 0){
|
||||
Arena *dev_arena = arena_alloc();
|
||||
ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev));
|
||||
MemoryZeroStruct(dev);
|
||||
dev->arena = dev_arena;
|
||||
arena->dev = dev;
|
||||
result = dev;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_equip_profile__dev(Arena *arena){
|
||||
ArenaDev *dev = arena_equip__dev(arena);
|
||||
if (dev->prof == 0){
|
||||
dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf));
|
||||
MemoryZeroStruct(dev->prof);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){
|
||||
Assert(arena != out_arena);
|
||||
|
||||
//- get dev & disable
|
||||
ArenaDev *dev = arena->dev;
|
||||
arena->dev = 0;
|
||||
|
||||
//- get prof
|
||||
ArenaProf *prof = (dev != 0)?dev->prof:0;
|
||||
|
||||
//- not equipped with prof
|
||||
if (prof == 0){
|
||||
str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n"));
|
||||
}
|
||||
|
||||
//- print prof
|
||||
if (prof != 0){
|
||||
Temp scratch = temp_begin(dev->arena);
|
||||
|
||||
//- make flat array
|
||||
U64 note_count = prof->count;
|
||||
ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count);
|
||||
{
|
||||
ArenaProfNode **note_ptr = notes;
|
||||
for (ArenaProfNode *node = prof->first;
|
||||
node != 0;
|
||||
node = node->next, note_ptr += 1){
|
||||
*note_ptr = node;
|
||||
}
|
||||
}
|
||||
|
||||
//- file name size
|
||||
U64 max_file_name_size = 0;
|
||||
{
|
||||
ArenaProfNode **note_ptr = notes;
|
||||
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||
max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size);
|
||||
}
|
||||
}
|
||||
|
||||
//- sort (> size, < [address])
|
||||
for (U64 i = 0; i < note_count; i += 1){
|
||||
ArenaProfNode **i_note = notes + i;
|
||||
ArenaProfNode **min_note = i_note;
|
||||
for (U64 j = i + 1; j < note_count; j += 1){
|
||||
ArenaProfNode **j_note = notes + j;
|
||||
if ((**j_note).size > (**min_note).size ||
|
||||
((**j_note).size == (**min_note).size && *j_note < *min_note)){
|
||||
min_note = j_note;
|
||||
}
|
||||
}
|
||||
if (min_note != i_note){
|
||||
ArenaProfNode *t = *i_note;
|
||||
*i_note = *min_note;
|
||||
*min_note = t;
|
||||
}
|
||||
}
|
||||
|
||||
//- total size
|
||||
U64 total_size = 0;
|
||||
{
|
||||
ArenaProfNode **note_ptr = notes;
|
||||
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||
ArenaProfNode *note = *note_ptr;
|
||||
total_size += note->size;
|
||||
}
|
||||
}
|
||||
|
||||
//- print
|
||||
{
|
||||
str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size);
|
||||
|
||||
ArenaProfNode **note_ptr = notes;
|
||||
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||
ArenaProfNode *note = *note_ptr;
|
||||
String8 location = push_str8f(scratch.arena, "%S:%5llu:",
|
||||
note->file_name, note->line);
|
||||
F32 percent = 100.f*((F32)note->size)/total_size;
|
||||
str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n",
|
||||
max_file_name_size + 7, str8_varg(location),
|
||||
note->size, percent, note->count);
|
||||
}
|
||||
}
|
||||
|
||||
temp_end(scratch);
|
||||
}
|
||||
|
||||
//- restore dev
|
||||
arena->dev = dev;
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line,
|
||||
U64 size, U64 count){
|
||||
// find existing profile node
|
||||
ArenaProfNode *prof_node = 0;
|
||||
for (ArenaProfNode *node = prof->first;
|
||||
node != 0;
|
||||
node = node->next){
|
||||
if (node->line == line && str8_match(file_name, node->file_name, 0)){
|
||||
prof_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// make new histogram node if necessary
|
||||
if (prof_node == 0){
|
||||
prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node));
|
||||
SLLQueuePush(prof->first, prof->last, prof_node);
|
||||
prof->count += 1;
|
||||
prof_node->file_name = file_name;
|
||||
prof_node->line = line;
|
||||
}
|
||||
// record this allocation
|
||||
prof_node->size += size;
|
||||
prof_node->count += count;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_ARENA_DEV_H
|
||||
#define BASE_ARENA_DEV_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Dev Arena Types
|
||||
|
||||
typedef struct ArenaDev ArenaDev;
|
||||
struct ArenaDev
|
||||
{
|
||||
Arena *arena;
|
||||
struct ArenaProf *prof;
|
||||
};
|
||||
|
||||
typedef struct ArenaProf ArenaProf;
|
||||
struct ArenaProf
|
||||
{
|
||||
struct ArenaProfNode *first;
|
||||
struct ArenaProfNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct ArenaProfNode ArenaProfNode;
|
||||
struct ArenaProfNode
|
||||
{
|
||||
ArenaProfNode *next;
|
||||
String8 file_name;
|
||||
U64 line;
|
||||
U64 size;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Dev Arena Functions
|
||||
|
||||
#if ENABLE_DEV
|
||||
internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr);
|
||||
internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub);
|
||||
internal ArenaDev* arena_equip__dev(Arena *arena);
|
||||
internal void arena_equip_profile__dev(Arena *arena);
|
||||
internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out);
|
||||
internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count);
|
||||
#endif
|
||||
|
||||
#endif // BASE_ARENA_DEV_H
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
|
||||
|
||||
internal U64
|
||||
count_bits_set16(U16 val)
|
||||
{
|
||||
return __popcnt16(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
return __popcnt(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set64(U64 val)
|
||||
{
|
||||
return __popcnt64(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz32(U32 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanForward(&idx, mask);
|
||||
return idx;
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz64(U64 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanForward64(&idx, mask);
|
||||
return idx;
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz32(U32 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanReverse(&idx, mask);
|
||||
return 31 - idx;
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz64(U64 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanReverse64(&idx, mask);
|
||||
return 63 - idx;
|
||||
}
|
||||
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
|
||||
internal U64
|
||||
count_bits_set16(U16 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set64(U64 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz64(U64 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
# error "bits not defined for this target"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_BITS_H
|
||||
#define BASE_BITS_H
|
||||
|
||||
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
|
||||
|
||||
internal U64 count_bits_set16(U16 val);
|
||||
internal U64 count_bits_set32(U32 val);
|
||||
internal U64 count_bits_set64(U64 val);
|
||||
|
||||
internal U64 ctz32(U32 val);
|
||||
internal U64 ctz64(U64 val);
|
||||
internal U64 clz32(U32 val);
|
||||
internal U64 clz64(U64 val);
|
||||
|
||||
#endif // BASE_BITS_H
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,234 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
global U64 global_update_tick_idx = 0;
|
||||
global U64 async_threads_count = 0;
|
||||
global CondVar async_tick_start_cond_var = {0};
|
||||
global Mutex async_tick_start_mutex = {0};
|
||||
global Mutex async_tick_stop_mutex = {0};
|
||||
global B32 async_loop_again = 0;
|
||||
global B32 async_loop_again_high_priority = 0;
|
||||
global B32 global_async_exit = 0;
|
||||
thread_static B32 is_async_thread = 0;
|
||||
|
||||
internal void
|
||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
||||
{
|
||||
ThreadNameF("main_thread");
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: set up async thread group info
|
||||
async_tick_start_cond_var = cond_var_alloc();
|
||||
async_tick_start_mutex = mutex_alloc();
|
||||
async_tick_stop_mutex = mutex_alloc();
|
||||
|
||||
//- rjf: set up telemetry
|
||||
#if PROFILE_TELEMETRY
|
||||
local_persist char tm_data[MB(64)];
|
||||
tmLoadLibrary(TM_RELEASE);
|
||||
tmSetMaxThreadCount(256);
|
||||
tmInitialize(sizeof(tm_data), tm_data);
|
||||
#endif
|
||||
|
||||
//- rjf: set up spall
|
||||
#if PROFILE_SPALL
|
||||
spall_profile = spall_init_file_ex("spall_capture", 1, 0);
|
||||
#endif
|
||||
|
||||
//- rjf: parse command line
|
||||
String8List command_line_argument_strings = {0};
|
||||
{
|
||||
for EachIndex(idx, arguments_count)
|
||||
{
|
||||
str8_list_push(scratch.arena, &command_line_argument_strings, str8_cstring(arguments[idx]));
|
||||
}
|
||||
}
|
||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
||||
|
||||
//- rjf: begin captures
|
||||
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
|
||||
if(capture)
|
||||
{
|
||||
ProfBeginCapture(arguments[0]);
|
||||
ProfMsg(BUILD_TITLE);
|
||||
}
|
||||
|
||||
//- rjf: initialize all included layers
|
||||
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
|
||||
ac_init();
|
||||
#endif
|
||||
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
|
||||
async_init(&cmdline);
|
||||
#endif
|
||||
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
|
||||
c_init();
|
||||
#endif
|
||||
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
|
||||
fs_init();
|
||||
#endif
|
||||
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
|
||||
mtx_init();
|
||||
#endif
|
||||
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
|
||||
di_init(&cmdline);
|
||||
#endif
|
||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||
dmn_init();
|
||||
#endif
|
||||
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
|
||||
ctrl_init();
|
||||
#endif
|
||||
#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL)
|
||||
os_gfx_init();
|
||||
#endif
|
||||
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
||||
fp_init();
|
||||
#endif
|
||||
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
|
||||
r_init(&cmdline);
|
||||
#endif
|
||||
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
|
||||
fnt_init();
|
||||
#endif
|
||||
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
|
||||
d_init();
|
||||
#endif
|
||||
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
|
||||
rd_init(&cmdline);
|
||||
#endif
|
||||
|
||||
//- rjf: launch async threads
|
||||
Thread *async_threads = 0;
|
||||
U64 lane_broadcast_val = 0;
|
||||
{
|
||||
U64 num_main_threads = 1;
|
||||
#if defined(CTRL_CORE_H)
|
||||
num_main_threads += 1;
|
||||
#endif
|
||||
U64 num_async_threads = os_get_system_info()->logical_processor_count;
|
||||
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
|
||||
num_async_threads -= num_main_threads_clamped;
|
||||
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
|
||||
if(num_async_threads_string.size != 0)
|
||||
{
|
||||
try_u64_from_str8_c_rules(num_async_threads_string, &num_async_threads);
|
||||
}
|
||||
num_async_threads = Max(1, num_async_threads);
|
||||
Barrier barrier = barrier_alloc(num_async_threads);
|
||||
LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads);
|
||||
async_threads_count = num_async_threads;
|
||||
async_threads = push_array(scratch.arena, Thread, async_threads_count);
|
||||
for EachIndex(idx, num_async_threads)
|
||||
{
|
||||
lane_ctxs[idx].lane_idx = idx;
|
||||
lane_ctxs[idx].lane_count = async_threads_count;
|
||||
lane_ctxs[idx].barrier = barrier;
|
||||
lane_ctxs[idx].broadcast_memory = &lane_broadcast_val;
|
||||
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: call into entry point
|
||||
entry_point(&cmdline);
|
||||
|
||||
//- rjf: join async threads
|
||||
ins_atomic_u32_inc_eval(&global_async_exit);
|
||||
cond_var_broadcast(async_tick_start_cond_var);
|
||||
for EachIndex(idx, async_threads_count)
|
||||
{
|
||||
thread_join(async_threads[idx], max_U64);
|
||||
}
|
||||
|
||||
//- rjf: end captures
|
||||
if(capture)
|
||||
{
|
||||
ProfEndCapture();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
|
||||
{
|
||||
TCTX *tctx = tctx_alloc();
|
||||
tctx_select(tctx);
|
||||
entry_point(params);
|
||||
tctx_release(tctx);
|
||||
}
|
||||
|
||||
internal U64
|
||||
update_tick_idx(void)
|
||||
{
|
||||
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
update(void)
|
||||
{
|
||||
ProfTick(0);
|
||||
ins_atomic_u64_inc_eval(&global_update_tick_idx);
|
||||
#if defined(FONT_CACHE_H)
|
||||
fnt_frame();
|
||||
#endif
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
B32 result = frame();
|
||||
#else
|
||||
B32 result = 0;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
async_thread_entry_point(void *params)
|
||||
{
|
||||
LaneCtx lctx = *(LaneCtx *)params;
|
||||
lane_ctx(lctx);
|
||||
is_async_thread = 1;
|
||||
ThreadNameF("async_thread_%I64u", lane_idx());
|
||||
for(;;)
|
||||
{
|
||||
// rjf: wait for signal if we need, otherwise reset loop signal & continue
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
if(!ins_atomic_u32_eval(&async_loop_again))
|
||||
{
|
||||
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+1000000);
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&async_loop_again, 0);
|
||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
// rjf: do all ticks for all layers
|
||||
ProfScope("async tick")
|
||||
{
|
||||
#if defined(ARTIFACT_CACHE_H)
|
||||
ac_async_tick();
|
||||
#endif
|
||||
#if defined(CONTENT_H)
|
||||
c_async_tick();
|
||||
#endif
|
||||
#if defined(FILE_STREAM_H)
|
||||
fs_async_tick();
|
||||
#endif
|
||||
#if defined(DBG_INFO_H)
|
||||
di_async_tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
// rjf: take exit signal; break if set
|
||||
lane_sync();
|
||||
B32 need_exit = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
need_exit = ins_atomic_u32_eval(&global_async_exit);
|
||||
}
|
||||
lane_sync_u64(&need_exit, 0);
|
||||
if(need_exit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_ENTRY_POINT_H
|
||||
#define BASE_ENTRY_POINT_H
|
||||
|
||||
internal void main_thread_base_entry_point(int argc, char **argv);
|
||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||
internal U64 update_tick_idx(void);
|
||||
internal B32 update(void);
|
||||
internal void async_thread_entry_point(void *params);
|
||||
|
||||
#endif // BASE_ENTRY_POINT_H
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MD5
|
||||
|
||||
#include "third_party/martins_hash/md5.h"
|
||||
|
||||
internal MD5
|
||||
md5_from_data(String8 data)
|
||||
{
|
||||
md5_ctx ctx = {0};
|
||||
md5_init(&ctx);
|
||||
md5_update(&ctx, (void*)data.str, data.size);
|
||||
MD5 result = {0};
|
||||
md5_finish(&ctx, result.u8);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: SHA
|
||||
|
||||
#include "third_party/martins_hash/sha1.h"
|
||||
#include "third_party/martins_hash/sha256.h"
|
||||
|
||||
internal SHA1
|
||||
sha1_from_data(String8 data)
|
||||
{
|
||||
SHA1 result = {0};
|
||||
{
|
||||
sha1_ctx ctx = {0};
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, data.str, data.size);
|
||||
sha1_finish(&ctx, result.u8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal SHA256
|
||||
sha256_from_data(String8 data)
|
||||
{
|
||||
SHA256 result = {0};
|
||||
{
|
||||
sha256_ctx ctx = {0};
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, data.str, data.size);
|
||||
sha256_finish(&ctx, result.u8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_HASH_H
|
||||
#define BASE_HASH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hash Result Types
|
||||
|
||||
typedef union MD5 MD5;
|
||||
union MD5
|
||||
{
|
||||
U8 u8[16];
|
||||
U16 u16[8];
|
||||
U32 u32[4];
|
||||
U64 u64[2];
|
||||
U128 u128;
|
||||
};
|
||||
|
||||
typedef union SHA1 SHA1;
|
||||
union SHA1
|
||||
{
|
||||
U8 u8[20];
|
||||
};
|
||||
|
||||
typedef union SHA256 SHA256;
|
||||
union SHA256
|
||||
{
|
||||
U8 u8[32];
|
||||
U16 u16[16];
|
||||
U32 u32[8];
|
||||
U64 u64[4];
|
||||
U128 u128[2];
|
||||
U256 u256;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MD5
|
||||
|
||||
internal MD5 md5_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: SHA
|
||||
|
||||
internal SHA1 sha1_from_data(String8 data);
|
||||
internal SHA256 sha256_from_data(String8 data);
|
||||
|
||||
#endif // BASE_HASH_H
|
||||
+8
-12
@@ -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
@@ -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
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_INS_H
|
||||
#define BASE_INS_H
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Implementations of Intrinsics
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
# include <windows.h>
|
||||
# include <tmmintrin.h>
|
||||
# include <wmmintrin.h>
|
||||
# include <intrin.h>
|
||||
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(x), 0)
|
||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
|
||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
|
||||
# endif
|
||||
|
||||
#elif OS_LINUX
|
||||
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
|
||||
# endif
|
||||
|
||||
#else
|
||||
// TODO(allen):
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Intrinsic Checks
|
||||
|
||||
#if ARCH_X64
|
||||
|
||||
# if !defined(ins_atomic_u64_inc_eval)
|
||||
# error missing: ins_atomic_u64_inc_eval
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error the intrinsic set for this arch is not developed
|
||||
#endif
|
||||
|
||||
|
||||
#endif //BASE_INS_H
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_LINKED_LIST_H
|
||||
#define BASE_LINKED_LIST_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
|
||||
#define SetNil(nil,p) ((p) = nil)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Macros
|
||||
|
||||
//- rjf: Base Doubly-Linked-List Macros
|
||||
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
|
||||
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
|
||||
CheckNil(nil,p) ? \
|
||||
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
|
||||
((p)==(l)) ? \
|
||||
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
|
||||
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
|
||||
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
|
||||
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
|
||||
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
|
||||
((n) == (l) ? (l) = (l)->prev : (0)),\
|
||||
(CheckNil(nil,(n)->prev) ? (0) :\
|
||||
((n)->prev->next = (n)->next)),\
|
||||
(CheckNil(nil,(n)->next) ? (0) :\
|
||||
((n)->next->prev = (n)->prev)))
|
||||
|
||||
//- rjf: Base Singly-Linked-List Queue Macros
|
||||
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
|
||||
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||
((n)->next=(f),(f)=(n)))
|
||||
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
|
||||
(SetNil(nil,f),SetNil(nil,l)):\
|
||||
((f)=(f)->next))
|
||||
|
||||
//- rjf: Base Singly-Linked-List Stack Macros
|
||||
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
|
||||
#define SLLStackPop_N(f,next) ((f)=(f)->next)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Convenience Wrappers
|
||||
|
||||
//- rjf: Doubly-Linked-List Wrappers
|
||||
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||
|
||||
//- rjf: Singly-Linked-List Queue Wrappers
|
||||
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
|
||||
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
|
||||
|
||||
//- rjf: Singly-Linked-List Stack Wrappers
|
||||
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
|
||||
#define SLLStackPop(f) SLLStackPop_N(f,next)
|
||||
|
||||
#endif //BASE_LINKED_LIST_H
|
||||
@@ -1,103 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals/Thread-Locals
|
||||
|
||||
C_LINKAGE thread_static Log *log_active;
|
||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||
C_LINKAGE thread_static Log *log_active = 0;
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Creation/Selection
|
||||
|
||||
internal Log *
|
||||
log_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
Log *log = push_array(arena, Log, 1);
|
||||
log->arena = arena;
|
||||
return log;
|
||||
}
|
||||
|
||||
internal void
|
||||
log_release(Log *log)
|
||||
{
|
||||
arena_release(log->arena);
|
||||
}
|
||||
|
||||
internal void
|
||||
log_select(Log *log)
|
||||
{
|
||||
log_active = log;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Building/Clearing
|
||||
|
||||
internal void
|
||||
log_msg(LogMsgKind kind, String8 string)
|
||||
{
|
||||
if(log_active != 0 && log_active->top_scope != 0)
|
||||
{
|
||||
String8 string_copy = push_str8_copy(log_active->arena, string);
|
||||
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
log_msgf(LogMsgKind kind, char *fmt, ...)
|
||||
{
|
||||
if(log_active != 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
log_msg(kind, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Scopes
|
||||
|
||||
internal void
|
||||
log_scope_begin(void)
|
||||
{
|
||||
if(log_active != 0)
|
||||
{
|
||||
U64 pos = arena_pos(log_active->arena);
|
||||
LogScope *scope = push_array(log_active->arena, LogScope, 1);
|
||||
scope->pos = pos;
|
||||
SLLStackPush(log_active->top_scope, scope);
|
||||
}
|
||||
}
|
||||
|
||||
internal LogScopeResult
|
||||
log_scope_end(Arena *arena)
|
||||
{
|
||||
LogScopeResult result = {0};
|
||||
if(log_active != 0)
|
||||
{
|
||||
LogScope *scope = log_active->top_scope;
|
||||
if(scope != 0)
|
||||
{
|
||||
SLLStackPop(log_active->top_scope);
|
||||
if(arena != 0)
|
||||
{
|
||||
for EachEnumVal(LogMsgKind, kind)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
|
||||
result.strings[kind] = indented_from_string(arena, result_unindented);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
arena_pop_to(log_active->arena, scope->pos);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_LOG_H
|
||||
#define BASE_LOG_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Types
|
||||
|
||||
typedef enum LogMsgKind
|
||||
{
|
||||
LogMsgKind_Info,
|
||||
LogMsgKind_UserError,
|
||||
LogMsgKind_COUNT
|
||||
}
|
||||
LogMsgKind;
|
||||
|
||||
typedef struct LogScope LogScope;
|
||||
struct LogScope
|
||||
{
|
||||
LogScope *next;
|
||||
U64 pos;
|
||||
String8List strings[LogMsgKind_COUNT];
|
||||
};
|
||||
|
||||
typedef struct LogScopeResult LogScopeResult;
|
||||
struct LogScopeResult
|
||||
{
|
||||
String8 strings[LogMsgKind_COUNT];
|
||||
};
|
||||
|
||||
typedef struct Log Log;
|
||||
struct Log
|
||||
{
|
||||
Arena *arena;
|
||||
LogScope *top_scope;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Creation/Selection
|
||||
|
||||
internal Log *log_alloc(void);
|
||||
internal void log_release(Log *log);
|
||||
internal void log_select(Log *log);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Building
|
||||
|
||||
internal void log_msg(LogMsgKind kind, String8 string);
|
||||
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
|
||||
#define log_info(s) log_msg(LogMsgKind_Info, (s))
|
||||
#define log_infof(...) log_msgf(LogMsgKind_Info, __VA_ARGS__)
|
||||
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
|
||||
#define log_user_errorf(...) log_msgf(LogMsgKind_UserError, __VA_ARGS__)
|
||||
|
||||
#define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
|
||||
#define LogInfoNamedBlockF(...) DeferLoop((log_infof(__VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Scopes
|
||||
|
||||
internal void log_scope_begin(void);
|
||||
internal LogScopeResult log_scope_end(Arena *arena);
|
||||
|
||||
#endif // BASE_LOG_H
|
||||
+1
-20
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -1,421 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Lookups
|
||||
|
||||
internal Member *
|
||||
member_from_name(Type *type, String8 name)
|
||||
{
|
||||
Member *member = &member_nil;
|
||||
if(type->members != 0 && name.size != 0)
|
||||
{
|
||||
for(U64 idx = 0; idx < type->count; idx += 1)
|
||||
{
|
||||
if(str8_match(type->members[idx].name, name, 0))
|
||||
{
|
||||
member = &type->members[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return member;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info * Instance Operations
|
||||
|
||||
internal void
|
||||
typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
typedef struct RebaseTypeTask RebaseTypeTask;
|
||||
struct RebaseTypeTask
|
||||
{
|
||||
RebaseTypeTask *next;
|
||||
Type *type;
|
||||
U8 *ptr;
|
||||
};
|
||||
RebaseTypeTask start_task = {0, type, data.str};
|
||||
RebaseTypeTask *first_task = &start_task;
|
||||
RebaseTypeTask *last_task = first_task;
|
||||
for(RebaseTypeTask *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
switch(t->type->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case TypeKind_Ptr:
|
||||
{
|
||||
*(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr));
|
||||
}break;
|
||||
case TypeKind_Array:
|
||||
{
|
||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
||||
{
|
||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->ptr = t->ptr + t->type->direct->size * idx;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}break;
|
||||
case TypeKind_Struct:
|
||||
{
|
||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
||||
{
|
||||
Member *member = &t->type->members[idx];
|
||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
||||
task->type = member->type;
|
||||
task->ptr = t->ptr + member->value;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal String8
|
||||
serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List strings = {0};
|
||||
str8_serial_begin(scratch.arena, &strings);
|
||||
{
|
||||
typedef struct SerializeTypeTask SerializeTypeTask;
|
||||
struct SerializeTypeTask
|
||||
{
|
||||
SerializeTypeTask *next;
|
||||
Type *type;
|
||||
U64 count;
|
||||
U8 *src;
|
||||
Type *containing_type;
|
||||
U8 *containing_ptr;
|
||||
B32 is_post_header;
|
||||
};
|
||||
SerializeTypeTask start_task = {0, type, 1, data.str};
|
||||
SerializeTypeTask *first_task = &start_task;
|
||||
SerializeTypeTask *last_task = first_task;
|
||||
for(SerializeTypeTask *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
switch(t->type->kind)
|
||||
{
|
||||
//- rjf: leaf -> just copy the data directly
|
||||
default:
|
||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
||||
{
|
||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
||||
}break;
|
||||
|
||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise just write as plain data
|
||||
case TypeKind_Ptr:
|
||||
{
|
||||
// rjf: unpack info about this pointer
|
||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
||||
{
|
||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
||||
{
|
||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: indexification -> subtract base, divide direct size, write index
|
||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size);
|
||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
||||
}
|
||||
|
||||
// rjf: offsetification -> subtract base, write offsets
|
||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base);
|
||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
||||
// delimit our size, so push a new post-header task for pointer.
|
||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
||||
{
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type;
|
||||
task->count = t->count;
|
||||
task->src = t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
task->is_post_header = 1;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
||||
// destination contents
|
||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
||||
{
|
||||
// rjf: determine count of this pointer
|
||||
U64 count = 0;
|
||||
{
|
||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
||||
}
|
||||
|
||||
// rjf: push task
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = count;
|
||||
task->src = *(void **)t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: catch-all: write pointer value
|
||||
else
|
||||
{
|
||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: arrays -> descend to underlying type, + count
|
||||
case TypeKind_Array:
|
||||
{
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->type->count;
|
||||
task->src = t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
|
||||
//- rjf: struct -> descend to members
|
||||
case TypeKind_Struct:
|
||||
{
|
||||
U64 off = 0;
|
||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
||||
{
|
||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
||||
{
|
||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->members[member_idx].type;
|
||||
task->count = 1;
|
||||
task->src = t->src + idx*t->type->size + t->type->members[member_idx].value;
|
||||
task->containing_type = t->type;
|
||||
task->containing_ptr = t->src;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: enum -> descend to basic type interpretation
|
||||
case TypeKind_Enum:
|
||||
{
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->count;
|
||||
task->src = t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 result = str8_serial_end(arena, &strings);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
||||
{
|
||||
String8 result = {0};
|
||||
result.size = type->size;
|
||||
result.str = push_array(arena, U8, result.size);
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
typedef struct DeserializeTypeTask DeserializeTypeTask;
|
||||
struct DeserializeTypeTask
|
||||
{
|
||||
DeserializeTypeTask *next;
|
||||
Type *type;
|
||||
U64 count;
|
||||
U8 *dst;
|
||||
Type *containing_type;
|
||||
U8 *containing_ptr;
|
||||
B32 is_post_header;
|
||||
};
|
||||
U64 read_off = 0;
|
||||
DeserializeTypeTask start_task = {0, type, 1, result.str};
|
||||
DeserializeTypeTask *first_task = &start_task;
|
||||
DeserializeTypeTask *last_task = first_task;
|
||||
for(DeserializeTypeTask *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
U8 *t_src = data.str + read_off;
|
||||
switch(t->type->kind)
|
||||
{
|
||||
//- rjf: leaf -> copy the data directly
|
||||
default:
|
||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
||||
{
|
||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
||||
read_off += t->type->size*t->count;
|
||||
}break;
|
||||
|
||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
|
||||
case TypeKind_Ptr:
|
||||
{
|
||||
// rjf: unpack info about this pointer
|
||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
||||
{
|
||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
||||
{
|
||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: indexification -> add base, multiply direct size
|
||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size;
|
||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
||||
read_off += sizeof(ptr_value);
|
||||
}
|
||||
|
||||
// rjf: offsetification -> subtract base, write offsets
|
||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base;
|
||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
||||
read_off += sizeof(ptr_value);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
||||
// delimit our size, so push a new post-header task for pointer.
|
||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
||||
{
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type;
|
||||
task->count = t->count;
|
||||
task->dst = t->dst;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
task->is_post_header = 1;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
||||
// destination contents
|
||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
||||
{
|
||||
// rjf: determine count of this pointer
|
||||
U64 count = 0;
|
||||
{
|
||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
||||
}
|
||||
|
||||
// rjf: allocate buffer for pointer destination; write address into pointer value slot
|
||||
U64 ptr_dest_buffer_size = (count+1)*t->type->direct->size;
|
||||
U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size);
|
||||
MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer));
|
||||
|
||||
// rjf: push task
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = count;
|
||||
task->dst = ptr_dest_buffer;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: catch-all: read pointer value
|
||||
else
|
||||
{
|
||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
||||
read_off += t->type->size*t->count;
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: arrays -> descend to underlying type, + count
|
||||
case TypeKind_Array:
|
||||
{
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->type->count;
|
||||
task->dst = t->dst;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
|
||||
//- rjf: struct -> descend to members
|
||||
case TypeKind_Struct:
|
||||
{
|
||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
||||
{
|
||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
||||
{
|
||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->members[member_idx].type;
|
||||
task->count = 1;
|
||||
task->dst = t->dst + idx*t->type->size + t->type->members[member_idx].value;
|
||||
task->containing_type = t->type;
|
||||
task->containing_ptr = t->dst;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: enum -> descend to basic type interpretation
|
||||
case TypeKind_Enum:
|
||||
{
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->count;
|
||||
task->dst = t->dst;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
if(params->advance_out != 0)
|
||||
{
|
||||
params->advance_out[0] = read_off;
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 data_srlz = serialized_from_typed_data(scratch.arena, type, data, params);
|
||||
String8 data_copy = deserialized_from_typed_data(arena, type, data_srlz, params);
|
||||
scratch_end(scratch);
|
||||
return data_copy;
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_META_H
|
||||
#define BASE_META_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Meta Markup Features
|
||||
|
||||
#define EmbedFile(name, path)
|
||||
#define TweakB32(name, default) (TWEAK_##name)
|
||||
#define TweakF32(name, default, min, max) (TWEAK_##name)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tweak Info Tables
|
||||
|
||||
typedef struct TweakB32Info TweakB32Info;
|
||||
struct TweakB32Info
|
||||
{
|
||||
String8 name;
|
||||
B32 default_value;
|
||||
B32 *value_ptr;
|
||||
};
|
||||
|
||||
typedef struct TweakF32Info TweakF32Info;
|
||||
struct TweakF32Info
|
||||
{
|
||||
String8 name;
|
||||
F32 default_value;
|
||||
Rng1F32 value_range;
|
||||
F32 *value_ptr;
|
||||
};
|
||||
|
||||
typedef struct TweakB32InfoTable TweakB32InfoTable;
|
||||
struct TweakB32InfoTable
|
||||
{
|
||||
TweakB32Info *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct TweakF32InfoTable TweakF32InfoTable;
|
||||
struct TweakF32InfoTable
|
||||
{
|
||||
TweakF32Info *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct EmbedInfo EmbedInfo;
|
||||
struct EmbedInfo
|
||||
{
|
||||
String8 name;
|
||||
String8 *data;
|
||||
U128 *hash;
|
||||
};
|
||||
|
||||
typedef struct EmbedInfoTable EmbedInfoTable;
|
||||
struct EmbedInfoTable
|
||||
{
|
||||
EmbedInfo *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Types
|
||||
|
||||
typedef enum TypeKind
|
||||
{
|
||||
TypeKind_Null,
|
||||
|
||||
// rjf: leaves
|
||||
TypeKind_Void, TypeKind_FirstLeaf = TypeKind_Void,
|
||||
TypeKind_U8,
|
||||
TypeKind_U16,
|
||||
TypeKind_U32,
|
||||
TypeKind_U64,
|
||||
TypeKind_S8,
|
||||
TypeKind_S16,
|
||||
TypeKind_S32,
|
||||
TypeKind_S64,
|
||||
TypeKind_B8,
|
||||
TypeKind_B16,
|
||||
TypeKind_B32,
|
||||
TypeKind_B64,
|
||||
TypeKind_F32,
|
||||
TypeKind_F64, TypeKind_LastLeaf = TypeKind_F64,
|
||||
|
||||
// rjf: operators
|
||||
TypeKind_Ptr,
|
||||
TypeKind_Array,
|
||||
|
||||
// rjf: user-defined-types
|
||||
TypeKind_Struct,
|
||||
TypeKind_Union,
|
||||
TypeKind_Enum,
|
||||
|
||||
TypeKind_COUNT
|
||||
}
|
||||
TypeKind;
|
||||
|
||||
typedef U32 TypeFlags;
|
||||
enum
|
||||
{
|
||||
TypeFlag_IsPlainText = (1<<0),
|
||||
TypeFlag_IsCodeText = (1<<1),
|
||||
TypeFlag_IsPathText = (1<<2),
|
||||
};
|
||||
|
||||
typedef U32 MemberFlags;
|
||||
enum
|
||||
{
|
||||
MemberFlag_DoNotSerialize = (1<<0),
|
||||
};
|
||||
|
||||
typedef struct Type Type;
|
||||
typedef struct Member Member;
|
||||
struct Member
|
||||
{
|
||||
String8 name;
|
||||
String8 pretty_name;
|
||||
Type *type;
|
||||
U64 value;
|
||||
MemberFlags flags;
|
||||
};
|
||||
|
||||
typedef struct Type Type;
|
||||
struct Type
|
||||
{
|
||||
TypeKind kind;
|
||||
TypeFlags flags;
|
||||
U64 size;
|
||||
Type *direct;
|
||||
String8 name;
|
||||
String8 count_delimiter_name; // gathered from surrounding members, turns *->[1] into *->[N]
|
||||
U64 count;
|
||||
Member *members;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Serialization Parameters
|
||||
|
||||
typedef struct TypeSerializePtrRefInfo TypeSerializePtrRefInfo;
|
||||
struct TypeSerializePtrRefInfo
|
||||
{
|
||||
Type *type; // pointers to this
|
||||
void *indexify_base; // can be indexified using this
|
||||
void *offsetify_base; // can be offsetified using this
|
||||
void *nil_ptr; // is terminal if matching 0 or this
|
||||
};
|
||||
|
||||
typedef struct TypeSerializeParams TypeSerializeParams;
|
||||
struct TypeSerializeParams
|
||||
{
|
||||
U64 *advance_out;
|
||||
TypeSerializePtrRefInfo *ptr_ref_infos;
|
||||
U64 ptr_ref_infos_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Name -> Type Info
|
||||
|
||||
#define type(T) (&T##__type)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Table Initializer Helpers
|
||||
|
||||
#define member_lit_comp(S, ti, m, ...) {str8_lit_comp(#m), {0}, (ti), OffsetOf(S, m), __VA_ARGS__}
|
||||
#define struct_members(S) read_only global Member S##__members[] =
|
||||
#define struct_type(S, ...) read_only global Type S##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#S), {0}, ArrayCount(S##__members), S##__members, __VA_ARGS__}
|
||||
#define named_struct_type(name, S, ...) read_only global Type name##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#name), {0}, ArrayCount(name##__members), name##__members, __VA_ARGS__}
|
||||
#define ptr_type(name, ti, ...) read_only global Type name = {TypeKind_Ptr, 0, sizeof(void *), (ti), __VA_ARGS__}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global Type type_nil = {TypeKind_Null, 0, 0, &type_nil};
|
||||
read_only global Member member_nil = {{0}, {0}, &type_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Built-In Types
|
||||
|
||||
//- rjf: leaves
|
||||
read_only global Type void__type = {TypeKind_Void, 0, 0, &type_nil, str8_lit_comp("void")};
|
||||
read_only global Type U8__type = {TypeKind_U8, 0, sizeof(U8), &type_nil, str8_lit_comp("U8")};
|
||||
read_only global Type U16__type = {TypeKind_U16, 0, sizeof(U16), &type_nil, str8_lit_comp("U16")};
|
||||
read_only global Type U32__type = {TypeKind_U32, 0, sizeof(U32), &type_nil, str8_lit_comp("U32")};
|
||||
read_only global Type U64__type = {TypeKind_U64, 0, sizeof(U64), &type_nil, str8_lit_comp("U64")};
|
||||
read_only global Type S8__type = {TypeKind_S8, 0, sizeof(S8), &type_nil, str8_lit_comp("S8")};
|
||||
read_only global Type S16__type = {TypeKind_S16, 0, sizeof(S16), &type_nil, str8_lit_comp("S16")};
|
||||
read_only global Type S32__type = {TypeKind_S32, 0, sizeof(S32), &type_nil, str8_lit_comp("S32")};
|
||||
read_only global Type S64__type = {TypeKind_S64, 0, sizeof(S64), &type_nil, str8_lit_comp("S64")};
|
||||
read_only global Type B8__type = {TypeKind_B8, 0, sizeof(B8), &type_nil, str8_lit_comp("B8")};
|
||||
read_only global Type B16__type = {TypeKind_B16, 0, sizeof(B16), &type_nil, str8_lit_comp("B16")};
|
||||
read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, str8_lit_comp("B32")};
|
||||
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")};
|
||||
read_only global Type F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
|
||||
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
|
||||
read_only global Type *type_kind_type_table[] =
|
||||
{
|
||||
&type_nil,
|
||||
type(void),
|
||||
type(U8),
|
||||
type(U16),
|
||||
type(U32),
|
||||
type(U64),
|
||||
type(S8),
|
||||
type(S16),
|
||||
type(S32),
|
||||
type(S64),
|
||||
type(B8),
|
||||
type(B16),
|
||||
type(B32),
|
||||
type(B64),
|
||||
type(F32),
|
||||
type(F64),
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
};
|
||||
|
||||
//- rjf: Rng1U64
|
||||
struct_members(Rng1U64)
|
||||
{
|
||||
member_lit_comp(Rng1U64, type(U64), min),
|
||||
member_lit_comp(Rng1U64, type(U64), max),
|
||||
};
|
||||
struct_type(Rng1U64);
|
||||
|
||||
//- rjf: String8
|
||||
ptr_type(String8__str_ptr_type, type(U8), str8_lit_comp("size"));
|
||||
struct_members(String8)
|
||||
{
|
||||
member_lit_comp(String8, &String8__str_ptr_type, str),
|
||||
member_lit_comp(String8, type(U64), size),
|
||||
};
|
||||
struct_type(String8);
|
||||
|
||||
//- rjf: String8Node
|
||||
extern Type String8Node__type;
|
||||
Type String8Node__ptr_type = {TypeKind_Ptr, 0, sizeof(void *), &String8Node__type};
|
||||
Member String8Node__members[] =
|
||||
{
|
||||
{str8_lit_comp("next"), {0}, &String8Node__ptr_type, OffsetOf(String8Node, next)},
|
||||
{str8_lit_comp("string"), {0}, type(String8), OffsetOf(String8Node, string)},
|
||||
};
|
||||
Type String8Node__type =
|
||||
{
|
||||
TypeKind_Struct,
|
||||
0,
|
||||
sizeof(String8Node),
|
||||
&type_nil,
|
||||
str8_lit_comp("String8Node"),
|
||||
{0},
|
||||
ArrayCount(String8Node__members),
|
||||
String8Node__members,
|
||||
};
|
||||
|
||||
//- rjf: String8List
|
||||
Member String8List__members[] =
|
||||
{
|
||||
{str8_lit_comp("first"), {0}, &String8Node__ptr_type, OffsetOf(String8List, first)},
|
||||
{str8_lit_comp("last"), {0}, &String8Node__ptr_type, OffsetOf(String8List, last), MemberFlag_DoNotSerialize},
|
||||
{str8_lit_comp("node_count"), {0}, type(U64), OffsetOf(String8List, node_count)},
|
||||
{str8_lit_comp("total_size"), {0}, type(U64), OffsetOf(String8List, total_size)},
|
||||
};
|
||||
Type String8List__type =
|
||||
{
|
||||
TypeKind_Struct,
|
||||
0,
|
||||
sizeof(String8List),
|
||||
&type_nil,
|
||||
str8_lit_comp("String8List"),
|
||||
{0},
|
||||
ArrayCount(String8List__members),
|
||||
String8List__members,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Lookups
|
||||
|
||||
internal Member *member_from_name(Type *type, String8 name);
|
||||
#define EachMember(T, it) (Member *it = (type(T))->members; it != 0 && it < (type(T))->members + (type(T))->count; it += 1)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info * Instance Operations
|
||||
|
||||
internal void typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr);
|
||||
internal String8 serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
||||
internal String8 deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
||||
internal String8 deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
||||
#define struct_rebase_ptrs(T, ptr, base) typed_data_rebase_ptrs(type(T), str8_struct(ptr), (base))
|
||||
#define serialized_from_struct(arena, T, ptr, ...) serialized_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__})
|
||||
#define struct_from_serialized(arena, T, string, ...) (T *)deserialized_from_typed_data((arena), type(T), (string), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
||||
#define deep_copy_from_struct(arena, T, ptr, ...) (T *)deep_copy_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
||||
|
||||
#endif // BASE_META_H
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if PROFILE_SPALL
|
||||
internal inline void
|
||||
spall_begin(char *fmt, ...)
|
||||
{
|
||||
if(spall_buffer.data == 0)
|
||||
{
|
||||
spall_buffer.length = MB(1);
|
||||
spall_buffer.data = os_reserve(spall_buffer.length);
|
||||
os_commit(spall_buffer.data, spall_buffer.length);
|
||||
spall_buffer_init(&spall_profile, &spall_buffer);
|
||||
}
|
||||
if(spall_pid == 0)
|
||||
{
|
||||
spall_pid = os_get_process_info()->pid;
|
||||
}
|
||||
if(spall_tid == 0)
|
||||
{
|
||||
spall_tid = os_tid();
|
||||
}
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, os_now_microseconds(), spall_tid, spall_pid);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
#endif
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_PROFILE_H
|
||||
#define BASE_PROFILE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zero Settings
|
||||
|
||||
#if !defined(PROFILE_TELEMETRY)
|
||||
# define PROFILE_TELEMETRY 0
|
||||
#endif
|
||||
#if !defined(PROFILE_SPALL)
|
||||
# define PROFILE_SPALL 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# include "rad_tm.h"
|
||||
# if OS_WINDOWS
|
||||
# pragma comment(lib, "ws2_32.lib")
|
||||
# pragma comment(lib, "rad_tm_win64.lib")
|
||||
# endif
|
||||
#elif PROFILE_SPALL
|
||||
# include "spall.h"
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Telemetry Profile Defines
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
||||
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
||||
# define ProfTick(...) tmTick(0)
|
||||
# define ProfIsCapturing(...) tmRunning()
|
||||
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
||||
# define ProfEndCapture(...) tmClose(0)
|
||||
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
||||
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
||||
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||
# define ProfColor(color) tmZoneColor((((color) & 0xff000000) >> 24) / 255.f, (((color) & 0x00ff0000) >> 16) / 255.f, (((color) & 0x0000ff00) >> 8) / 255.f)
|
||||
# define ProfBeginV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
# define ProfNoteV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Spall Profile Defines
|
||||
|
||||
#if PROFILE_SPALL
|
||||
global U64 spall_capturing = 0;
|
||||
global SpallProfile spall_profile = {0};
|
||||
thread_static SpallBuffer spall_buffer = {0};
|
||||
thread_static U32 spall_tid = 0;
|
||||
thread_static U32 spall_pid = 0;
|
||||
internal inline void spall_begin(char *fmt, ...);
|
||||
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
||||
# define ProfBeginDynamic(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
||||
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, os_now_microseconds(), spall_tid, spall_pid)), 0 : 0)
|
||||
# define ProfTick(...)
|
||||
# define ProfIsCapturing(...) (!!spall_capturing)
|
||||
# define ProfBeginCapture(...) (spall_capturing = 1)
|
||||
# define ProfEndCapture(...) (spall_capturing = 0, spall_flush(&spall_profile))
|
||||
# define ProfThreadName(...)
|
||||
# define ProfMsg(...)
|
||||
# define ProfBeginLockWait(...)
|
||||
# define ProfEndLockWait(...)
|
||||
# define ProfLockTake(...)
|
||||
# define ProfLockDrop(...)
|
||||
# define ProfColor(color)
|
||||
# define ProfBeginV(...)
|
||||
# define ProfNoteV(...)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zeroify Undefined Defines
|
||||
|
||||
#if !defined(ProfBegin)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
# define ProfBeginV(...) (0)
|
||||
# define ProfNoteV(...) (0)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helper Wrappers
|
||||
|
||||
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
||||
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
||||
|
||||
#endif // BASE_PROFILE_H
|
||||
@@ -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, ¶ms);
|
||||
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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Functions
|
||||
|
||||
internal Thread
|
||||
thread_launch(ThreadEntryPointFunctionType *f, void *p)
|
||||
{
|
||||
Thread thread = os_thread_launch(f, p);
|
||||
return thread;
|
||||
}
|
||||
|
||||
internal B32
|
||||
thread_join(Thread thread, U64 endt_us)
|
||||
{
|
||||
B32 result = os_thread_join(thread, endt_us);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
thread_detach(Thread thread)
|
||||
{
|
||||
os_thread_detach(thread);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Synchronization Primitive Functions
|
||||
|
||||
//- rjf: recursive mutexes
|
||||
|
||||
internal Mutex mutex_alloc(void) {return os_mutex_alloc();}
|
||||
internal void mutex_release(Mutex mutex) {os_mutex_release(mutex);}
|
||||
internal void mutex_take(Mutex mutex) {os_mutex_take(mutex);}
|
||||
internal void mutex_drop(Mutex mutex) {os_mutex_drop(mutex);}
|
||||
|
||||
//- rjf: reader/writer mutexes
|
||||
|
||||
internal RWMutex rw_mutex_alloc(void) {return os_rw_mutex_alloc();}
|
||||
internal void rw_mutex_release(RWMutex mutex) {os_rw_mutex_release(mutex);}
|
||||
internal void rw_mutex_take(RWMutex mutex, B32 write_mode) {os_rw_mutex_take(mutex, write_mode);}
|
||||
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode) {os_rw_mutex_drop(mutex, write_mode);}
|
||||
|
||||
//- rjf: condition variables
|
||||
|
||||
internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();}
|
||||
internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);}
|
||||
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);}
|
||||
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) {return os_cond_var_wait_rw(cv, mutex_rw, write_mode, endt_us);}
|
||||
internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);}
|
||||
internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);}
|
||||
|
||||
//- rjf: cross-process semaphores
|
||||
|
||||
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name) {return os_semaphore_alloc(initial_count, max_count, name);}
|
||||
internal void semaphore_release(Semaphore semaphore) {os_semaphore_release(semaphore);}
|
||||
internal Semaphore semaphore_open(String8 name) {return os_semaphore_open(name);}
|
||||
internal void semaphore_close(Semaphore semaphore) {os_semaphore_close(semaphore);}
|
||||
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us) {return os_semaphore_take(semaphore, endt_us);}
|
||||
internal void semaphore_drop(Semaphore semaphore) {os_semaphore_drop(semaphore);}
|
||||
|
||||
//- rjf: barriers
|
||||
|
||||
internal Barrier barrier_alloc(U64 count) {return os_barrier_alloc(count);}
|
||||
internal void barrier_release(Barrier barrier) {os_barrier_release(barrier);}
|
||||
internal void barrier_wait(Barrier barrier) {os_barrier_wait(barrier);}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Stripe Functions
|
||||
|
||||
internal StripeArray
|
||||
stripe_array_alloc(Arena *arena)
|
||||
{
|
||||
StripeArray array = {0};
|
||||
array.count = os_get_system_info()->logical_processor_count;
|
||||
array.v = push_array(arena, Stripe, array.count);
|
||||
for EachIndex(idx, array.count)
|
||||
{
|
||||
array.v[idx].arena = arena_alloc();
|
||||
array.v[idx].rw_mutex = rw_mutex_alloc();
|
||||
array.v[idx].cv = cond_var_alloc();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal void
|
||||
stripe_array_release(StripeArray *stripes)
|
||||
{
|
||||
for EachIndex(idx, stripes->count)
|
||||
{
|
||||
arena_release(stripes->v[idx].arena);
|
||||
rw_mutex_release(stripes->v[idx].rw_mutex);
|
||||
cond_var_release(stripes->v[idx].cv);
|
||||
}
|
||||
}
|
||||
|
||||
internal Stripe *
|
||||
stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx)
|
||||
{
|
||||
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
|
||||
return stripe;
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_THREADS_H
|
||||
#define BASE_THREADS_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Types
|
||||
|
||||
typedef struct Thread Thread;
|
||||
struct Thread
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
typedef void ThreadEntryPointFunctionType(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Synchronization Primitive Types
|
||||
|
||||
typedef struct Mutex Mutex;
|
||||
struct Mutex
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct RWMutex RWMutex;
|
||||
struct RWMutex
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct CondVar CondVar;
|
||||
struct CondVar
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct Semaphore Semaphore;
|
||||
struct Semaphore
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct Barrier Barrier;
|
||||
struct Barrier
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Stripes
|
||||
|
||||
typedef struct Stripe Stripe;
|
||||
struct Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
RWMutex rw_mutex;
|
||||
CondVar cv;
|
||||
void *free;
|
||||
};
|
||||
|
||||
typedef struct StripeArray StripeArray;
|
||||
struct StripeArray
|
||||
{
|
||||
Stripe *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Functions
|
||||
|
||||
internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
|
||||
internal B32 thread_join(Thread thread, U64 endt_us);
|
||||
internal void thread_detach(Thread thread);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Synchronization Primitive Functions
|
||||
|
||||
//- rjf: recursive mutexes
|
||||
internal Mutex mutex_alloc(void);
|
||||
internal void mutex_release(Mutex mutex);
|
||||
internal void mutex_take(Mutex mutex);
|
||||
internal void mutex_drop(Mutex mutex);
|
||||
|
||||
//- rjf: reader/writer mutexes
|
||||
internal RWMutex rw_mutex_alloc(void);
|
||||
internal void rw_mutex_release(RWMutex mutex);
|
||||
internal void rw_mutex_take(RWMutex mutex, B32 write_mode);
|
||||
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode);
|
||||
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
|
||||
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
|
||||
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
|
||||
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
|
||||
|
||||
//- rjf: condition variables
|
||||
internal CondVar cond_var_alloc(void);
|
||||
internal void cond_var_release(CondVar cv);
|
||||
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
|
||||
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us);
|
||||
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us);
|
||||
#define cond_var_wait_rw_r(cv, m, endt) cond_var_wait_rw((cv), (m), (0), (endt))
|
||||
#define cond_var_wait_rw_w(cv, m, endt) cond_var_wait_rw((cv), (m), (1), (endt))
|
||||
internal void cond_var_signal(CondVar cv);
|
||||
internal void cond_var_broadcast(CondVar cv);
|
||||
|
||||
//- rjf: cross-process semaphores
|
||||
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
|
||||
internal void semaphore_release(Semaphore semaphore);
|
||||
internal Semaphore semaphore_open(String8 name);
|
||||
internal void semaphore_close(Semaphore semaphore);
|
||||
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
|
||||
internal void semaphore_drop(Semaphore semaphore);
|
||||
|
||||
//- rjf: barriers
|
||||
internal Barrier barrier_alloc(U64 count);
|
||||
internal void barrier_release(Barrier barrier);
|
||||
internal void barrier_wait(Barrier barrier);
|
||||
|
||||
//- rjf: scope macros
|
||||
#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex))
|
||||
#define RWMutexScope(mutex, write_mode) DeferLoop(rw_mutex_take((mutex), (write_mode)), rw_mutex_drop((mutex), (write_mode)))
|
||||
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
|
||||
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
|
||||
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Stripe Functions
|
||||
|
||||
internal StripeArray stripe_array_alloc(Arena *arena);
|
||||
internal void stripe_array_release(StripeArray *stripes);
|
||||
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
|
||||
|
||||
#endif // BASE_THREADS_H
|
||||
@@ -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
@@ -1,630 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: CV Numerics
|
||||
|
||||
@table(name val)
|
||||
CV_NumericKindTable:
|
||||
{
|
||||
{CHAR 0x8000}
|
||||
{SHORT 0x8001}
|
||||
{USHORT 0x8002}
|
||||
{LONG 0x8003}
|
||||
{ULONG 0x8004}
|
||||
{FLOAT32 0x8005}
|
||||
{FLOAT64 0x8006}
|
||||
{FLOAT80 0x8007}
|
||||
{FLOAT128 0x8008}
|
||||
{QUADWORD 0x8009}
|
||||
{UQUADWORD 0x800a}
|
||||
{FLOAT48 0x800b}
|
||||
{COMPLEX32 0x800c}
|
||||
{COMPLEX64 0x800d}
|
||||
{COMPLEX80 0x800e}
|
||||
{COMPLEX128 0x800f}
|
||||
{VARSTRING 0x8010}
|
||||
{OCTWORD 0x8017}
|
||||
{UOCTWORD 0x8018}
|
||||
{DECIMAL 0x8019}
|
||||
{DATE 0x801a}
|
||||
{UTF8STRING 0x801b}
|
||||
{FLOAT16 0x801c}
|
||||
}
|
||||
|
||||
@enum(U16) CV_NumericKind:
|
||||
{
|
||||
@expand(CV_NumericKindTable a) `$(a.name) = $(a.val)`
|
||||
}
|
||||
|
||||
@enum2string_switch(CV_NumericKind)
|
||||
cv_string_from_numeric_kind:
|
||||
{
|
||||
@expand(CV_NumericKindTable a) `case CV_NumericKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: CV Architectures
|
||||
|
||||
@table(name val)
|
||||
CV_ArchTable:
|
||||
{
|
||||
{8080 0x00}
|
||||
{8086 0x01}
|
||||
{80286 0x02}
|
||||
{80386 0x03}
|
||||
{80486 0x04}
|
||||
{PENTIUM 0x05}
|
||||
{PENTIUMII 0x06}
|
||||
{PENTIUMIII 0x07}
|
||||
{MIPS 0x10}
|
||||
{MIPS16 0x11}
|
||||
{MIPS32 0x12}
|
||||
{MIPS64 0x13}
|
||||
{MIPSI 0x14}
|
||||
{MIPSII 0x15}
|
||||
{MIPSIII 0x16}
|
||||
{MIPSIV 0x17}
|
||||
{MIPSV 0x18}
|
||||
{M68000 0x20}
|
||||
{M68010 0x21}
|
||||
{M68020 0x22}
|
||||
{M68030 0x23}
|
||||
{M68040 0x24}
|
||||
{ALPHA 0x30}
|
||||
{ALPHA_21164 0x31}
|
||||
{ALPHA_21164A 0x32}
|
||||
{ALPHA_21264 0x33}
|
||||
{ALPHA_21364 0x34}
|
||||
{PPC601 0x40}
|
||||
{PPC603 0x41}
|
||||
{PPC604 0x42}
|
||||
{PPC620 0x43}
|
||||
{PPCFP 0x44}
|
||||
{PPCBE 0x45}
|
||||
{SH3 0x50}
|
||||
{SH3E 0x51}
|
||||
{SH3DSP 0x52}
|
||||
{SH4 0x53}
|
||||
{SHMEDIA 0x54}
|
||||
{ARM3 0x60}
|
||||
{ARM4 0x61}
|
||||
{ARM4T 0x62}
|
||||
{ARM5 0x63}
|
||||
{ARM5T 0x64}
|
||||
{ARM6 0x65}
|
||||
{ARM_XMAC 0x66}
|
||||
{ARM_WMMX 0x67}
|
||||
{ARM7 0x68}
|
||||
{OMNI 0x70}
|
||||
{IA64_1 0x80}
|
||||
{IA64_2 0x81}
|
||||
{CEE 0x90}
|
||||
{AM33 0xA0}
|
||||
{M32R 0xB0}
|
||||
{TRICORE 0xC0}
|
||||
{X64 0xD0}
|
||||
{EBC 0xE0}
|
||||
{THUMB 0xF0}
|
||||
{ARMNT 0xF4}
|
||||
{ARM64 0xF6}
|
||||
{D3D11_SHADER 0x100}
|
||||
}
|
||||
|
||||
@enum(U16) CV_Arch:
|
||||
{
|
||||
@expand(CV_ArchTable a) `$(a.name) = $(a.val)`,
|
||||
`IA64 = CV_Arch_IA64_1`,
|
||||
`PENTIUMPRO = CV_Arch_PENTIUMII`,
|
||||
`MIPSR4000 = CV_Arch_MIPS`,
|
||||
`ALPHA_21064 = CV_Arch_ALPHA`,
|
||||
`AMD64 = CV_Arch_X64`,
|
||||
}
|
||||
|
||||
@enum2string_switch(CV_Arch)
|
||||
cv_string_from_arch:
|
||||
{
|
||||
@expand(CV_ArchTable a) `case CV_Arch_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: CV Registers
|
||||
|
||||
@table(name val) CV_AllRegTable:
|
||||
{
|
||||
{ERR 30000}
|
||||
{TEB 30001}
|
||||
{TIMER 30002}
|
||||
{EFAD1 30003}
|
||||
{EFAD2 30004}
|
||||
{EFAD3 30005}
|
||||
{VFRAME 30006}
|
||||
{HANDLE 30007}
|
||||
{PARAMS 30008}
|
||||
{LOCALS 30009}
|
||||
{TID 30010}
|
||||
{ENV 30011}
|
||||
{CMDLN 30012}
|
||||
}
|
||||
|
||||
@enum(U16) CV_AllReg:
|
||||
{
|
||||
@expand(CV_AllRegTable a) `$(a.name) = $(a.val)`
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: CV Sym Kinds
|
||||
|
||||
@table(name header_type_name val) CV_SymKindTable:
|
||||
{
|
||||
{COMPILE Compile 0x0001}
|
||||
{REGISTER_16t - 0x0002}
|
||||
{CONSTANT_16t - 0x0003}
|
||||
{UDT_16t - 0x0004}
|
||||
{SSEARCH StartSearch 0x0005}
|
||||
{END - 0x0006}
|
||||
{SKIP - 0x0007}
|
||||
{CVRESERVE - 0x0008}
|
||||
{OBJNAME_ST - 0x0009}
|
||||
{ENDARG - 0x000a}
|
||||
{COBOLUDT_16t - 0x000b}
|
||||
{MANYREG_16t - 0x000c}
|
||||
{RETURN Return 0x000d}
|
||||
{ENTRYTHIS - 0x000e}
|
||||
{BPREL16 - 0x0100}
|
||||
{LDATA16 - 0x0101}
|
||||
{GDATA16 - 0x0102}
|
||||
{PUB16 - 0x0103}
|
||||
{LPROC16 - 0x0104}
|
||||
{GPROC16 - 0x0105}
|
||||
{THUNK16 - 0x0106}
|
||||
{BLOCK16 - 0x0107}
|
||||
{WITH16 - 0x0108}
|
||||
{LABEL16 - 0x0109}
|
||||
{CEXMODEL16 - 0x010a}
|
||||
{VFTABLE16 - 0x010b}
|
||||
{REGREL16 - 0x010c}
|
||||
{BPREL32_16t - 0x0200}
|
||||
{LDATA32_16t - 0x0201}
|
||||
{GDATA32_16t - 0x0202}
|
||||
{PUB32_16t - 0x0203}
|
||||
{LPROC32_16t - 0x0204}
|
||||
{GPROC32_16t - 0x0205}
|
||||
{THUNK32_ST - 0x0206}
|
||||
{BLOCK32_ST - 0x0207}
|
||||
{WITH32_ST - 0x0208}
|
||||
{LABEL32_ST - 0x0209}
|
||||
{CEXMODEL32 - 0x020a}
|
||||
{VFTABLE32_16t - 0x020b}
|
||||
{REGREL32_16t - 0x020c}
|
||||
{LTHREAD32_16t - 0x020d}
|
||||
{GTHREAD32_16t - 0x020e}
|
||||
{SLINK32 SLink32 0x020f}
|
||||
{LPROCMIPS_16t - 0x0300}
|
||||
{GPROCMIPS_16t - 0x0301}
|
||||
{PROCREF_ST - 0x0400}
|
||||
{DATAREF_ST - 0x0401}
|
||||
{ALIGN - 0x0402}
|
||||
{LPROCREF_ST - 0x0403}
|
||||
{OEM OEM 0x0404}
|
||||
{TI16_MAX - 0x1000}
|
||||
{CONSTANT_ST - 0x1002}
|
||||
{UDT_ST - 0x1003}
|
||||
{COBOLUDT_ST - 0x1004}
|
||||
{MANYREG_ST - 0x1005}
|
||||
{BPREL32_ST - 0x1006}
|
||||
{LDATA32_ST - 0x1007}
|
||||
{GDATA32_ST - 0x1008}
|
||||
{PUB32_ST - 0x1009}
|
||||
{LPROC32_ST - 0x100a}
|
||||
{GPROC32_ST - 0x100b}
|
||||
{VFTABLE32 VPath32 0x100c}
|
||||
{REGREL32_ST - 0x100d}
|
||||
{LTHREAD32_ST - 0x100e}
|
||||
{GTHREAD32_ST - 0x100f}
|
||||
{LPROCMIPS_ST - 0x1010}
|
||||
{GPROCMIPS_ST - 0x1011}
|
||||
{FRAMEPROC Frameproc 0x1012}
|
||||
{COMPILE2_ST - 0x1013}
|
||||
{MANYREG2_ST - 0x1014}
|
||||
{LPROCIA64_ST - 0x1015}
|
||||
{GPROCIA64_ST - 0x1016}
|
||||
{LOCALSLOT_ST - 0x1017}
|
||||
{PARAMSLOT_ST - 0x1018}
|
||||
{ANNOTATION Annotation 0x1019}
|
||||
{GMANPROC_ST - 0x101a}
|
||||
{LMANPROC_ST - 0x101b}
|
||||
{RESERVED1 - 0x101c}
|
||||
{RESERVED2 - 0x101d}
|
||||
{RESERVED3 - 0x101e}
|
||||
{RESERVED4 - 0x101f}
|
||||
{LMANDATA_ST - 0x1020}
|
||||
{GMANDATA_ST - 0x1021}
|
||||
{MANFRAMEREL_ST - 0x1022}
|
||||
{MANREGISTER_ST - 0x1023}
|
||||
{MANSLOT_ST - 0x1024}
|
||||
{MANMANYREG_ST - 0x1025}
|
||||
{MANREGREL_ST - 0x1026}
|
||||
{MANMANYREG2_ST - 0x1027}
|
||||
{MANTYPREF - 0x1028}
|
||||
{UNAMESPACE_ST - 0x1029}
|
||||
{ST_MAX - 0x1100}
|
||||
{OBJNAME ObjName 0x1101}
|
||||
{THUNK32 Thunk32 0x1102}
|
||||
{BLOCK32 Block32 0x1103}
|
||||
{WITH32 - 0x1104}
|
||||
{LABEL32 Label32 0x1105}
|
||||
{REGISTER Register 0x1106}
|
||||
{CONSTANT Constant 0x1107}
|
||||
{UDT UDT 0x1108}
|
||||
{COBOLUDT - 0x1109}
|
||||
{MANYREG Manyreg 0x110a}
|
||||
{BPREL32 BPRel32 0x110b}
|
||||
{LDATA32 Data32 0x110c}
|
||||
{GDATA32 Data32 0x110d}
|
||||
{PUB32 Pub32 0x110e}
|
||||
{LPROC32 Proc32 0x110f}
|
||||
{GPROC32 Proc32 0x1110}
|
||||
{REGREL32 Regrel32 0x1111}
|
||||
{LTHREAD32 Thread32 0x1112}
|
||||
{GTHREAD32 Thread32 0x1113}
|
||||
{LPROCMIPS - 0x1114}
|
||||
{GPROCMIPS - 0x1115}
|
||||
{COMPILE2 Compile2 0x1116}
|
||||
{MANYREG2 Manyreg2 0x1117}
|
||||
{LPROCIA64 - 0x1118}
|
||||
{GPROCIA64 - 0x1119}
|
||||
{LOCALSLOT Slot 0x111a}
|
||||
{PARAMSLOT - 0x111b}
|
||||
{LMANDATA - 0x111c}
|
||||
{GMANDATA - 0x111d}
|
||||
{MANFRAMEREL AttrFrameRel 0x111e}
|
||||
{MANREGISTER AttrReg 0x111f}
|
||||
{MANSLOT - 0x1120}
|
||||
{MANMANYREG AttrManyReg 0x1121}
|
||||
{MANREGREL AttrRegRel 0x1122}
|
||||
{MANMANYREG2 - 0x1123}
|
||||
{UNAMESPACE UNamespace 0x1124}
|
||||
{PROCREF Ref2 0x1125}
|
||||
{DATAREF Ref2 0x1126}
|
||||
{LPROCREF Ref2 0x1127}
|
||||
{ANNOTATIONREF - 0x1128}
|
||||
{TOKENREF - 0x1129}
|
||||
{GMANPROC - 0x112a}
|
||||
{LMANPROC - 0x112b}
|
||||
{TRAMPOLINE Trampoline 0x112c}
|
||||
{MANCONSTANT - 0x112d}
|
||||
{ATTR_FRAMEREL AttrFrameRel 0x112e}
|
||||
{ATTR_REGISTER AttrReg 0x112f}
|
||||
{ATTR_REGREL AttrRegRel 0x1130}
|
||||
{ATTR_MANYREG AttrManyReg 0x1131}
|
||||
{SEPCODE Sepcode 0x1132}
|
||||
{DEFRANGE_2005 - 0x1134}
|
||||
{DEFRANGE2_2005 - 0x1135}
|
||||
{SECTION Section 0x1136}
|
||||
{COFFGROUP CoffGroup 0x1137}
|
||||
{EXPORT Export 0x1138}
|
||||
{CALLSITEINFO CallSiteInfo 0x1139}
|
||||
{FRAMECOOKIE FrameCookie 0x113a}
|
||||
{DISCARDED Discarded 0x113b}
|
||||
{COMPILE3 Compile3 0x113c}
|
||||
{ENVBLOCK EnvBlock 0x113d}
|
||||
{LOCAL Local 0x113e}
|
||||
{DEFRANGE - 0x113f}
|
||||
{DEFRANGE_SUBFIELD DefrangeSubfield 0x1140}
|
||||
{DEFRANGE_REGISTER DefrangeRegister 0x1141}
|
||||
{DEFRANGE_FRAMEPOINTER_REL DefrangeFramepointerRel 0x1142}
|
||||
{DEFRANGE_SUBFIELD_REGISTER DefrangeSubfieldRegister 0x1143}
|
||||
{DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE DefrangeFramepointerRelFullScope 0x1144}
|
||||
{DEFRANGE_REGISTER_REL DefrangeRegisterRel 0x1145}
|
||||
{LPROC32_ID - 0x1146}
|
||||
{GPROC32_ID - 0x1147}
|
||||
{LPROCMIPS_ID - 0x1148}
|
||||
{GPROCMIPS_ID - 0x1149}
|
||||
{LPROCIA64_ID - 0x114a}
|
||||
{GPROCIA64_ID - 0x114b}
|
||||
{BUILDINFO BuildInfo 0x114c}
|
||||
{INLINESITE InlineSite 0x114d}
|
||||
{INLINESITE_END - 0x114e}
|
||||
{PROC_ID_END - 0x114f}
|
||||
{DEFRANGE_HLSL - 0x1150}
|
||||
{GDATA_HLSL - 0x1151}
|
||||
{LDATA_HLSL - 0x1152}
|
||||
{FILESTATIC FileStatic 0x1153}
|
||||
{LPROC32_DPC - 0x1155}
|
||||
{LPROC32_DPC_ID - 0x1156}
|
||||
{DEFRANGE_DPC_PTR_TAG - 0x1157}
|
||||
{DPC_SYM_TAG_MAP - 0x1158}
|
||||
{ARMSWITCHTABLE - 0x1159}
|
||||
{CALLEES FunctionList 0x115a}
|
||||
{CALLERS FunctionList 0x115b}
|
||||
{POGODATA PogoInfo 0x115c}
|
||||
{INLINESITE2 InlineSite2 0x115d}
|
||||
{HEAPALLOCSITE HeapAllocSite 0x115e}
|
||||
{MOD_TYPEREF ModTypeRef 0x115f}
|
||||
{REF_MINIPDB RefMiniPdb 0x1160}
|
||||
{PDBMAP - 0x1161}
|
||||
{GDATA_HLSL32 - 0x1162}
|
||||
{LDATA_HLSL32 - 0x1163}
|
||||
{GDATA_HLSL32_EX - 0x1164}
|
||||
{LDATA_HLSL32_EX - 0x1165}
|
||||
{FASTLINK FastLink 0x1167}
|
||||
{INLINEES Inlinees 0x1168}
|
||||
}
|
||||
|
||||
@enum(U16) CV_SymKind:
|
||||
{
|
||||
@expand(CV_SymKindTable a) `$(a.name) = $(a.val)`
|
||||
}
|
||||
|
||||
@enum2string_switch(CV_SymKind)
|
||||
cv_string_from_sym_kind:
|
||||
{
|
||||
@expand(CV_SymKindTable a) `case CV_SymKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
||||
}
|
||||
|
||||
@gen(functions)
|
||||
{
|
||||
`internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);`;
|
||||
}
|
||||
|
||||
@gen(functions) @c_file
|
||||
{
|
||||
`internal U64`;
|
||||
`cv_header_struct_size_from_sym_kind(CV_SymKind v)`;
|
||||
`{`;
|
||||
`U64 result = 0;`;
|
||||
`switch(v)`;
|
||||
`{`;
|
||||
`default:{}break;`;
|
||||
@expand(CV_SymKindTable a) `$(a.header_type_name != "-" -> "case CV_SymKind_"..a.name..":{result = sizeof(CV_Sym"..a.header_type_name..");}break;")`;
|
||||
`}`;
|
||||
`return result;`;
|
||||
`}`;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: CV Basic Types
|
||||
|
||||
@table(name val type_name)
|
||||
CV_BasicTypeTable:
|
||||
{
|
||||
{NOTYPE 0x00 "" }
|
||||
{ABS 0x01 "" }
|
||||
{SEGMENT 0x02 "" }
|
||||
{VOID 0x03 "void" }
|
||||
{CURRENCY 0x04 "" }
|
||||
{NBASICSTR 0x05 "" }
|
||||
{FBASICSTR 0x06 "" }
|
||||
{NOTTRANS 0x07 "" }
|
||||
{HRESULT 0x08 "HRESULT" }
|
||||
{CHAR 0x10 "CHAR" }
|
||||
{SHORT 0x11 "SHORT" }
|
||||
{LONG 0x12 "LONG" }
|
||||
{QUAD 0x13 "QUAD" }
|
||||
{OCT 0x14 "OCT" }
|
||||
{UCHAR 0x20 "UCHAR" }
|
||||
{USHORT 0x21 "USHORT" }
|
||||
{ULONG 0x22 "ULONG" }
|
||||
{UQUAD 0x23 "UQUAD" }
|
||||
{UOCT 0x24 "UOCT" }
|
||||
{BOOL8 0x30 "BOOL8" }
|
||||
{BOOL16 0x31 "BOOL16" }
|
||||
{BOOL32 0x32 "BOOL32" }
|
||||
{BOOL64 0x33 "BOOL64" }
|
||||
{FLOAT32 0x40 "FLOAT32" }
|
||||
{FLOAT64 0x41 "FLOAT64" }
|
||||
{FLOAT80 0x42 "FLOAT80" }
|
||||
{FLOAT128 0x43 "FLOAT128" }
|
||||
{FLOAT48 0x44 "FLOAT48" }
|
||||
{FLOAT32PP 0x45 "FLOAT32PP" }
|
||||
{FLOAT16 0x46 "FLOAT16" }
|
||||
{COMPLEX32 0x50 "ComplexF32" }
|
||||
{COMPLEX64 0x51 "ComplexF64" }
|
||||
{COMPLEX80 0x52 "ComplexF80" }
|
||||
{COMPLEX128 0x53 "ComplexF128" }
|
||||
{BIT 0x60 "" }
|
||||
{PASCHAR 0x61 "" }
|
||||
{BOOL32FF 0x62 "BOOL32FF" }
|
||||
{INT8 0x68 "int8" }
|
||||
{UINT8 0x69 "uint8" }
|
||||
{RCHAR 0x70 "char" }
|
||||
{WCHAR 0x71 "WCHAR" }
|
||||
{INT16 0x72 "int16" }
|
||||
{UINT16 0x73 "uint16" }
|
||||
{INT32 0x74 "int32" }
|
||||
{UINT32 0x75 "uint32" }
|
||||
{INT64 0x76 "int64" }
|
||||
{UINT64 0x77 "uint64" }
|
||||
{INT128 0x78 "int128" }
|
||||
{UINT128 0x79 "uint128" }
|
||||
{CHAR16 0x7a "char16" }
|
||||
{CHAR32 0x7b "char32" }
|
||||
{CHAR8 0x7c "char" }
|
||||
{PTR 0xf0 "PTR" }
|
||||
}
|
||||
|
||||
@enum(U8) CV_BasicType:
|
||||
{
|
||||
@expand(CV_BasicTypeTable a) `$(a.name) = $(a.val)`
|
||||
}
|
||||
|
||||
@enum2string_switch(CV_BasicType) cv_string_from_basic_type:
|
||||
{
|
||||
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.name)");}break`
|
||||
}
|
||||
|
||||
@enum2string_switch(CV_BasicType) cv_type_name_from_basic_type:
|
||||
{
|
||||
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.type_name)");}break`
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: CV Leaf Kinds
|
||||
|
||||
@table(name header_type_name val)
|
||||
CV_LeafKindTable:
|
||||
{
|
||||
{NOTYPE - 0x0000}
|
||||
{MODIFIER_16t - 0x0001}
|
||||
{POINTER_16t - 0x0002}
|
||||
{ARRAY_16t - 0x0003}
|
||||
{CLASS_16t - 0x0004}
|
||||
{STRUCTURE_16t - 0x0005}
|
||||
{UNION_16t - 0x0006}
|
||||
{ENUM_16t - 0x0007}
|
||||
{PROCEDURE_16t - 0x0008}
|
||||
{MFUNCTION_16t - 0x0009}
|
||||
{VTSHAPE VTShape 0x000a}
|
||||
{COBOL0_16t - 0x000b}
|
||||
{COBOL1 - 0x000c}
|
||||
{BARRAY_16t - 0x000d}
|
||||
{LABEL Label 0x000e}
|
||||
{NULL - 0x000f}
|
||||
{NOTTRAN - 0x0010}
|
||||
{DIMARRAY_16t - 0x0011}
|
||||
{VFTPATH_16t - 0x0012}
|
||||
{PRECOMP_16t - 0x0013}
|
||||
{ENDPRECOMP - 0x0014}
|
||||
{OEM_16t - 0x0015}
|
||||
{TYPESERVER_ST - 0x0016}
|
||||
{SKIP_16t - 0x0200}
|
||||
{ARGLIST_16t - 0x0201}
|
||||
{DEFARG_16t - 0x0202}
|
||||
{LIST - 0x0203}
|
||||
{FIELDLIST_16t - 0x0204}
|
||||
{DERIVED_16t - 0x0205}
|
||||
{BITFIELD_16t - 0x0206}
|
||||
{METHODLIST_16t - 0x0207}
|
||||
{DIMCONU_16t - 0x0208}
|
||||
{DIMCONLU_16t - 0x0209}
|
||||
{DIMVARU_16t - 0x020a}
|
||||
{DIMVARLU_16t - 0x020b}
|
||||
{REFSYM - 0x020c}
|
||||
{BCLASS_16t - 0x0400}
|
||||
{VBCLASS_16t - 0x0401}
|
||||
{IVBCLASS_16t - 0x0402}
|
||||
{ENUMERATE_ST - 0x0403}
|
||||
{FRIENDFCN_16t - 0x0404}
|
||||
{INDEX_16t - 0x0405}
|
||||
{MEMBER_16t - 0x0406}
|
||||
{STMEMBER_16t - 0x0407}
|
||||
{METHOD_16t - 0x0408}
|
||||
{NESTTYPE_16t - 0x0409}
|
||||
{VFUNCTAB_16t - 0x040a}
|
||||
{FRIENDCLS_16t - 0x040b}
|
||||
{ONEMETHOD_16t - 0x040c}
|
||||
{VFUNCOFF_16t - 0x040d}
|
||||
{TI16_MAX - 0x1000}
|
||||
{MODIFIER Modifier 0x1001}
|
||||
{POINTER Pointer 0x1002}
|
||||
{ARRAY_ST - 0x1003}
|
||||
{CLASS_ST - 0x1004}
|
||||
{STRUCTURE_ST - 0x1005}
|
||||
{UNION_ST - 0x1006}
|
||||
{ENUM_ST - 0x1007}
|
||||
{PROCEDURE Procedure 0x1008}
|
||||
{MFUNCTION MFunction 0x1009}
|
||||
{COBOL0 - 0x100a}
|
||||
{BARRAY - 0x100b}
|
||||
{DIMARRAY_ST - 0x100c}
|
||||
{VFTPATH VFPath 0x100d}
|
||||
{PRECOMP_ST - 0x100e}
|
||||
{OEM - 0x100f}
|
||||
{ALIAS_ST - 0x1010}
|
||||
{OEM2 - 0x1011}
|
||||
{SKIP Skip 0x1200}
|
||||
{ARGLIST ArgList 0x1201}
|
||||
{DEFARG_ST - 0x1202}
|
||||
{FIELDLIST - 0x1203}
|
||||
{DERIVED - 0x1204}
|
||||
{BITFIELD BitField 0x1205}
|
||||
{METHODLIST MethodListMember 0x1206}
|
||||
{DIMCONU - 0x1207}
|
||||
{DIMCONLU - 0x1208}
|
||||
{DIMVARU - 0x1209}
|
||||
{DIMVARLU - 0x120a}
|
||||
{BCLASS BClass 0x1400}
|
||||
{VBCLASS VBClass 0x1401}
|
||||
{IVBCLASS - 0x1402}
|
||||
{FRIENDFCN_ST - 0x1403}
|
||||
{INDEX Index 0x1404}
|
||||
{MEMBER_ST - 0x1405}
|
||||
{STMEMBER_ST - 0x1406}
|
||||
{METHOD_ST - 0x1407}
|
||||
{NESTTYPE_ST - 0x1408}
|
||||
{VFUNCTAB VFuncTab 0x1409}
|
||||
{FRIENDCLS - 0x140a}
|
||||
{ONEMETHOD_ST - 0x140b}
|
||||
{VFUNCOFF VFuncOff 0x140c}
|
||||
{NESTTYPEEX_ST - 0x140d}
|
||||
{MEMBERMODIFY_ST - 0x140e}
|
||||
{MANAGED_ST - 0x140f}
|
||||
{ST_MAX - 0x1500}
|
||||
{TYPESERVER TypeServer 0x1501}
|
||||
{ENUMERATE Enumerate 0x1502}
|
||||
{ARRAY Array 0x1503}
|
||||
{CLASS Struct 0x1504}
|
||||
{STRUCTURE Struct 0x1505}
|
||||
{UNION Union 0x1506}
|
||||
{ENUM Enum 0x1507}
|
||||
{DIMARRAY - 0x1508}
|
||||
{PRECOMP PreComp 0x1509}
|
||||
{ALIAS Alias 0x150a}
|
||||
{DEFARG - 0x150b}
|
||||
{FRIENDFCN - 0x150c}
|
||||
{MEMBER Member 0x150d}
|
||||
{STMEMBER StMember 0x150e}
|
||||
{METHOD Method 0x150f}
|
||||
{NESTTYPE NestType 0x1510}
|
||||
{ONEMETHOD OneMethod 0x1511}
|
||||
{NESTTYPEEX NestTypeEx 0x1512}
|
||||
{MEMBERMODIFY - 0x1513}
|
||||
{MANAGED - 0x1514}
|
||||
{TYPESERVER2 TypeServer2 0x1515}
|
||||
{STRIDED_ARRAY - 0x1516}
|
||||
{HLSL - 0x1517}
|
||||
{MODIFIER_EX - 0x1518}
|
||||
{INTERFACE Struct 0x1519}
|
||||
{BINTERFACE - 0x151a}
|
||||
{VECTOR - 0x151b}
|
||||
{MATRIX - 0x151c}
|
||||
{VFTABLE - 0x151d}
|
||||
{FUNC_ID FuncId 0x1601}
|
||||
{MFUNC_ID MFuncId 0x1602}
|
||||
{BUILDINFO BuildInfo 0x1603}
|
||||
{SUBSTR_LIST SubstrList 0x1604}
|
||||
{STRING_ID StringId 0x1605}
|
||||
{UDT_SRC_LINE UDTSrcLine 0x1606}
|
||||
{UDT_MOD_SRC_LINE UDTModSrcLine 0x1607}
|
||||
{CLASS2 Struct2 0x1608}
|
||||
{STRUCT2 Struct2 0x1609}
|
||||
}
|
||||
|
||||
@enum(U16) CV_LeafKind:
|
||||
{
|
||||
@expand(CV_LeafKindTable a) `$(a.name) = $(a.val)`;
|
||||
}
|
||||
|
||||
@enum2string_switch(CV_LeafKind)
|
||||
cv_string_from_leaf_kind:
|
||||
{
|
||||
@expand(CV_LeafKindTable a) `case CV_LeafKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
||||
}
|
||||
|
||||
@gen(functions)
|
||||
{
|
||||
`internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);`;
|
||||
}
|
||||
|
||||
@gen(functions) @c_file
|
||||
{
|
||||
`internal U64`;
|
||||
`cv_header_struct_size_from_leaf_kind(CV_LeafKind v)`;
|
||||
`{`;
|
||||
`U64 result = 0;`;
|
||||
`switch(v)`;
|
||||
`{`;
|
||||
`default:{}break;`;
|
||||
@expand(CV_LeafKindTable a) `$(a.header_type_name != "-" -> "case CV_LeafKind_"..a.name..":{result = sizeof(CV_Leaf"..a.header_type_name..");}break;")`;
|
||||
`}`;
|
||||
`return result;`;
|
||||
`}`;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8
|
||||
cv_string_from_numeric(Arena *arena, CV_NumericParsed num)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (num.kind) {
|
||||
case CV_NumericKind_FLOAT16: NotImplemented; break; // TODO: format float16
|
||||
case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break;
|
||||
case CV_NumericKind_FLOAT48: NotImplemented; break; // TODO: format float48
|
||||
case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break;
|
||||
case CV_NumericKind_FLOAT80: NotImplemented; break; // TODO: format float80
|
||||
case CV_NumericKind_FLOAT128: NotImplemented; break; // TODO: format float128
|
||||
case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break;
|
||||
case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break;
|
||||
case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break;
|
||||
case CV_NumericKind_QUADWORD: result = push_str8f(arena, "%lld", *(S64*)num.val); break;
|
||||
case CV_NumericKind_USHORT: result = push_str8f(arena, "%u", *(U16*)num.val); break;
|
||||
case CV_NumericKind_ULONG: result = push_str8f(arena, "%u", *(U32*)num.val); break;
|
||||
case CV_NumericKind_UQUADWORD: result = push_str8f(arena, "%llu", *(U64*)num.val); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CODEVIEW_DUMP_H
|
||||
#define CODEVIEW_DUMP_H
|
||||
|
||||
internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num);
|
||||
|
||||
#endif // CODEVIEW_DUMP_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,305 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CODEVIEW_PARSE_H
|
||||
#define CODEVIEW_PARSE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Common Parser Types
|
||||
|
||||
// CV_Numeric layout
|
||||
// x: U16
|
||||
// buf: U8[]
|
||||
// case (x < 0x8000): kind=U16 val=x
|
||||
// case (x >= 0x8000): kind=x val=buf
|
||||
|
||||
typedef struct CV_NumericParsed CV_NumericParsed;
|
||||
struct CV_NumericParsed
|
||||
{
|
||||
CV_NumericKind kind;
|
||||
U8 *val;
|
||||
U64 encoded_size;
|
||||
};
|
||||
|
||||
typedef struct CV_RecRange CV_RecRange;
|
||||
struct CV_RecRange
|
||||
{
|
||||
U32 off;
|
||||
CV_RecHeader hdr;
|
||||
};
|
||||
|
||||
#define CV_REC_RANGE_CHUNK_SIZE 511
|
||||
|
||||
typedef struct CV_RecRangeChunk CV_RecRangeChunk;
|
||||
struct CV_RecRangeChunk
|
||||
{
|
||||
struct CV_RecRangeChunk *next;
|
||||
CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE];
|
||||
};
|
||||
|
||||
typedef struct CV_RecRangeStream CV_RecRangeStream;
|
||||
struct CV_RecRangeStream
|
||||
{
|
||||
CV_RecRangeChunk *first_chunk;
|
||||
CV_RecRangeChunk *last_chunk;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct CV_RecRangeArray CV_RecRangeArray;
|
||||
struct CV_RecRangeArray
|
||||
{
|
||||
CV_RecRange *ranges;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Sym Parser Types
|
||||
|
||||
typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo;
|
||||
struct CV_SymTopLevelInfo
|
||||
{
|
||||
CV_Arch arch;
|
||||
CV_Language language;
|
||||
String8 compiler_name;
|
||||
};
|
||||
|
||||
typedef struct CV_SymParsed CV_SymParsed;
|
||||
struct CV_SymParsed
|
||||
{
|
||||
// source information
|
||||
String8 data;
|
||||
U64 sym_align;
|
||||
|
||||
// sym index derived from source
|
||||
CV_RecRangeArray sym_ranges;
|
||||
|
||||
// top-level info derived from the syms
|
||||
CV_SymTopLevelInfo info;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Leaf Parser Types
|
||||
|
||||
typedef struct CV_LeafParsed CV_LeafParsed;
|
||||
struct CV_LeafParsed
|
||||
{
|
||||
// source information
|
||||
String8 data;
|
||||
CV_TypeId itype_first;
|
||||
CV_TypeId itype_opl;
|
||||
|
||||
// leaf index derived from source
|
||||
CV_RecRangeArray leaf_ranges;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView C13 Info Parser Types
|
||||
|
||||
typedef struct CV_C13InlineSiteDecoder CV_C13InlineSiteDecoder;
|
||||
struct CV_C13InlineSiteDecoder
|
||||
{
|
||||
U64 cursor;
|
||||
U64 parent_voff;
|
||||
CV_InlineRangeKind range_kind;
|
||||
U32 code_length;
|
||||
U32 code_offset;
|
||||
U32 file_off;
|
||||
S32 ln;
|
||||
S32 cn;
|
||||
U64 code_offset_lo;
|
||||
B32 code_offset_changed;
|
||||
B32 code_offset_lo_changed;
|
||||
B32 code_length_changed;
|
||||
B32 ln_changed;
|
||||
B32 file_off_changed;
|
||||
Rng1U64 last_range;
|
||||
U32 file_count;
|
||||
Rng1U64 file_last_range;
|
||||
U64 file_line_count;
|
||||
U64 file_last_ln;
|
||||
};
|
||||
|
||||
typedef U32 CV_C13InlineSiteDecoderStepFlags;
|
||||
enum
|
||||
{
|
||||
CV_C13InlineSiteDecoderStepFlag_EmitRange = (1 << 0),
|
||||
CV_C13InlineSiteDecoderStepFlag_ExtendLastRange = (1 << 1),
|
||||
CV_C13InlineSiteDecoderStepFlag_EmitFile = (1 << 2),
|
||||
CV_C13InlineSiteDecoderStepFlag_EmitLine = (1 << 3),
|
||||
};
|
||||
|
||||
typedef struct CV_C13InlineSiteDecoderStep CV_C13InlineSiteDecoderStep;
|
||||
struct CV_C13InlineSiteDecoderStep
|
||||
{
|
||||
CV_C13InlineSiteDecoderStepFlags flags;
|
||||
Rng1U64 range;
|
||||
U64 line_voff;
|
||||
U64 line_voff_end;
|
||||
U64 ln;
|
||||
U64 cn;
|
||||
U32 file_off;
|
||||
};
|
||||
|
||||
typedef struct CV_C13LinesParsed CV_C13LinesParsed;
|
||||
struct CV_C13LinesParsed
|
||||
{
|
||||
// raw info
|
||||
U32 sec_idx;
|
||||
U32 file_off;
|
||||
U64 secrel_base_off;
|
||||
|
||||
// parsed info
|
||||
String8 file_name;
|
||||
CV_C13ChecksumKind checksum_kind;
|
||||
String8 checksum;
|
||||
U64 *voffs; // [line_count + 1]
|
||||
U32 *line_nums; // [line_count]
|
||||
U16 *col_nums; // [2*line_count]
|
||||
U32 line_count;
|
||||
};
|
||||
|
||||
typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode;
|
||||
struct CV_C13LinesParsedNode
|
||||
{
|
||||
CV_C13LinesParsedNode *next;
|
||||
CV_C13LinesParsed v;
|
||||
};
|
||||
|
||||
typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed;
|
||||
struct CV_C13InlineeLinesParsed
|
||||
{
|
||||
CV_ItemId inlinee;
|
||||
U32 file_off;
|
||||
String8 file_name;
|
||||
CV_C13ChecksumKind checksum_kind;
|
||||
String8 checksum;
|
||||
U32 first_source_ln;
|
||||
U32 extra_file_count;
|
||||
U32 *extra_files;
|
||||
};
|
||||
|
||||
typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode;
|
||||
struct CV_C13InlineeLinesParsedNode
|
||||
{
|
||||
CV_C13InlineeLinesParsedNode *next;
|
||||
CV_C13InlineeLinesParsedNode *hash_next;
|
||||
CV_C13InlineeLinesParsed v;
|
||||
};
|
||||
|
||||
typedef struct CV_C13SubSectionNode CV_C13SubSectionNode;
|
||||
struct CV_C13SubSectionNode
|
||||
{
|
||||
struct CV_C13SubSectionNode *next;
|
||||
CV_C13SubSectionKind kind;
|
||||
U32 off;
|
||||
U32 size;
|
||||
CV_C13LinesParsedNode *lines_first;
|
||||
CV_C13LinesParsedNode *lines_last;
|
||||
CV_C13InlineeLinesParsedNode *inlinee_lines_first;
|
||||
CV_C13InlineeLinesParsedNode *inlinee_lines_last;
|
||||
};
|
||||
|
||||
typedef struct CV_C13Parsed CV_C13Parsed;
|
||||
struct CV_C13Parsed
|
||||
{
|
||||
// rjf: source data
|
||||
String8 data;
|
||||
|
||||
// rjf: full sub-section list
|
||||
CV_C13SubSectionNode *first_sub_section;
|
||||
CV_C13SubSectionNode *last_sub_section;
|
||||
U64 sub_section_count;
|
||||
|
||||
// rjf: fastpath to file checksums section
|
||||
CV_C13SubSectionNode *file_chksms_sub_section;
|
||||
|
||||
// rjf: fastpath to map inlinee CV_ItemId -> CV_InlineeLinesParsed quickly
|
||||
CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots;
|
||||
U64 inlinee_lines_parsed_slots_count;
|
||||
};
|
||||
|
||||
typedef struct CV_UDTInfo CV_UDTInfo;
|
||||
struct CV_UDTInfo
|
||||
{
|
||||
String8 name;
|
||||
String8 unique_name;
|
||||
CV_TypeProps props;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Compound Types
|
||||
|
||||
typedef struct CV_TypeIdArray CV_TypeIdArray;
|
||||
struct CV_TypeIdArray
|
||||
{
|
||||
CV_TypeId *itypes;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
//- Hasher
|
||||
|
||||
internal U64 cv_hash_from_string(String8 string);
|
||||
internal U64 cv_hash_from_item_id(CV_ItemId item_id);
|
||||
|
||||
//- Numeric Decoder
|
||||
|
||||
internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl);
|
||||
internal U64 cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out);
|
||||
|
||||
internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num);
|
||||
internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num);
|
||||
internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num);
|
||||
|
||||
internal U64 cv_u64_from_numeric(CV_NumericParsed *num);
|
||||
internal S64 cv_s64_from_numeric(CV_NumericParsed *num);
|
||||
internal F64 cv_f64_from_numeric(CV_NumericParsed *num);
|
||||
|
||||
//- Inlinee Lines Binary Annot Decoder
|
||||
|
||||
internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value);
|
||||
internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value);
|
||||
internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value);
|
||||
|
||||
internal CV_C13InlineSiteDecoder cv_c13_inline_site_decoder_init(U32 file_off, U32 first_source_ln, U32 parent_voff);
|
||||
internal CV_C13InlineSiteDecoderStep cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots);
|
||||
|
||||
//- Symbol/Leaf Helpers
|
||||
|
||||
internal B32 cv_is_udt_name_anon(String8 name);
|
||||
|
||||
internal B32 cv_is_global_symbol(CV_SymKind kind);
|
||||
internal B32 cv_is_typedef(CV_SymKind kind);
|
||||
internal B32 cv_is_scope_symbol(CV_SymKind kind);
|
||||
internal B32 cv_is_end_symbol(CV_SymKind kind);
|
||||
|
||||
internal B32 cv_is_udt(CV_LeafKind kind);
|
||||
internal B32 cv_is_leaf_type_server(CV_LeafKind kind);
|
||||
internal B32 cv_is_leaf_pch(CV_LeafKind kind);
|
||||
internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind);
|
||||
|
||||
internal CV_TypeIndexInfoList cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data);
|
||||
internal CV_TypeIndexInfoList cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data);
|
||||
internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data);
|
||||
internal String8Array cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data);
|
||||
|
||||
internal U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data);
|
||||
internal String8 cv_name_from_symbol(CV_SymKind kind, String8 data);
|
||||
|
||||
internal CV_UDTInfo cv_get_udt_info(CV_LeafKind kind, String8 data);
|
||||
internal String8 cv_name_from_udt_info(CV_UDTInfo udt_info);
|
||||
|
||||
//- rjf: record range stream parsing
|
||||
internal CV_RecRangeStream * cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align);
|
||||
internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream);
|
||||
|
||||
//- rjf: sym stream parsing
|
||||
internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align);
|
||||
|
||||
//- rjf: leaf stream parsing
|
||||
internal CV_LeafParsed * cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first);
|
||||
internal CV_C13Parsed * cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections);
|
||||
|
||||
#endif // CODEVIEW_PARSE_H
|
||||
|
||||
@@ -1,718 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
internal String8
|
||||
cv_string_from_numeric_kind(CV_NumericKind v)
|
||||
{
|
||||
String8 result = str8_lit("<Unknown CV_NumericKind>");
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_NumericKind_CHAR:{result = str8_lit("CHAR");}break;
|
||||
case CV_NumericKind_SHORT:{result = str8_lit("SHORT");}break;
|
||||
case CV_NumericKind_USHORT:{result = str8_lit("USHORT");}break;
|
||||
case CV_NumericKind_LONG:{result = str8_lit("LONG");}break;
|
||||
case CV_NumericKind_ULONG:{result = str8_lit("ULONG");}break;
|
||||
case CV_NumericKind_FLOAT32:{result = str8_lit("FLOAT32");}break;
|
||||
case CV_NumericKind_FLOAT64:{result = str8_lit("FLOAT64");}break;
|
||||
case CV_NumericKind_FLOAT80:{result = str8_lit("FLOAT80");}break;
|
||||
case CV_NumericKind_FLOAT128:{result = str8_lit("FLOAT128");}break;
|
||||
case CV_NumericKind_QUADWORD:{result = str8_lit("QUADWORD");}break;
|
||||
case CV_NumericKind_UQUADWORD:{result = str8_lit("UQUADWORD");}break;
|
||||
case CV_NumericKind_FLOAT48:{result = str8_lit("FLOAT48");}break;
|
||||
case CV_NumericKind_COMPLEX32:{result = str8_lit("COMPLEX32");}break;
|
||||
case CV_NumericKind_COMPLEX64:{result = str8_lit("COMPLEX64");}break;
|
||||
case CV_NumericKind_COMPLEX80:{result = str8_lit("COMPLEX80");}break;
|
||||
case CV_NumericKind_COMPLEX128:{result = str8_lit("COMPLEX128");}break;
|
||||
case CV_NumericKind_VARSTRING:{result = str8_lit("VARSTRING");}break;
|
||||
case CV_NumericKind_OCTWORD:{result = str8_lit("OCTWORD");}break;
|
||||
case CV_NumericKind_UOCTWORD:{result = str8_lit("UOCTWORD");}break;
|
||||
case CV_NumericKind_DECIMAL:{result = str8_lit("DECIMAL");}break;
|
||||
case CV_NumericKind_DATE:{result = str8_lit("DATE");}break;
|
||||
case CV_NumericKind_UTF8STRING:{result = str8_lit("UTF8STRING");}break;
|
||||
case CV_NumericKind_FLOAT16:{result = str8_lit("FLOAT16");}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cv_string_from_arch(CV_Arch v)
|
||||
{
|
||||
String8 result = str8_lit("<Unknown CV_Arch>");
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_Arch_8080:{result = str8_lit("8080");}break;
|
||||
case CV_Arch_8086:{result = str8_lit("8086");}break;
|
||||
case CV_Arch_80286:{result = str8_lit("80286");}break;
|
||||
case CV_Arch_80386:{result = str8_lit("80386");}break;
|
||||
case CV_Arch_80486:{result = str8_lit("80486");}break;
|
||||
case CV_Arch_PENTIUM:{result = str8_lit("PENTIUM");}break;
|
||||
case CV_Arch_PENTIUMII:{result = str8_lit("PENTIUMII");}break;
|
||||
case CV_Arch_PENTIUMIII:{result = str8_lit("PENTIUMIII");}break;
|
||||
case CV_Arch_MIPS:{result = str8_lit("MIPS");}break;
|
||||
case CV_Arch_MIPS16:{result = str8_lit("MIPS16");}break;
|
||||
case CV_Arch_MIPS32:{result = str8_lit("MIPS32");}break;
|
||||
case CV_Arch_MIPS64:{result = str8_lit("MIPS64");}break;
|
||||
case CV_Arch_MIPSI:{result = str8_lit("MIPSI");}break;
|
||||
case CV_Arch_MIPSII:{result = str8_lit("MIPSII");}break;
|
||||
case CV_Arch_MIPSIII:{result = str8_lit("MIPSIII");}break;
|
||||
case CV_Arch_MIPSIV:{result = str8_lit("MIPSIV");}break;
|
||||
case CV_Arch_MIPSV:{result = str8_lit("MIPSV");}break;
|
||||
case CV_Arch_M68000:{result = str8_lit("M68000");}break;
|
||||
case CV_Arch_M68010:{result = str8_lit("M68010");}break;
|
||||
case CV_Arch_M68020:{result = str8_lit("M68020");}break;
|
||||
case CV_Arch_M68030:{result = str8_lit("M68030");}break;
|
||||
case CV_Arch_M68040:{result = str8_lit("M68040");}break;
|
||||
case CV_Arch_ALPHA:{result = str8_lit("ALPHA");}break;
|
||||
case CV_Arch_ALPHA_21164:{result = str8_lit("ALPHA_21164");}break;
|
||||
case CV_Arch_ALPHA_21164A:{result = str8_lit("ALPHA_21164A");}break;
|
||||
case CV_Arch_ALPHA_21264:{result = str8_lit("ALPHA_21264");}break;
|
||||
case CV_Arch_ALPHA_21364:{result = str8_lit("ALPHA_21364");}break;
|
||||
case CV_Arch_PPC601:{result = str8_lit("PPC601");}break;
|
||||
case CV_Arch_PPC603:{result = str8_lit("PPC603");}break;
|
||||
case CV_Arch_PPC604:{result = str8_lit("PPC604");}break;
|
||||
case CV_Arch_PPC620:{result = str8_lit("PPC620");}break;
|
||||
case CV_Arch_PPCFP:{result = str8_lit("PPCFP");}break;
|
||||
case CV_Arch_PPCBE:{result = str8_lit("PPCBE");}break;
|
||||
case CV_Arch_SH3:{result = str8_lit("SH3");}break;
|
||||
case CV_Arch_SH3E:{result = str8_lit("SH3E");}break;
|
||||
case CV_Arch_SH3DSP:{result = str8_lit("SH3DSP");}break;
|
||||
case CV_Arch_SH4:{result = str8_lit("SH4");}break;
|
||||
case CV_Arch_SHMEDIA:{result = str8_lit("SHMEDIA");}break;
|
||||
case CV_Arch_ARM3:{result = str8_lit("ARM3");}break;
|
||||
case CV_Arch_ARM4:{result = str8_lit("ARM4");}break;
|
||||
case CV_Arch_ARM4T:{result = str8_lit("ARM4T");}break;
|
||||
case CV_Arch_ARM5:{result = str8_lit("ARM5");}break;
|
||||
case CV_Arch_ARM5T:{result = str8_lit("ARM5T");}break;
|
||||
case CV_Arch_ARM6:{result = str8_lit("ARM6");}break;
|
||||
case CV_Arch_ARM_XMAC:{result = str8_lit("ARM_XMAC");}break;
|
||||
case CV_Arch_ARM_WMMX:{result = str8_lit("ARM_WMMX");}break;
|
||||
case CV_Arch_ARM7:{result = str8_lit("ARM7");}break;
|
||||
case CV_Arch_OMNI:{result = str8_lit("OMNI");}break;
|
||||
case CV_Arch_IA64_1:{result = str8_lit("IA64_1");}break;
|
||||
case CV_Arch_IA64_2:{result = str8_lit("IA64_2");}break;
|
||||
case CV_Arch_CEE:{result = str8_lit("CEE");}break;
|
||||
case CV_Arch_AM33:{result = str8_lit("AM33");}break;
|
||||
case CV_Arch_M32R:{result = str8_lit("M32R");}break;
|
||||
case CV_Arch_TRICORE:{result = str8_lit("TRICORE");}break;
|
||||
case CV_Arch_X64:{result = str8_lit("X64");}break;
|
||||
case CV_Arch_EBC:{result = str8_lit("EBC");}break;
|
||||
case CV_Arch_THUMB:{result = str8_lit("THUMB");}break;
|
||||
case CV_Arch_ARMNT:{result = str8_lit("ARMNT");}break;
|
||||
case CV_Arch_ARM64:{result = str8_lit("ARM64");}break;
|
||||
case CV_Arch_D3D11_SHADER:{result = str8_lit("D3D11_SHADER");}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cv_string_from_sym_kind(CV_SymKind v)
|
||||
{
|
||||
String8 result = str8_lit("<Unknown CV_SymKind>");
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_SymKind_COMPILE:{result = str8_lit("COMPILE");}break;
|
||||
case CV_SymKind_REGISTER_16t:{result = str8_lit("REGISTER_16t");}break;
|
||||
case CV_SymKind_CONSTANT_16t:{result = str8_lit("CONSTANT_16t");}break;
|
||||
case CV_SymKind_UDT_16t:{result = str8_lit("UDT_16t");}break;
|
||||
case CV_SymKind_SSEARCH:{result = str8_lit("SSEARCH");}break;
|
||||
case CV_SymKind_END:{result = str8_lit("END");}break;
|
||||
case CV_SymKind_SKIP:{result = str8_lit("SKIP");}break;
|
||||
case CV_SymKind_CVRESERVE:{result = str8_lit("CVRESERVE");}break;
|
||||
case CV_SymKind_OBJNAME_ST:{result = str8_lit("OBJNAME_ST");}break;
|
||||
case CV_SymKind_ENDARG:{result = str8_lit("ENDARG");}break;
|
||||
case CV_SymKind_COBOLUDT_16t:{result = str8_lit("COBOLUDT_16t");}break;
|
||||
case CV_SymKind_MANYREG_16t:{result = str8_lit("MANYREG_16t");}break;
|
||||
case CV_SymKind_RETURN:{result = str8_lit("RETURN");}break;
|
||||
case CV_SymKind_ENTRYTHIS:{result = str8_lit("ENTRYTHIS");}break;
|
||||
case CV_SymKind_BPREL16:{result = str8_lit("BPREL16");}break;
|
||||
case CV_SymKind_LDATA16:{result = str8_lit("LDATA16");}break;
|
||||
case CV_SymKind_GDATA16:{result = str8_lit("GDATA16");}break;
|
||||
case CV_SymKind_PUB16:{result = str8_lit("PUB16");}break;
|
||||
case CV_SymKind_LPROC16:{result = str8_lit("LPROC16");}break;
|
||||
case CV_SymKind_GPROC16:{result = str8_lit("GPROC16");}break;
|
||||
case CV_SymKind_THUNK16:{result = str8_lit("THUNK16");}break;
|
||||
case CV_SymKind_BLOCK16:{result = str8_lit("BLOCK16");}break;
|
||||
case CV_SymKind_WITH16:{result = str8_lit("WITH16");}break;
|
||||
case CV_SymKind_LABEL16:{result = str8_lit("LABEL16");}break;
|
||||
case CV_SymKind_CEXMODEL16:{result = str8_lit("CEXMODEL16");}break;
|
||||
case CV_SymKind_VFTABLE16:{result = str8_lit("VFTABLE16");}break;
|
||||
case CV_SymKind_REGREL16:{result = str8_lit("REGREL16");}break;
|
||||
case CV_SymKind_BPREL32_16t:{result = str8_lit("BPREL32_16t");}break;
|
||||
case CV_SymKind_LDATA32_16t:{result = str8_lit("LDATA32_16t");}break;
|
||||
case CV_SymKind_GDATA32_16t:{result = str8_lit("GDATA32_16t");}break;
|
||||
case CV_SymKind_PUB32_16t:{result = str8_lit("PUB32_16t");}break;
|
||||
case CV_SymKind_LPROC32_16t:{result = str8_lit("LPROC32_16t");}break;
|
||||
case CV_SymKind_GPROC32_16t:{result = str8_lit("GPROC32_16t");}break;
|
||||
case CV_SymKind_THUNK32_ST:{result = str8_lit("THUNK32_ST");}break;
|
||||
case CV_SymKind_BLOCK32_ST:{result = str8_lit("BLOCK32_ST");}break;
|
||||
case CV_SymKind_WITH32_ST:{result = str8_lit("WITH32_ST");}break;
|
||||
case CV_SymKind_LABEL32_ST:{result = str8_lit("LABEL32_ST");}break;
|
||||
case CV_SymKind_CEXMODEL32:{result = str8_lit("CEXMODEL32");}break;
|
||||
case CV_SymKind_VFTABLE32_16t:{result = str8_lit("VFTABLE32_16t");}break;
|
||||
case CV_SymKind_REGREL32_16t:{result = str8_lit("REGREL32_16t");}break;
|
||||
case CV_SymKind_LTHREAD32_16t:{result = str8_lit("LTHREAD32_16t");}break;
|
||||
case CV_SymKind_GTHREAD32_16t:{result = str8_lit("GTHREAD32_16t");}break;
|
||||
case CV_SymKind_SLINK32:{result = str8_lit("SLINK32");}break;
|
||||
case CV_SymKind_LPROCMIPS_16t:{result = str8_lit("LPROCMIPS_16t");}break;
|
||||
case CV_SymKind_GPROCMIPS_16t:{result = str8_lit("GPROCMIPS_16t");}break;
|
||||
case CV_SymKind_PROCREF_ST:{result = str8_lit("PROCREF_ST");}break;
|
||||
case CV_SymKind_DATAREF_ST:{result = str8_lit("DATAREF_ST");}break;
|
||||
case CV_SymKind_ALIGN:{result = str8_lit("ALIGN");}break;
|
||||
case CV_SymKind_LPROCREF_ST:{result = str8_lit("LPROCREF_ST");}break;
|
||||
case CV_SymKind_OEM:{result = str8_lit("OEM");}break;
|
||||
case CV_SymKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break;
|
||||
case CV_SymKind_CONSTANT_ST:{result = str8_lit("CONSTANT_ST");}break;
|
||||
case CV_SymKind_UDT_ST:{result = str8_lit("UDT_ST");}break;
|
||||
case CV_SymKind_COBOLUDT_ST:{result = str8_lit("COBOLUDT_ST");}break;
|
||||
case CV_SymKind_MANYREG_ST:{result = str8_lit("MANYREG_ST");}break;
|
||||
case CV_SymKind_BPREL32_ST:{result = str8_lit("BPREL32_ST");}break;
|
||||
case CV_SymKind_LDATA32_ST:{result = str8_lit("LDATA32_ST");}break;
|
||||
case CV_SymKind_GDATA32_ST:{result = str8_lit("GDATA32_ST");}break;
|
||||
case CV_SymKind_PUB32_ST:{result = str8_lit("PUB32_ST");}break;
|
||||
case CV_SymKind_LPROC32_ST:{result = str8_lit("LPROC32_ST");}break;
|
||||
case CV_SymKind_GPROC32_ST:{result = str8_lit("GPROC32_ST");}break;
|
||||
case CV_SymKind_VFTABLE32:{result = str8_lit("VFTABLE32");}break;
|
||||
case CV_SymKind_REGREL32_ST:{result = str8_lit("REGREL32_ST");}break;
|
||||
case CV_SymKind_LTHREAD32_ST:{result = str8_lit("LTHREAD32_ST");}break;
|
||||
case CV_SymKind_GTHREAD32_ST:{result = str8_lit("GTHREAD32_ST");}break;
|
||||
case CV_SymKind_LPROCMIPS_ST:{result = str8_lit("LPROCMIPS_ST");}break;
|
||||
case CV_SymKind_GPROCMIPS_ST:{result = str8_lit("GPROCMIPS_ST");}break;
|
||||
case CV_SymKind_FRAMEPROC:{result = str8_lit("FRAMEPROC");}break;
|
||||
case CV_SymKind_COMPILE2_ST:{result = str8_lit("COMPILE2_ST");}break;
|
||||
case CV_SymKind_MANYREG2_ST:{result = str8_lit("MANYREG2_ST");}break;
|
||||
case CV_SymKind_LPROCIA64_ST:{result = str8_lit("LPROCIA64_ST");}break;
|
||||
case CV_SymKind_GPROCIA64_ST:{result = str8_lit("GPROCIA64_ST");}break;
|
||||
case CV_SymKind_LOCALSLOT_ST:{result = str8_lit("LOCALSLOT_ST");}break;
|
||||
case CV_SymKind_PARAMSLOT_ST:{result = str8_lit("PARAMSLOT_ST");}break;
|
||||
case CV_SymKind_ANNOTATION:{result = str8_lit("ANNOTATION");}break;
|
||||
case CV_SymKind_GMANPROC_ST:{result = str8_lit("GMANPROC_ST");}break;
|
||||
case CV_SymKind_LMANPROC_ST:{result = str8_lit("LMANPROC_ST");}break;
|
||||
case CV_SymKind_RESERVED1:{result = str8_lit("RESERVED1");}break;
|
||||
case CV_SymKind_RESERVED2:{result = str8_lit("RESERVED2");}break;
|
||||
case CV_SymKind_RESERVED3:{result = str8_lit("RESERVED3");}break;
|
||||
case CV_SymKind_RESERVED4:{result = str8_lit("RESERVED4");}break;
|
||||
case CV_SymKind_LMANDATA_ST:{result = str8_lit("LMANDATA_ST");}break;
|
||||
case CV_SymKind_GMANDATA_ST:{result = str8_lit("GMANDATA_ST");}break;
|
||||
case CV_SymKind_MANFRAMEREL_ST:{result = str8_lit("MANFRAMEREL_ST");}break;
|
||||
case CV_SymKind_MANREGISTER_ST:{result = str8_lit("MANREGISTER_ST");}break;
|
||||
case CV_SymKind_MANSLOT_ST:{result = str8_lit("MANSLOT_ST");}break;
|
||||
case CV_SymKind_MANMANYREG_ST:{result = str8_lit("MANMANYREG_ST");}break;
|
||||
case CV_SymKind_MANREGREL_ST:{result = str8_lit("MANREGREL_ST");}break;
|
||||
case CV_SymKind_MANMANYREG2_ST:{result = str8_lit("MANMANYREG2_ST");}break;
|
||||
case CV_SymKind_MANTYPREF:{result = str8_lit("MANTYPREF");}break;
|
||||
case CV_SymKind_UNAMESPACE_ST:{result = str8_lit("UNAMESPACE_ST");}break;
|
||||
case CV_SymKind_ST_MAX:{result = str8_lit("ST_MAX");}break;
|
||||
case CV_SymKind_OBJNAME:{result = str8_lit("OBJNAME");}break;
|
||||
case CV_SymKind_THUNK32:{result = str8_lit("THUNK32");}break;
|
||||
case CV_SymKind_BLOCK32:{result = str8_lit("BLOCK32");}break;
|
||||
case CV_SymKind_WITH32:{result = str8_lit("WITH32");}break;
|
||||
case CV_SymKind_LABEL32:{result = str8_lit("LABEL32");}break;
|
||||
case CV_SymKind_REGISTER:{result = str8_lit("REGISTER");}break;
|
||||
case CV_SymKind_CONSTANT:{result = str8_lit("CONSTANT");}break;
|
||||
case CV_SymKind_UDT:{result = str8_lit("UDT");}break;
|
||||
case CV_SymKind_COBOLUDT:{result = str8_lit("COBOLUDT");}break;
|
||||
case CV_SymKind_MANYREG:{result = str8_lit("MANYREG");}break;
|
||||
case CV_SymKind_BPREL32:{result = str8_lit("BPREL32");}break;
|
||||
case CV_SymKind_LDATA32:{result = str8_lit("LDATA32");}break;
|
||||
case CV_SymKind_GDATA32:{result = str8_lit("GDATA32");}break;
|
||||
case CV_SymKind_PUB32:{result = str8_lit("PUB32");}break;
|
||||
case CV_SymKind_LPROC32:{result = str8_lit("LPROC32");}break;
|
||||
case CV_SymKind_GPROC32:{result = str8_lit("GPROC32");}break;
|
||||
case CV_SymKind_REGREL32:{result = str8_lit("REGREL32");}break;
|
||||
case CV_SymKind_LTHREAD32:{result = str8_lit("LTHREAD32");}break;
|
||||
case CV_SymKind_GTHREAD32:{result = str8_lit("GTHREAD32");}break;
|
||||
case CV_SymKind_LPROCMIPS:{result = str8_lit("LPROCMIPS");}break;
|
||||
case CV_SymKind_GPROCMIPS:{result = str8_lit("GPROCMIPS");}break;
|
||||
case CV_SymKind_COMPILE2:{result = str8_lit("COMPILE2");}break;
|
||||
case CV_SymKind_MANYREG2:{result = str8_lit("MANYREG2");}break;
|
||||
case CV_SymKind_LPROCIA64:{result = str8_lit("LPROCIA64");}break;
|
||||
case CV_SymKind_GPROCIA64:{result = str8_lit("GPROCIA64");}break;
|
||||
case CV_SymKind_LOCALSLOT:{result = str8_lit("LOCALSLOT");}break;
|
||||
case CV_SymKind_PARAMSLOT:{result = str8_lit("PARAMSLOT");}break;
|
||||
case CV_SymKind_LMANDATA:{result = str8_lit("LMANDATA");}break;
|
||||
case CV_SymKind_GMANDATA:{result = str8_lit("GMANDATA");}break;
|
||||
case CV_SymKind_MANFRAMEREL:{result = str8_lit("MANFRAMEREL");}break;
|
||||
case CV_SymKind_MANREGISTER:{result = str8_lit("MANREGISTER");}break;
|
||||
case CV_SymKind_MANSLOT:{result = str8_lit("MANSLOT");}break;
|
||||
case CV_SymKind_MANMANYREG:{result = str8_lit("MANMANYREG");}break;
|
||||
case CV_SymKind_MANREGREL:{result = str8_lit("MANREGREL");}break;
|
||||
case CV_SymKind_MANMANYREG2:{result = str8_lit("MANMANYREG2");}break;
|
||||
case CV_SymKind_UNAMESPACE:{result = str8_lit("UNAMESPACE");}break;
|
||||
case CV_SymKind_PROCREF:{result = str8_lit("PROCREF");}break;
|
||||
case CV_SymKind_DATAREF:{result = str8_lit("DATAREF");}break;
|
||||
case CV_SymKind_LPROCREF:{result = str8_lit("LPROCREF");}break;
|
||||
case CV_SymKind_ANNOTATIONREF:{result = str8_lit("ANNOTATIONREF");}break;
|
||||
case CV_SymKind_TOKENREF:{result = str8_lit("TOKENREF");}break;
|
||||
case CV_SymKind_GMANPROC:{result = str8_lit("GMANPROC");}break;
|
||||
case CV_SymKind_LMANPROC:{result = str8_lit("LMANPROC");}break;
|
||||
case CV_SymKind_TRAMPOLINE:{result = str8_lit("TRAMPOLINE");}break;
|
||||
case CV_SymKind_MANCONSTANT:{result = str8_lit("MANCONSTANT");}break;
|
||||
case CV_SymKind_ATTR_FRAMEREL:{result = str8_lit("ATTR_FRAMEREL");}break;
|
||||
case CV_SymKind_ATTR_REGISTER:{result = str8_lit("ATTR_REGISTER");}break;
|
||||
case CV_SymKind_ATTR_REGREL:{result = str8_lit("ATTR_REGREL");}break;
|
||||
case CV_SymKind_ATTR_MANYREG:{result = str8_lit("ATTR_MANYREG");}break;
|
||||
case CV_SymKind_SEPCODE:{result = str8_lit("SEPCODE");}break;
|
||||
case CV_SymKind_DEFRANGE_2005:{result = str8_lit("DEFRANGE_2005");}break;
|
||||
case CV_SymKind_DEFRANGE2_2005:{result = str8_lit("DEFRANGE2_2005");}break;
|
||||
case CV_SymKind_SECTION:{result = str8_lit("SECTION");}break;
|
||||
case CV_SymKind_COFFGROUP:{result = str8_lit("COFFGROUP");}break;
|
||||
case CV_SymKind_EXPORT:{result = str8_lit("EXPORT");}break;
|
||||
case CV_SymKind_CALLSITEINFO:{result = str8_lit("CALLSITEINFO");}break;
|
||||
case CV_SymKind_FRAMECOOKIE:{result = str8_lit("FRAMECOOKIE");}break;
|
||||
case CV_SymKind_DISCARDED:{result = str8_lit("DISCARDED");}break;
|
||||
case CV_SymKind_COMPILE3:{result = str8_lit("COMPILE3");}break;
|
||||
case CV_SymKind_ENVBLOCK:{result = str8_lit("ENVBLOCK");}break;
|
||||
case CV_SymKind_LOCAL:{result = str8_lit("LOCAL");}break;
|
||||
case CV_SymKind_DEFRANGE:{result = str8_lit("DEFRANGE");}break;
|
||||
case CV_SymKind_DEFRANGE_SUBFIELD:{result = str8_lit("DEFRANGE_SUBFIELD");}break;
|
||||
case CV_SymKind_DEFRANGE_REGISTER:{result = str8_lit("DEFRANGE_REGISTER");}break;
|
||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL");}break;
|
||||
case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = str8_lit("DEFRANGE_SUBFIELD_REGISTER");}break;
|
||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE");}break;
|
||||
case CV_SymKind_DEFRANGE_REGISTER_REL:{result = str8_lit("DEFRANGE_REGISTER_REL");}break;
|
||||
case CV_SymKind_LPROC32_ID:{result = str8_lit("LPROC32_ID");}break;
|
||||
case CV_SymKind_GPROC32_ID:{result = str8_lit("GPROC32_ID");}break;
|
||||
case CV_SymKind_LPROCMIPS_ID:{result = str8_lit("LPROCMIPS_ID");}break;
|
||||
case CV_SymKind_GPROCMIPS_ID:{result = str8_lit("GPROCMIPS_ID");}break;
|
||||
case CV_SymKind_LPROCIA64_ID:{result = str8_lit("LPROCIA64_ID");}break;
|
||||
case CV_SymKind_GPROCIA64_ID:{result = str8_lit("GPROCIA64_ID");}break;
|
||||
case CV_SymKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
|
||||
case CV_SymKind_INLINESITE:{result = str8_lit("INLINESITE");}break;
|
||||
case CV_SymKind_INLINESITE_END:{result = str8_lit("INLINESITE_END");}break;
|
||||
case CV_SymKind_PROC_ID_END:{result = str8_lit("PROC_ID_END");}break;
|
||||
case CV_SymKind_DEFRANGE_HLSL:{result = str8_lit("DEFRANGE_HLSL");}break;
|
||||
case CV_SymKind_GDATA_HLSL:{result = str8_lit("GDATA_HLSL");}break;
|
||||
case CV_SymKind_LDATA_HLSL:{result = str8_lit("LDATA_HLSL");}break;
|
||||
case CV_SymKind_FILESTATIC:{result = str8_lit("FILESTATIC");}break;
|
||||
case CV_SymKind_LPROC32_DPC:{result = str8_lit("LPROC32_DPC");}break;
|
||||
case CV_SymKind_LPROC32_DPC_ID:{result = str8_lit("LPROC32_DPC_ID");}break;
|
||||
case CV_SymKind_DEFRANGE_DPC_PTR_TAG:{result = str8_lit("DEFRANGE_DPC_PTR_TAG");}break;
|
||||
case CV_SymKind_DPC_SYM_TAG_MAP:{result = str8_lit("DPC_SYM_TAG_MAP");}break;
|
||||
case CV_SymKind_ARMSWITCHTABLE:{result = str8_lit("ARMSWITCHTABLE");}break;
|
||||
case CV_SymKind_CALLEES:{result = str8_lit("CALLEES");}break;
|
||||
case CV_SymKind_CALLERS:{result = str8_lit("CALLERS");}break;
|
||||
case CV_SymKind_POGODATA:{result = str8_lit("POGODATA");}break;
|
||||
case CV_SymKind_INLINESITE2:{result = str8_lit("INLINESITE2");}break;
|
||||
case CV_SymKind_HEAPALLOCSITE:{result = str8_lit("HEAPALLOCSITE");}break;
|
||||
case CV_SymKind_MOD_TYPEREF:{result = str8_lit("MOD_TYPEREF");}break;
|
||||
case CV_SymKind_REF_MINIPDB:{result = str8_lit("REF_MINIPDB");}break;
|
||||
case CV_SymKind_PDBMAP:{result = str8_lit("PDBMAP");}break;
|
||||
case CV_SymKind_GDATA_HLSL32:{result = str8_lit("GDATA_HLSL32");}break;
|
||||
case CV_SymKind_LDATA_HLSL32:{result = str8_lit("LDATA_HLSL32");}break;
|
||||
case CV_SymKind_GDATA_HLSL32_EX:{result = str8_lit("GDATA_HLSL32_EX");}break;
|
||||
case CV_SymKind_LDATA_HLSL32_EX:{result = str8_lit("LDATA_HLSL32_EX");}break;
|
||||
case CV_SymKind_FASTLINK:{result = str8_lit("FASTLINK");}break;
|
||||
case CV_SymKind_INLINEES:{result = str8_lit("INLINEES");}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cv_string_from_basic_type(CV_BasicType v)
|
||||
{
|
||||
String8 result = str8_lit("<Unknown CV_BasicType>");
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_BasicType_NOTYPE:{result = str8_lit("NOTYPE");}break;
|
||||
case CV_BasicType_ABS:{result = str8_lit("ABS");}break;
|
||||
case CV_BasicType_SEGMENT:{result = str8_lit("SEGMENT");}break;
|
||||
case CV_BasicType_VOID:{result = str8_lit("VOID");}break;
|
||||
case CV_BasicType_CURRENCY:{result = str8_lit("CURRENCY");}break;
|
||||
case CV_BasicType_NBASICSTR:{result = str8_lit("NBASICSTR");}break;
|
||||
case CV_BasicType_FBASICSTR:{result = str8_lit("FBASICSTR");}break;
|
||||
case CV_BasicType_NOTTRANS:{result = str8_lit("NOTTRANS");}break;
|
||||
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
|
||||
case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break;
|
||||
case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break;
|
||||
case CV_BasicType_LONG:{result = str8_lit("LONG");}break;
|
||||
case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break;
|
||||
case CV_BasicType_OCT:{result = str8_lit("OCT");}break;
|
||||
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
|
||||
case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break;
|
||||
case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break;
|
||||
case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break;
|
||||
case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break;
|
||||
case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break;
|
||||
case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break;
|
||||
case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break;
|
||||
case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break;
|
||||
case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break;
|
||||
case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break;
|
||||
case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break;
|
||||
case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break;
|
||||
case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break;
|
||||
case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break;
|
||||
case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break;
|
||||
case CV_BasicType_COMPLEX32:{result = str8_lit("COMPLEX32");}break;
|
||||
case CV_BasicType_COMPLEX64:{result = str8_lit("COMPLEX64");}break;
|
||||
case CV_BasicType_COMPLEX80:{result = str8_lit("COMPLEX80");}break;
|
||||
case CV_BasicType_COMPLEX128:{result = str8_lit("COMPLEX128");}break;
|
||||
case CV_BasicType_BIT:{result = str8_lit("BIT");}break;
|
||||
case CV_BasicType_PASCHAR:{result = str8_lit("PASCHAR");}break;
|
||||
case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break;
|
||||
case CV_BasicType_INT8:{result = str8_lit("INT8");}break;
|
||||
case CV_BasicType_UINT8:{result = str8_lit("UINT8");}break;
|
||||
case CV_BasicType_RCHAR:{result = str8_lit("RCHAR");}break;
|
||||
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
|
||||
case CV_BasicType_INT16:{result = str8_lit("INT16");}break;
|
||||
case CV_BasicType_UINT16:{result = str8_lit("UINT16");}break;
|
||||
case CV_BasicType_INT32:{result = str8_lit("INT32");}break;
|
||||
case CV_BasicType_UINT32:{result = str8_lit("UINT32");}break;
|
||||
case CV_BasicType_INT64:{result = str8_lit("INT64");}break;
|
||||
case CV_BasicType_UINT64:{result = str8_lit("UINT64");}break;
|
||||
case CV_BasicType_INT128:{result = str8_lit("INT128");}break;
|
||||
case CV_BasicType_UINT128:{result = str8_lit("UINT128");}break;
|
||||
case CV_BasicType_CHAR16:{result = str8_lit("CHAR16");}break;
|
||||
case CV_BasicType_CHAR32:{result = str8_lit("CHAR32");}break;
|
||||
case CV_BasicType_CHAR8:{result = str8_lit("CHAR8");}break;
|
||||
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cv_type_name_from_basic_type(CV_BasicType v)
|
||||
{
|
||||
String8 result = str8_lit("<Unknown CV_BasicType>");
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_BasicType_NOTYPE:{result = str8_lit("");}break;
|
||||
case CV_BasicType_ABS:{result = str8_lit("");}break;
|
||||
case CV_BasicType_SEGMENT:{result = str8_lit("");}break;
|
||||
case CV_BasicType_VOID:{result = str8_lit("void");}break;
|
||||
case CV_BasicType_CURRENCY:{result = str8_lit("");}break;
|
||||
case CV_BasicType_NBASICSTR:{result = str8_lit("");}break;
|
||||
case CV_BasicType_FBASICSTR:{result = str8_lit("");}break;
|
||||
case CV_BasicType_NOTTRANS:{result = str8_lit("");}break;
|
||||
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
|
||||
case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break;
|
||||
case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break;
|
||||
case CV_BasicType_LONG:{result = str8_lit("LONG");}break;
|
||||
case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break;
|
||||
case CV_BasicType_OCT:{result = str8_lit("OCT");}break;
|
||||
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
|
||||
case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break;
|
||||
case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break;
|
||||
case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break;
|
||||
case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break;
|
||||
case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break;
|
||||
case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break;
|
||||
case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break;
|
||||
case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break;
|
||||
case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break;
|
||||
case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break;
|
||||
case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break;
|
||||
case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break;
|
||||
case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break;
|
||||
case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break;
|
||||
case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break;
|
||||
case CV_BasicType_COMPLEX32:{result = str8_lit("ComplexF32");}break;
|
||||
case CV_BasicType_COMPLEX64:{result = str8_lit("ComplexF64");}break;
|
||||
case CV_BasicType_COMPLEX80:{result = str8_lit("ComplexF80");}break;
|
||||
case CV_BasicType_COMPLEX128:{result = str8_lit("ComplexF128");}break;
|
||||
case CV_BasicType_BIT:{result = str8_lit("");}break;
|
||||
case CV_BasicType_PASCHAR:{result = str8_lit("");}break;
|
||||
case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break;
|
||||
case CV_BasicType_INT8:{result = str8_lit("int8");}break;
|
||||
case CV_BasicType_UINT8:{result = str8_lit("uint8");}break;
|
||||
case CV_BasicType_RCHAR:{result = str8_lit("char");}break;
|
||||
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
|
||||
case CV_BasicType_INT16:{result = str8_lit("int16");}break;
|
||||
case CV_BasicType_UINT16:{result = str8_lit("uint16");}break;
|
||||
case CV_BasicType_INT32:{result = str8_lit("int32");}break;
|
||||
case CV_BasicType_UINT32:{result = str8_lit("uint32");}break;
|
||||
case CV_BasicType_INT64:{result = str8_lit("int64");}break;
|
||||
case CV_BasicType_UINT64:{result = str8_lit("uint64");}break;
|
||||
case CV_BasicType_INT128:{result = str8_lit("int128");}break;
|
||||
case CV_BasicType_UINT128:{result = str8_lit("uint128");}break;
|
||||
case CV_BasicType_CHAR16:{result = str8_lit("char16");}break;
|
||||
case CV_BasicType_CHAR32:{result = str8_lit("char32");}break;
|
||||
case CV_BasicType_CHAR8:{result = str8_lit("char");}break;
|
||||
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cv_string_from_leaf_kind(CV_LeafKind v)
|
||||
{
|
||||
String8 result = str8_lit("<Unknown CV_LeafKind>");
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_LeafKind_NOTYPE:{result = str8_lit("NOTYPE");}break;
|
||||
case CV_LeafKind_MODIFIER_16t:{result = str8_lit("MODIFIER_16t");}break;
|
||||
case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break;
|
||||
case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break;
|
||||
case CV_LeafKind_CLASS_16t:{result = str8_lit("CLASS_16t");}break;
|
||||
case CV_LeafKind_STRUCTURE_16t:{result = str8_lit("STRUCTURE_16t");}break;
|
||||
case CV_LeafKind_UNION_16t:{result = str8_lit("UNION_16t");}break;
|
||||
case CV_LeafKind_ENUM_16t:{result = str8_lit("ENUM_16t");}break;
|
||||
case CV_LeafKind_PROCEDURE_16t:{result = str8_lit("PROCEDURE_16t");}break;
|
||||
case CV_LeafKind_MFUNCTION_16t:{result = str8_lit("MFUNCTION_16t");}break;
|
||||
case CV_LeafKind_VTSHAPE:{result = str8_lit("VTSHAPE");}break;
|
||||
case CV_LeafKind_COBOL0_16t:{result = str8_lit("COBOL0_16t");}break;
|
||||
case CV_LeafKind_COBOL1:{result = str8_lit("COBOL1");}break;
|
||||
case CV_LeafKind_BARRAY_16t:{result = str8_lit("BARRAY_16t");}break;
|
||||
case CV_LeafKind_LABEL:{result = str8_lit("LABEL");}break;
|
||||
case CV_LeafKind_NULL:{result = str8_lit("NULL");}break;
|
||||
case CV_LeafKind_NOTTRAN:{result = str8_lit("NOTTRAN");}break;
|
||||
case CV_LeafKind_DIMARRAY_16t:{result = str8_lit("DIMARRAY_16t");}break;
|
||||
case CV_LeafKind_VFTPATH_16t:{result = str8_lit("VFTPATH_16t");}break;
|
||||
case CV_LeafKind_PRECOMP_16t:{result = str8_lit("PRECOMP_16t");}break;
|
||||
case CV_LeafKind_ENDPRECOMP:{result = str8_lit("ENDPRECOMP");}break;
|
||||
case CV_LeafKind_OEM_16t:{result = str8_lit("OEM_16t");}break;
|
||||
case CV_LeafKind_TYPESERVER_ST:{result = str8_lit("TYPESERVER_ST");}break;
|
||||
case CV_LeafKind_SKIP_16t:{result = str8_lit("SKIP_16t");}break;
|
||||
case CV_LeafKind_ARGLIST_16t:{result = str8_lit("ARGLIST_16t");}break;
|
||||
case CV_LeafKind_DEFARG_16t:{result = str8_lit("DEFARG_16t");}break;
|
||||
case CV_LeafKind_LIST:{result = str8_lit("LIST");}break;
|
||||
case CV_LeafKind_FIELDLIST_16t:{result = str8_lit("FIELDLIST_16t");}break;
|
||||
case CV_LeafKind_DERIVED_16t:{result = str8_lit("DERIVED_16t");}break;
|
||||
case CV_LeafKind_BITFIELD_16t:{result = str8_lit("BITFIELD_16t");}break;
|
||||
case CV_LeafKind_METHODLIST_16t:{result = str8_lit("METHODLIST_16t");}break;
|
||||
case CV_LeafKind_DIMCONU_16t:{result = str8_lit("DIMCONU_16t");}break;
|
||||
case CV_LeafKind_DIMCONLU_16t:{result = str8_lit("DIMCONLU_16t");}break;
|
||||
case CV_LeafKind_DIMVARU_16t:{result = str8_lit("DIMVARU_16t");}break;
|
||||
case CV_LeafKind_DIMVARLU_16t:{result = str8_lit("DIMVARLU_16t");}break;
|
||||
case CV_LeafKind_REFSYM:{result = str8_lit("REFSYM");}break;
|
||||
case CV_LeafKind_BCLASS_16t:{result = str8_lit("BCLASS_16t");}break;
|
||||
case CV_LeafKind_VBCLASS_16t:{result = str8_lit("VBCLASS_16t");}break;
|
||||
case CV_LeafKind_IVBCLASS_16t:{result = str8_lit("IVBCLASS_16t");}break;
|
||||
case CV_LeafKind_ENUMERATE_ST:{result = str8_lit("ENUMERATE_ST");}break;
|
||||
case CV_LeafKind_FRIENDFCN_16t:{result = str8_lit("FRIENDFCN_16t");}break;
|
||||
case CV_LeafKind_INDEX_16t:{result = str8_lit("INDEX_16t");}break;
|
||||
case CV_LeafKind_MEMBER_16t:{result = str8_lit("MEMBER_16t");}break;
|
||||
case CV_LeafKind_STMEMBER_16t:{result = str8_lit("STMEMBER_16t");}break;
|
||||
case CV_LeafKind_METHOD_16t:{result = str8_lit("METHOD_16t");}break;
|
||||
case CV_LeafKind_NESTTYPE_16t:{result = str8_lit("NESTTYPE_16t");}break;
|
||||
case CV_LeafKind_VFUNCTAB_16t:{result = str8_lit("VFUNCTAB_16t");}break;
|
||||
case CV_LeafKind_FRIENDCLS_16t:{result = str8_lit("FRIENDCLS_16t");}break;
|
||||
case CV_LeafKind_ONEMETHOD_16t:{result = str8_lit("ONEMETHOD_16t");}break;
|
||||
case CV_LeafKind_VFUNCOFF_16t:{result = str8_lit("VFUNCOFF_16t");}break;
|
||||
case CV_LeafKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break;
|
||||
case CV_LeafKind_MODIFIER:{result = str8_lit("MODIFIER");}break;
|
||||
case CV_LeafKind_POINTER:{result = str8_lit("POINTER");}break;
|
||||
case CV_LeafKind_ARRAY_ST:{result = str8_lit("ARRAY_ST");}break;
|
||||
case CV_LeafKind_CLASS_ST:{result = str8_lit("CLASS_ST");}break;
|
||||
case CV_LeafKind_STRUCTURE_ST:{result = str8_lit("STRUCTURE_ST");}break;
|
||||
case CV_LeafKind_UNION_ST:{result = str8_lit("UNION_ST");}break;
|
||||
case CV_LeafKind_ENUM_ST:{result = str8_lit("ENUM_ST");}break;
|
||||
case CV_LeafKind_PROCEDURE:{result = str8_lit("PROCEDURE");}break;
|
||||
case CV_LeafKind_MFUNCTION:{result = str8_lit("MFUNCTION");}break;
|
||||
case CV_LeafKind_COBOL0:{result = str8_lit("COBOL0");}break;
|
||||
case CV_LeafKind_BARRAY:{result = str8_lit("BARRAY");}break;
|
||||
case CV_LeafKind_DIMARRAY_ST:{result = str8_lit("DIMARRAY_ST");}break;
|
||||
case CV_LeafKind_VFTPATH:{result = str8_lit("VFTPATH");}break;
|
||||
case CV_LeafKind_PRECOMP_ST:{result = str8_lit("PRECOMP_ST");}break;
|
||||
case CV_LeafKind_OEM:{result = str8_lit("OEM");}break;
|
||||
case CV_LeafKind_ALIAS_ST:{result = str8_lit("ALIAS_ST");}break;
|
||||
case CV_LeafKind_OEM2:{result = str8_lit("OEM2");}break;
|
||||
case CV_LeafKind_SKIP:{result = str8_lit("SKIP");}break;
|
||||
case CV_LeafKind_ARGLIST:{result = str8_lit("ARGLIST");}break;
|
||||
case CV_LeafKind_DEFARG_ST:{result = str8_lit("DEFARG_ST");}break;
|
||||
case CV_LeafKind_FIELDLIST:{result = str8_lit("FIELDLIST");}break;
|
||||
case CV_LeafKind_DERIVED:{result = str8_lit("DERIVED");}break;
|
||||
case CV_LeafKind_BITFIELD:{result = str8_lit("BITFIELD");}break;
|
||||
case CV_LeafKind_METHODLIST:{result = str8_lit("METHODLIST");}break;
|
||||
case CV_LeafKind_DIMCONU:{result = str8_lit("DIMCONU");}break;
|
||||
case CV_LeafKind_DIMCONLU:{result = str8_lit("DIMCONLU");}break;
|
||||
case CV_LeafKind_DIMVARU:{result = str8_lit("DIMVARU");}break;
|
||||
case CV_LeafKind_DIMVARLU:{result = str8_lit("DIMVARLU");}break;
|
||||
case CV_LeafKind_BCLASS:{result = str8_lit("BCLASS");}break;
|
||||
case CV_LeafKind_VBCLASS:{result = str8_lit("VBCLASS");}break;
|
||||
case CV_LeafKind_IVBCLASS:{result = str8_lit("IVBCLASS");}break;
|
||||
case CV_LeafKind_FRIENDFCN_ST:{result = str8_lit("FRIENDFCN_ST");}break;
|
||||
case CV_LeafKind_INDEX:{result = str8_lit("INDEX");}break;
|
||||
case CV_LeafKind_MEMBER_ST:{result = str8_lit("MEMBER_ST");}break;
|
||||
case CV_LeafKind_STMEMBER_ST:{result = str8_lit("STMEMBER_ST");}break;
|
||||
case CV_LeafKind_METHOD_ST:{result = str8_lit("METHOD_ST");}break;
|
||||
case CV_LeafKind_NESTTYPE_ST:{result = str8_lit("NESTTYPE_ST");}break;
|
||||
case CV_LeafKind_VFUNCTAB:{result = str8_lit("VFUNCTAB");}break;
|
||||
case CV_LeafKind_FRIENDCLS:{result = str8_lit("FRIENDCLS");}break;
|
||||
case CV_LeafKind_ONEMETHOD_ST:{result = str8_lit("ONEMETHOD_ST");}break;
|
||||
case CV_LeafKind_VFUNCOFF:{result = str8_lit("VFUNCOFF");}break;
|
||||
case CV_LeafKind_NESTTYPEEX_ST:{result = str8_lit("NESTTYPEEX_ST");}break;
|
||||
case CV_LeafKind_MEMBERMODIFY_ST:{result = str8_lit("MEMBERMODIFY_ST");}break;
|
||||
case CV_LeafKind_MANAGED_ST:{result = str8_lit("MANAGED_ST");}break;
|
||||
case CV_LeafKind_ST_MAX:{result = str8_lit("ST_MAX");}break;
|
||||
case CV_LeafKind_TYPESERVER:{result = str8_lit("TYPESERVER");}break;
|
||||
case CV_LeafKind_ENUMERATE:{result = str8_lit("ENUMERATE");}break;
|
||||
case CV_LeafKind_ARRAY:{result = str8_lit("ARRAY");}break;
|
||||
case CV_LeafKind_CLASS:{result = str8_lit("CLASS");}break;
|
||||
case CV_LeafKind_STRUCTURE:{result = str8_lit("STRUCTURE");}break;
|
||||
case CV_LeafKind_UNION:{result = str8_lit("UNION");}break;
|
||||
case CV_LeafKind_ENUM:{result = str8_lit("ENUM");}break;
|
||||
case CV_LeafKind_DIMARRAY:{result = str8_lit("DIMARRAY");}break;
|
||||
case CV_LeafKind_PRECOMP:{result = str8_lit("PRECOMP");}break;
|
||||
case CV_LeafKind_ALIAS:{result = str8_lit("ALIAS");}break;
|
||||
case CV_LeafKind_DEFARG:{result = str8_lit("DEFARG");}break;
|
||||
case CV_LeafKind_FRIENDFCN:{result = str8_lit("FRIENDFCN");}break;
|
||||
case CV_LeafKind_MEMBER:{result = str8_lit("MEMBER");}break;
|
||||
case CV_LeafKind_STMEMBER:{result = str8_lit("STMEMBER");}break;
|
||||
case CV_LeafKind_METHOD:{result = str8_lit("METHOD");}break;
|
||||
case CV_LeafKind_NESTTYPE:{result = str8_lit("NESTTYPE");}break;
|
||||
case CV_LeafKind_ONEMETHOD:{result = str8_lit("ONEMETHOD");}break;
|
||||
case CV_LeafKind_NESTTYPEEX:{result = str8_lit("NESTTYPEEX");}break;
|
||||
case CV_LeafKind_MEMBERMODIFY:{result = str8_lit("MEMBERMODIFY");}break;
|
||||
case CV_LeafKind_MANAGED:{result = str8_lit("MANAGED");}break;
|
||||
case CV_LeafKind_TYPESERVER2:{result = str8_lit("TYPESERVER2");}break;
|
||||
case CV_LeafKind_STRIDED_ARRAY:{result = str8_lit("STRIDED_ARRAY");}break;
|
||||
case CV_LeafKind_HLSL:{result = str8_lit("HLSL");}break;
|
||||
case CV_LeafKind_MODIFIER_EX:{result = str8_lit("MODIFIER_EX");}break;
|
||||
case CV_LeafKind_INTERFACE:{result = str8_lit("INTERFACE");}break;
|
||||
case CV_LeafKind_BINTERFACE:{result = str8_lit("BINTERFACE");}break;
|
||||
case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break;
|
||||
case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break;
|
||||
case CV_LeafKind_VFTABLE:{result = str8_lit("VFTABLE");}break;
|
||||
case CV_LeafKind_FUNC_ID:{result = str8_lit("FUNC_ID");}break;
|
||||
case CV_LeafKind_MFUNC_ID:{result = str8_lit("MFUNC_ID");}break;
|
||||
case CV_LeafKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
|
||||
case CV_LeafKind_SUBSTR_LIST:{result = str8_lit("SUBSTR_LIST");}break;
|
||||
case CV_LeafKind_STRING_ID:{result = str8_lit("STRING_ID");}break;
|
||||
case CV_LeafKind_UDT_SRC_LINE:{result = str8_lit("UDT_SRC_LINE");}break;
|
||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = str8_lit("UDT_MOD_SRC_LINE");}break;
|
||||
case CV_LeafKind_CLASS2:{result = str8_lit("CLASS2");}break;
|
||||
case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
cv_header_struct_size_from_sym_kind(CV_SymKind v)
|
||||
{
|
||||
U64 result = 0;
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_SymKind_COMPILE:{result = sizeof(CV_SymCompile);}break;
|
||||
case CV_SymKind_SSEARCH:{result = sizeof(CV_SymStartSearch);}break;
|
||||
case CV_SymKind_RETURN:{result = sizeof(CV_SymReturn);}break;
|
||||
case CV_SymKind_SLINK32:{result = sizeof(CV_SymSLink32);}break;
|
||||
case CV_SymKind_OEM:{result = sizeof(CV_SymOEM);}break;
|
||||
case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break;
|
||||
case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break;
|
||||
case CV_SymKind_ANNOTATION:{result = sizeof(CV_SymAnnotation);}break;
|
||||
case CV_SymKind_OBJNAME:{result = sizeof(CV_SymObjName);}break;
|
||||
case CV_SymKind_THUNK32:{result = sizeof(CV_SymThunk32);}break;
|
||||
case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break;
|
||||
case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break;
|
||||
case CV_SymKind_REGISTER:{result = sizeof(CV_SymRegister);}break;
|
||||
case CV_SymKind_CONSTANT:{result = sizeof(CV_SymConstant);}break;
|
||||
case CV_SymKind_UDT:{result = sizeof(CV_SymUDT);}break;
|
||||
case CV_SymKind_MANYREG:{result = sizeof(CV_SymManyreg);}break;
|
||||
case CV_SymKind_BPREL32:{result = sizeof(CV_SymBPRel32);}break;
|
||||
case CV_SymKind_LDATA32:{result = sizeof(CV_SymData32);}break;
|
||||
case CV_SymKind_GDATA32:{result = sizeof(CV_SymData32);}break;
|
||||
case CV_SymKind_PUB32:{result = sizeof(CV_SymPub32);}break;
|
||||
case CV_SymKind_LPROC32:{result = sizeof(CV_SymProc32);}break;
|
||||
case CV_SymKind_GPROC32:{result = sizeof(CV_SymProc32);}break;
|
||||
case CV_SymKind_REGREL32:{result = sizeof(CV_SymRegrel32);}break;
|
||||
case CV_SymKind_LTHREAD32:{result = sizeof(CV_SymThread32);}break;
|
||||
case CV_SymKind_GTHREAD32:{result = sizeof(CV_SymThread32);}break;
|
||||
case CV_SymKind_COMPILE2:{result = sizeof(CV_SymCompile2);}break;
|
||||
case CV_SymKind_MANYREG2:{result = sizeof(CV_SymManyreg2);}break;
|
||||
case CV_SymKind_LOCALSLOT:{result = sizeof(CV_SymSlot);}break;
|
||||
case CV_SymKind_MANFRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
|
||||
case CV_SymKind_MANREGISTER:{result = sizeof(CV_SymAttrReg);}break;
|
||||
case CV_SymKind_MANMANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
|
||||
case CV_SymKind_MANREGREL:{result = sizeof(CV_SymAttrRegRel);}break;
|
||||
case CV_SymKind_UNAMESPACE:{result = sizeof(CV_SymUNamespace);}break;
|
||||
case CV_SymKind_PROCREF:{result = sizeof(CV_SymRef2);}break;
|
||||
case CV_SymKind_DATAREF:{result = sizeof(CV_SymRef2);}break;
|
||||
case CV_SymKind_LPROCREF:{result = sizeof(CV_SymRef2);}break;
|
||||
case CV_SymKind_TRAMPOLINE:{result = sizeof(CV_SymTrampoline);}break;
|
||||
case CV_SymKind_ATTR_FRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
|
||||
case CV_SymKind_ATTR_REGISTER:{result = sizeof(CV_SymAttrReg);}break;
|
||||
case CV_SymKind_ATTR_REGREL:{result = sizeof(CV_SymAttrRegRel);}break;
|
||||
case CV_SymKind_ATTR_MANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
|
||||
case CV_SymKind_SEPCODE:{result = sizeof(CV_SymSepcode);}break;
|
||||
case CV_SymKind_SECTION:{result = sizeof(CV_SymSection);}break;
|
||||
case CV_SymKind_COFFGROUP:{result = sizeof(CV_SymCoffGroup);}break;
|
||||
case CV_SymKind_EXPORT:{result = sizeof(CV_SymExport);}break;
|
||||
case CV_SymKind_CALLSITEINFO:{result = sizeof(CV_SymCallSiteInfo);}break;
|
||||
case CV_SymKind_FRAMECOOKIE:{result = sizeof(CV_SymFrameCookie);}break;
|
||||
case CV_SymKind_DISCARDED:{result = sizeof(CV_SymDiscarded);}break;
|
||||
case CV_SymKind_COMPILE3:{result = sizeof(CV_SymCompile3);}break;
|
||||
case CV_SymKind_ENVBLOCK:{result = sizeof(CV_SymEnvBlock);}break;
|
||||
case CV_SymKind_LOCAL:{result = sizeof(CV_SymLocal);}break;
|
||||
case CV_SymKind_DEFRANGE_SUBFIELD:{result = sizeof(CV_SymDefrangeSubfield);}break;
|
||||
case CV_SymKind_DEFRANGE_REGISTER:{result = sizeof(CV_SymDefrangeRegister);}break;
|
||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = sizeof(CV_SymDefrangeFramepointerRel);}break;
|
||||
case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = sizeof(CV_SymDefrangeSubfieldRegister);}break;
|
||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = sizeof(CV_SymDefrangeFramepointerRelFullScope);}break;
|
||||
case CV_SymKind_DEFRANGE_REGISTER_REL:{result = sizeof(CV_SymDefrangeRegisterRel);}break;
|
||||
case CV_SymKind_BUILDINFO:{result = sizeof(CV_SymBuildInfo);}break;
|
||||
case CV_SymKind_INLINESITE:{result = sizeof(CV_SymInlineSite);}break;
|
||||
case CV_SymKind_FILESTATIC:{result = sizeof(CV_SymFileStatic);}break;
|
||||
case CV_SymKind_CALLEES:{result = sizeof(CV_SymFunctionList);}break;
|
||||
case CV_SymKind_CALLERS:{result = sizeof(CV_SymFunctionList);}break;
|
||||
case CV_SymKind_POGODATA:{result = sizeof(CV_SymPogoInfo);}break;
|
||||
case CV_SymKind_INLINESITE2:{result = sizeof(CV_SymInlineSite2);}break;
|
||||
case CV_SymKind_HEAPALLOCSITE:{result = sizeof(CV_SymHeapAllocSite);}break;
|
||||
case CV_SymKind_MOD_TYPEREF:{result = sizeof(CV_SymModTypeRef);}break;
|
||||
case CV_SymKind_REF_MINIPDB:{result = sizeof(CV_SymRefMiniPdb);}break;
|
||||
case CV_SymKind_FASTLINK:{result = sizeof(CV_SymFastLink);}break;
|
||||
case CV_SymKind_INLINEES:{result = sizeof(CV_SymInlinees);}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
internal U64
|
||||
cv_header_struct_size_from_leaf_kind(CV_LeafKind v)
|
||||
{
|
||||
U64 result = 0;
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_LeafKind_VTSHAPE:{result = sizeof(CV_LeafVTShape);}break;
|
||||
case CV_LeafKind_LABEL:{result = sizeof(CV_LeafLabel);}break;
|
||||
case CV_LeafKind_MODIFIER:{result = sizeof(CV_LeafModifier);}break;
|
||||
case CV_LeafKind_POINTER:{result = sizeof(CV_LeafPointer);}break;
|
||||
case CV_LeafKind_PROCEDURE:{result = sizeof(CV_LeafProcedure);}break;
|
||||
case CV_LeafKind_MFUNCTION:{result = sizeof(CV_LeafMFunction);}break;
|
||||
case CV_LeafKind_VFTPATH:{result = sizeof(CV_LeafVFPath);}break;
|
||||
case CV_LeafKind_SKIP:{result = sizeof(CV_LeafSkip);}break;
|
||||
case CV_LeafKind_ARGLIST:{result = sizeof(CV_LeafArgList);}break;
|
||||
case CV_LeafKind_BITFIELD:{result = sizeof(CV_LeafBitField);}break;
|
||||
case CV_LeafKind_METHODLIST:{result = sizeof(CV_LeafMethodListMember);}break;
|
||||
case CV_LeafKind_BCLASS:{result = sizeof(CV_LeafBClass);}break;
|
||||
case CV_LeafKind_VBCLASS:{result = sizeof(CV_LeafVBClass);}break;
|
||||
case CV_LeafKind_INDEX:{result = sizeof(CV_LeafIndex);}break;
|
||||
case CV_LeafKind_VFUNCTAB:{result = sizeof(CV_LeafVFuncTab);}break;
|
||||
case CV_LeafKind_VFUNCOFF:{result = sizeof(CV_LeafVFuncOff);}break;
|
||||
case CV_LeafKind_TYPESERVER:{result = sizeof(CV_LeafTypeServer);}break;
|
||||
case CV_LeafKind_ENUMERATE:{result = sizeof(CV_LeafEnumerate);}break;
|
||||
case CV_LeafKind_ARRAY:{result = sizeof(CV_LeafArray);}break;
|
||||
case CV_LeafKind_CLASS:{result = sizeof(CV_LeafStruct);}break;
|
||||
case CV_LeafKind_STRUCTURE:{result = sizeof(CV_LeafStruct);}break;
|
||||
case CV_LeafKind_UNION:{result = sizeof(CV_LeafUnion);}break;
|
||||
case CV_LeafKind_ENUM:{result = sizeof(CV_LeafEnum);}break;
|
||||
case CV_LeafKind_PRECOMP:{result = sizeof(CV_LeafPreComp);}break;
|
||||
case CV_LeafKind_ALIAS:{result = sizeof(CV_LeafAlias);}break;
|
||||
case CV_LeafKind_MEMBER:{result = sizeof(CV_LeafMember);}break;
|
||||
case CV_LeafKind_STMEMBER:{result = sizeof(CV_LeafStMember);}break;
|
||||
case CV_LeafKind_METHOD:{result = sizeof(CV_LeafMethod);}break;
|
||||
case CV_LeafKind_NESTTYPE:{result = sizeof(CV_LeafNestType);}break;
|
||||
case CV_LeafKind_ONEMETHOD:{result = sizeof(CV_LeafOneMethod);}break;
|
||||
case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break;
|
||||
case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break;
|
||||
case CV_LeafKind_INTERFACE:{result = sizeof(CV_LeafStruct);}break;
|
||||
case CV_LeafKind_FUNC_ID:{result = sizeof(CV_LeafFuncId);}break;
|
||||
case CV_LeafKind_MFUNC_ID:{result = sizeof(CV_LeafMFuncId);}break;
|
||||
case CV_LeafKind_BUILDINFO:{result = sizeof(CV_LeafBuildInfo);}break;
|
||||
case CV_LeafKind_SUBSTR_LIST:{result = sizeof(CV_LeafSubstrList);}break;
|
||||
case CV_LeafKind_STRING_ID:{result = sizeof(CV_LeafStringId);}break;
|
||||
case CV_LeafKind_UDT_SRC_LINE:{result = sizeof(CV_LeafUDTSrcLine);}break;
|
||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = sizeof(CV_LeafUDTModSrcLine);}break;
|
||||
case CV_LeafKind_CLASS2:{result = sizeof(CV_LeafStruct2);}break;
|
||||
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,528 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef CODEVIEW_META_H
|
||||
#define CODEVIEW_META_H
|
||||
|
||||
typedef U16 CV_NumericKind;
|
||||
typedef enum CV_NumericKindEnum
|
||||
{
|
||||
CV_NumericKind_CHAR = 0x8000,
|
||||
CV_NumericKind_SHORT = 0x8001,
|
||||
CV_NumericKind_USHORT = 0x8002,
|
||||
CV_NumericKind_LONG = 0x8003,
|
||||
CV_NumericKind_ULONG = 0x8004,
|
||||
CV_NumericKind_FLOAT32 = 0x8005,
|
||||
CV_NumericKind_FLOAT64 = 0x8006,
|
||||
CV_NumericKind_FLOAT80 = 0x8007,
|
||||
CV_NumericKind_FLOAT128 = 0x8008,
|
||||
CV_NumericKind_QUADWORD = 0x8009,
|
||||
CV_NumericKind_UQUADWORD = 0x800a,
|
||||
CV_NumericKind_FLOAT48 = 0x800b,
|
||||
CV_NumericKind_COMPLEX32 = 0x800c,
|
||||
CV_NumericKind_COMPLEX64 = 0x800d,
|
||||
CV_NumericKind_COMPLEX80 = 0x800e,
|
||||
CV_NumericKind_COMPLEX128 = 0x800f,
|
||||
CV_NumericKind_VARSTRING = 0x8010,
|
||||
CV_NumericKind_OCTWORD = 0x8017,
|
||||
CV_NumericKind_UOCTWORD = 0x8018,
|
||||
CV_NumericKind_DECIMAL = 0x8019,
|
||||
CV_NumericKind_DATE = 0x801a,
|
||||
CV_NumericKind_UTF8STRING = 0x801b,
|
||||
CV_NumericKind_FLOAT16 = 0x801c,
|
||||
} CV_NumericKindEnum;
|
||||
|
||||
typedef U16 CV_Arch;
|
||||
typedef enum CV_ArchEnum
|
||||
{
|
||||
CV_Arch_8080 = 0x00,
|
||||
CV_Arch_8086 = 0x01,
|
||||
CV_Arch_80286 = 0x02,
|
||||
CV_Arch_80386 = 0x03,
|
||||
CV_Arch_80486 = 0x04,
|
||||
CV_Arch_PENTIUM = 0x05,
|
||||
CV_Arch_PENTIUMII = 0x06,
|
||||
CV_Arch_PENTIUMIII = 0x07,
|
||||
CV_Arch_MIPS = 0x10,
|
||||
CV_Arch_MIPS16 = 0x11,
|
||||
CV_Arch_MIPS32 = 0x12,
|
||||
CV_Arch_MIPS64 = 0x13,
|
||||
CV_Arch_MIPSI = 0x14,
|
||||
CV_Arch_MIPSII = 0x15,
|
||||
CV_Arch_MIPSIII = 0x16,
|
||||
CV_Arch_MIPSIV = 0x17,
|
||||
CV_Arch_MIPSV = 0x18,
|
||||
CV_Arch_M68000 = 0x20,
|
||||
CV_Arch_M68010 = 0x21,
|
||||
CV_Arch_M68020 = 0x22,
|
||||
CV_Arch_M68030 = 0x23,
|
||||
CV_Arch_M68040 = 0x24,
|
||||
CV_Arch_ALPHA = 0x30,
|
||||
CV_Arch_ALPHA_21164 = 0x31,
|
||||
CV_Arch_ALPHA_21164A = 0x32,
|
||||
CV_Arch_ALPHA_21264 = 0x33,
|
||||
CV_Arch_ALPHA_21364 = 0x34,
|
||||
CV_Arch_PPC601 = 0x40,
|
||||
CV_Arch_PPC603 = 0x41,
|
||||
CV_Arch_PPC604 = 0x42,
|
||||
CV_Arch_PPC620 = 0x43,
|
||||
CV_Arch_PPCFP = 0x44,
|
||||
CV_Arch_PPCBE = 0x45,
|
||||
CV_Arch_SH3 = 0x50,
|
||||
CV_Arch_SH3E = 0x51,
|
||||
CV_Arch_SH3DSP = 0x52,
|
||||
CV_Arch_SH4 = 0x53,
|
||||
CV_Arch_SHMEDIA = 0x54,
|
||||
CV_Arch_ARM3 = 0x60,
|
||||
CV_Arch_ARM4 = 0x61,
|
||||
CV_Arch_ARM4T = 0x62,
|
||||
CV_Arch_ARM5 = 0x63,
|
||||
CV_Arch_ARM5T = 0x64,
|
||||
CV_Arch_ARM6 = 0x65,
|
||||
CV_Arch_ARM_XMAC = 0x66,
|
||||
CV_Arch_ARM_WMMX = 0x67,
|
||||
CV_Arch_ARM7 = 0x68,
|
||||
CV_Arch_OMNI = 0x70,
|
||||
CV_Arch_IA64_1 = 0x80,
|
||||
CV_Arch_IA64_2 = 0x81,
|
||||
CV_Arch_CEE = 0x90,
|
||||
CV_Arch_AM33 = 0xA0,
|
||||
CV_Arch_M32R = 0xB0,
|
||||
CV_Arch_TRICORE = 0xC0,
|
||||
CV_Arch_X64 = 0xD0,
|
||||
CV_Arch_EBC = 0xE0,
|
||||
CV_Arch_THUMB = 0xF0,
|
||||
CV_Arch_ARMNT = 0xF4,
|
||||
CV_Arch_ARM64 = 0xF6,
|
||||
CV_Arch_D3D11_SHADER = 0x100,
|
||||
CV_Arch_IA64 = CV_Arch_IA64_1,
|
||||
CV_Arch_PENTIUMPRO = CV_Arch_PENTIUMII,
|
||||
CV_Arch_MIPSR4000 = CV_Arch_MIPS,
|
||||
CV_Arch_ALPHA_21064 = CV_Arch_ALPHA,
|
||||
CV_Arch_AMD64 = CV_Arch_X64,
|
||||
} CV_ArchEnum;
|
||||
|
||||
typedef U16 CV_AllReg;
|
||||
typedef enum CV_AllRegEnum
|
||||
{
|
||||
CV_AllReg_ERR = 30000,
|
||||
CV_AllReg_TEB = 30001,
|
||||
CV_AllReg_TIMER = 30002,
|
||||
CV_AllReg_EFAD1 = 30003,
|
||||
CV_AllReg_EFAD2 = 30004,
|
||||
CV_AllReg_EFAD3 = 30005,
|
||||
CV_AllReg_VFRAME = 30006,
|
||||
CV_AllReg_HANDLE = 30007,
|
||||
CV_AllReg_PARAMS = 30008,
|
||||
CV_AllReg_LOCALS = 30009,
|
||||
CV_AllReg_TID = 30010,
|
||||
CV_AllReg_ENV = 30011,
|
||||
CV_AllReg_CMDLN = 30012,
|
||||
} CV_AllRegEnum;
|
||||
|
||||
typedef U16 CV_SymKind;
|
||||
typedef enum CV_SymKindEnum
|
||||
{
|
||||
CV_SymKind_COMPILE = 0x0001,
|
||||
CV_SymKind_REGISTER_16t = 0x0002,
|
||||
CV_SymKind_CONSTANT_16t = 0x0003,
|
||||
CV_SymKind_UDT_16t = 0x0004,
|
||||
CV_SymKind_SSEARCH = 0x0005,
|
||||
CV_SymKind_END = 0x0006,
|
||||
CV_SymKind_SKIP = 0x0007,
|
||||
CV_SymKind_CVRESERVE = 0x0008,
|
||||
CV_SymKind_OBJNAME_ST = 0x0009,
|
||||
CV_SymKind_ENDARG = 0x000a,
|
||||
CV_SymKind_COBOLUDT_16t = 0x000b,
|
||||
CV_SymKind_MANYREG_16t = 0x000c,
|
||||
CV_SymKind_RETURN = 0x000d,
|
||||
CV_SymKind_ENTRYTHIS = 0x000e,
|
||||
CV_SymKind_BPREL16 = 0x0100,
|
||||
CV_SymKind_LDATA16 = 0x0101,
|
||||
CV_SymKind_GDATA16 = 0x0102,
|
||||
CV_SymKind_PUB16 = 0x0103,
|
||||
CV_SymKind_LPROC16 = 0x0104,
|
||||
CV_SymKind_GPROC16 = 0x0105,
|
||||
CV_SymKind_THUNK16 = 0x0106,
|
||||
CV_SymKind_BLOCK16 = 0x0107,
|
||||
CV_SymKind_WITH16 = 0x0108,
|
||||
CV_SymKind_LABEL16 = 0x0109,
|
||||
CV_SymKind_CEXMODEL16 = 0x010a,
|
||||
CV_SymKind_VFTABLE16 = 0x010b,
|
||||
CV_SymKind_REGREL16 = 0x010c,
|
||||
CV_SymKind_BPREL32_16t = 0x0200,
|
||||
CV_SymKind_LDATA32_16t = 0x0201,
|
||||
CV_SymKind_GDATA32_16t = 0x0202,
|
||||
CV_SymKind_PUB32_16t = 0x0203,
|
||||
CV_SymKind_LPROC32_16t = 0x0204,
|
||||
CV_SymKind_GPROC32_16t = 0x0205,
|
||||
CV_SymKind_THUNK32_ST = 0x0206,
|
||||
CV_SymKind_BLOCK32_ST = 0x0207,
|
||||
CV_SymKind_WITH32_ST = 0x0208,
|
||||
CV_SymKind_LABEL32_ST = 0x0209,
|
||||
CV_SymKind_CEXMODEL32 = 0x020a,
|
||||
CV_SymKind_VFTABLE32_16t = 0x020b,
|
||||
CV_SymKind_REGREL32_16t = 0x020c,
|
||||
CV_SymKind_LTHREAD32_16t = 0x020d,
|
||||
CV_SymKind_GTHREAD32_16t = 0x020e,
|
||||
CV_SymKind_SLINK32 = 0x020f,
|
||||
CV_SymKind_LPROCMIPS_16t = 0x0300,
|
||||
CV_SymKind_GPROCMIPS_16t = 0x0301,
|
||||
CV_SymKind_PROCREF_ST = 0x0400,
|
||||
CV_SymKind_DATAREF_ST = 0x0401,
|
||||
CV_SymKind_ALIGN = 0x0402,
|
||||
CV_SymKind_LPROCREF_ST = 0x0403,
|
||||
CV_SymKind_OEM = 0x0404,
|
||||
CV_SymKind_TI16_MAX = 0x1000,
|
||||
CV_SymKind_CONSTANT_ST = 0x1002,
|
||||
CV_SymKind_UDT_ST = 0x1003,
|
||||
CV_SymKind_COBOLUDT_ST = 0x1004,
|
||||
CV_SymKind_MANYREG_ST = 0x1005,
|
||||
CV_SymKind_BPREL32_ST = 0x1006,
|
||||
CV_SymKind_LDATA32_ST = 0x1007,
|
||||
CV_SymKind_GDATA32_ST = 0x1008,
|
||||
CV_SymKind_PUB32_ST = 0x1009,
|
||||
CV_SymKind_LPROC32_ST = 0x100a,
|
||||
CV_SymKind_GPROC32_ST = 0x100b,
|
||||
CV_SymKind_VFTABLE32 = 0x100c,
|
||||
CV_SymKind_REGREL32_ST = 0x100d,
|
||||
CV_SymKind_LTHREAD32_ST = 0x100e,
|
||||
CV_SymKind_GTHREAD32_ST = 0x100f,
|
||||
CV_SymKind_LPROCMIPS_ST = 0x1010,
|
||||
CV_SymKind_GPROCMIPS_ST = 0x1011,
|
||||
CV_SymKind_FRAMEPROC = 0x1012,
|
||||
CV_SymKind_COMPILE2_ST = 0x1013,
|
||||
CV_SymKind_MANYREG2_ST = 0x1014,
|
||||
CV_SymKind_LPROCIA64_ST = 0x1015,
|
||||
CV_SymKind_GPROCIA64_ST = 0x1016,
|
||||
CV_SymKind_LOCALSLOT_ST = 0x1017,
|
||||
CV_SymKind_PARAMSLOT_ST = 0x1018,
|
||||
CV_SymKind_ANNOTATION = 0x1019,
|
||||
CV_SymKind_GMANPROC_ST = 0x101a,
|
||||
CV_SymKind_LMANPROC_ST = 0x101b,
|
||||
CV_SymKind_RESERVED1 = 0x101c,
|
||||
CV_SymKind_RESERVED2 = 0x101d,
|
||||
CV_SymKind_RESERVED3 = 0x101e,
|
||||
CV_SymKind_RESERVED4 = 0x101f,
|
||||
CV_SymKind_LMANDATA_ST = 0x1020,
|
||||
CV_SymKind_GMANDATA_ST = 0x1021,
|
||||
CV_SymKind_MANFRAMEREL_ST = 0x1022,
|
||||
CV_SymKind_MANREGISTER_ST = 0x1023,
|
||||
CV_SymKind_MANSLOT_ST = 0x1024,
|
||||
CV_SymKind_MANMANYREG_ST = 0x1025,
|
||||
CV_SymKind_MANREGREL_ST = 0x1026,
|
||||
CV_SymKind_MANMANYREG2_ST = 0x1027,
|
||||
CV_SymKind_MANTYPREF = 0x1028,
|
||||
CV_SymKind_UNAMESPACE_ST = 0x1029,
|
||||
CV_SymKind_ST_MAX = 0x1100,
|
||||
CV_SymKind_OBJNAME = 0x1101,
|
||||
CV_SymKind_THUNK32 = 0x1102,
|
||||
CV_SymKind_BLOCK32 = 0x1103,
|
||||
CV_SymKind_WITH32 = 0x1104,
|
||||
CV_SymKind_LABEL32 = 0x1105,
|
||||
CV_SymKind_REGISTER = 0x1106,
|
||||
CV_SymKind_CONSTANT = 0x1107,
|
||||
CV_SymKind_UDT = 0x1108,
|
||||
CV_SymKind_COBOLUDT = 0x1109,
|
||||
CV_SymKind_MANYREG = 0x110a,
|
||||
CV_SymKind_BPREL32 = 0x110b,
|
||||
CV_SymKind_LDATA32 = 0x110c,
|
||||
CV_SymKind_GDATA32 = 0x110d,
|
||||
CV_SymKind_PUB32 = 0x110e,
|
||||
CV_SymKind_LPROC32 = 0x110f,
|
||||
CV_SymKind_GPROC32 = 0x1110,
|
||||
CV_SymKind_REGREL32 = 0x1111,
|
||||
CV_SymKind_LTHREAD32 = 0x1112,
|
||||
CV_SymKind_GTHREAD32 = 0x1113,
|
||||
CV_SymKind_LPROCMIPS = 0x1114,
|
||||
CV_SymKind_GPROCMIPS = 0x1115,
|
||||
CV_SymKind_COMPILE2 = 0x1116,
|
||||
CV_SymKind_MANYREG2 = 0x1117,
|
||||
CV_SymKind_LPROCIA64 = 0x1118,
|
||||
CV_SymKind_GPROCIA64 = 0x1119,
|
||||
CV_SymKind_LOCALSLOT = 0x111a,
|
||||
CV_SymKind_PARAMSLOT = 0x111b,
|
||||
CV_SymKind_LMANDATA = 0x111c,
|
||||
CV_SymKind_GMANDATA = 0x111d,
|
||||
CV_SymKind_MANFRAMEREL = 0x111e,
|
||||
CV_SymKind_MANREGISTER = 0x111f,
|
||||
CV_SymKind_MANSLOT = 0x1120,
|
||||
CV_SymKind_MANMANYREG = 0x1121,
|
||||
CV_SymKind_MANREGREL = 0x1122,
|
||||
CV_SymKind_MANMANYREG2 = 0x1123,
|
||||
CV_SymKind_UNAMESPACE = 0x1124,
|
||||
CV_SymKind_PROCREF = 0x1125,
|
||||
CV_SymKind_DATAREF = 0x1126,
|
||||
CV_SymKind_LPROCREF = 0x1127,
|
||||
CV_SymKind_ANNOTATIONREF = 0x1128,
|
||||
CV_SymKind_TOKENREF = 0x1129,
|
||||
CV_SymKind_GMANPROC = 0x112a,
|
||||
CV_SymKind_LMANPROC = 0x112b,
|
||||
CV_SymKind_TRAMPOLINE = 0x112c,
|
||||
CV_SymKind_MANCONSTANT = 0x112d,
|
||||
CV_SymKind_ATTR_FRAMEREL = 0x112e,
|
||||
CV_SymKind_ATTR_REGISTER = 0x112f,
|
||||
CV_SymKind_ATTR_REGREL = 0x1130,
|
||||
CV_SymKind_ATTR_MANYREG = 0x1131,
|
||||
CV_SymKind_SEPCODE = 0x1132,
|
||||
CV_SymKind_DEFRANGE_2005 = 0x1134,
|
||||
CV_SymKind_DEFRANGE2_2005 = 0x1135,
|
||||
CV_SymKind_SECTION = 0x1136,
|
||||
CV_SymKind_COFFGROUP = 0x1137,
|
||||
CV_SymKind_EXPORT = 0x1138,
|
||||
CV_SymKind_CALLSITEINFO = 0x1139,
|
||||
CV_SymKind_FRAMECOOKIE = 0x113a,
|
||||
CV_SymKind_DISCARDED = 0x113b,
|
||||
CV_SymKind_COMPILE3 = 0x113c,
|
||||
CV_SymKind_ENVBLOCK = 0x113d,
|
||||
CV_SymKind_LOCAL = 0x113e,
|
||||
CV_SymKind_DEFRANGE = 0x113f,
|
||||
CV_SymKind_DEFRANGE_SUBFIELD = 0x1140,
|
||||
CV_SymKind_DEFRANGE_REGISTER = 0x1141,
|
||||
CV_SymKind_DEFRANGE_FRAMEPOINTER_REL = 0x1142,
|
||||
CV_SymKind_DEFRANGE_SUBFIELD_REGISTER = 0x1143,
|
||||
CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 0x1144,
|
||||
CV_SymKind_DEFRANGE_REGISTER_REL = 0x1145,
|
||||
CV_SymKind_LPROC32_ID = 0x1146,
|
||||
CV_SymKind_GPROC32_ID = 0x1147,
|
||||
CV_SymKind_LPROCMIPS_ID = 0x1148,
|
||||
CV_SymKind_GPROCMIPS_ID = 0x1149,
|
||||
CV_SymKind_LPROCIA64_ID = 0x114a,
|
||||
CV_SymKind_GPROCIA64_ID = 0x114b,
|
||||
CV_SymKind_BUILDINFO = 0x114c,
|
||||
CV_SymKind_INLINESITE = 0x114d,
|
||||
CV_SymKind_INLINESITE_END = 0x114e,
|
||||
CV_SymKind_PROC_ID_END = 0x114f,
|
||||
CV_SymKind_DEFRANGE_HLSL = 0x1150,
|
||||
CV_SymKind_GDATA_HLSL = 0x1151,
|
||||
CV_SymKind_LDATA_HLSL = 0x1152,
|
||||
CV_SymKind_FILESTATIC = 0x1153,
|
||||
CV_SymKind_LPROC32_DPC = 0x1155,
|
||||
CV_SymKind_LPROC32_DPC_ID = 0x1156,
|
||||
CV_SymKind_DEFRANGE_DPC_PTR_TAG = 0x1157,
|
||||
CV_SymKind_DPC_SYM_TAG_MAP = 0x1158,
|
||||
CV_SymKind_ARMSWITCHTABLE = 0x1159,
|
||||
CV_SymKind_CALLEES = 0x115a,
|
||||
CV_SymKind_CALLERS = 0x115b,
|
||||
CV_SymKind_POGODATA = 0x115c,
|
||||
CV_SymKind_INLINESITE2 = 0x115d,
|
||||
CV_SymKind_HEAPALLOCSITE = 0x115e,
|
||||
CV_SymKind_MOD_TYPEREF = 0x115f,
|
||||
CV_SymKind_REF_MINIPDB = 0x1160,
|
||||
CV_SymKind_PDBMAP = 0x1161,
|
||||
CV_SymKind_GDATA_HLSL32 = 0x1162,
|
||||
CV_SymKind_LDATA_HLSL32 = 0x1163,
|
||||
CV_SymKind_GDATA_HLSL32_EX = 0x1164,
|
||||
CV_SymKind_LDATA_HLSL32_EX = 0x1165,
|
||||
CV_SymKind_FASTLINK = 0x1167,
|
||||
CV_SymKind_INLINEES = 0x1168,
|
||||
} CV_SymKindEnum;
|
||||
|
||||
typedef U8 CV_BasicType;
|
||||
typedef enum CV_BasicTypeEnum
|
||||
{
|
||||
CV_BasicType_NOTYPE = 0x00,
|
||||
CV_BasicType_ABS = 0x01,
|
||||
CV_BasicType_SEGMENT = 0x02,
|
||||
CV_BasicType_VOID = 0x03,
|
||||
CV_BasicType_CURRENCY = 0x04,
|
||||
CV_BasicType_NBASICSTR = 0x05,
|
||||
CV_BasicType_FBASICSTR = 0x06,
|
||||
CV_BasicType_NOTTRANS = 0x07,
|
||||
CV_BasicType_HRESULT = 0x08,
|
||||
CV_BasicType_CHAR = 0x10,
|
||||
CV_BasicType_SHORT = 0x11,
|
||||
CV_BasicType_LONG = 0x12,
|
||||
CV_BasicType_QUAD = 0x13,
|
||||
CV_BasicType_OCT = 0x14,
|
||||
CV_BasicType_UCHAR = 0x20,
|
||||
CV_BasicType_USHORT = 0x21,
|
||||
CV_BasicType_ULONG = 0x22,
|
||||
CV_BasicType_UQUAD = 0x23,
|
||||
CV_BasicType_UOCT = 0x24,
|
||||
CV_BasicType_BOOL8 = 0x30,
|
||||
CV_BasicType_BOOL16 = 0x31,
|
||||
CV_BasicType_BOOL32 = 0x32,
|
||||
CV_BasicType_BOOL64 = 0x33,
|
||||
CV_BasicType_FLOAT32 = 0x40,
|
||||
CV_BasicType_FLOAT64 = 0x41,
|
||||
CV_BasicType_FLOAT80 = 0x42,
|
||||
CV_BasicType_FLOAT128 = 0x43,
|
||||
CV_BasicType_FLOAT48 = 0x44,
|
||||
CV_BasicType_FLOAT32PP = 0x45,
|
||||
CV_BasicType_FLOAT16 = 0x46,
|
||||
CV_BasicType_COMPLEX32 = 0x50,
|
||||
CV_BasicType_COMPLEX64 = 0x51,
|
||||
CV_BasicType_COMPLEX80 = 0x52,
|
||||
CV_BasicType_COMPLEX128 = 0x53,
|
||||
CV_BasicType_BIT = 0x60,
|
||||
CV_BasicType_PASCHAR = 0x61,
|
||||
CV_BasicType_BOOL32FF = 0x62,
|
||||
CV_BasicType_INT8 = 0x68,
|
||||
CV_BasicType_UINT8 = 0x69,
|
||||
CV_BasicType_RCHAR = 0x70,
|
||||
CV_BasicType_WCHAR = 0x71,
|
||||
CV_BasicType_INT16 = 0x72,
|
||||
CV_BasicType_UINT16 = 0x73,
|
||||
CV_BasicType_INT32 = 0x74,
|
||||
CV_BasicType_UINT32 = 0x75,
|
||||
CV_BasicType_INT64 = 0x76,
|
||||
CV_BasicType_UINT64 = 0x77,
|
||||
CV_BasicType_INT128 = 0x78,
|
||||
CV_BasicType_UINT128 = 0x79,
|
||||
CV_BasicType_CHAR16 = 0x7a,
|
||||
CV_BasicType_CHAR32 = 0x7b,
|
||||
CV_BasicType_CHAR8 = 0x7c,
|
||||
CV_BasicType_PTR = 0xf0,
|
||||
} CV_BasicTypeEnum;
|
||||
|
||||
typedef U16 CV_LeafKind;
|
||||
typedef enum CV_LeafKindEnum
|
||||
{
|
||||
CV_LeafKind_NOTYPE = 0x0000,
|
||||
CV_LeafKind_MODIFIER_16t = 0x0001,
|
||||
CV_LeafKind_POINTER_16t = 0x0002,
|
||||
CV_LeafKind_ARRAY_16t = 0x0003,
|
||||
CV_LeafKind_CLASS_16t = 0x0004,
|
||||
CV_LeafKind_STRUCTURE_16t = 0x0005,
|
||||
CV_LeafKind_UNION_16t = 0x0006,
|
||||
CV_LeafKind_ENUM_16t = 0x0007,
|
||||
CV_LeafKind_PROCEDURE_16t = 0x0008,
|
||||
CV_LeafKind_MFUNCTION_16t = 0x0009,
|
||||
CV_LeafKind_VTSHAPE = 0x000a,
|
||||
CV_LeafKind_COBOL0_16t = 0x000b,
|
||||
CV_LeafKind_COBOL1 = 0x000c,
|
||||
CV_LeafKind_BARRAY_16t = 0x000d,
|
||||
CV_LeafKind_LABEL = 0x000e,
|
||||
CV_LeafKind_NULL = 0x000f,
|
||||
CV_LeafKind_NOTTRAN = 0x0010,
|
||||
CV_LeafKind_DIMARRAY_16t = 0x0011,
|
||||
CV_LeafKind_VFTPATH_16t = 0x0012,
|
||||
CV_LeafKind_PRECOMP_16t = 0x0013,
|
||||
CV_LeafKind_ENDPRECOMP = 0x0014,
|
||||
CV_LeafKind_OEM_16t = 0x0015,
|
||||
CV_LeafKind_TYPESERVER_ST = 0x0016,
|
||||
CV_LeafKind_SKIP_16t = 0x0200,
|
||||
CV_LeafKind_ARGLIST_16t = 0x0201,
|
||||
CV_LeafKind_DEFARG_16t = 0x0202,
|
||||
CV_LeafKind_LIST = 0x0203,
|
||||
CV_LeafKind_FIELDLIST_16t = 0x0204,
|
||||
CV_LeafKind_DERIVED_16t = 0x0205,
|
||||
CV_LeafKind_BITFIELD_16t = 0x0206,
|
||||
CV_LeafKind_METHODLIST_16t = 0x0207,
|
||||
CV_LeafKind_DIMCONU_16t = 0x0208,
|
||||
CV_LeafKind_DIMCONLU_16t = 0x0209,
|
||||
CV_LeafKind_DIMVARU_16t = 0x020a,
|
||||
CV_LeafKind_DIMVARLU_16t = 0x020b,
|
||||
CV_LeafKind_REFSYM = 0x020c,
|
||||
CV_LeafKind_BCLASS_16t = 0x0400,
|
||||
CV_LeafKind_VBCLASS_16t = 0x0401,
|
||||
CV_LeafKind_IVBCLASS_16t = 0x0402,
|
||||
CV_LeafKind_ENUMERATE_ST = 0x0403,
|
||||
CV_LeafKind_FRIENDFCN_16t = 0x0404,
|
||||
CV_LeafKind_INDEX_16t = 0x0405,
|
||||
CV_LeafKind_MEMBER_16t = 0x0406,
|
||||
CV_LeafKind_STMEMBER_16t = 0x0407,
|
||||
CV_LeafKind_METHOD_16t = 0x0408,
|
||||
CV_LeafKind_NESTTYPE_16t = 0x0409,
|
||||
CV_LeafKind_VFUNCTAB_16t = 0x040a,
|
||||
CV_LeafKind_FRIENDCLS_16t = 0x040b,
|
||||
CV_LeafKind_ONEMETHOD_16t = 0x040c,
|
||||
CV_LeafKind_VFUNCOFF_16t = 0x040d,
|
||||
CV_LeafKind_TI16_MAX = 0x1000,
|
||||
CV_LeafKind_MODIFIER = 0x1001,
|
||||
CV_LeafKind_POINTER = 0x1002,
|
||||
CV_LeafKind_ARRAY_ST = 0x1003,
|
||||
CV_LeafKind_CLASS_ST = 0x1004,
|
||||
CV_LeafKind_STRUCTURE_ST = 0x1005,
|
||||
CV_LeafKind_UNION_ST = 0x1006,
|
||||
CV_LeafKind_ENUM_ST = 0x1007,
|
||||
CV_LeafKind_PROCEDURE = 0x1008,
|
||||
CV_LeafKind_MFUNCTION = 0x1009,
|
||||
CV_LeafKind_COBOL0 = 0x100a,
|
||||
CV_LeafKind_BARRAY = 0x100b,
|
||||
CV_LeafKind_DIMARRAY_ST = 0x100c,
|
||||
CV_LeafKind_VFTPATH = 0x100d,
|
||||
CV_LeafKind_PRECOMP_ST = 0x100e,
|
||||
CV_LeafKind_OEM = 0x100f,
|
||||
CV_LeafKind_ALIAS_ST = 0x1010,
|
||||
CV_LeafKind_OEM2 = 0x1011,
|
||||
CV_LeafKind_SKIP = 0x1200,
|
||||
CV_LeafKind_ARGLIST = 0x1201,
|
||||
CV_LeafKind_DEFARG_ST = 0x1202,
|
||||
CV_LeafKind_FIELDLIST = 0x1203,
|
||||
CV_LeafKind_DERIVED = 0x1204,
|
||||
CV_LeafKind_BITFIELD = 0x1205,
|
||||
CV_LeafKind_METHODLIST = 0x1206,
|
||||
CV_LeafKind_DIMCONU = 0x1207,
|
||||
CV_LeafKind_DIMCONLU = 0x1208,
|
||||
CV_LeafKind_DIMVARU = 0x1209,
|
||||
CV_LeafKind_DIMVARLU = 0x120a,
|
||||
CV_LeafKind_BCLASS = 0x1400,
|
||||
CV_LeafKind_VBCLASS = 0x1401,
|
||||
CV_LeafKind_IVBCLASS = 0x1402,
|
||||
CV_LeafKind_FRIENDFCN_ST = 0x1403,
|
||||
CV_LeafKind_INDEX = 0x1404,
|
||||
CV_LeafKind_MEMBER_ST = 0x1405,
|
||||
CV_LeafKind_STMEMBER_ST = 0x1406,
|
||||
CV_LeafKind_METHOD_ST = 0x1407,
|
||||
CV_LeafKind_NESTTYPE_ST = 0x1408,
|
||||
CV_LeafKind_VFUNCTAB = 0x1409,
|
||||
CV_LeafKind_FRIENDCLS = 0x140a,
|
||||
CV_LeafKind_ONEMETHOD_ST = 0x140b,
|
||||
CV_LeafKind_VFUNCOFF = 0x140c,
|
||||
CV_LeafKind_NESTTYPEEX_ST = 0x140d,
|
||||
CV_LeafKind_MEMBERMODIFY_ST = 0x140e,
|
||||
CV_LeafKind_MANAGED_ST = 0x140f,
|
||||
CV_LeafKind_ST_MAX = 0x1500,
|
||||
CV_LeafKind_TYPESERVER = 0x1501,
|
||||
CV_LeafKind_ENUMERATE = 0x1502,
|
||||
CV_LeafKind_ARRAY = 0x1503,
|
||||
CV_LeafKind_CLASS = 0x1504,
|
||||
CV_LeafKind_STRUCTURE = 0x1505,
|
||||
CV_LeafKind_UNION = 0x1506,
|
||||
CV_LeafKind_ENUM = 0x1507,
|
||||
CV_LeafKind_DIMARRAY = 0x1508,
|
||||
CV_LeafKind_PRECOMP = 0x1509,
|
||||
CV_LeafKind_ALIAS = 0x150a,
|
||||
CV_LeafKind_DEFARG = 0x150b,
|
||||
CV_LeafKind_FRIENDFCN = 0x150c,
|
||||
CV_LeafKind_MEMBER = 0x150d,
|
||||
CV_LeafKind_STMEMBER = 0x150e,
|
||||
CV_LeafKind_METHOD = 0x150f,
|
||||
CV_LeafKind_NESTTYPE = 0x1510,
|
||||
CV_LeafKind_ONEMETHOD = 0x1511,
|
||||
CV_LeafKind_NESTTYPEEX = 0x1512,
|
||||
CV_LeafKind_MEMBERMODIFY = 0x1513,
|
||||
CV_LeafKind_MANAGED = 0x1514,
|
||||
CV_LeafKind_TYPESERVER2 = 0x1515,
|
||||
CV_LeafKind_STRIDED_ARRAY = 0x1516,
|
||||
CV_LeafKind_HLSL = 0x1517,
|
||||
CV_LeafKind_MODIFIER_EX = 0x1518,
|
||||
CV_LeafKind_INTERFACE = 0x1519,
|
||||
CV_LeafKind_BINTERFACE = 0x151a,
|
||||
CV_LeafKind_VECTOR = 0x151b,
|
||||
CV_LeafKind_MATRIX = 0x151c,
|
||||
CV_LeafKind_VFTABLE = 0x151d,
|
||||
CV_LeafKind_FUNC_ID = 0x1601,
|
||||
CV_LeafKind_MFUNC_ID = 0x1602,
|
||||
CV_LeafKind_BUILDINFO = 0x1603,
|
||||
CV_LeafKind_SUBSTR_LIST = 0x1604,
|
||||
CV_LeafKind_STRING_ID = 0x1605,
|
||||
CV_LeafKind_UDT_SRC_LINE = 0x1606,
|
||||
CV_LeafKind_UDT_MOD_SRC_LINE = 0x1607,
|
||||
CV_LeafKind_CLASS2 = 0x1608,
|
||||
CV_LeafKind_STRUCT2 = 0x1609,
|
||||
} CV_LeafKindEnum;
|
||||
|
||||
internal String8 cv_string_from_numeric_kind(CV_NumericKind v);
|
||||
internal String8 cv_string_from_arch(CV_Arch v);
|
||||
internal String8 cv_string_from_sym_kind(CV_SymKind v);
|
||||
internal String8 cv_string_from_basic_type(CV_BasicType v);
|
||||
internal String8 cv_type_name_from_basic_type(CV_BasicType v);
|
||||
internal String8 cv_string_from_leaf_kind(CV_LeafKind v);
|
||||
internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);
|
||||
internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);
|
||||
#endif // CODEVIEW_META_H
|
||||
+928
-763
File diff suppressed because it is too large
Load Diff
+678
-463
File diff suppressed because it is too large
Load Diff
@@ -1,819 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if 0
|
||||
internal void
|
||||
coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp);
|
||||
|
||||
rd_printf("Name : %S" , header.name );
|
||||
rd_printf("Time Stamp: (%#x) %S" , header.time_stamp, time_stamp );
|
||||
rd_printf("User ID : %u" , header.user_id );
|
||||
rd_printf("Group ID : %u" , header.group_id);
|
||||
rd_printf("Mode : %S" , header.mode );
|
||||
rd_printf("Data : [%#llx-%#llx)", header.data_range.min, header.data_range.max);
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_section_table(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 string_table,
|
||||
COFF_Symbol32Array symbol_table,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *section_table)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 *symlinks = push_array(scratch.arena, String8, section_count);
|
||||
for (U64 i = 0; i < symbol_table.count; ++i) {
|
||||
COFF_Symbol32 *symbol = symbol_table.v+i;
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class);
|
||||
if (interp == COFF_SymbolValueInterp_Regular &&
|
||||
symbol->aux_symbol_count == 0 &&
|
||||
(symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) {
|
||||
if (symbol->section_number > 0 && symbol->section_number <= symbol_table.count) {
|
||||
COFF_SectionHeader *header = section_table+(symbol->section_number-1);
|
||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
||||
symlinks[symbol->section_number-1] = coff_read_symbol_name(string_table, &symbol->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += symbol->aux_symbol_count;
|
||||
}
|
||||
|
||||
if (section_count) {
|
||||
rd_printf("# Section Table");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s",
|
||||
"No.",
|
||||
"Name",
|
||||
"VirtSize",
|
||||
"VirtOff",
|
||||
"FileSize",
|
||||
"FileOff",
|
||||
"RelocOff",
|
||||
"LinesOff",
|
||||
"RelocCnt",
|
||||
"LineCnt",
|
||||
"Align",
|
||||
"Flags",
|
||||
"Symlink");
|
||||
|
||||
for (U64 i = 0; i < section_count; ++i) {
|
||||
COFF_SectionHeader *header = section_table+i;
|
||||
|
||||
String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name));
|
||||
String8 full_name = coff_name_from_section_header(string_table, header);
|
||||
|
||||
String8 align;
|
||||
{
|
||||
U64 align_size = coff_align_size_from_section_flags(header->flags);
|
||||
align = push_str8f(scratch.arena, "%u", align_size);
|
||||
}
|
||||
|
||||
String8 flags;
|
||||
{
|
||||
String8List mem_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_MemRead) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "r");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemWrite) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "w");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemExecute) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "x");
|
||||
}
|
||||
|
||||
String8List cnt_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_CntCode) {
|
||||
str8_list_pushf(scratch.arena, &cnt_flags, "c");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_CntInitializedData) {
|
||||
str8_list_pushf(scratch.arena, &cnt_flags, "d");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
str8_list_pushf(scratch.arena, &cnt_flags, "u");
|
||||
}
|
||||
|
||||
String8List mem_extra_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_MemShared) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "s");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_Mem16Bit) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "h");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemLocked) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "l");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemDiscardable) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "d");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemNotCached) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "c");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemNotPaged) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "p");
|
||||
}
|
||||
|
||||
String8List lnk_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_LnkRemove) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "r");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "c");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkOther) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "o");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkInfo) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "i");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "f");
|
||||
}
|
||||
|
||||
String8List other_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_TypeNoPad) {
|
||||
str8_list_pushf(scratch.arena, &other_flags, "n");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_GpRel) {
|
||||
str8_list_pushf(scratch.arena, &other_flags, "g");
|
||||
}
|
||||
|
||||
String8 mem = str8_list_join(scratch.arena, &mem_flags, 0);
|
||||
String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0);
|
||||
String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0);
|
||||
String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0);
|
||||
String8 oth = str8_list_join(scratch.arena, &other_flags, 0);
|
||||
|
||||
String8List f = {0};
|
||||
str8_list_push(scratch.arena, &f, mem);
|
||||
str8_list_push(scratch.arena, &f, cnt);
|
||||
str8_list_push(scratch.arena, &f, ext);
|
||||
str8_list_push(scratch.arena, &f, lnk);
|
||||
str8_list_push(scratch.arena, &f, oth);
|
||||
|
||||
flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") });
|
||||
|
||||
if (!flags.size) {
|
||||
flags = str8_lit("none");
|
||||
}
|
||||
}
|
||||
|
||||
String8List l = {0};
|
||||
str8_list_pushf(scratch.arena, &l, "%-4x", i+1 );
|
||||
str8_list_pushf(scratch.arena, &l, "%-8S", name );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->vsize );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->voff );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->fsize );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->foff );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff);
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count);
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->line_count );
|
||||
str8_list_pushf(scratch.arena, &l, "%-5S", align );
|
||||
str8_list_pushf(scratch.arena, &l, "%-10S", flags );
|
||||
if (symlinks[i].size > 0) {
|
||||
str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]);
|
||||
} else {
|
||||
str8_list_pushf(scratch.arena, &l, "[no symlink]");
|
||||
}
|
||||
|
||||
String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), });
|
||||
rd_printf("%S", line);
|
||||
|
||||
if (full_name.size != name.size) {
|
||||
rd_indent();
|
||||
rd_printf("Full Name: %S", full_name);
|
||||
rd_unindent();
|
||||
}
|
||||
}
|
||||
|
||||
rd_newline();
|
||||
rd_printf("Flags:");
|
||||
rd_indent();
|
||||
rd_printf("r = MemRead w = MemWrite x = MemExecute");
|
||||
rd_printf("c = CntCode d = InitializedData u = UninitializedData");
|
||||
rd_printf("s = MemShared h = Mem16bit l = MemLocked d = MemDiscardable c = MemNotCached p = MemNotPaged");
|
||||
rd_printf("r = LnkRemove c = LnkComdat o = LnkOther i = LnkInfo f = LnkNRelocOvfl");
|
||||
rd_printf("g = GpRel n = TypeNoPad");
|
||||
rd_unindent();
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_disasm_sections(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
COFF_MachineType machine,
|
||||
U64 image_base,
|
||||
B32 is_obj,
|
||||
RD_MarkerArray *section_markers,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections)
|
||||
{
|
||||
if (section_count) {
|
||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
||||
COFF_SectionHeader *sect = sections+sect_idx;
|
||||
if (sect->flags & COFF_SectionFlag_CntCode) {
|
||||
U64 sect_off = is_obj ? sect->foff : sect->voff;
|
||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
||||
String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
||||
U64 sect_number = sect_idx+1;
|
||||
RD_MarkerArray markers = section_markers[sect_number];
|
||||
|
||||
rd_printf("# Disassembly [Section No. %#llx]", sect_number);
|
||||
rd_indent();
|
||||
rd_print_disasm(arena, out, indent, arch_from_coff_machine(machine), image_base, sect_off, markers.count, markers.v, raw_code);
|
||||
rd_unindent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_raw_data_sections(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
B32 is_obj,
|
||||
RD_MarkerArray *section_markers,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *section_table)
|
||||
{
|
||||
if (section_count) {
|
||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
||||
COFF_SectionHeader *sect = section_table+sect_idx;
|
||||
if (sect->fsize > 0) {
|
||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
||||
String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
||||
RD_MarkerArray markers = section_markers[sect_idx];
|
||||
|
||||
rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1));
|
||||
rd_indent();
|
||||
rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect);
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_relocs(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
String8 string_table,
|
||||
COFF_MachineType machine,
|
||||
U64 sect_count,
|
||||
COFF_SectionHeader *sect_headers,
|
||||
COFF_Symbol32Array symbols)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
B32 print_header = 1;
|
||||
|
||||
for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) {
|
||||
COFF_SectionHeader *sect_header = sect_headers+sect_idx;
|
||||
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header);
|
||||
|
||||
if (reloc_info.count) {
|
||||
if (print_header) {
|
||||
print_header = 0;
|
||||
rd_printf("# Relocations");
|
||||
rd_indent();
|
||||
}
|
||||
|
||||
rd_printf("## Section %llx", sect_idx);
|
||||
rd_indent();
|
||||
|
||||
rd_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName");
|
||||
|
||||
for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) {
|
||||
COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx;
|
||||
String8 type = coff_string_from_reloc(machine, reloc->type);
|
||||
U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type);
|
||||
|
||||
U64 apply_foff = sect_header->foff + reloc->apply_off;
|
||||
if (apply_foff + apply_size > raw_data.size) {
|
||||
rd_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
U64 raw_apply;
|
||||
AssertAlways(apply_size <= sizeof(raw_apply));
|
||||
MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size);
|
||||
S64 apply = extend_sign64(raw_apply, apply_size);
|
||||
|
||||
if (reloc->isymbol > symbols.count) {
|
||||
rd_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
COFF_Symbol32 *symbol = symbols.v+reloc->isymbol;
|
||||
String8 symbol_name = coff_read_symbol_name(string_table, &symbol->name);
|
||||
|
||||
String8List line = {0};
|
||||
str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx );
|
||||
str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off);
|
||||
str8_list_pushf(scratch.arena, &line, "%-16S", type );
|
||||
str8_list_pushf(scratch.arena, &line, "%016x", apply );
|
||||
str8_list_pushf(scratch.arena, &line, "%S", symbol_name );
|
||||
|
||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")});
|
||||
rd_printf("%S", l);
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
}
|
||||
}
|
||||
|
||||
if (!print_header) {
|
||||
rd_unindent();
|
||||
}
|
||||
rd_newline();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_symbol_table(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
B32 is_big_obj,
|
||||
String8 string_table,
|
||||
COFF_Symbol32Array symbols)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
if (symbols.count) {
|
||||
rd_printf("# Symbol Table");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s",
|
||||
"No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name");
|
||||
|
||||
for (U64 i = 0; i < symbols.count; ++i) {
|
||||
COFF_Symbol32 *symbol = &symbols.v[i];
|
||||
String8 name = coff_read_symbol_name(string_table, &symbol->name);
|
||||
String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb);
|
||||
String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb);
|
||||
String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class);
|
||||
String8 section_number;
|
||||
switch (symbol->section_number) {
|
||||
case COFF_Symbol_UndefinedSection: section_number = str8_lit("Undef"); break;
|
||||
case COFF_Symbol_AbsSection32: section_number = str8_lit("Abs"); break;
|
||||
case COFF_Symbol_DebugSection32: section_number = str8_lit("Debug"); break;
|
||||
default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break;
|
||||
}
|
||||
|
||||
String8List line = {0};
|
||||
str8_list_pushf(scratch.arena, &line, "%-4x", i );
|
||||
str8_list_pushf(scratch.arena, &line, "%08x", symbol->value );
|
||||
str8_list_pushf(scratch.arena, &line, "%-10S", section_number );
|
||||
str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count);
|
||||
str8_list_pushf(scratch.arena, &line, "%-4S", msb );
|
||||
str8_list_pushf(scratch.arena, &line, "%-4S", lsb );
|
||||
str8_list_pushf(scratch.arena, &line, "%-16S", storage_class );
|
||||
str8_list_pushf(scratch.arena, &line, "%S", name );
|
||||
|
||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")});
|
||||
rd_printf("%S", l);
|
||||
|
||||
rd_indent();
|
||||
for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) {
|
||||
void *raw_aux = &symbols.v[k];
|
||||
switch (symbol->storage_class) {
|
||||
case COFF_SymStorageClass_External: {
|
||||
COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k];
|
||||
rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x",
|
||||
func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func);
|
||||
} break;
|
||||
case COFF_SymStorageClass_Function: {
|
||||
COFF_SymbolFunc *func = raw_aux;
|
||||
rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func);
|
||||
} break;
|
||||
case COFF_SymStorageClass_WeakExternal: {
|
||||
COFF_SymbolWeakExt *weak = raw_aux;
|
||||
String8 type = coff_string_from_weak_ext_type(weak->characteristics);
|
||||
rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type);
|
||||
} break;
|
||||
case COFF_SymStorageClass_File: {
|
||||
COFF_SymbolFile *file = raw_aux;
|
||||
String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name));
|
||||
rd_printf("Name %S", name);
|
||||
} break;
|
||||
case COFF_SymStorageClass_Static: {
|
||||
COFF_SymbolSecDef *sd = raw_aux;
|
||||
String8 selection = coff_string_from_comdat_select_type(sd->selection);
|
||||
U32 number = sd->number_lo;
|
||||
if (is_big_obj) {
|
||||
number |= (U32)sd->number_hi << 16;
|
||||
}
|
||||
if (number) {
|
||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S",
|
||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection);
|
||||
} else {
|
||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x",
|
||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
rd_printf("???");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
i += symbol->aux_symbol_count;
|
||||
rd_unindent();
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
||||
String8 machine = coff_string_from_machine_type(header->machine);
|
||||
|
||||
rd_printf("# Big Obj");
|
||||
rd_indent();
|
||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp);
|
||||
rd_printf("Machine : %#x (%S)", header->machine, machine );
|
||||
rd_printf("Section Count: %u", header->section_count );
|
||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff);
|
||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
||||
String8 machine = coff_string_from_machine_type(header->machine);
|
||||
String8 flags = coff_string_from_flags(scratch.arena, header->flags);
|
||||
|
||||
rd_printf("# COFF File Header");
|
||||
rd_indent();
|
||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp );
|
||||
rd_printf("Machine : %#x %S", header->machine, machine );
|
||||
rd_printf("Section Count : %u", header->section_count );
|
||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff );
|
||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
||||
rd_printf("Optional Header Size: %#x (%m)", header->optional_header_size, header->optional_header_size);
|
||||
rd_printf("Flags : %#x (%S)", header->flags, flags );
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 machine = coff_string_from_machine_type(header->machine);
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
||||
|
||||
rd_printf("# Import");
|
||||
rd_indent();
|
||||
rd_printf("Version : %u", header->version );
|
||||
rd_printf("Machine : %S", machine );
|
||||
rd_printf("Time Stamp: %#x (%S)", header->time_stamp, time_stamp );
|
||||
rd_printf("Data Size : %#x (%m)", header->data_size, header->data_size);
|
||||
rd_printf("Hint : %u", header->hint_or_ordinal);
|
||||
rd_printf("Type : %u", header->type );
|
||||
rd_printf("Import By : %u", header->import_by );
|
||||
rd_printf("Function : %S", header->func_name );
|
||||
rd_printf("DLL : %S", header->dll_name );
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
||||
|
||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
||||
|
||||
COFF_BigObjHeader *big_obj = (COFF_BigObjHeader *)raw_header.str;
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_32(scratch.arena, raw_data, header_info.symbol_table_range.min, big_obj->symbol_count);
|
||||
|
||||
if (opts & RD_Option_Headers) {
|
||||
coff_print_big_obj_header(arena, out, indent, big_obj);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Sections) {
|
||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count);
|
||||
Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count);
|
||||
|
||||
if (sect_headers_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read big obj section headers");
|
||||
goto exit;
|
||||
}
|
||||
if (big_obj->symbol_count) {
|
||||
if (symbols_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read big obj symbol table");
|
||||
goto exit;
|
||||
}
|
||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
||||
rd_errorf("section headers and symbol table ranges overlap");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, big_obj->section_count, section_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Relocs) {
|
||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, big_obj->machine, big_obj->section_count, section_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Symbols) {
|
||||
coff_print_symbol_table(arena, out, indent, raw_data, 1, raw_string_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
||||
|
||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
||||
|
||||
COFF_FileHeader *header = (COFF_FileHeader *)raw_header.str;
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_16(scratch.arena, raw_data, header_info.symbol_table_range.min, header->symbol_count);
|
||||
Arch arch = arch_from_coff_machine(header->machine);
|
||||
|
||||
if (opts & RD_Option_Headers) {
|
||||
coff_print_file_header(arena, out, indent, header);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Sections) {
|
||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count);
|
||||
Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count);
|
||||
|
||||
if (sect_headers_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read obj section headers");
|
||||
goto exit;
|
||||
}
|
||||
if (header->symbol_count) {
|
||||
if (symbols_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read obj symbol table");
|
||||
goto exit;
|
||||
}
|
||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
||||
rd_errorf("section headers and symbol table ranges overlap");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, header->section_count, section_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Relocs) {
|
||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, header->machine, header->section_count, section_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Symbols) {
|
||||
coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
RD_MarkerArray *section_markers = 0;
|
||||
if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) {
|
||||
section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, header->section_count, symbol_table);
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Rawdata) {
|
||||
coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, section_table);
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Disasm) {
|
||||
coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, section_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Codeview) {
|
||||
cv_format_debug_sections(arena, out, indent, raw_data, raw_string_table, header->section_count, section_table);
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Dwarf) {
|
||||
DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
|
||||
dw_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
|
||||
}
|
||||
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive);
|
||||
|
||||
if (archive_parse.error.size) {
|
||||
rd_errorf("%S", archive_parse.error);
|
||||
return;
|
||||
}
|
||||
|
||||
COFF_ArchiveFirstMember first_member = archive_parse.first_member;
|
||||
{
|
||||
rd_printf("# First Header");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("Symbol Count : %u", first_member.symbol_count);
|
||||
rd_printf("String Table Size: %#llx (%M)", first_member.string_table.size, first_member.string_table.size);
|
||||
|
||||
rd_printf("Members:");
|
||||
rd_indent();
|
||||
|
||||
String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0);
|
||||
|
||||
if (string_table.node_count == first_member.member_offset_count) {
|
||||
String8Node *string_n = string_table.first;
|
||||
|
||||
for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) {
|
||||
U32 offset = from_be_u32(first_member.member_offsets[i]);
|
||||
rd_printf("[%4u] %#08x %S", i, offset, string_n->string);
|
||||
}
|
||||
} else {
|
||||
rd_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count);
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (archive_parse.has_second_header) {
|
||||
COFF_ArchiveSecondMember second_member = archive_parse.second_member;
|
||||
|
||||
rd_printf("# Second Header");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("Member Count : %u", second_member.member_count);
|
||||
rd_printf("Symbol Count : %u", second_member.symbol_count);
|
||||
rd_printf("String Table Size: %#llx (%M)", second_member.string_table.size, second_member.string_table.size);
|
||||
|
||||
String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0);
|
||||
|
||||
rd_printf("Members:");
|
||||
rd_indent();
|
||||
if (second_member.symbol_index_count == second_member.symbol_count) {
|
||||
String8Node *string_n = string_table.first;
|
||||
for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) {
|
||||
U16 symbol_number = second_member.symbol_indices[i];
|
||||
if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) {
|
||||
U16 symbol_idx = symbol_number - 1;
|
||||
U32 member_offset = second_member.member_offsets[i];
|
||||
rd_printf("[%4u] %#08x %S", i, member_offset, string_n->string);
|
||||
} else {
|
||||
rd_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rd_errorf("Symbol index count %u doesn't match symbol count %u",
|
||||
second_member.symbol_index_count, second_member.symbol_count);
|
||||
}
|
||||
rd_unindent();
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (archive_parse.has_long_names && opts & RD_Option_LongNames) {
|
||||
rd_printf("# Long Names");
|
||||
rd_indent();
|
||||
|
||||
String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0);
|
||||
U64 name_idx = 0;
|
||||
for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) {
|
||||
U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str);
|
||||
rd_printf("[%-4u] %#08x %S", name_idx, offset, name_n->string);
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
U64 member_offset_count = 0;
|
||||
U32 *member_offsets = 0;
|
||||
if (archive_parse.has_second_header) {
|
||||
member_offset_count = archive_parse.second_member.member_offset_count;
|
||||
member_offsets = archive_parse.second_member.member_offsets;
|
||||
} else {
|
||||
HashTable *ht = hash_table_init(scratch.arena, 0x1000);
|
||||
for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) {
|
||||
U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]);
|
||||
if (!hash_table_search_u32(ht, member_offset)) {
|
||||
hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0);
|
||||
}
|
||||
}
|
||||
member_offset_count = ht->count;
|
||||
member_offsets = keys_from_hash_table_u32(scratch.arena, ht);
|
||||
radsort(member_offsets, member_offset_count, u32_is_before);
|
||||
}
|
||||
|
||||
rd_printf("# Members");
|
||||
rd_indent();
|
||||
|
||||
for (U64 i = 0; i < member_offset_count; ++i) {
|
||||
U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size;
|
||||
U64 member_offset = member_offsets[i];
|
||||
String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset));
|
||||
COFF_ArchiveMember member = coff_archive_member_from_data(raw_member);
|
||||
COFF_DataType member_type = coff_data_type_from_data(member.data);
|
||||
|
||||
rd_printf("Member @ %#llx", member_offset);
|
||||
rd_indent();
|
||||
|
||||
if (opts & RD_Option_Headers) {
|
||||
coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
switch (member_type) {
|
||||
case COFF_DataType_Obj: {
|
||||
coff_print_obj(arena, out, indent, member.data, opts);
|
||||
} break;
|
||||
case COFF_DataType_BigObj: {
|
||||
coff_print_big_obj(arena, out, indent, member.data, opts);
|
||||
} break;
|
||||
case COFF_DataType_Import: {
|
||||
if (opts & RD_Option_Headers) {
|
||||
COFF_ParsedArchiveImportHeader header = {0};
|
||||
U64 parse_size = coff_parse_import(member.data, 0, &header);
|
||||
if (parse_size) {
|
||||
coff_print_import(arena, out, indent, &header);
|
||||
} else {
|
||||
rd_errorf("not enough bytes to parse import header");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case COFF_DataType_Null: {
|
||||
rd_errorf("unknown member format", member_offset);
|
||||
} break;
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef COFF_DUMP_H
|
||||
#define COFF_DUMP_H
|
||||
|
||||
#if 0
|
||||
internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names);
|
||||
internal void coff_print_section_table (Arena *arena, String8List *out, String8 indent, String8 string_table, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers);
|
||||
internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
|
||||
internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
|
||||
internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 string_table, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols);
|
||||
internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, String8 string_table, COFF_Symbol32Array symbols);
|
||||
internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header);
|
||||
internal void coff_print_file_header (Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header);
|
||||
internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header);
|
||||
internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
|
||||
internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
|
||||
internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts);
|
||||
#endif
|
||||
|
||||
#endif // COFF_DUMP_H
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "coff/coff.c"
|
||||
#include "coff/coff_parse.c"
|
||||
#include "coff/coff_dump.c"
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef COFF_INC_H
|
||||
#define COFF_INC_H
|
||||
|
||||
#include "coff/coff.h"
|
||||
#include "coff/coff_parse.h"
|
||||
#include "coff/coff_dump.h"
|
||||
|
||||
#endif // COFF_INC_H
|
||||
@@ -1,387 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal COFF_LibWriterSymbolNode *
|
||||
coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol)
|
||||
{
|
||||
COFF_LibWriterSymbolNode *node = push_array_no_zero(arena, COFF_LibWriterSymbolNode, 1);
|
||||
node->next = 0;
|
||||
node->data = symbol;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal COFF_LibWriterMemberNode *
|
||||
coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member)
|
||||
{
|
||||
COFF_LibWriterMemberNode *node = push_array_no_zero(arena, COFF_LibWriterMemberNode, 1);
|
||||
node->next = 0;
|
||||
node->data = member;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal COFF_LibWriterSymbol *
|
||||
coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list)
|
||||
{
|
||||
COFF_LibWriterSymbol *arr = push_array_no_zero(arena, COFF_LibWriterSymbol, list.count + 2);
|
||||
COFF_LibWriterSymbol *ptr = arr + 1;
|
||||
for (COFF_LibWriterSymbolNode *i = list.first; i != 0; i = i->next, ptr += 1) {
|
||||
*ptr = i->data;
|
||||
}
|
||||
MemoryZeroStruct(&arr[0]);
|
||||
MemoryZeroStruct(&arr[list.count+1]);
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal COFF_LibWriterMember *
|
||||
coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list)
|
||||
{
|
||||
COFF_LibWriterMember *arr = push_array_no_zero(arena, COFF_LibWriterMember, list.count);
|
||||
COFF_LibWriterMember *ptr = arr;
|
||||
for (COFF_LibWriterMemberNode *i = list.first; i != 0; i = i->next, ptr += 1) {
|
||||
ptr->name = push_str8_copy(arena, i->data.name);
|
||||
ptr->data = push_str8_copy(arena, i->data.data);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_lib_writer_symbol_name_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const COFF_LibWriterSymbol *sa = raw_a;
|
||||
const COFF_LibWriterSymbol *sb = raw_b;
|
||||
return str8_compar_case_sensitive(&sa->name, &sb->name);
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_lib_writer_symbol_is_before_name(void *raw_a, void *raw_b)
|
||||
{
|
||||
return coff_lib_writer_symbol_name_compar(raw_a, raw_b) < 0;
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_lib_writer_symbol_is_before_member_idx(void *raw_a, void *raw_b)
|
||||
{
|
||||
COFF_LibWriterSymbol *a = raw_a, *b = raw_b;
|
||||
return a->member_idx < b->member_idx;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count)
|
||||
{
|
||||
Assert(count >= 2);
|
||||
radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_name);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count)
|
||||
{
|
||||
Assert(count >= 2);
|
||||
radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_member_idx);
|
||||
}
|
||||
|
||||
internal COFF_LibWriter *
|
||||
coff_lib_writer_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
COFF_LibWriter *writer = push_array(arena, COFF_LibWriter, 1);
|
||||
writer->arena = arena;
|
||||
return writer;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_lib_writer_release(COFF_LibWriter **writer_ptr)
|
||||
{
|
||||
arena_release((*writer_ptr)->arena);
|
||||
*writer_ptr = 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data)
|
||||
{
|
||||
U64 member_idx = writer->member_list.count;
|
||||
|
||||
// push obj member
|
||||
COFF_LibWriterMember member = { .name = obj_path, .data = obj_data };
|
||||
COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member);
|
||||
|
||||
// push external symbols
|
||||
COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data);
|
||||
String8 string_table = str8_substr(obj_data, obj_header.string_table_range);
|
||||
String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range);
|
||||
COFF_ParsedSymbol symbol;
|
||||
for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
|
||||
symbol = coff_parse_symbol(obj_header, string_table, symbol_table, symbol_idx);
|
||||
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
|
||||
if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) {
|
||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
COFF_LibWriterSymbol lib_symbol = { .name = symbol.name, .member_idx = member_idx };
|
||||
coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return member_idx;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type)
|
||||
{
|
||||
U64 member_idx = lib_writer->member_list.count;
|
||||
|
||||
String8 member_data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type);
|
||||
COFF_LibWriterMember member = { .name = dll_name, .data = member_data };
|
||||
COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member);
|
||||
|
||||
if (name.size) {
|
||||
switch (import_type) {
|
||||
case COFF_ImportHeader_Code: {
|
||||
COFF_LibWriterSymbol thunk_symbol = {0};
|
||||
thunk_symbol.name = push_str8_copy(lib_writer->arena, name);
|
||||
thunk_symbol.member_idx = member_idx;
|
||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, thunk_symbol);
|
||||
|
||||
COFF_LibWriterSymbol imp_symbol = {0};
|
||||
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
|
||||
imp_symbol.member_idx = member_idx;
|
||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
|
||||
} break;
|
||||
case COFF_ImportHeader_Data: {
|
||||
COFF_LibWriterSymbol imp_symbol = {0};
|
||||
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
|
||||
imp_symbol.member_idx = member_idx;
|
||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
|
||||
} break;
|
||||
case COFF_ImportHeader_Const: { NotImplemented; } break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// member lists -> arrays
|
||||
U64 member_count = lib_writer->member_list.count;
|
||||
COFF_LibWriterMember *member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list);
|
||||
|
||||
// serialize members
|
||||
U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count);
|
||||
String8List long_names_list = {0};
|
||||
String8List member_data_list = {0};
|
||||
{
|
||||
HashTable *name_ht = hash_table_init(scratch.arena, 1024);
|
||||
for EachIndex(member_idx, member_count) {
|
||||
COFF_LibWriterMember *member = &member_array[member_idx];
|
||||
|
||||
// make member name
|
||||
String8 name;
|
||||
U64 name_with_slash_size = member->name.size + 1;
|
||||
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
|
||||
// have we seen this member name before?
|
||||
KeyValuePair *is_present = hash_table_search_string(name_ht, member->name);
|
||||
if (is_present) {
|
||||
name = is_present->value_string;
|
||||
} else {
|
||||
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
|
||||
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
|
||||
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
|
||||
}
|
||||
} else {
|
||||
name = push_str8f(scratch.arena, "%S/", member->name);
|
||||
}
|
||||
|
||||
member_offsets[member_idx] = member_data_list.total_size;
|
||||
|
||||
String8 member_data = member->data;
|
||||
String8 member_header = coff_make_lib_member_header(scratch.arena, name, time_stamp, 0, 0, mode, member_data.size);
|
||||
|
||||
str8_list_push(scratch.arena, &member_data_list, member_header);
|
||||
str8_list_push(scratch.arena, &member_data_list, member_data);
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_data_list.total_size, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
||||
str8_list_push(scratch.arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write long names member
|
||||
if (long_names_list.total_size) {
|
||||
String8 header = coff_make_lib_member_header(scratch.arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size);
|
||||
String8 data = str8_list_join(scratch.arena, &long_names_list, 0);
|
||||
U64 member_offset = member_data_list.total_size + data.size + header.size;
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
||||
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
str8_list_push_front(scratch.arena, &member_data_list, data);
|
||||
str8_list_push_front(scratch.arena, &member_data_list, header);
|
||||
}
|
||||
|
||||
// compute size for symbol string table
|
||||
U32 name_buffer_size = 0;
|
||||
for (COFF_LibWriterSymbolNode *node = lib_writer->symbol_list.first; node != 0; node = node->next) {
|
||||
name_buffer_size += node->data.name.size;
|
||||
name_buffer_size += 1; // null
|
||||
}
|
||||
|
||||
// compute members base offset
|
||||
U64 members_base_offset;
|
||||
{
|
||||
U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * lib_writer->symbol_list.count + name_buffer_size;
|
||||
U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * lib_writer->symbol_list.count + name_buffer_size;
|
||||
U64 sizeof_long_names = sizeof(COFF_ArchiveMemberHeader) + long_names_list.total_size;
|
||||
|
||||
sizeof_first_header = AlignPow2(sizeof_first_header, COFF_Archive_MemberAlign);
|
||||
sizeof_second_header = AlignPow2(sizeof_second_header, COFF_Archive_MemberAlign);
|
||||
sizeof_long_names = AlignPow2(sizeof_long_names, COFF_Archive_MemberAlign);
|
||||
|
||||
members_base_offset = sizeof(g_coff_archive_sig);
|
||||
members_base_offset += sizeof_first_header;
|
||||
if (emit_second_member) {
|
||||
members_base_offset += sizeof_second_header;
|
||||
}
|
||||
if (long_names_list.total_size) {
|
||||
members_base_offset += sizeof_long_names;
|
||||
}
|
||||
}
|
||||
|
||||
// write second linker member
|
||||
if (emit_second_member) {
|
||||
U64 symbols_count;
|
||||
COFF_LibWriterSymbol *symbols;
|
||||
{
|
||||
U64 symbols_count_with_null = lib_writer->symbol_list.count + 2;
|
||||
COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list);
|
||||
coff_lib_writer_symbol_array_sort_on_name(symbols_with_null, symbols_count_with_null);
|
||||
|
||||
symbols_count = symbols_count_with_null - 2;
|
||||
symbols = symbols_with_null + 1;
|
||||
}
|
||||
|
||||
// write symbol name buffer
|
||||
U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size);
|
||||
{
|
||||
U64 name_cursor = 0;
|
||||
for EachIndex(symbol_idx, symbols_count) {
|
||||
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
|
||||
MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size);
|
||||
name_buffer[name_cursor + symbol->name.size] = '\0';
|
||||
name_cursor += symbol->name.size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
U32 member_count32 = safe_cast_u32(member_count);
|
||||
U32 symbol_count32 = safe_cast_u32(symbols_count);
|
||||
|
||||
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, member_count);
|
||||
U16 *member_idx16_arr = push_array_no_zero(scratch.arena, U16, symbols_count);
|
||||
|
||||
// write member offset array
|
||||
for EachIndex(member_idx, member_count) {
|
||||
U64 member_offset = members_base_offset + member_offsets[member_idx];
|
||||
U32 member_off32 = safe_cast_u32(member_offset);
|
||||
member_off32_arr[member_idx] = member_off32;
|
||||
}
|
||||
|
||||
// write member offset indices for each symbol
|
||||
for EachIndex(symbol_idx, symbols_count) {
|
||||
// member offset indices are 1-based
|
||||
U64 member_idx = symbols[symbol_idx].member_idx + 1;
|
||||
U16 member_idx16 = safe_cast_u16(member_idx);
|
||||
member_idx16_arr[symbol_idx] = member_idx16;
|
||||
}
|
||||
|
||||
// layout second member data
|
||||
String8List second_member_data_list = {0};
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&member_count32));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_off32_arr, member_count));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&symbol_count32));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_idx16_arr, symbols_count));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8(name_buffer, name_buffer_size));
|
||||
|
||||
String8 member_data = str8_list_join(scratch.arena, &second_member_data_list, 0);
|
||||
String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
|
||||
|
||||
U64 member_offset = member_data_list.total_size + member_data.size + member_header.size;
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
||||
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
str8_list_push_front(scratch.arena, &member_data_list, member_data);
|
||||
str8_list_push_front(scratch.arena, &member_data_list, member_header);
|
||||
}
|
||||
|
||||
// write first linker member (obsolete, but kept for compatability reasons)
|
||||
{
|
||||
U64 symbols_count;
|
||||
COFF_LibWriterSymbol *symbols;
|
||||
{
|
||||
U64 symbols_count_with_null = lib_writer->symbol_list.count + 2;
|
||||
COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list);
|
||||
coff_lib_writer_symbol_array_sort_on_member_idx(symbols_with_null, symbols_count_with_null);
|
||||
|
||||
symbols_count = symbols_count_with_null - 2;
|
||||
symbols = symbols_with_null + 1;
|
||||
}
|
||||
|
||||
// write symbol name buffer
|
||||
U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size);
|
||||
{
|
||||
U64 name_cursor = 0;
|
||||
for EachIndex(symbol_idx, symbols_count) {
|
||||
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
|
||||
MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size);
|
||||
name_buffer[name_cursor + symbol->name.size] = '\0';
|
||||
name_cursor += symbol->name.size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
U32 symbol_count_be = from_be_u32(symbols_count);
|
||||
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, symbols_count);
|
||||
|
||||
for EachIndex(symbol_idx, symbols_count) {
|
||||
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
|
||||
|
||||
// write big endian member offset
|
||||
U64 member_offset = members_base_offset + member_offsets[symbol->member_idx];
|
||||
U32 member_off32 = from_be_u32(safe_cast_u32(member_offset));
|
||||
member_off32_arr[symbol_idx] = member_off32;
|
||||
}
|
||||
|
||||
// layout first member data
|
||||
String8List first_member_data_list = {0};
|
||||
str8_list_push(scratch.arena, &first_member_data_list, str8_struct(&symbol_count_be));
|
||||
str8_list_push(scratch.arena, &first_member_data_list, str8_array(member_off32_arr, symbols_count));
|
||||
str8_list_push(scratch.arena, &first_member_data_list, str8(name_buffer, name_buffer_size));
|
||||
|
||||
String8 member_data = str8_list_join(scratch.arena, &first_member_data_list, 0);
|
||||
String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
|
||||
|
||||
U64 member_offset = sizeof(g_coff_archive_sig) + member_header.size + member_data.size;
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(scratch.arena, U8, pad_size);
|
||||
str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
str8_list_push_front(scratch.arena, &member_data_list, member_data);
|
||||
str8_list_push_front(scratch.arena, &member_data_list, member_header);
|
||||
}
|
||||
|
||||
// archive signature
|
||||
str8_list_push_front(scratch.arena, &member_data_list, str8_struct(&g_coff_archive_sig));
|
||||
|
||||
String8 raw_lib = str8_list_join(arena, &member_data_list, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return raw_lib;
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef COFF_LIB_WRITER_H
|
||||
#define COFF_LIB_WRITER_H
|
||||
|
||||
typedef struct COFF_LibWriterMember
|
||||
{
|
||||
String8 name;
|
||||
String8 data;
|
||||
} COFF_LibWriterMember;
|
||||
|
||||
typedef struct COFF_LibWriterMemberNode
|
||||
{
|
||||
COFF_LibWriterMember data;
|
||||
struct COFF_LibWriterMemberNode *next;
|
||||
} COFF_LibWriterMemberNode;
|
||||
|
||||
typedef struct COFF_LibWriterMemberList
|
||||
{
|
||||
U64 count;
|
||||
COFF_LibWriterMemberNode *first;
|
||||
COFF_LibWriterMemberNode *last;
|
||||
} COFF_LibWriterMemberList;
|
||||
|
||||
typedef struct COFF_LibWriterSymbol
|
||||
{
|
||||
String8 name;
|
||||
U64 member_idx;
|
||||
} COFF_LibWriterSymbol;
|
||||
|
||||
typedef struct COFF_LibWriterSymbolNode
|
||||
{
|
||||
COFF_LibWriterSymbol data;
|
||||
struct COFF_LibWriterSymbolNode *next;
|
||||
} COFF_LibWriterSymbolNode;
|
||||
|
||||
typedef struct COFF_LibWriterSymbolList
|
||||
{
|
||||
U64 count;
|
||||
COFF_LibWriterSymbolNode *first;
|
||||
COFF_LibWriterSymbolNode *last;
|
||||
} COFF_LibWriterSymbolList;
|
||||
|
||||
typedef struct COFF_LibWriter
|
||||
{
|
||||
Arena *arena;
|
||||
COFF_LibWriterMemberList member_list;
|
||||
COFF_LibWriterSymbolList symbol_list;
|
||||
} COFF_LibWriter;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal COFF_LibWriterSymbolNode * coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol);
|
||||
internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member);
|
||||
|
||||
internal COFF_LibWriterSymbol * coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list);
|
||||
internal COFF_LibWriterMember * coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list);
|
||||
|
||||
internal void coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count);
|
||||
internal void coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count);
|
||||
|
||||
internal COFF_LibWriter * coff_lib_writer_alloc(void);
|
||||
internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr);
|
||||
internal U64 coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data);
|
||||
internal void coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type);
|
||||
internal String8 coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member);
|
||||
|
||||
#endif // COFF_LIB_WRITER_H
|
||||
|
||||
@@ -1,500 +0,0 @@
|
||||
internal COFF_ObjWriter*
|
||||
coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1);
|
||||
obj_writer->arena = arena;
|
||||
obj_writer->time_stamp = time_stamp;
|
||||
obj_writer->machine = machine;
|
||||
return obj_writer;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_obj_writer_release(COFF_ObjWriter **obj_writer)
|
||||
{
|
||||
arena_release((*obj_writer)->arena);
|
||||
*obj_writer = 0;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List srl = {0};
|
||||
|
||||
String8List string_table = {0};
|
||||
U32 *string_table_size = push_array(scratch.arena, U32, 1);
|
||||
*string_table_size = sizeof(*string_table_size);
|
||||
str8_list_push(scratch.arena, &string_table, str8_struct(string_table_size));
|
||||
|
||||
//
|
||||
// assing section numbers
|
||||
//
|
||||
U64 obj_sections_count;
|
||||
COFF_ObjSection **obj_sections;
|
||||
{
|
||||
obj_sections_count = obj_writer->sect_count;
|
||||
obj_sections = push_array(scratch.arena, COFF_ObjSection *, obj_writer->sect_count);
|
||||
U64 sect_idx = 0;
|
||||
for (COFF_ObjSectionNode *sect_n = obj_writer->sect_first; sect_n != 0; sect_n = sect_n->next, sect_idx += 1) {
|
||||
COFF_ObjSection *sect = §_n->v;
|
||||
sect->section_number = sect_idx+1;
|
||||
obj_sections[sect_idx] = sect;
|
||||
|
||||
}
|
||||
}
|
||||
AssertAlways(obj_sections_count <= max_U16);
|
||||
|
||||
//
|
||||
// serialize symbol table
|
||||
//
|
||||
String8List symbol_table = {0};
|
||||
{
|
||||
{
|
||||
U64 symbol_idx = 0;
|
||||
for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) {
|
||||
COFF_ObjSymbol *s = &symbol_n->v;
|
||||
|
||||
// assign symbol index
|
||||
s->idx = symbol_idx++;
|
||||
symbol_idx += s->aux_symbols.node_count;
|
||||
}
|
||||
}
|
||||
|
||||
U64 symbol_idx = 0;
|
||||
for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) {
|
||||
COFF_ObjSymbol *s = &symbol_n->v;
|
||||
|
||||
COFF_Symbol16 *d = push_array(scratch.arena, COFF_Symbol16, 1);
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d));
|
||||
|
||||
COFF_SymbolName name = {0};
|
||||
// long name
|
||||
if (s->name.size > sizeof(name.short_name)) {
|
||||
U64 string_table_offset = string_table.total_size;
|
||||
str8_list_push(scratch.arena, &string_table, s->name);
|
||||
str8_list_push(scratch.arena, &string_table, str8_lit("\0"));
|
||||
|
||||
name.long_name.zeroes = 0;
|
||||
name.long_name.string_table_offset = safe_cast_u32(string_table_offset);
|
||||
}
|
||||
// short name
|
||||
else {
|
||||
MemoryCopyStr8(name.short_name, s->name);
|
||||
MemoryZeroTyped(name.short_name + s->name.size, sizeof(name.short_name) - s->name.size);
|
||||
}
|
||||
|
||||
// symbol header
|
||||
AssertAlways(s->aux_symbols.node_count <= max_U8);
|
||||
d->name = name;
|
||||
d->value = s->value;
|
||||
switch (s->loc.type) {
|
||||
case COFF_SymbolLocation_Null: break;
|
||||
case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break;
|
||||
case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break;
|
||||
case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break;
|
||||
case COFF_SymbolLocation_Common: d->section_number = COFF_Symbol_UndefinedSection; break;
|
||||
}
|
||||
d->type = s->type;
|
||||
d->storage_class = s->storage_class;
|
||||
d->aux_symbol_count = 0;
|
||||
|
||||
U64 start_symbol_idx = symbol_idx;
|
||||
if (s->storage_class == COFF_SymStorageClass_WeakExternal) {
|
||||
if (s->aux_symbols.node_count > 0) {
|
||||
COFF_ObjSymbolWeak *s_weak = (COFF_ObjSymbolWeak *)s->aux_symbols.first->string.str;
|
||||
COFF_SymbolWeakExt *d_weak = push_array(scratch.arena, COFF_SymbolWeakExt, 1);
|
||||
d_weak->tag_index = s_weak->tag ? s_weak->tag->idx : max_U32;
|
||||
d_weak->characteristics = s_weak->characteristics;
|
||||
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_weak));
|
||||
symbol_idx += 1;
|
||||
}
|
||||
} else if (s->storage_class == COFF_SymStorageClass_Static) {
|
||||
if (s->aux_symbols.node_count > 0) {
|
||||
Assert(s->loc.type == COFF_SymbolLocation_Section);
|
||||
COFF_ObjSection *sect = s->loc.u.section;
|
||||
|
||||
COFF_ObjSymbolSecDef *s_sd = (COFF_ObjSymbolSecDef *)s->aux_symbols.first->string.str;
|
||||
COFF_SymbolSecDef *d_sd = push_array(scratch.arena, COFF_SymbolSecDef, 1);
|
||||
|
||||
d_sd->length = safe_cast_u32(sect->data.total_size);
|
||||
d_sd->number_of_relocations = (U16)sect->reloc_count;
|
||||
d_sd->check_sum = 0;
|
||||
d_sd->number_lo = s_sd->selection == COFF_ComdatSelect_Associative ? safe_cast_u16(s_sd->associate->section_number) : 0;
|
||||
d_sd->selection = s_sd->selection;
|
||||
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_sd));
|
||||
symbol_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
U8 processed_aux_symbol_count = (U8)(symbol_idx - start_symbol_idx);
|
||||
|
||||
for (U64 aux_idx = processed_aux_symbol_count; aux_idx < s->aux_symbols.node_count; aux_idx += 1) {
|
||||
COFF_Symbol16 *a = push_array(scratch.arena, COFF_Symbol16, 1);
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(a));
|
||||
}
|
||||
|
||||
d->aux_symbol_count = (U8)s->aux_symbols.node_count;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// file header
|
||||
//
|
||||
COFF_FileHeader *file_header = push_array(scratch.arena, COFF_FileHeader, 1);
|
||||
file_header->machine = obj_writer->machine;
|
||||
file_header->section_count = obj_sections_count;
|
||||
file_header->time_stamp = obj_writer->time_stamp;
|
||||
file_header->symbol_table_foff = 0;
|
||||
file_header->symbol_count = safe_cast_u32(symbol_table.node_count);
|
||||
file_header->optional_header_size = 0;
|
||||
file_header->flags = 0;
|
||||
str8_list_push(scratch.arena, &srl, str8_struct(file_header));
|
||||
|
||||
//
|
||||
// section table
|
||||
//
|
||||
|
||||
COFF_SectionHeader *sectab = push_array(scratch.arena, COFF_SectionHeader, obj_sections_count);
|
||||
str8_list_push(scratch.arena, &srl, str8_array(sectab, obj_sections_count));
|
||||
{
|
||||
for (U64 sect_idx = 0; sect_idx < obj_sections_count; sect_idx += 1) {
|
||||
COFF_ObjSection *s = obj_sections[sect_idx];
|
||||
COFF_SectionHeader *d = §ab[sect_idx];
|
||||
|
||||
// section name
|
||||
String8 sect_name = s->name;
|
||||
if (sect_name.size > sizeof(d->name)) {
|
||||
U64 sect_name_off = string_table.total_size;
|
||||
str8_list_push(scratch.arena, &string_table, push_cstr(scratch.arena, sect_name));
|
||||
|
||||
sect_name = push_str8f(scratch.arena, "/%u", sect_name_off);
|
||||
AssertAlways(sect_name.size <= sizeof(d->name));
|
||||
}
|
||||
|
||||
// alloc zero nodes
|
||||
for (String8Node *data_n = s->data.first; data_n != 0; data_n = data_n->next) {
|
||||
if (data_n->string.str == 0 && data_n->string.size > 0) {
|
||||
data_n->string = str8(push_array(scratch.arena, U8, data_n->string.size), data_n->string.size);
|
||||
}
|
||||
}
|
||||
|
||||
// section data
|
||||
U64 data_foff = 0;
|
||||
U64 data_size = 0;
|
||||
if (s->data.total_size > 0) {
|
||||
data_foff = srl.total_size;
|
||||
data_size = s->data.total_size;
|
||||
str8_list_concat_in_place(&srl, &s->data);
|
||||
}
|
||||
|
||||
// section relocs
|
||||
U64 relocs_foff = 0;
|
||||
if (s->reloc_count) {
|
||||
AssertAlways(s->reloc_count <= max_U16);
|
||||
COFF_Reloc *relocs = push_array(scratch.arena, COFF_Reloc, s->reloc_count);
|
||||
U64 reloc_idx = 0;
|
||||
for (COFF_ObjRelocNode *reloc_n = s->reloc_first; reloc_n != 0; reloc_n = reloc_n->next, reloc_idx += 1) {
|
||||
COFF_ObjReloc *rs = &reloc_n->v;
|
||||
COFF_Reloc *rd = &relocs[reloc_idx];
|
||||
rd->apply_off = rs->apply_off;
|
||||
rd->isymbol = rs->symbol->idx;
|
||||
rd->type = rs->type;
|
||||
}
|
||||
relocs_foff = srl.total_size;
|
||||
str8_list_push(scratch.arena, &srl, str8_array(relocs, s->reloc_count));
|
||||
}
|
||||
|
||||
// section header
|
||||
MemoryCopyStr8(d->name, sect_name);
|
||||
MemoryZeroTyped(d->name + sect_name.size, sizeof(d->name) - sect_name.size);
|
||||
d->vsize = 0;
|
||||
d->voff = 0;
|
||||
d->fsize = data_size;
|
||||
d->foff = data_foff;
|
||||
d->relocs_foff = relocs_foff;
|
||||
d->lines_foff = 0;
|
||||
d->reloc_count = safe_cast_u32(s->reloc_count);
|
||||
d->line_count = 0;
|
||||
d->flags = s->flags;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// symbol table
|
||||
//
|
||||
if (symbol_table.total_size || string_table.total_size > sizeof(*string_table_size)) {
|
||||
file_header->symbol_table_foff = srl.total_size;
|
||||
str8_list_concat_in_place(&srl, &symbol_table);
|
||||
}
|
||||
|
||||
//
|
||||
// string table
|
||||
//
|
||||
if (string_table.total_size) {
|
||||
*string_table_size = safe_cast_u32(string_table.total_size);
|
||||
str8_list_concat_in_place(&srl, &string_table);
|
||||
}
|
||||
|
||||
//
|
||||
// join
|
||||
//
|
||||
String8 obj = str8_list_join(arena, &srl, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return obj;
|
||||
}
|
||||
|
||||
internal COFF_ObjSection *
|
||||
coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
|
||||
{
|
||||
COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
|
||||
SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
|
||||
obj_writer->sect_count += 1;
|
||||
|
||||
COFF_ObjSection *sect = §_n->v;
|
||||
sect->name = name;
|
||||
sect->flags = flags;
|
||||
|
||||
if (data.size) {
|
||||
str8_list_push(obj_writer->arena, §->data, data);
|
||||
}
|
||||
|
||||
return sect;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class)
|
||||
{
|
||||
COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1);
|
||||
SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n);
|
||||
obj_writer->symbol_count += 1;
|
||||
|
||||
COFF_ObjSymbol *s = &n->v;
|
||||
s->name = name;
|
||||
s->value = value;
|
||||
s->loc = loc;
|
||||
s->type = type;
|
||||
s->storage_class = storage_class;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Section;
|
||||
loc.u.section = section;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
|
||||
{
|
||||
COFF_SymbolType type = { .u.msb = COFF_SymDType_Func };
|
||||
COFF_SymbolLocation loc = { .type = COFF_SymbolLocation_Section, .u.section = section };
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Section;
|
||||
loc.u.section = section;
|
||||
|
||||
COFF_SymbolType symtype = {0};
|
||||
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, loc, symtype, COFF_SymStorageClass_Static);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection)
|
||||
{
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, section->name, 0, section);
|
||||
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
|
||||
sd->selection = selection;
|
||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate)
|
||||
{
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, head->name, 0, head);
|
||||
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
|
||||
sd->selection = COFF_ComdatSelect_Associative;
|
||||
sd->associate = associate;
|
||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
COFF_SymbolType symtype = {0};
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, COFF_Symbol_UndefinedSection, loc, symtype, COFF_SymStorageClass_WeakExternal);
|
||||
|
||||
COFF_ObjSymbolWeak *weak_ext = push_array(obj_writer->arena, COFF_ObjSymbolWeak, 1);
|
||||
weak_ext->tag = tag;
|
||||
weak_ext->characteristics = characteristics;
|
||||
|
||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(weak_ext));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Abs;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, storage_class);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Undef;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
type.u.msb = COFF_SymDType_Func;
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Undef;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Undef;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_Section);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Section;
|
||||
loc.u.section = sect;
|
||||
|
||||
// strip align flags
|
||||
COFF_SectionFlags expected_flags = sect->flags & ~(COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift);
|
||||
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, expected_flags, loc, type, COFF_SymStorageClass_Section);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Common;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, size, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol)
|
||||
{
|
||||
AssertAlways(weak_symbol->storage_class == COFF_SymStorageClass_WeakExternal);
|
||||
COFF_ObjSymbolWeak *w = (COFF_ObjSymbolWeak *)weak_symbol->aux_symbols.first->string.str;
|
||||
w->tag = default_symbol;
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc*
|
||||
coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType type)
|
||||
{
|
||||
COFF_ObjRelocNode *reloc_n = push_array(obj_writer->arena, COFF_ObjRelocNode, 1);
|
||||
SLLQueuePush(sect->reloc_first, sect->reloc_last, reloc_n);
|
||||
sect->reloc_count += 1;
|
||||
|
||||
COFF_ObjReloc *reloc = &reloc_n->v;
|
||||
reloc->apply_off = apply_off;
|
||||
reloc->symbol = symbol;
|
||||
reloc->type = type;
|
||||
|
||||
return reloc;
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc *
|
||||
coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
||||
{
|
||||
COFF_RelocType reloc_type = 0;
|
||||
switch (obj_writer->machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32; break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc *
|
||||
coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
||||
{
|
||||
COFF_RelocType reloc_type = 0;
|
||||
switch (obj_writer->machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr64; break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc *
|
||||
coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
||||
{
|
||||
COFF_RelocType reloc_type = 0;
|
||||
switch (obj_writer->machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32Nb; break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive)
|
||||
{
|
||||
if (obj_writer->drectve_sect == 0) {
|
||||
local_persist const U8 bom_sig[] = { ' ', ' ', ' ' };
|
||||
obj_writer->drectve_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".drectve"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove|COFF_SectionFlag_Align1Bytes, str8_array_fixed(bom_sig));
|
||||
}
|
||||
String8List *data = &obj_writer->drectve_sect->data;
|
||||
str8_list_push(obj_writer->arena, data, directive);
|
||||
str8_list_pushf(obj_writer->arena, data, " ");
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_obj_section_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
COFF_ObjSection **a = raw_a;
|
||||
COFF_ObjSection **b = raw_b;
|
||||
return (*a)->section_number < (*b)->section_number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
#ifndef COFF_OBJ_WRITER_H
|
||||
#define COFF_OBJ_WRITER_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COFF_SymbolLocation_Null,
|
||||
COFF_SymbolLocation_Section,
|
||||
COFF_SymbolLocation_Abs,
|
||||
COFF_SymbolLocation_Undef,
|
||||
COFF_SymbolLocation_Common,
|
||||
} COFF_SymbolLocationType;
|
||||
|
||||
typedef struct COFF_SymbolLocation
|
||||
{
|
||||
COFF_SymbolLocationType type;
|
||||
union {
|
||||
struct COFF_ObjSection *section;
|
||||
} u;
|
||||
} COFF_SymbolLocation;
|
||||
|
||||
typedef struct COFF_ObjSymbolWeak
|
||||
{
|
||||
struct COFF_ObjSymbol *tag;
|
||||
COFF_WeakExtType characteristics;
|
||||
} COFF_ObjSymbolWeak;
|
||||
|
||||
typedef struct COFF_ObjSymbolSecDef
|
||||
{
|
||||
COFF_ComdatSelectType selection;
|
||||
struct COFF_ObjSection *associate;
|
||||
} COFF_ObjSymbolSecDef;
|
||||
|
||||
typedef struct COFF_ObjSymbol
|
||||
{
|
||||
String8 name;
|
||||
U32 value;
|
||||
COFF_SymbolLocation loc;
|
||||
COFF_SymbolType type;
|
||||
COFF_SymStorageClass storage_class;
|
||||
String8List aux_symbols;
|
||||
U32 idx;
|
||||
} COFF_ObjSymbol;
|
||||
|
||||
typedef struct COFF_ObjSymbolNode
|
||||
{
|
||||
struct COFF_ObjSymbolNode *next;
|
||||
COFF_ObjSymbol v;
|
||||
} COFF_ObjSymbolNode;
|
||||
|
||||
typedef struct COFF_ObjReloc
|
||||
{
|
||||
U32 apply_off;
|
||||
COFF_ObjSymbol *symbol;
|
||||
COFF_RelocType type;
|
||||
} COFF_ObjReloc;
|
||||
|
||||
typedef struct COFF_ObjRelocNode
|
||||
{
|
||||
struct COFF_ObjRelocNode *next;
|
||||
COFF_ObjReloc v;
|
||||
} COFF_ObjRelocNode;
|
||||
|
||||
typedef struct COFF_ObjSection
|
||||
{
|
||||
String8 name;
|
||||
String8List data;
|
||||
COFF_SectionFlags flags;
|
||||
|
||||
U64 reloc_count;
|
||||
COFF_ObjRelocNode *reloc_first;
|
||||
COFF_ObjRelocNode *reloc_last;
|
||||
|
||||
U32 section_number;
|
||||
} COFF_ObjSection;
|
||||
|
||||
typedef struct COFF_ObjSectionNode
|
||||
{
|
||||
struct COFF_ObjSectionNode *next;
|
||||
COFF_ObjSection v;
|
||||
} COFF_ObjSectionNode;
|
||||
|
||||
typedef struct COFF_ObjWriter
|
||||
{
|
||||
Arena *arena;
|
||||
COFF_TimeStamp time_stamp;
|
||||
COFF_MachineType machine;
|
||||
U64 symbol_count;
|
||||
COFF_ObjSymbolNode *symbol_first;
|
||||
COFF_ObjSymbolNode *symbol_last;
|
||||
U64 sect_count;
|
||||
COFF_ObjSectionNode *sect_first;
|
||||
COFF_ObjSectionNode *sect_last;
|
||||
COFF_ObjSection *drectve_sect;
|
||||
} COFF_ObjWriter;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal COFF_ObjWriter * coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
|
||||
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
|
||||
internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer);
|
||||
|
||||
internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
|
||||
|
||||
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size);
|
||||
|
||||
internal void coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol);
|
||||
|
||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
|
||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
||||
|
||||
internal void coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive);
|
||||
|
||||
#endif // COFF_OBJ_WRITER_H
|
||||
|
||||
@@ -1,991 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal B32
|
||||
coff_is_big_obj(String8 raw_coff)
|
||||
{
|
||||
B32 is_big_obj = 0;
|
||||
if (raw_coff.size >= sizeof(COFF_BigObjHeader)) {
|
||||
COFF_BigObjHeader *file_header32 = (COFF_BigObjHeader*)(raw_coff.str);
|
||||
is_big_obj = file_header32->sig1 == COFF_MachineType_Unknown &&
|
||||
file_header32->sig2 == max_U16 &&
|
||||
file_header32->version >= 2 &&
|
||||
MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0;
|
||||
}
|
||||
return is_big_obj;
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_is_obj(String8 raw_coff)
|
||||
{
|
||||
B32 is_obj = 0;
|
||||
|
||||
if (raw_coff.size >= sizeof(COFF_FileHeader)) {
|
||||
COFF_FileHeader *header = (COFF_FileHeader*)(raw_coff.str);
|
||||
|
||||
// validate machine
|
||||
B32 is_machine_type_valid = 0;
|
||||
switch (header->machine) {
|
||||
case COFF_MachineType_Unknown:
|
||||
case COFF_MachineType_X86: case COFF_MachineType_X64:
|
||||
case COFF_MachineType_Am33: case COFF_MachineType_Arm:
|
||||
case COFF_MachineType_Arm64: case COFF_MachineType_ArmNt:
|
||||
case COFF_MachineType_Ebc: case COFF_MachineType_Ia64:
|
||||
case COFF_MachineType_M32R: case COFF_MachineType_Mips16:
|
||||
case COFF_MachineType_MipsFpu:case COFF_MachineType_MipsFpu16:
|
||||
case COFF_MachineType_PowerPc:case COFF_MachineType_PowerPcFp:
|
||||
case COFF_MachineType_R4000: case COFF_MachineType_RiscV32:
|
||||
case COFF_MachineType_RiscV64:case COFF_MachineType_RiscV128:
|
||||
case COFF_MachineType_Sh3: case COFF_MachineType_Sh3Dsp:
|
||||
case COFF_MachineType_Sh4: case COFF_MachineType_Sh5:
|
||||
case COFF_MachineType_Thumb: case COFF_MachineType_WceMipsV2:
|
||||
{
|
||||
is_machine_type_valid = 1;
|
||||
}break;
|
||||
}
|
||||
|
||||
if (is_machine_type_valid) {
|
||||
// validate section count
|
||||
U64 section_count = header->section_count;
|
||||
U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader);
|
||||
if (raw_coff.size >= section_hdr_opl_off) {
|
||||
|
||||
COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(raw_coff.str + sizeof(*header));
|
||||
COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count;
|
||||
|
||||
// validate section ranges
|
||||
B32 is_sect_range_valid = 1;
|
||||
for (COFF_SectionHeader *sec_hdr = section_hdrs;
|
||||
sec_hdr < section_hdr_opl;
|
||||
sec_hdr += 1) {
|
||||
if (!(sec_hdr->flags & COFF_SectionFlag_CntUninitializedData)) {
|
||||
U64 min = sec_hdr->foff;
|
||||
U64 max = min + sec_hdr->fsize;
|
||||
if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= raw_coff.size)) {
|
||||
is_sect_range_valid = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_sect_range_valid) {
|
||||
// validate symbol table
|
||||
U64 symbol_table_off = header->symbol_table_foff;
|
||||
U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count;
|
||||
U64 symbol_table_opl_off = symbol_table_off + symbol_table_size;
|
||||
|
||||
// don't validate symbol table when there is none
|
||||
if (symbol_table_off == 0 && symbol_table_size == 0) {
|
||||
symbol_table_off = section_hdr_opl_off;
|
||||
symbol_table_opl_off = section_hdr_opl_off;
|
||||
}
|
||||
|
||||
is_obj = (section_hdr_opl_off <= symbol_table_off &&
|
||||
symbol_table_off <= symbol_table_opl_off &&
|
||||
symbol_table_opl_off <= raw_coff.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return is_obj;
|
||||
}
|
||||
|
||||
internal COFF_FileHeaderInfo
|
||||
coff_file_header_info_from_data(String8 raw_coff)
|
||||
{
|
||||
COFF_FileHeaderInfo info = {0};
|
||||
if (coff_is_big_obj(raw_coff)) {
|
||||
COFF_BigObjHeader *header32 = (COFF_BigObjHeader*)raw_coff.str;
|
||||
info.is_big_obj = 1;
|
||||
info.machine = header32->machine;
|
||||
info.section_count_no_null = header32->section_count;
|
||||
info.symbol_count = header32->symbol_count;
|
||||
info.symbol_size = sizeof(COFF_Symbol32);
|
||||
info.header_range = rng_1u64(0, sizeof(COFF_BigObjHeader));
|
||||
info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header32->section_count);
|
||||
info.symbol_table_range = rng_1u64(header32->symbol_table_foff, header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count);
|
||||
info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size);
|
||||
} else if (coff_is_obj(raw_coff)) {
|
||||
COFF_FileHeader *header16 = (COFF_FileHeader*)raw_coff.str;
|
||||
info.is_big_obj = 0;
|
||||
info.machine = header16->machine;
|
||||
info.section_count_no_null = header16->section_count;
|
||||
info.symbol_count = header16->symbol_count;
|
||||
info.symbol_size = sizeof(COFF_Symbol16);
|
||||
info.header_range = rng_1u64(0, sizeof(COFF_FileHeader));
|
||||
info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header16->section_count);
|
||||
info.symbol_table_range = rng_1u64(header16->symbol_table_foff, header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count);
|
||||
info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
internal COFF_SectionHeader **
|
||||
coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range)
|
||||
{
|
||||
U64 section_count = dim_1u64(section_table_range) / sizeof(COFF_SectionHeader);
|
||||
COFF_SectionHeader **section_table = push_array_no_zero(arena, COFF_SectionHeader *, section_count+1);
|
||||
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
|
||||
for (U64 i = 0; i < section_count; ++i) {
|
||||
section_table[i+1] = str8_deserial_get_raw_ptr(data, section_table_range.min + i*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
|
||||
}
|
||||
return section_table;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
|
||||
{
|
||||
COFF_ParsedSymbol result = {0};
|
||||
result.name = coff_read_symbol_name(string_table, &sym32->name);
|
||||
result.value = sym32->value;
|
||||
result.section_number = sym32->section_number;
|
||||
result.type = sym32->type;
|
||||
result.storage_class = sym32->storage_class;
|
||||
result.aux_symbol_count = sym32->aux_symbol_count;
|
||||
result.raw_symbol = sym32;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
|
||||
{
|
||||
COFF_ParsedSymbol result = {0};
|
||||
result.name = coff_read_symbol_name(string_table, &sym16->name);
|
||||
result.value = sym16->value;
|
||||
if (sym16->section_number == COFF_Symbol_DebugSection16) {
|
||||
result.section_number = COFF_Symbol_DebugSection32;
|
||||
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
|
||||
result.section_number = COFF_Symbol_AbsSection32;
|
||||
} else {
|
||||
result.section_number = (U32)sym16->section_number;
|
||||
}
|
||||
result.type = sym16->type;
|
||||
result.storage_class = sym16->storage_class;
|
||||
result.aux_symbol_count = sym16->aux_symbol_count;
|
||||
result.raw_symbol = sym16;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx)
|
||||
{
|
||||
COFF_ParsedSymbol symbol;
|
||||
if (header.is_big_obj) {
|
||||
symbol = coff_parse_symbol32(string_table, (COFF_Symbol32 *)symbol_table.str + symbol_idx);
|
||||
} else {
|
||||
symbol = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + symbol_idx);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal COFF_Symbol32Array
|
||||
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
|
||||
{
|
||||
COFF_Symbol32Array result = {0};
|
||||
result.count = symbol_count;
|
||||
result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8);
|
||||
|
||||
Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count);
|
||||
String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range);
|
||||
COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str;
|
||||
|
||||
for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) {
|
||||
COFF_Symbol16 *sym16 = &sym16_arr[isymbol];
|
||||
COFF_Symbol32 *sym32 = &result.v[isymbol];
|
||||
|
||||
sym32->name = sym16->name;
|
||||
sym32->value = sym16->value;
|
||||
if (sym16->section_number == COFF_Symbol_DebugSection16) {
|
||||
sym32->section_number = COFF_Symbol_DebugSection32;
|
||||
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
|
||||
sym32->section_number = COFF_Symbol_AbsSection32;
|
||||
} else {
|
||||
sym32->section_number = (U32)sym16->section_number;
|
||||
}
|
||||
sym32->type.v = sym16->type.v;
|
||||
sym32->storage_class = sym16->storage_class;
|
||||
sym32->aux_symbol_count = sym16->aux_symbol_count;
|
||||
|
||||
// copy aux symbols
|
||||
for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) {
|
||||
COFF_Symbol16 *aux16 = sym16_arr + iaux;
|
||||
COFF_Symbol32 *aux32 = result.v + iaux;
|
||||
|
||||
// 32bit COFF uses 16bit aux symbols
|
||||
MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16));
|
||||
MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16));
|
||||
}
|
||||
|
||||
// take into account aux symbols
|
||||
isymbol += sym32->aux_symbol_count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_Symbol32Array
|
||||
coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count)
|
||||
{
|
||||
COFF_Symbol32Array result;
|
||||
result.count = symbol_count;
|
||||
result.v = (COFF_Symbol32 *)(data.str + symbol_array_off);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_Symbol32Array
|
||||
coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size)
|
||||
{
|
||||
COFF_Symbol32Array result = {0};
|
||||
switch (symbol_size) {
|
||||
case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_array_off, symbol_count); break;
|
||||
case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_array_off, symbol_count); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_Symbol16Node *
|
||||
coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol)
|
||||
{
|
||||
COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1);
|
||||
node->next = 0;
|
||||
node->data = symbol;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal COFF_SymbolValueInterpType
|
||||
coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class)
|
||||
{
|
||||
if (storage_class == COFF_SymStorageClass_Section && section_number == COFF_Symbol_UndefinedSection) {
|
||||
return COFF_SymbolValueInterp_Undefined;
|
||||
}
|
||||
if (storage_class == COFF_SymStorageClass_External && value == 0 && section_number == COFF_Symbol_UndefinedSection) {
|
||||
return COFF_SymbolValueInterp_Undefined;
|
||||
}
|
||||
if (storage_class == COFF_SymStorageClass_External && value != 0 && section_number == COFF_Symbol_UndefinedSection) {
|
||||
return COFF_SymbolValueInterp_Common;
|
||||
}
|
||||
if (section_number == COFF_Symbol_AbsSection32) {
|
||||
return COFF_SymbolValueInterp_Abs;
|
||||
}
|
||||
if (section_number == COFF_Symbol_DebugSection32) {
|
||||
return COFF_SymbolValueInterp_Debug;
|
||||
}
|
||||
if (storage_class == COFF_SymStorageClass_WeakExternal) {
|
||||
return COFF_SymbolValueInterp_Weak;
|
||||
}
|
||||
return COFF_SymbolValueInterp_Regular;
|
||||
}
|
||||
|
||||
internal COFF_SymbolValueInterpType
|
||||
coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol)
|
||||
{
|
||||
return coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol)
|
||||
{
|
||||
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
|
||||
return interp == COFF_SymbolValueInterp_Undefined && symbol.storage_class == COFF_SymStorageClass_External;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out)
|
||||
{
|
||||
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Regular);
|
||||
Assert(symbol.aux_symbol_count > 0);
|
||||
|
||||
if (is_big_obj) {
|
||||
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
|
||||
if (selection_out) *selection_out = sd->selection;
|
||||
if (length_out) *length_out = sd->length;
|
||||
if (check_sum_out) *check_sum_out = sd->check_sum;
|
||||
if (number_out) *number_out = Compose32Bit(sd->number_hi, sd->number_lo);
|
||||
} else {
|
||||
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
|
||||
if (selection_out) *selection_out = sd->selection;
|
||||
if (length_out) *length_out = sd->length;
|
||||
if (check_sum_out) *check_sum_out = sd->check_sum;
|
||||
if (number_out) *number_out = sd->number_lo;
|
||||
}
|
||||
}
|
||||
|
||||
internal COFF_SymbolWeakExt *
|
||||
coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj)
|
||||
{
|
||||
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Weak);
|
||||
Assert(symbol.aux_symbol_count > 0);
|
||||
|
||||
void *tag;
|
||||
if (is_big_obj) {
|
||||
tag = (COFF_SymbolWeakExt *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
|
||||
} else {
|
||||
tag = (COFF_SymbolWeakExt *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
internal COFF_RelocNode *
|
||||
coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc)
|
||||
{
|
||||
COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1);
|
||||
node->data = reloc;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal COFF_RelocInfo
|
||||
coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header)
|
||||
{
|
||||
COFF_RelocInfo result = {0};
|
||||
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl && header->reloc_count == max_U16) {
|
||||
COFF_Reloc counter;
|
||||
U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter);
|
||||
if (read_size == sizeof(counter) && counter.apply_off > 0) {
|
||||
result.array_off = header->relocs_foff + sizeof(COFF_Reloc);
|
||||
result.count = counter.apply_off - 1; // exclude counter entry
|
||||
}
|
||||
} else {
|
||||
result.array_off = header->relocs_foff;
|
||||
result.count = header->reloc_count;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_resource_string_from_str16(Arena *arena, String16 string)
|
||||
{
|
||||
AssertAlways(string.size <= max_U16);
|
||||
U16 size16 = (U16)string.size;
|
||||
|
||||
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
|
||||
MemoryCopy(buffer + 0, &size16, sizeof(size16));
|
||||
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
|
||||
|
||||
return str8_array(buffer, size16 + 1);
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_resource_string_from_str8(Arena *arena, String8 string)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String16 string16 = str16_from_8(scratch.arena, string);
|
||||
String8 result = coff_resource_string_from_str16(arena, string16);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_resource_number_from_u16(Arena *arena, U16 number)
|
||||
{
|
||||
U16 *buffer = push_array_no_zero(arena, U16, 2);
|
||||
buffer[0] = max_U16;
|
||||
buffer[1] = number;
|
||||
return str8_array(buffer, 2);
|
||||
}
|
||||
|
||||
internal COFF_ResourceID
|
||||
coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16)
|
||||
{
|
||||
COFF_ResourceID id = {0};
|
||||
id.type = id_16->type;
|
||||
switch (id_16->type) {
|
||||
case COFF_ResourceIDType_Null: break;
|
||||
case COFF_ResourceIDType_Number: {
|
||||
id.u.number = id_16->u.number;
|
||||
} break;
|
||||
case COFF_ResourceIDType_String: {
|
||||
id.u.string = str8_from_16(arena, id_16->u.string);
|
||||
} break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_read_resource_id_utf16(String8 raw_res, U64 off, COFF_ResourceID16 *id_out)
|
||||
{
|
||||
U64 cursor = off;
|
||||
|
||||
U16 flag = 0;
|
||||
str8_deserial_read_struct(raw_res, cursor, &flag);
|
||||
|
||||
if (flag == max_U16) {
|
||||
id_out->type = COFF_ResourceIDType_Number;
|
||||
cursor += sizeof(flag);
|
||||
cursor += str8_deserial_read_struct(raw_res, cursor, &id_out->u.number);
|
||||
} else {
|
||||
id_out->type = COFF_ResourceIDType_String;
|
||||
cursor += str8_deserial_read_windows_utf16_string16(raw_res, cursor, &id_out->u.string);
|
||||
}
|
||||
|
||||
U64 read_size = cursor - off;
|
||||
read_size = AlignPow2(read_size, COFF_ResourceAlign);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out)
|
||||
{
|
||||
String8 raw_header = str8_skip(raw_res, off);
|
||||
U64 header_cursor = 0;
|
||||
|
||||
// prefix
|
||||
COFF_ResourceHeaderPrefix prefix = {0};
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
|
||||
|
||||
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
|
||||
raw_header = str8_prefix(raw_header, prefix.header_size);
|
||||
|
||||
// header
|
||||
COFF_ResourceID16 type_16 = {0};
|
||||
COFF_ResourceID16 name_16 = {0};
|
||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
|
||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
|
||||
Assert(prefix.header_size == header_cursor);
|
||||
|
||||
// convert utf-16 resource ids to utf-8
|
||||
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
|
||||
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
|
||||
|
||||
// read data
|
||||
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
|
||||
Assert(prefix.data_size == data_read_size);
|
||||
|
||||
// compute read size
|
||||
U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_ResourceAlign);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal COFF_ParsedResourceList
|
||||
coff_resource_list_from_data(Arena *arena, String8 data)
|
||||
{
|
||||
COFF_ParsedResourceList list = {0};
|
||||
U64 cursor;
|
||||
for (cursor = 0 ; cursor < data.size; ) {
|
||||
COFF_ParsedResourceNode *node = push_array(arena, COFF_ParsedResourceNode, 1);
|
||||
cursor += coff_read_resource(arena, data, cursor, &node->data);
|
||||
SLLQueuePush(list.first, list.last, node);
|
||||
++list.count;
|
||||
}
|
||||
Assert(cursor == data.size);
|
||||
return list;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_write_resource_id(Arena *arena, COFF_ResourceID id)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (id.type) {
|
||||
case COFF_ResourceIDType_Null: break;
|
||||
case COFF_ResourceIDType_Number: {
|
||||
result = coff_resource_number_from_u16(arena, id.u.number);
|
||||
} break;
|
||||
case COFF_ResourceIDType_String: {
|
||||
result = coff_resource_string_from_str8(arena, id.u.string);
|
||||
} break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_write_resource(Arena *arena,
|
||||
COFF_ResourceID type,
|
||||
COFF_ResourceID name,
|
||||
U32 data_version,
|
||||
COFF_ResourceMemoryFlags memory_flags,
|
||||
U16 language_id,
|
||||
U32 version,
|
||||
U32 characteristics,
|
||||
String8 data)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List list = {0};
|
||||
|
||||
COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
|
||||
String8 packed_type = coff_write_resource_id(scratch.arena, type);
|
||||
String8 packed_name = coff_write_resource_id(scratch.arena, name);
|
||||
|
||||
// prefix + header
|
||||
str8_list_push(scratch.arena, &list, str8_struct(prefix));
|
||||
str8_list_push(scratch.arena, &list, packed_type);
|
||||
str8_list_push(scratch.arena, &list, packed_name);
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&version));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
|
||||
|
||||
prefix->data_size = safe_cast_u32(data.size);
|
||||
prefix->header_size = safe_cast_u32(list.total_size);
|
||||
|
||||
// data
|
||||
str8_list_push(scratch.arena, &list, data);
|
||||
|
||||
// magic
|
||||
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
|
||||
|
||||
// align
|
||||
U64 align_size = AlignPow2(list.total_size, COFF_ResourceAlign) - list.total_size;
|
||||
U8 *align = push_array(scratch.arena, U8, align_size);
|
||||
str8_list_push(scratch.arena, &list, str8(align, align_size));
|
||||
|
||||
// join
|
||||
String8 res = str8_list_join(arena, &list, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return res;
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_resource_id_compar(void *raw_a, void *raw_b)
|
||||
{
|
||||
int cmp;
|
||||
COFF_ResourceID *a = raw_a;
|
||||
COFF_ResourceID *b = raw_b;
|
||||
if (a->type == b->type) {
|
||||
switch (a->type) {
|
||||
default:
|
||||
case COFF_ResourceIDType_Null: cmp = 0; break;
|
||||
case COFF_ResourceIDType_Number: cmp = MemoryCompare(&a->u.number, &b->u.number, sizeof(a->u.number)); break;
|
||||
case COFF_ResourceIDType_String: cmp = strncmp((char *)a->u.string.str, (char *)b->u.string.str, Min(a->u.string.size, b->u.string.size)); break;
|
||||
}
|
||||
} else {
|
||||
cmp = a->type < b->type ? -1 : a->type > b->type ? +1 : 0;
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_is_import(String8 raw_archive_member)
|
||||
{
|
||||
B32 is_import = 0;
|
||||
if (raw_archive_member.size >= sizeof(U16)*2) {
|
||||
U16 *sig1 = (U16*)raw_archive_member.str;
|
||||
U16 *sig2 = sig1 + 1;
|
||||
is_import = *sig1 == COFF_MachineType_Unknown && *sig2 == 0xffff;
|
||||
}
|
||||
return is_import;
|
||||
}
|
||||
|
||||
internal COFF_DataType
|
||||
coff_data_type_from_data(String8 raw_archive_member)
|
||||
{
|
||||
B32 is_big_obj = coff_is_big_obj(raw_archive_member);
|
||||
if (is_big_obj) {
|
||||
return COFF_DataType_BigObj;
|
||||
}
|
||||
B32 is_import = coff_is_import(raw_archive_member);
|
||||
if (is_import) {
|
||||
return COFF_DataType_Import;
|
||||
}
|
||||
return COFF_DataType_Obj;
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_is_regular_archive(String8 raw_archive)
|
||||
{
|
||||
B32 is_archive = 0;
|
||||
U8 sig[sizeof(g_coff_archive_sig)];
|
||||
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
|
||||
is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0;
|
||||
}
|
||||
return is_archive;
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_is_thin_archive(String8 raw_archive)
|
||||
{
|
||||
B32 is_archive = 0;
|
||||
U8 sig[sizeof(g_coff_thin_archive_sig)];
|
||||
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
|
||||
is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0;
|
||||
}
|
||||
return is_archive;
|
||||
}
|
||||
|
||||
internal COFF_ArchiveType
|
||||
coff_archive_type_from_data(String8 raw_archive)
|
||||
{
|
||||
if (coff_is_regular_archive(raw_archive)) {
|
||||
return COFF_Archive_Regular;
|
||||
} else if (coff_is_thin_archive(raw_archive)) {
|
||||
return COFF_Archive_Thin;
|
||||
}
|
||||
return COFF_Archive_Null;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out)
|
||||
{
|
||||
COFF_ArchiveMemberHeader *header = str8_deserial_get_raw_ptr(raw_archive, offset, sizeof(*header));
|
||||
if (header) {
|
||||
String8 name = str8_skip_chop_whitespace(str8_cstring_capped(header->name, header->name + sizeof(header->name) ));
|
||||
String8 date = str8_skip_chop_whitespace(str8_cstring_capped(header->date, header->date + sizeof(header->date) ));
|
||||
String8 user_id = str8_skip_chop_whitespace(str8_cstring_capped(header->user_id, header->user_id + sizeof(header->user_id) ));
|
||||
String8 group_id = str8_skip_chop_whitespace(str8_cstring_capped(header->group_id, header->group_id + sizeof(header->group_id)));
|
||||
String8 mode = str8_skip_chop_whitespace(str8_cstring_capped(header->mode, header->mode + sizeof(header->mode) ));
|
||||
String8 size = str8_skip_chop_whitespace(str8_cstring_capped(header->size, header->size + sizeof(header->size) ));
|
||||
String8 end = str8_cstring_capped(header->end, header->end + sizeof(header->end));
|
||||
|
||||
U32 data_size = u32_from_str8(size, 10);
|
||||
U64 data_off = offset + sizeof(COFF_ArchiveMemberHeader);
|
||||
|
||||
header_out->name = name;
|
||||
header_out->time_stamp = u32_from_str8(date, 10);
|
||||
header_out->user_id = u32_from_str8(user_id, 10);
|
||||
header_out->group_id = u32_from_str8(group_id, 10);
|
||||
header_out->mode = mode;
|
||||
header_out->is_end_correct = str8_match_lit("`\n", end, 0);
|
||||
header_out->data_range = rng_1u64(data_off, data_off + data_size);
|
||||
|
||||
return sizeof(*header);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal COFF_ArchiveFirstMember
|
||||
coff_parse_first_archive_member(COFF_ArchiveMember *member)
|
||||
{
|
||||
Assert(str8_match_lit("/", member->header.name, 0));
|
||||
|
||||
U64 cursor = 0;
|
||||
|
||||
U32 symbol_count = 0;
|
||||
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
|
||||
|
||||
symbol_count = from_be_u32(symbol_count);
|
||||
|
||||
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32));
|
||||
cursor += dim_1u64(member_offsets_range);
|
||||
|
||||
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
|
||||
cursor += dim_1u64(string_table_range);
|
||||
|
||||
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
|
||||
U32 *member_offsets = (U32 *)raw_member_offsets.str;
|
||||
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
|
||||
|
||||
COFF_ArchiveFirstMember result = {0};
|
||||
result.symbol_count = symbol_count;
|
||||
result.member_offset_count = member_offset_count;
|
||||
result.member_offsets = member_offsets;
|
||||
result.string_table = str8_substr(member->data, string_table_range);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_ArchiveSecondMember
|
||||
coff_parse_second_archive_member(COFF_ArchiveMember *member)
|
||||
{
|
||||
COFF_ArchiveSecondMember result = {0};
|
||||
|
||||
if (str8_match_lit("/", member->header.name, 0)) {
|
||||
U64 cursor = 0;
|
||||
|
||||
U32 member_count = 0;
|
||||
cursor += str8_deserial_read_struct(member->data, cursor, &member_count);
|
||||
|
||||
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32));
|
||||
cursor += dim_1u64(member_offsets_range);
|
||||
|
||||
U32 symbol_count = 0;
|
||||
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
|
||||
|
||||
Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16));
|
||||
cursor += dim_1u64(symbol_indices_range);
|
||||
|
||||
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
|
||||
|
||||
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
|
||||
String8 raw_indices = str8_substr(member->data, symbol_indices_range);
|
||||
|
||||
U32 *member_offsets = (U32 *)raw_member_offsets.str;
|
||||
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
|
||||
|
||||
U16 *symbol_indices = (U16 *)raw_indices.str;
|
||||
U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]);
|
||||
|
||||
result.member_count = member_count;
|
||||
result.symbol_count = symbol_count;
|
||||
result.member_offsets = member_offsets;
|
||||
result.member_offset_count = member_offset_count;
|
||||
result.symbol_indices = symbol_indices;
|
||||
result.symbol_index_count = symbol_index_count;
|
||||
result.string_table = str8_substr(member->data, string_table_range);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_decode_raw_member_name(String8 long_names, String8 name)
|
||||
{
|
||||
String8 result = name;
|
||||
if (name.size > 0 && name.str[0] == '/') {
|
||||
String8 offset_str = str8(name.str + 1, name.size - 1);
|
||||
U64 offset = u64_from_str8(offset_str, 10);
|
||||
if (offset < long_names.size) {
|
||||
U8 *ptr = long_names.str + offset;
|
||||
U8 *opl = long_names.str + long_names.size;
|
||||
for (; ptr < opl; ++ptr) {
|
||||
if (*ptr == '\0' || *ptr == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = str8_range(long_names.str + offset, ptr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_decode_member_name(String8 long_names, String8 name)
|
||||
{
|
||||
String8 member_name = coff_decode_raw_member_name(long_names, name);
|
||||
String8 slash = str8_lit("/");
|
||||
if (str8_ends_with(member_name, slash, 0)) {
|
||||
member_name = str8_chop(member_name, slash.size);
|
||||
}
|
||||
return member_name;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out)
|
||||
{
|
||||
COFF_ImportHeader *header = str8_deserial_get_raw_ptr(raw_archive_member, offset, sizeof(*header));
|
||||
if (header) {
|
||||
Rng1U64 data_range = rng_1u64(offset + sizeof(*header), offset + sizeof(*header) + header->data_size);
|
||||
String8 raw_data = str8_substr(raw_archive_member, data_range);
|
||||
U64 data_cursor = 0;
|
||||
|
||||
header_out->version = header->version;
|
||||
header_out->machine = header->machine;
|
||||
header_out->time_stamp = header->time_stamp;
|
||||
header_out->data_size = header->data_size;
|
||||
header_out->hint_or_ordinal = header->hint_or_ordinal;
|
||||
header_out->type = COFF_ImportHeader_ExtractType(header->flags);
|
||||
header_out->import_by = COFF_ImportHeader_ExtractImportBy(header->flags);
|
||||
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->func_name);
|
||||
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->dll_name);
|
||||
|
||||
Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size);
|
||||
U64 read_size = sizeof(*header) + header->data_size;
|
||||
return read_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal COFF_ArchiveMember
|
||||
coff_archive_member_from_offset(String8 raw_archive, U64 offset)
|
||||
{
|
||||
COFF_ArchiveMember member = {0};
|
||||
coff_regular_archive_member_iter_next(raw_archive, &offset, &member);
|
||||
return member;
|
||||
}
|
||||
|
||||
internal COFF_ArchiveMember
|
||||
coff_archive_member_from_data(String8 raw_archive_member)
|
||||
{
|
||||
return coff_archive_member_from_offset(raw_archive_member, 0);
|
||||
}
|
||||
|
||||
internal COFF_ParsedArchiveImportHeader
|
||||
coff_archive_import_from_data(String8 raw_archive_member)
|
||||
{
|
||||
COFF_ParsedArchiveImportHeader header = {0};
|
||||
coff_parse_import(raw_archive_member, 0, &header);
|
||||
return header;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_regular_archive_member_iter_init(String8 raw_archive)
|
||||
{
|
||||
U64 cursor = raw_archive.size;
|
||||
if (coff_is_regular_archive(raw_archive)) {
|
||||
cursor = sizeof(g_coff_archive_sig);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
|
||||
{
|
||||
B32 is_parsed = 0;
|
||||
|
||||
member_out->header.is_end_correct = 0;
|
||||
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
|
||||
|
||||
if (member_out->header.is_end_correct) {
|
||||
member_out->offset = *offset;
|
||||
member_out->data = str8_substr(raw_archive, member_out->header.data_range);
|
||||
|
||||
U64 read_size = AlignPow2(header_size + dim_1u64(member_out->header.data_range), COFF_Archive_MemberAlign);
|
||||
*offset += read_size;
|
||||
|
||||
is_parsed = 1;
|
||||
}
|
||||
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_thin_archive_member_iter_init(String8 raw_archive)
|
||||
{
|
||||
U64 cursor = raw_archive.size;
|
||||
if (coff_is_thin_archive(raw_archive)) {
|
||||
cursor = sizeof(g_coff_thin_archive_sig);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
|
||||
{
|
||||
B32 is_parsed = 0;
|
||||
|
||||
member_out->header.is_end_correct = 0;
|
||||
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
|
||||
|
||||
if (member_out->header.is_end_correct) {
|
||||
Rng1U64 data_in_archive_range = {0};
|
||||
if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) {
|
||||
data_in_archive_range = member_out->header.data_range;
|
||||
}
|
||||
|
||||
member_out->offset = *offset;
|
||||
member_out->data = str8_substr(raw_archive, data_in_archive_range);
|
||||
|
||||
U64 read_size = AlignPow2(header_size + dim_1u64(data_in_archive_range), COFF_Archive_MemberAlign);
|
||||
*offset += read_size;
|
||||
|
||||
is_parsed = 1;
|
||||
}
|
||||
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal COFF_ArchiveParse
|
||||
coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list)
|
||||
{
|
||||
String8 error = str8_zero();
|
||||
B32 has_second_header = 0;
|
||||
B32 has_long_names = 0;
|
||||
COFF_ArchiveMember first_header = {0};
|
||||
COFF_ArchiveMember second_header = {0};
|
||||
COFF_ArchiveMember long_names_member = {0};
|
||||
|
||||
COFF_ArchiveMemberNode *ptr = member_list.first;
|
||||
|
||||
if (ptr) {
|
||||
if (str8_match_lit("/", ptr->data.header.name, 0)) {
|
||||
if (ptr->data.header.is_end_correct) {
|
||||
first_header = ptr->data;
|
||||
ptr = ptr->next;
|
||||
} else {
|
||||
error = str8_lit("first header doesn't have correct end");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error = str8_lit("missing first header");
|
||||
}
|
||||
|
||||
if (!error.size && ptr) {
|
||||
if (str8_match_lit("/", ptr->data.header.name, 0)) {
|
||||
if (ptr->data.header.is_end_correct) {
|
||||
second_header = ptr->data;
|
||||
ptr = ptr->next;
|
||||
has_second_header = 1;
|
||||
} else {
|
||||
error = str8_lit("second header doesn't have correct end");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!error.size && ptr) {
|
||||
if (str8_match_lit("//", ptr->data.header.name, 0)) {
|
||||
if (ptr->data.header.is_end_correct) {
|
||||
long_names_member = ptr->data;
|
||||
ptr = ptr->next;
|
||||
has_long_names;
|
||||
} else {
|
||||
error = str8_lit("long names header doesn't have correct end");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
COFF_ArchiveParse parse = {0};
|
||||
parse.has_second_header = has_second_header;
|
||||
parse.has_long_names = has_long_names;
|
||||
parse.first_member = coff_parse_first_archive_member(&first_header);
|
||||
parse.second_member = coff_parse_second_archive_member(&second_header);
|
||||
parse.long_names = long_names_member.data;
|
||||
parse.error = error;
|
||||
|
||||
return parse;
|
||||
}
|
||||
|
||||
internal COFF_ArchiveParse
|
||||
coff_regular_archive_parse_from_data(String8 raw_archive)
|
||||
{
|
||||
COFF_ArchiveMemberList list = {0};
|
||||
COFF_ArchiveMemberNode node_arr[3] = {0};
|
||||
U64 cursor = coff_regular_archive_member_iter_init(raw_archive);
|
||||
for (U64 i = 0; i < ArrayCount(node_arr); ++i) {
|
||||
COFF_ArchiveMemberNode *node = &node_arr[i];
|
||||
if (!coff_regular_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
|
||||
break;
|
||||
}
|
||||
coff_archive_member_list_push_node(&list, node);
|
||||
}
|
||||
return coff_archive_parse_from_member_list(list);
|
||||
}
|
||||
|
||||
internal COFF_ArchiveParse
|
||||
coff_thin_archive_parse_from_data(String8 raw_archive)
|
||||
{
|
||||
COFF_ArchiveMemberList list = {0};
|
||||
COFF_ArchiveMemberNode node_arr[3] = {0};
|
||||
U64 cursor = coff_thin_archive_member_iter_init(raw_archive);
|
||||
for (U64 i = 0; i < ArrayCount(node_arr); i += 1) {
|
||||
COFF_ArchiveMemberNode *node = &node_arr[i];
|
||||
if (!coff_thin_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
|
||||
break;
|
||||
}
|
||||
coff_archive_member_list_push_node(&list, node);
|
||||
}
|
||||
return coff_archive_parse_from_member_list(list);
|
||||
}
|
||||
|
||||
internal COFF_ArchiveParse
|
||||
coff_archive_parse_from_data(String8 raw_archive)
|
||||
{
|
||||
COFF_ArchiveType type = coff_archive_type_from_data(raw_archive);
|
||||
switch (type) {
|
||||
case COFF_Archive_Null: break;
|
||||
case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive);
|
||||
case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive);
|
||||
}
|
||||
COFF_ArchiveParse null_parse = {0};
|
||||
return null_parse;
|
||||
}
|
||||
|
||||
@@ -1,329 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef COFF_PARSE_H
|
||||
#define COFF_PARSE_H
|
||||
|
||||
typedef struct COFF_FileHeaderInfo
|
||||
{
|
||||
B32 is_big_obj;
|
||||
COFF_MachineType machine;
|
||||
U64 header_size;
|
||||
U64 section_count_no_null;
|
||||
U64 symbol_size;
|
||||
U64 symbol_count;
|
||||
Rng1U64 header_range;
|
||||
Rng1U64 section_table_range;
|
||||
Rng1U64 symbol_table_range;
|
||||
Rng1U64 string_table_range;
|
||||
} COFF_FileHeaderInfo;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct COFF_SectionHeaderArray
|
||||
{
|
||||
U64 count;
|
||||
COFF_SectionHeader *v;
|
||||
} COFF_SectionHeaderArray;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct COFF_Symbol16Node
|
||||
{
|
||||
struct COFF_Symbol16Node *next;
|
||||
COFF_Symbol16 data;
|
||||
} COFF_Symbol16Node;
|
||||
|
||||
typedef struct COFF_Symbol16List
|
||||
{
|
||||
U64 count;
|
||||
COFF_Symbol16Node *first;
|
||||
COFF_Symbol16Node *last;
|
||||
} COFF_Symbol16List;
|
||||
|
||||
typedef struct COFF_Symbol32Array
|
||||
{
|
||||
U64 count;
|
||||
COFF_Symbol32 *v;
|
||||
} COFF_Symbol32Array;
|
||||
|
||||
typedef struct COFF_ParsedSymbol
|
||||
{
|
||||
String8 name;
|
||||
U64 value;
|
||||
U32 section_number;
|
||||
COFF_SymbolType type;
|
||||
COFF_SymStorageClass storage_class;
|
||||
U8 aux_symbol_count;
|
||||
void *raw_symbol;
|
||||
} COFF_ParsedSymbol;
|
||||
|
||||
typedef U32 COFF_SymbolValueInterpType;
|
||||
enum
|
||||
{
|
||||
COFF_SymbolValueInterp_Regular, // symbol has section and offset.
|
||||
COFF_SymbolValueInterp_Weak, // symbol is overridable.
|
||||
COFF_SymbolValueInterp_Undefined, // symbol doesn't have a reference section.
|
||||
COFF_SymbolValueInterp_Common, // symbol has no section but still has size.
|
||||
COFF_SymbolValueInterp_Abs, // symbol has an absolute (non-relocatable) value and is not an address.
|
||||
COFF_SymbolValueInterp_Debug // symbol is used to provide general type of debugging information.
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct COFF_RelocNode
|
||||
{
|
||||
struct COFF_RelocNode *next;
|
||||
COFF_Reloc data;
|
||||
} COFF_RelocNode;
|
||||
|
||||
typedef struct COFF_RelocList
|
||||
{
|
||||
U64 count;
|
||||
COFF_RelocNode *first;
|
||||
COFF_RelocNode *last;
|
||||
} COFF_RelocList;
|
||||
|
||||
typedef struct COFF_RelocArray
|
||||
{
|
||||
U64 count;
|
||||
COFF_Reloc *v;
|
||||
} COFF_RelocArray;
|
||||
|
||||
typedef struct COFF_RelocInfo
|
||||
{
|
||||
U64 array_off;
|
||||
U64 count;
|
||||
} COFF_RelocInfo;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef U32 COFF_ResourceIDType;
|
||||
enum COFF_ResourceIDTypeEnum
|
||||
{
|
||||
COFF_ResourceIDType_Null,
|
||||
COFF_ResourceIDType_Number,
|
||||
COFF_ResourceIDType_String,
|
||||
COFF_ResourceIDType_Count
|
||||
};
|
||||
|
||||
typedef struct COFF_ResourceID16
|
||||
{
|
||||
COFF_ResourceIDType type;
|
||||
union {
|
||||
U16 number;
|
||||
String16 string;
|
||||
} u;
|
||||
} COFF_ResourceID16;
|
||||
|
||||
typedef struct COFF_ResourceID
|
||||
{
|
||||
COFF_ResourceIDType type;
|
||||
union {
|
||||
U16 number;
|
||||
String8 string;
|
||||
} u;
|
||||
} COFF_ResourceID;
|
||||
|
||||
typedef struct COFF_ParsedResource
|
||||
{
|
||||
COFF_ResourceID type;
|
||||
COFF_ResourceID name;
|
||||
U32 data_version;
|
||||
COFF_ResourceMemoryFlags memory_flags;
|
||||
U16 language_id;
|
||||
U32 version;
|
||||
U32 characteristics;
|
||||
String8 data;
|
||||
} COFF_ParsedResource;
|
||||
|
||||
typedef struct COFF_ParsedResourceNode
|
||||
{
|
||||
struct COFF_ParsedResourceNode *next;
|
||||
COFF_ParsedResource data;
|
||||
} COFF_ParsedResourceNode;
|
||||
|
||||
typedef struct COFF_ParsedResourceList
|
||||
{
|
||||
U64 count;
|
||||
COFF_ParsedResourceNode *first;
|
||||
COFF_ParsedResourceNode *last;
|
||||
} COFF_ParsedResourceList;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COFF_DataType_Null,
|
||||
COFF_DataType_Obj,
|
||||
COFF_DataType_BigObj,
|
||||
COFF_DataType_Import
|
||||
} COFF_DataType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COFF_Archive_Null,
|
||||
COFF_Archive_Regular,
|
||||
COFF_Archive_Thin
|
||||
} COFF_ArchiveType;
|
||||
|
||||
typedef struct COFF_ParsedArchiveMemberHeader
|
||||
{
|
||||
String8 name; // padded to 16 bytes with spaces
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 user_id; // unix artifact that does not have meaning on windows
|
||||
U32 group_id; // unix artifact that does not have meaning on windows
|
||||
String8 mode; // octal representation the members file mode
|
||||
B32 is_end_correct; // set to true if found correct signature after header
|
||||
Rng1U64 data_range;
|
||||
} COFF_ParsedArchiveMemberHeader;
|
||||
|
||||
typedef struct COFF_ParsedArchiveImportHeader
|
||||
{
|
||||
B32 is_sig_correct;
|
||||
U16 version;
|
||||
COFF_MachineType machine;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 data_size;
|
||||
U16 hint_or_ordinal;
|
||||
COFF_ImportType type;
|
||||
COFF_ImportByType import_by;
|
||||
String8 func_name;
|
||||
String8 dll_name;
|
||||
} COFF_ParsedArchiveImportHeader;
|
||||
|
||||
typedef struct COFF_ArchiveMember
|
||||
{
|
||||
COFF_ParsedArchiveMemberHeader header;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
} COFF_ArchiveMember;
|
||||
|
||||
typedef struct COFF_ArchiveFirstMember
|
||||
{
|
||||
U32 symbol_count;
|
||||
U64 member_offset_count;
|
||||
U32 *member_offsets;
|
||||
String8 string_table;
|
||||
} COFF_ArchiveFirstMember;
|
||||
|
||||
typedef struct COFF_ArchiveSecondMember
|
||||
{
|
||||
U32 member_count;
|
||||
U32 symbol_count;
|
||||
U64 member_offset_count;
|
||||
U32 *member_offsets;
|
||||
U64 symbol_index_count;
|
||||
U16 *symbol_indices;
|
||||
String8 string_table;
|
||||
} COFF_ArchiveSecondMember;
|
||||
|
||||
typedef struct COFF_ArchiveMemberNode
|
||||
{
|
||||
struct COFF_ArchiveMemberNode *next;
|
||||
COFF_ArchiveMember data;
|
||||
} COFF_ArchiveMemberNode;
|
||||
|
||||
typedef struct COFF_ArchiveMemberList
|
||||
{
|
||||
U64 count;
|
||||
COFF_ArchiveMemberNode *first;
|
||||
COFF_ArchiveMemberNode *last;
|
||||
} COFF_ArchiveMemberList;
|
||||
|
||||
typedef struct COFF_ArchiveParse
|
||||
{
|
||||
B32 has_second_header;
|
||||
B32 has_long_names;
|
||||
COFF_ArchiveFirstMember first_member;
|
||||
COFF_ArchiveSecondMember second_member;
|
||||
String8 long_names;
|
||||
String8 error;
|
||||
} COFF_ArchiveParse;
|
||||
|
||||
////////////////////////////////
|
||||
// Obj Header
|
||||
|
||||
internal B32 coff_is_big_obj(String8 raw_coff);
|
||||
internal B32 coff_is_obj (String8 raw_coff);
|
||||
internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff);
|
||||
|
||||
////////////////////////////////
|
||||
// Section
|
||||
|
||||
internal COFF_SectionHeader ** coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range);
|
||||
|
||||
////////////////////////////////
|
||||
// Symbol
|
||||
|
||||
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
|
||||
internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16);
|
||||
internal COFF_ParsedSymbol coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
|
||||
|
||||
internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
|
||||
internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
|
||||
internal COFF_Symbol32Array coff_symbol_array_from_data (Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size);
|
||||
|
||||
internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol);
|
||||
|
||||
internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class);
|
||||
internal COFF_SymbolValueInterpType coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol);
|
||||
internal B32 coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol);
|
||||
|
||||
internal void coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out);
|
||||
internal COFF_SymbolWeakExt * coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj);
|
||||
|
||||
////////////////////////////////
|
||||
// Reloc
|
||||
|
||||
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
|
||||
|
||||
////////////////////////////////
|
||||
// Resource
|
||||
|
||||
internal String8 coff_resource_string_from_str16 (Arena *arena, String16 string);
|
||||
internal String8 coff_resource_string_from_str8 (Arena *arena, String8 string);
|
||||
internal String8 coff_resource_number_from_u16 (Arena *arena, U16 number);
|
||||
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16);
|
||||
|
||||
internal U64 coff_read_resource_id_utf16 (String8 raw_res, U64 off, COFF_ResourceID16 *id_out);
|
||||
internal U64 coff_read_resource (Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out);
|
||||
internal COFF_ParsedResourceList coff_resource_list_from_data(Arena *arena, String8 data);
|
||||
|
||||
internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
|
||||
internal String8 coff_write_resource (Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
|
||||
|
||||
internal int coff_resource_id_compar(void *raw_a, void *raw_b); // COFF_ResourceID
|
||||
|
||||
////////////////////////////////
|
||||
// Archive
|
||||
|
||||
internal B32 coff_is_import (String8 raw_archive_member);
|
||||
internal COFF_DataType coff_data_type_from_data (String8 raw_archive_member);
|
||||
internal B32 coff_is_regular_archive (String8 raw_archive);
|
||||
internal B32 coff_is_thin_archive (String8 raw_archive);
|
||||
internal COFF_ArchiveType coff_archive_type_from_data(String8 raw_archive);
|
||||
|
||||
internal U64 coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out);
|
||||
internal COFF_ArchiveFirstMember coff_parse_first_archive_member (COFF_ArchiveMember *member);
|
||||
internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member);
|
||||
internal String8 coff_decode_raw_member_name (String8 long_names, String8 name);
|
||||
internal String8 coff_decode_member_name (String8 long_names, String8 name);
|
||||
internal U64 coff_parse_import (String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out);
|
||||
|
||||
internal COFF_ArchiveMember coff_archive_member_from_offset(String8 raw_archive, U64 offset);
|
||||
internal COFF_ArchiveMember coff_archive_member_from_data (String8 raw_archive_member);
|
||||
internal COFF_ParsedArchiveImportHeader coff_archive_import_from_data (String8 raw_archive_member);
|
||||
|
||||
internal U64 coff_regular_archive_member_iter_init(String8 raw_archive);
|
||||
internal B32 coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
|
||||
|
||||
internal U64 coff_thin_archive_member_iter_init(String8 raw_archive);
|
||||
internal B32 coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
|
||||
|
||||
internal COFF_ArchiveParse coff_regular_archive_parse_from_member_list(COFF_ArchiveMemberList list);
|
||||
internal COFF_ArchiveParse coff_thin_archive_parse_from_data (String8 raw_archive);
|
||||
internal COFF_ArchiveParse coff_regular_archive_parse_from_data (String8 raw_archive);
|
||||
internal COFF_ArchiveParse coff_archive_parse_from_data (String8 raw_archive);
|
||||
|
||||
#endif // COFF_PARSE_H
|
||||
@@ -1,111 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal CFG_KeyMap *
|
||||
cfg_key_map_from_cfg(Arena *arena)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
CFG_KeyMap *key_map = push_array(arena, CFG_KeyMap, 1);
|
||||
{
|
||||
key_map->name_slots_count = 4096;
|
||||
key_map->name_slots = push_array(arena, CFG_KeyMapSlot, key_map->name_slots_count);
|
||||
key_map->binding_slots_count = 4096;
|
||||
key_map->binding_slots = push_array(arena, CFG_KeyMapSlot, key_map->binding_slots_count);
|
||||
|
||||
//- rjf: gather & parse all explicitly stored keybinding sets
|
||||
CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings"));
|
||||
for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next)
|
||||
{
|
||||
CFG_Node *keybindings_root = n->v;
|
||||
for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next)
|
||||
{
|
||||
String8 name = {0};
|
||||
CFG_Binding binding = {0};
|
||||
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(0){}
|
||||
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
|
||||
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
|
||||
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
|
||||
else
|
||||
{
|
||||
OS_Key key = OS_Key_Null;
|
||||
for EachEnumVal(OS_Key, k)
|
||||
{
|
||||
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
key = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(key != OS_Key_Null)
|
||||
{
|
||||
binding.key = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = child->string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(name.size != 0)
|
||||
{
|
||||
U64 name_hash = d_hash_from_string(name);
|
||||
U64 binding_hash = d_hash_from_string(str8_struct(&binding));
|
||||
U64 name_slot_idx = name_hash%key_map->name_slots_count;
|
||||
U64 binding_slot_idx = binding_hash%key_map->binding_slots_count;
|
||||
CFG_KeyMapNode *n = push_array(arena, CFG_KeyMapNode, 1);
|
||||
n->cfg_id = keybinding->id;
|
||||
n->name = push_str8_copy(arena, name);
|
||||
n->binding = binding;
|
||||
SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next);
|
||||
SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return key_map;
|
||||
}
|
||||
|
||||
internal CFG_KeyMapNodePtrList
|
||||
cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string)
|
||||
{
|
||||
CFG_KeyMapNodePtrList list = {0};
|
||||
{
|
||||
U64 hash = d_hash_from_string(string);
|
||||
U64 slot_idx = hash%key_map->name_slots_count;
|
||||
for(CFG_KeyMapNode *n = key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next)
|
||||
{
|
||||
if(str8_match(n->name, string, 0))
|
||||
{
|
||||
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
|
||||
ptr->v = n;
|
||||
SLLQueuePush(list.first, list.last, ptr);
|
||||
list.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
internal CFG_KeyMapNodePtrList
|
||||
cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding)
|
||||
{
|
||||
CFG_KeyMapNodePtrList list = {0};
|
||||
{
|
||||
U64 hash = d_hash_from_string(str8_struct(&binding));
|
||||
U64 slot_idx = hash%key_map->binding_slots_count;
|
||||
for(CFG_KeyMapNode *n = key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next)
|
||||
{
|
||||
if(MemoryMatchStruct(&binding, &n->binding))
|
||||
{
|
||||
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
|
||||
ptr->v = n;
|
||||
SLLQueuePush(list.first, list.last, ptr);
|
||||
list.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_BINDINGS_H
|
||||
#define CONFIG_BINDINGS_H
|
||||
|
||||
typedef struct CFG_Binding CFG_Binding;
|
||||
struct CFG_Binding
|
||||
{
|
||||
OS_Key key;
|
||||
OS_Modifiers modifiers;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
|
||||
struct CFG_KeyMapNode
|
||||
{
|
||||
CFG_KeyMapNode *name_hash_next;
|
||||
CFG_KeyMapNode *binding_hash_next;
|
||||
CFG_ID cfg_id;
|
||||
String8 name;
|
||||
CFG_Binding binding;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapNodePtr CFG_KeyMapNodePtr;
|
||||
struct CFG_KeyMapNodePtr
|
||||
{
|
||||
CFG_KeyMapNodePtr *next;
|
||||
CFG_KeyMapNode *v;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapNodePtrList CFG_KeyMapNodePtrList;
|
||||
struct CFG_KeyMapNodePtrList
|
||||
{
|
||||
CFG_KeyMapNodePtr *first;
|
||||
CFG_KeyMapNodePtr *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapSlot CFG_KeyMapSlot;
|
||||
struct CFG_KeyMapSlot
|
||||
{
|
||||
CFG_KeyMapNode *first;
|
||||
CFG_KeyMapNode *last;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMap CFG_KeyMap;
|
||||
struct CFG_KeyMap
|
||||
{
|
||||
U64 name_slots_count;
|
||||
CFG_KeyMapSlot *name_slots;
|
||||
U64 binding_slots_count;
|
||||
CFG_KeyMapSlot *binding_slots;
|
||||
};
|
||||
|
||||
internal CFG_KeyMap *cfg_key_map_from_cfg(Arena *arena);
|
||||
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string);
|
||||
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding);
|
||||
|
||||
#endif // CONFIG_BINDINGS_H
|
||||
@@ -1,896 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: ID Functions
|
||||
|
||||
internal void
|
||||
cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id)
|
||||
{
|
||||
CFG_IDNode *n = push_array(arena, CFG_IDNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
n->v = id;
|
||||
}
|
||||
|
||||
internal CFG_IDList
|
||||
cfg_id_list_copy(Arena *arena, CFG_IDList *src)
|
||||
{
|
||||
CFG_IDList dst = {0};
|
||||
for EachNode(n, CFG_IDNode, src->first)
|
||||
{
|
||||
cfg_id_list_push(arena, &dst, n->v);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Pointer Data Structure Functions
|
||||
|
||||
internal void
|
||||
cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
|
||||
{
|
||||
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
|
||||
DLLPushBack(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
n->v = node;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
|
||||
{
|
||||
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
|
||||
DLLPushFront(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
n->v = node;
|
||||
}
|
||||
|
||||
internal CFG_NodePtrArray
|
||||
cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list)
|
||||
{
|
||||
CFG_NodePtrArray array = {0};
|
||||
array.count = list->count;
|
||||
array.v = push_array_no_zero(arena, CFG_Node *, array.count);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, CFG_NodePtrNode, list->first)
|
||||
{
|
||||
array.v[idx] = n->v;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Data Structure Functions
|
||||
|
||||
internal void
|
||||
cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema)
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(name);
|
||||
U64 slot_idx = hash%table->slots_count;
|
||||
CFG_SchemaNode *node = 0;
|
||||
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->name, name, 0))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = push_array(arena, CFG_SchemaNode, 1);
|
||||
node->name = str8_copy(arena, name);
|
||||
node->schema = schema;
|
||||
SLLStackPush(table->slots[slot_idx], node);
|
||||
}
|
||||
}
|
||||
|
||||
internal MD_Node *
|
||||
cfg_schema_from_name(CFG_SchemaTable *table, String8 name)
|
||||
{
|
||||
MD_Node *result = &md_nil_node;
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(name);
|
||||
U64 slot_idx = hash%table->slots_count;
|
||||
CFG_SchemaNode *node = 0;
|
||||
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->name, name, 0))
|
||||
{
|
||||
result = n->schema;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal MD_NodePtrList
|
||||
cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name)
|
||||
{
|
||||
MD_NodePtrList result = {0};
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List tasks = {0};
|
||||
String8Node seed_task = {0, name};
|
||||
str8_list_push_node(&tasks, &seed_task);
|
||||
for EachNode(task, String8Node, tasks.first)
|
||||
{
|
||||
MD_Node *schema = cfg_schema_from_name(table, task->string);
|
||||
if(!md_node_is_nil(schema))
|
||||
{
|
||||
md_node_ptr_list_push_front(arena, &result, schema);
|
||||
for MD_EachNode(tag, schema->first_tag)
|
||||
{
|
||||
if(str8_match(tag->string, str8_lit("inherit"), 0))
|
||||
{
|
||||
str8_list_push(scratch.arena, &tasks, tag->first->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Reading Functions
|
||||
|
||||
//- rjf: context selection
|
||||
|
||||
internal void
|
||||
cfg_ctx_select(CFG_Ctx *ctx)
|
||||
{
|
||||
cfg_ctx = ctx;
|
||||
}
|
||||
|
||||
//- rjf: tree navigations
|
||||
|
||||
internal U64
|
||||
cfg_change_gen(void)
|
||||
{
|
||||
U64 result = 0;
|
||||
if(cfg_ctx != 0)
|
||||
{
|
||||
result = cfg_ctx->change_gen;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_root(void)
|
||||
{
|
||||
CFG_Node *result = &cfg_nil_node;
|
||||
if(cfg_ctx != 0)
|
||||
{
|
||||
result = cfg_ctx->root;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_from_id(CFG_ID id)
|
||||
{
|
||||
CFG_Node *result = &cfg_nil_node;
|
||||
if(id != 0 &&
|
||||
id == cfg_ctx->last_accessed_id &&
|
||||
id == cfg_ctx->last_accessed->id)
|
||||
{
|
||||
result = cfg_ctx->last_accessed;
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&id));
|
||||
U64 slot_idx = hash%cfg_ctx->id_slots_count;
|
||||
for(CFG_NodePtrNode *n = cfg_ctx->id_slots[slot_idx].first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->v->id == id)
|
||||
{
|
||||
result = n->v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cfg_ctx->last_accessed_id = id;
|
||||
cfg_ctx->last_accessed = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_child_from_string(CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *child = &cfg_nil_node;
|
||||
if(string.size != 0)
|
||||
{
|
||||
for(CFG_Node *c = parent->first; c != &cfg_nil_node; c = c->next)
|
||||
{
|
||||
if(str8_match(c->string, string, 0))
|
||||
{
|
||||
child = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *result = cfg_node_child_from_string(parent, string);
|
||||
if(result == &cfg_nil_node)
|
||||
{
|
||||
result = parent;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_NodePtrList
|
||||
cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_NodePtrList result = {0};
|
||||
for(CFG_Node *child = parent->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(str8_match(child->string, string, 0))
|
||||
{
|
||||
cfg_node_ptr_list_push(arena, &result, child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_NodePtrList
|
||||
cfg_node_top_level_list_from_string(Arena *arena, String8 string)
|
||||
{
|
||||
CFG_NodePtrList result = {0};
|
||||
for(CFG_Node *bucket = cfg_ctx->root->first; bucket != &cfg_nil_node; bucket = bucket->next)
|
||||
{
|
||||
for(CFG_Node *tln = bucket->first; tln != &cfg_nil_node; tln = tln->next)
|
||||
{
|
||||
if(str8_match(tln->string, string, 0))
|
||||
{
|
||||
cfg_node_ptr_list_push(arena, &result, tln);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_NodeRec
|
||||
cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node)
|
||||
{
|
||||
CFG_NodeRec rec = {&cfg_nil_node};
|
||||
if(node->first != &cfg_nil_node)
|
||||
{
|
||||
rec.next = node->first;
|
||||
rec.push_count = 1;
|
||||
}
|
||||
else for(CFG_Node *p = node; p != root; p = p->parent, rec.pop_count += 1)
|
||||
{
|
||||
if(p->next != &cfg_nil_node)
|
||||
{
|
||||
rec.next = p->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
//- rjf: serialization
|
||||
|
||||
internal String8
|
||||
cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List strings = {0};
|
||||
{
|
||||
typedef struct NestTask NestTask;
|
||||
struct NestTask
|
||||
{
|
||||
NestTask *next;
|
||||
CFG_Node *cfg;
|
||||
MD_Node *schema;
|
||||
B32 is_simple;
|
||||
};
|
||||
NestTask *top_nest_task = 0;
|
||||
CFG_NodeRec rec = {0};
|
||||
for(CFG_Node *c = root; c != &cfg_nil_node; c = rec.next)
|
||||
{
|
||||
// rjf: look up parent's schemas
|
||||
MD_NodePtrList schemas = {0};
|
||||
if(top_nest_task != 0)
|
||||
{
|
||||
CFG_Node *parent = top_nest_task->cfg;
|
||||
schemas = cfg_schemas_from_name(scratch.arena, schema_table, parent->string);
|
||||
}
|
||||
|
||||
// rjf: look up child schema
|
||||
MD_Node *c_schema = &md_nil_node;
|
||||
for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next)
|
||||
{
|
||||
c_schema = md_child_from_string(n->v, c->string, 0);
|
||||
}
|
||||
|
||||
// rjf: push name of this node
|
||||
if(c->string.size != 0 || c->first == &cfg_nil_node)
|
||||
{
|
||||
// rjf: extract the textualized form for this string (we may need to escape / relativize)
|
||||
String8 c_serialized_string = c->string;
|
||||
{
|
||||
MD_Node *c_schema = &md_nil_node;
|
||||
if(top_nest_task != 0)
|
||||
{
|
||||
c_schema = top_nest_task->schema;
|
||||
}
|
||||
|
||||
// rjf: paths -> relativize
|
||||
if(!md_node_has_tag(c_schema->first, str8_lit("no_relativize"), 0))
|
||||
{
|
||||
if(str8_match(c_schema->first->string, str8_lit("path"), 0))
|
||||
{
|
||||
String8 path_absolute = c->string;
|
||||
String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path);
|
||||
c_serialized_string = path_relative;
|
||||
}
|
||||
else if(str8_match(c_schema->first->string, str8_lit("path_pt"), 0))
|
||||
{
|
||||
String8 value = c->string;
|
||||
String8TxtPtPair parts = str8_txt_pt_pair_from_string(value);
|
||||
String8 path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, parts.string, root_path);
|
||||
c_serialized_string = push_str8f(arena, "%S:%I64d:%I64d", path_relative, parts.pt.line, parts.pt.column);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: all strings -> escape
|
||||
c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string);
|
||||
}
|
||||
|
||||
// rjf: generate all strings for this node's string
|
||||
String8List c_name_strings = {0};
|
||||
{
|
||||
B32 name_can_be_pushed_standalone = 0;
|
||||
{
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string);
|
||||
name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier|
|
||||
MD_TokenFlag_Numeric|
|
||||
MD_TokenFlag_StringLiteral|
|
||||
MD_TokenFlag_Symbol));
|
||||
temp_end(temp);
|
||||
}
|
||||
if(name_can_be_pushed_standalone)
|
||||
{
|
||||
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
|
||||
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
|
||||
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if we're in a simple nesting task, then just break children by space
|
||||
if(top_nest_task != 0 && top_nest_task->is_simple)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(" "));
|
||||
}
|
||||
|
||||
// rjf: join c's strings with main string list
|
||||
str8_list_concat_in_place(&strings, &c_name_strings);
|
||||
}
|
||||
|
||||
// rjf: grab next recursion
|
||||
rec = cfg_node_rec__depth_first(root, c);
|
||||
|
||||
// rjf: push a new nesting task before descending to children
|
||||
if(c->first != &cfg_nil_node)
|
||||
{
|
||||
B32 is_simple_children_list = 1;
|
||||
for(CFG_Node *child = c->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(child->first != &cfg_nil_node && child != c->last)
|
||||
{
|
||||
is_simple_children_list = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
NestTask *task = push_array(scratch.arena, NestTask, 1);
|
||||
task->cfg = c;
|
||||
task->schema = c_schema;
|
||||
task->is_simple = is_simple_children_list;
|
||||
SLLStackPush(top_nest_task, task);
|
||||
}
|
||||
|
||||
// rjf: tree navigations -> encode hierarchy
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
if(top_nest_task->is_simple && c->string.size != 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(":"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(c->string.size != 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(":\n"));
|
||||
}
|
||||
str8_list_push(scratch.arena, &strings, str8_lit("{"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task))
|
||||
{
|
||||
if(top_nest_task->is_simple)
|
||||
{
|
||||
if(top_nest_task->cfg->string.size == 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(" }"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit("\n}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!top_nest_task || top_nest_task->is_simple == 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 result_unindented = str8_list_join(scratch.arena, &strings, 0);
|
||||
String8 result = indented_from_string(arena, result_unindented);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Writing Functions
|
||||
|
||||
//- rjf: state creation / destroying
|
||||
|
||||
internal CFG_State *
|
||||
cfg_state_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
CFG_State *state = push_array(arena, CFG_State, 1);
|
||||
state->arena = arena;
|
||||
state->ctx.id_slots_count = 4096;
|
||||
state->ctx.id_slots = push_array(arena, CFG_NodePtrSlot, state->ctx.id_slots_count);
|
||||
state->ctx.root = cfg_node_alloc(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_state_release(CFG_State *state)
|
||||
{
|
||||
arena_release(state->arena);
|
||||
}
|
||||
|
||||
//- rjf: state -> ctx
|
||||
|
||||
internal CFG_Ctx *
|
||||
cfg_state_ctx(CFG_State *state)
|
||||
{
|
||||
CFG_Ctx *ctx = &state->ctx;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
//- rjf: string allocations
|
||||
|
||||
internal U64
|
||||
cfg_string_bucket_num_from_size(U64 size)
|
||||
{
|
||||
U64 bucket_num = 0;
|
||||
if(size > 0)
|
||||
{
|
||||
for EachElement(idx, cfg_string_bucket_chunk_sizes)
|
||||
{
|
||||
if(size <= cfg_string_bucket_chunk_sizes[idx])
|
||||
{
|
||||
bucket_num = idx+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bucket_num;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cfg_string_alloc(CFG_State *state, String8 string)
|
||||
{
|
||||
//- rjf: allocate node
|
||||
CFG_StringChunkNode *node = 0;
|
||||
{
|
||||
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
|
||||
if(bucket_num == ArrayCount(cfg_string_bucket_chunk_sizes))
|
||||
{
|
||||
CFG_StringChunkNode *best_node = 0;
|
||||
CFG_StringChunkNode *best_node_prev = 0;
|
||||
U64 best_node_size = max_U64;
|
||||
{
|
||||
for(CFG_StringChunkNode *n = state->free_string_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next))
|
||||
{
|
||||
if(n->size >= string.size && n->size < best_node_size)
|
||||
{
|
||||
best_node = n;
|
||||
best_node_prev = prev;
|
||||
best_node_size = n->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(best_node != 0)
|
||||
{
|
||||
node = best_node;
|
||||
if(best_node_prev)
|
||||
{
|
||||
best_node_prev->next = best_node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->free_string_chunks[bucket_num-1] = best_node->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 chunk_size = u64_up_to_pow2(string.size);
|
||||
node = (CFG_StringChunkNode *)push_array(state->arena, U8, chunk_size);
|
||||
}
|
||||
}
|
||||
else if(bucket_num != 0)
|
||||
{
|
||||
node = state->free_string_chunks[bucket_num-1];
|
||||
if(node != 0)
|
||||
{
|
||||
SLLStackPop(state->free_string_chunks[bucket_num-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = (CFG_StringChunkNode *)push_array(state->arena, U8, cfg_string_bucket_chunk_sizes[bucket_num-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: fill node
|
||||
String8 result = {0};
|
||||
if(node != 0)
|
||||
{
|
||||
result.str = (U8 *)node;
|
||||
result.size = string.size;
|
||||
MemoryCopy(result.str, string.str, result.size);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_string_release(CFG_State *state, String8 string)
|
||||
{
|
||||
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
|
||||
if(1 <= bucket_num && bucket_num <= ArrayCount(cfg_string_bucket_chunk_sizes))
|
||||
{
|
||||
U64 bucket_idx = bucket_num-1;
|
||||
CFG_StringChunkNode *node = (CFG_StringChunkNode *)string.str;
|
||||
SLLStackPush(state->free_string_chunks[bucket_idx], node);
|
||||
node->size = u64_up_to_pow2(string.size);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: tree building
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_alloc(CFG_State *state)
|
||||
{
|
||||
state->ctx.change_gen += 1;
|
||||
|
||||
// rjf: allocate
|
||||
CFG_Node *result = state->free;
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
SLLStackPop(state->free);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_array_no_zero(state->arena, CFG_Node, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: generate ID & fill
|
||||
state->id_gen += 1;
|
||||
MemoryZeroStruct(result);
|
||||
result->first = result->last = result->next = result->prev = result->parent = &cfg_nil_node;
|
||||
result->id = state->id_gen;
|
||||
|
||||
// rjf: store to ID -> cfg map
|
||||
{
|
||||
CFG_NodePtrNode *cfg_id_node = state->free_id_node;
|
||||
if(cfg_id_node != 0)
|
||||
{
|
||||
SLLStackPop(state->free_id_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
cfg_id_node = push_array(state->arena, CFG_NodePtrNode, 1);
|
||||
}
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&result->id));
|
||||
U64 slot_idx = hash%state->ctx.id_slots_count;
|
||||
DLLPushBack(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, cfg_id_node);
|
||||
cfg_id_node->v = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_release(CFG_State *state, CFG_Node *node)
|
||||
{
|
||||
state->ctx.change_gen += 1;
|
||||
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// rjf: unhook from context
|
||||
cfg_node_unhook(state, node->parent, node);
|
||||
|
||||
// rjf: gather root & all descendants
|
||||
CFG_NodePtrList nodes = {0};
|
||||
for(CFG_Node *c = node; c != &cfg_nil_node; c = cfg_node_rec__depth_first(node, c).next)
|
||||
{
|
||||
cfg_node_ptr_list_push(scratch.arena, &nodes, c);
|
||||
}
|
||||
|
||||
// rjf: release all nodes
|
||||
for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next)
|
||||
{
|
||||
CFG_Node *c = n->v;
|
||||
cfg_string_release(state, c->string);
|
||||
SLLStackPush(state->free, c);
|
||||
c->first = c->last = c->prev = c->parent = 0;
|
||||
c->id = 0;
|
||||
c->string = str8_zero();
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
|
||||
U64 slot_idx = hash%state->ctx.id_slots_count;
|
||||
for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->v == c)
|
||||
{
|
||||
DLLRemove(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, n);
|
||||
SLLStackPush(state->free_id_node, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_release_all_children(CFG_State *state, CFG_Node *node)
|
||||
{
|
||||
for(CFG_Node *child = node->first, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
|
||||
{
|
||||
next = child->next;
|
||||
cfg_node_release(state, child);
|
||||
}
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *node = cfg_node_alloc(state);
|
||||
cfg_node_insert_child(state, parent, parent->last, node);
|
||||
cfg_node_equip_string(state, node, string);
|
||||
return node;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
CFG_Node *result = cfg_node_new(state, parent, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
string = push_str8_copy(scratch.arena, string);
|
||||
for(CFG_Node *child = parent->first->next, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
|
||||
{
|
||||
next = child->next;
|
||||
cfg_node_release(state, child);
|
||||
}
|
||||
if(parent->first == &cfg_nil_node)
|
||||
{
|
||||
cfg_node_new(state, parent, str8_zero());
|
||||
}
|
||||
CFG_Node *child = parent->first;
|
||||
cfg_node_equip_string(state, child, string);
|
||||
scratch_end(scratch);
|
||||
return child;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
CFG_Node *result = cfg_node_new_replace(state, parent, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root)
|
||||
{
|
||||
CFG_NodeRec rec = {0};
|
||||
CFG_Node *dst_root = &cfg_nil_node;
|
||||
CFG_Node *dst_parent = &cfg_nil_node;
|
||||
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
|
||||
{
|
||||
CFG_Node *dst = cfg_node_new(state, dst_parent, src->string);
|
||||
if(dst_root == &cfg_nil_node)
|
||||
{
|
||||
dst_root = dst;
|
||||
}
|
||||
rec = cfg_node_rec__depth_first(src_root, src);
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
dst_parent = dst;
|
||||
}
|
||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
||||
{
|
||||
dst_parent = dst_parent->parent;
|
||||
}
|
||||
}
|
||||
return dst_root;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string)
|
||||
{
|
||||
cfg_string_release(state, node->string);
|
||||
node->string = cfg_string_alloc(state, string);
|
||||
state->ctx.change_gen += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
cfg_node_equip_string(state, node, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child)
|
||||
{
|
||||
if(parent != &cfg_nil_node)
|
||||
{
|
||||
if(new_child->parent != &cfg_nil_node)
|
||||
{
|
||||
cfg_node_unhook(state, new_child->parent, new_child);
|
||||
}
|
||||
DLLInsert_NPZ(&cfg_nil_node, parent->first, parent->last, prev_child, new_child, next, prev);
|
||||
new_child->parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child)
|
||||
{
|
||||
if(child != &cfg_nil_node && parent == child->parent && parent != &cfg_nil_node)
|
||||
{
|
||||
DLLRemove_NPZ(&cfg_nil_node, parent->first, parent->last, child, next, prev);
|
||||
child->parent = &cfg_nil_node;
|
||||
}
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *node = cfg_node_child_from_string(parent, string);
|
||||
if(node == &cfg_nil_node)
|
||||
{
|
||||
node = cfg_node_new(state, parent, string);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
//- rjf: deserialization
|
||||
|
||||
internal CFG_NodePtrList
|
||||
cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string)
|
||||
{
|
||||
CFG_NodePtrList result = {0};
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
//- rjf: parse the string as metadesk
|
||||
MD_Node *root = md_tree_from_string(scratch.arena, string);
|
||||
|
||||
//- rjf: iterate the top-level metadesk trees, generate new cfg trees for each
|
||||
for MD_EachNode(tln, root->first)
|
||||
{
|
||||
CFG_Node *dst_root_n = &cfg_nil_node;
|
||||
CFG_Node *dst_active_parent_n = &cfg_nil_node;
|
||||
MD_NodeRec rec = {0};
|
||||
for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next)
|
||||
{
|
||||
// rjf: lookup schema for this string
|
||||
MD_Node *schema = &md_nil_node;
|
||||
{
|
||||
MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, schema_table, dst_active_parent_n->parent->string);
|
||||
for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next)
|
||||
{
|
||||
schema = md_child_from_string(n->v, dst_active_parent_n->string, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: extract & transform metadesk node's string (it is raw textual data, so we need to
|
||||
// go escaped -> raw, and derelativize paths)
|
||||
String8 dst_n_string = {0};
|
||||
{
|
||||
String8 src_n_string = src_n->string;
|
||||
String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string);
|
||||
if(!md_node_has_tag(schema->first, str8_lit("no_relativize"), 0))
|
||||
{
|
||||
if(str8_match(schema->first->string, str8_lit("path"), 0))
|
||||
{
|
||||
src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path);
|
||||
}
|
||||
else if(str8_match(schema->first->string, str8_lit("path_pt"), 0))
|
||||
{
|
||||
String8TxtPtPair parts = str8_txt_pt_pair_from_string(src_n_string__raw);
|
||||
src_n_string__raw = push_str8f(scratch.arena, "%S:%I64d:%I64d", path_absolute_dst_from_relative_dst_src(scratch.arena, parts.string, root_path), parts.pt.line, parts.pt.column);
|
||||
}
|
||||
}
|
||||
dst_n_string = src_n_string__raw;
|
||||
}
|
||||
|
||||
// rjf: allocate, fill, & insert new cfg for this metadesk node
|
||||
CFG_Node *dst_n = cfg_node_alloc(state);
|
||||
cfg_node_equip_string(state, dst_n, dst_n_string);
|
||||
if(dst_active_parent_n != &cfg_nil_node)
|
||||
{
|
||||
cfg_node_insert_child(state, dst_active_parent_n, dst_active_parent_n->last, dst_n);
|
||||
}
|
||||
|
||||
// rjf: recurse
|
||||
rec = md_node_rec_depth_first_pre(src_n, tln);
|
||||
if(dst_active_parent_n == &cfg_nil_node)
|
||||
{
|
||||
dst_root_n = dst_n;
|
||||
}
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
dst_active_parent_n = dst_n;
|
||||
}
|
||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
||||
{
|
||||
dst_active_parent_n = dst_active_parent_n->parent;
|
||||
}
|
||||
}
|
||||
cfg_node_ptr_list_push(arena, &result, dst_root_n);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_CORE_H
|
||||
#define CONFIG_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: IDs
|
||||
|
||||
typedef U64 CFG_ID;
|
||||
|
||||
typedef struct CFG_IDNode CFG_IDNode;
|
||||
struct CFG_IDNode
|
||||
{
|
||||
CFG_IDNode *next;
|
||||
CFG_ID v;
|
||||
};
|
||||
|
||||
typedef struct CFG_IDList CFG_IDList;
|
||||
struct CFG_IDList
|
||||
{
|
||||
CFG_IDNode *first;
|
||||
CFG_IDNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tree Types
|
||||
|
||||
typedef struct CFG_Node CFG_Node;
|
||||
struct CFG_Node
|
||||
{
|
||||
CFG_Node *first;
|
||||
CFG_Node *last;
|
||||
CFG_Node *next;
|
||||
CFG_Node *prev;
|
||||
CFG_Node *parent;
|
||||
CFG_ID id;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrNode CFG_NodePtrNode;
|
||||
struct CFG_NodePtrNode
|
||||
{
|
||||
CFG_NodePtrNode *next;
|
||||
CFG_NodePtrNode *prev;
|
||||
CFG_Node *v;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrSlot CFG_NodePtrSlot;
|
||||
struct CFG_NodePtrSlot
|
||||
{
|
||||
CFG_NodePtrNode *first;
|
||||
CFG_NodePtrNode *last;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrList CFG_NodePtrList;
|
||||
struct CFG_NodePtrList
|
||||
{
|
||||
CFG_NodePtrNode *first;
|
||||
CFG_NodePtrNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrArray CFG_NodePtrArray;
|
||||
struct CFG_NodePtrArray
|
||||
{
|
||||
CFG_Node **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodeRec CFG_NodeRec;
|
||||
struct CFG_NodeRec
|
||||
{
|
||||
CFG_Node *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Allocator
|
||||
|
||||
read_only global U64 cfg_string_bucket_chunk_sizes[] =
|
||||
{
|
||||
16,
|
||||
64,
|
||||
256,
|
||||
1024,
|
||||
4096,
|
||||
16384,
|
||||
65536,
|
||||
0xffffffffffffffffull,
|
||||
};
|
||||
|
||||
typedef struct CFG_StringChunkNode CFG_StringChunkNode;
|
||||
struct CFG_StringChunkNode
|
||||
{
|
||||
CFG_StringChunkNode *next;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config State Bundles
|
||||
|
||||
typedef struct CFG_Ctx CFG_Ctx;
|
||||
struct CFG_Ctx
|
||||
{
|
||||
CFG_Node *root;
|
||||
U64 id_slots_count;
|
||||
CFG_NodePtrSlot *id_slots;
|
||||
U64 change_gen;
|
||||
CFG_ID last_accessed_id;
|
||||
CFG_Node *last_accessed;
|
||||
};
|
||||
|
||||
typedef struct CFG_State CFG_State;
|
||||
struct CFG_State
|
||||
{
|
||||
Arena *arena;
|
||||
CFG_Node *free;
|
||||
CFG_NodePtrNode *free_id_node;
|
||||
CFG_StringChunkNode *free_string_chunks[ArrayCount(cfg_string_bucket_chunk_sizes)];
|
||||
U64 id_gen;
|
||||
CFG_Ctx ctx;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Table
|
||||
|
||||
typedef struct CFG_SchemaNode CFG_SchemaNode;
|
||||
struct CFG_SchemaNode
|
||||
{
|
||||
CFG_SchemaNode *next;
|
||||
String8 name;
|
||||
MD_Node *schema;
|
||||
};
|
||||
|
||||
typedef struct CFG_SchemaTable CFG_SchemaTable;
|
||||
struct CFG_SchemaTable
|
||||
{
|
||||
CFG_SchemaNode **slots;
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global CFG_Node cfg_nil_node =
|
||||
{
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
};
|
||||
|
||||
thread_static CFG_Ctx *cfg_ctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: ID Functions
|
||||
|
||||
internal void cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id);
|
||||
internal CFG_IDList cfg_id_list_copy(Arena *arena, CFG_IDList *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Pointer Data Structure Functions
|
||||
|
||||
internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
|
||||
internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
|
||||
#define cfg_node_ptr_list_first(list) ((list)->count ? (list)->first->v : &cfg_nil_node)
|
||||
#define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node)
|
||||
internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Data Structure Functions
|
||||
|
||||
internal void cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema);
|
||||
internal MD_Node *cfg_schema_from_name(CFG_SchemaTable *table, String8 name);
|
||||
internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Reading Functions
|
||||
|
||||
//- rjf: context selection
|
||||
internal void cfg_ctx_select(CFG_Ctx *ctx);
|
||||
|
||||
//- rjf: tree navigations
|
||||
internal U64 cfg_change_gen(void);
|
||||
internal CFG_Node *cfg_node_root(void);
|
||||
internal CFG_Node *cfg_node_from_id(CFG_ID id);
|
||||
internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string);
|
||||
internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string);
|
||||
internal CFG_NodePtrList cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string);
|
||||
internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, String8 string);
|
||||
internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node);
|
||||
|
||||
//- rjf: serialization
|
||||
internal String8 cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Writing Functions
|
||||
|
||||
//- rjf: state creation / destroying
|
||||
internal CFG_State *cfg_state_alloc(void);
|
||||
internal void cfg_state_release(CFG_State *state);
|
||||
|
||||
//- rjf: state -> ctx
|
||||
internal CFG_Ctx *cfg_state_ctx(CFG_State *state);
|
||||
|
||||
//- rjf: string allocations
|
||||
internal U64 cfg_string_bucket_num_from_size(U64 size);
|
||||
internal String8 cfg_string_alloc(CFG_State *state, String8 string);
|
||||
internal void cfg_string_release(CFG_State *state, String8 string);
|
||||
|
||||
//- rjf: tree building
|
||||
internal CFG_Node *cfg_node_alloc(CFG_State *state);
|
||||
internal void cfg_node_release(CFG_State *state, CFG_Node *node);
|
||||
internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node);
|
||||
internal CFG_Node *cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string);
|
||||
internal CFG_Node *cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...);
|
||||
internal CFG_Node *cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string);
|
||||
internal CFG_Node *cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...);
|
||||
internal CFG_Node *cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root);
|
||||
internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string);
|
||||
internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...);
|
||||
internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child);
|
||||
internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child);
|
||||
internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string);
|
||||
|
||||
//- rjf: deserialization
|
||||
internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string);
|
||||
|
||||
#endif // CONFIG_CORE_H
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "config_core.c"
|
||||
#include "config_panels.c"
|
||||
#if defined(OS_GFX_H)
|
||||
# include "config_bindings.c"
|
||||
#endif
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_INC_H
|
||||
#define CONFIG_INC_H
|
||||
|
||||
#include "config_core.h"
|
||||
#include "config_panels.h"
|
||||
#if defined(OS_GFX_H)
|
||||
# include "config_bindings.h"
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_INC_H
|
||||
@@ -1,217 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_window_from_cfg(CFG_Node *cfg)
|
||||
{
|
||||
CFG_Node *result = &cfg_nil_node;
|
||||
for(CFG_Node *c = cfg; c != &cfg_nil_node; c = c->parent)
|
||||
{
|
||||
if(c->parent->parent == cfg_node_root() && str8_match(c->string, str8_lit("window"), 0))
|
||||
{
|
||||
result = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_PanelTree
|
||||
cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
CFG_Node *wcfg = cfg_window_from_cfg(cfg_root);
|
||||
CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels"));
|
||||
CFG_PanelNode *dst_root = &cfg_nil_panel_node;
|
||||
CFG_PanelNode *dst_focused = &cfg_nil_panel_node;
|
||||
{
|
||||
Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y;
|
||||
CFG_NodeRec rec = {0};
|
||||
CFG_PanelNode *dst_active_parent = &cfg_nil_panel_node;
|
||||
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
|
||||
{
|
||||
// rjf: build a panel node
|
||||
CFG_PanelNode *dst = push_array(arena, CFG_PanelNode, 1);
|
||||
MemoryCopyStruct(dst, &cfg_nil_panel_node);
|
||||
dst->parent = dst_active_parent;
|
||||
if(dst_active_parent != &cfg_nil_panel_node)
|
||||
{
|
||||
DLLPushBack_NPZ(&cfg_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev);
|
||||
dst_active_parent->child_count += 1;
|
||||
}
|
||||
if(dst_root == &cfg_nil_panel_node)
|
||||
{
|
||||
dst_root = dst;
|
||||
}
|
||||
|
||||
// rjf: extract cfg info
|
||||
B32 panel_has_children = 0;
|
||||
dst->cfg = src;
|
||||
dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string));
|
||||
dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min);
|
||||
dst->split_axis = active_split_axis;
|
||||
for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next)
|
||||
{
|
||||
MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string);
|
||||
if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric)
|
||||
{
|
||||
panel_has_children = 1;
|
||||
}
|
||||
else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0))
|
||||
{
|
||||
// NOTE(rjf): skip - this is a panel option.
|
||||
}
|
||||
else if(str8_match(src_child->string, str8_lit("selected"), 0))
|
||||
{
|
||||
dst_focused = dst;
|
||||
}
|
||||
else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier)
|
||||
{
|
||||
cfg_node_ptr_list_push(arena, &dst->tabs, src_child);
|
||||
if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node)
|
||||
{
|
||||
dst->selected_tab = src_child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: recurse
|
||||
rec = cfg_node_rec__depth_first(src_root, src);
|
||||
if(!panel_has_children)
|
||||
{
|
||||
MemoryZeroStruct(&rec);
|
||||
rec.next = &cfg_nil_node;
|
||||
for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1)
|
||||
{
|
||||
if(p->next != &cfg_nil_node)
|
||||
{
|
||||
rec.next = p->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
dst_active_parent = dst;
|
||||
active_split_axis = axis2_flip(active_split_axis);
|
||||
}
|
||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
||||
{
|
||||
dst_active_parent = dst_active_parent->parent;
|
||||
active_split_axis = axis2_flip(active_split_axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
CFG_PanelTree tree = {dst_root, dst_focused};
|
||||
return tree;
|
||||
}
|
||||
|
||||
internal CFG_PanelNodeRec
|
||||
cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off)
|
||||
{
|
||||
CFG_PanelNodeRec rec = {&cfg_nil_panel_node};
|
||||
if(*MemberFromOffset(CFG_PanelNode **, panel, child_off) != &cfg_nil_panel_node)
|
||||
{
|
||||
rec.next = *MemberFromOffset(CFG_PanelNode **, panel, child_off);
|
||||
rec.push_count += 1;
|
||||
}
|
||||
else for(CFG_PanelNode *p = panel; p != &cfg_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1)
|
||||
{
|
||||
if(*MemberFromOffset(CFG_PanelNode **, p, sib_off) != &cfg_nil_panel_node)
|
||||
{
|
||||
rec.next = *MemberFromOffset(CFG_PanelNode **, p, sib_off);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
internal CFG_PanelNode *
|
||||
cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg)
|
||||
{
|
||||
CFG_PanelNode *result = &cfg_nil_panel_node;
|
||||
for(CFG_PanelNode *p = root;
|
||||
p != &cfg_nil_panel_node;
|
||||
p = cfg_panel_node_rec__depth_first_pre(root, p).next)
|
||||
{
|
||||
if(p->cfg == cfg)
|
||||
{
|
||||
result = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Rng2F32
|
||||
cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel)
|
||||
{
|
||||
Rng2F32 rect = parent_rect;
|
||||
if(parent != &cfg_nil_panel_node)
|
||||
{
|
||||
Vec2F32 parent_rect_size = dim_2f32(parent_rect);
|
||||
Axis2 axis = parent->split_axis;
|
||||
rect.p1.v[axis] = rect.p0.v[axis];
|
||||
for(CFG_PanelNode *child = parent->first; child != &cfg_nil_panel_node; child = child->next)
|
||||
{
|
||||
rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent;
|
||||
if(child == panel)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rect.p0.v[axis] = rect.p1.v[axis];
|
||||
}
|
||||
//rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis];
|
||||
//rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)];
|
||||
}
|
||||
rect.x0 = round_f32(rect.x0);
|
||||
rect.x1 = round_f32(rect.x1);
|
||||
rect.y0 = round_f32(rect.y0);
|
||||
rect.y1 = round_f32(rect.y1);
|
||||
return rect;
|
||||
}
|
||||
|
||||
internal Rng2F32
|
||||
cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// rjf: count ancestors
|
||||
U64 ancestor_count = 0;
|
||||
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
|
||||
{
|
||||
ancestor_count += 1;
|
||||
}
|
||||
|
||||
// rjf: gather ancestors
|
||||
CFG_PanelNode **ancestors = push_array(scratch.arena, CFG_PanelNode *, ancestor_count);
|
||||
{
|
||||
U64 ancestor_idx = 0;
|
||||
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
|
||||
{
|
||||
ancestors[ancestor_idx] = p;
|
||||
ancestor_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: go from highest ancestor => panel and calculate rect
|
||||
Rng2F32 parent_rect = root_rect;
|
||||
for(S64 ancestor_idx = (S64)ancestor_count-1;
|
||||
0 <= ancestor_idx && ancestor_idx < ancestor_count;
|
||||
ancestor_idx -= 1)
|
||||
{
|
||||
CFG_PanelNode *ancestor = ancestors[ancestor_idx];
|
||||
CFG_PanelNode *parent = ancestor->parent;
|
||||
if(parent != &cfg_nil_panel_node)
|
||||
{
|
||||
parent_rect = cfg_target_rect_from_panel_node_child(parent_rect, parent, ancestor);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: calculate final rect
|
||||
Rng2F32 rect = cfg_target_rect_from_panel_node_child(parent_rect, panel->parent, panel);
|
||||
|
||||
scratch_end(scratch);
|
||||
return rect;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_PANELS_H
|
||||
#define CONFIG_PANELS_H
|
||||
|
||||
typedef struct CFG_PanelNode CFG_PanelNode;
|
||||
struct CFG_PanelNode
|
||||
{
|
||||
// rjf: links data
|
||||
CFG_PanelNode *first;
|
||||
CFG_PanelNode *last;
|
||||
CFG_PanelNode *next;
|
||||
CFG_PanelNode *prev;
|
||||
CFG_PanelNode *parent;
|
||||
U64 child_count;
|
||||
CFG_Node *cfg;
|
||||
|
||||
// rjf: split data
|
||||
Axis2 split_axis;
|
||||
F32 pct_of_parent;
|
||||
|
||||
// rjf: tab params
|
||||
Side tab_side;
|
||||
|
||||
// rjf: which tabs are attached
|
||||
CFG_NodePtrList tabs;
|
||||
CFG_Node *selected_tab;
|
||||
};
|
||||
|
||||
typedef struct CFG_PanelTree CFG_PanelTree;
|
||||
struct CFG_PanelTree
|
||||
{
|
||||
CFG_PanelNode *root;
|
||||
CFG_PanelNode *focused;
|
||||
};
|
||||
|
||||
typedef struct CFG_PanelNodeRec CFG_PanelNodeRec;
|
||||
struct CFG_PanelNodeRec
|
||||
{
|
||||
CFG_PanelNode *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
read_only global CFG_PanelNode cfg_nil_panel_node =
|
||||
{
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
0,
|
||||
&cfg_nil_node,
|
||||
.selected_tab = &cfg_nil_node,
|
||||
};
|
||||
|
||||
internal CFG_Node *cfg_window_from_cfg(CFG_Node *cfg);
|
||||
internal CFG_PanelTree cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root);
|
||||
internal CFG_PanelNodeRec cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off);
|
||||
#define cfg_panel_node_rec__depth_first_pre(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, next), OffsetOf(CFG_PanelNode, first))
|
||||
#define cfg_panel_node_rec__depth_first_pre_rev(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, prev), OffsetOf(CFG_PanelNode, last))
|
||||
internal CFG_PanelNode *cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg);
|
||||
internal Rng2F32 cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel);
|
||||
internal Rng2F32 cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel);
|
||||
|
||||
#endif // CONFIG_PANELS_H
|
||||
@@ -1,522 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#undef LAYER_COLOR
|
||||
#define LAYER_COLOR 0x684123ff
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal C_ID
|
||||
c_id_make(U64 u64_0, U64 u64_1)
|
||||
{
|
||||
C_ID id;
|
||||
id.u128[0].u64[0] = u64_0;
|
||||
id.u128[0].u64[1] = u64_1;
|
||||
return id;
|
||||
}
|
||||
|
||||
internal B32
|
||||
c_id_match(C_ID a, C_ID b)
|
||||
{
|
||||
B32 result = MemoryMatchStruct(&a, &b);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal C_Key
|
||||
c_key_make(C_Root root, C_ID id)
|
||||
{
|
||||
C_Key key = {root, 0, id};
|
||||
return key;
|
||||
}
|
||||
|
||||
internal B32
|
||||
c_key_match(C_Key a, C_Key b)
|
||||
{
|
||||
return (MemoryMatchStruct(&a.root, &b.root) && c_id_match(a.id, b.id));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void
|
||||
c_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
c_shared = push_array(arena, C_Shared, 1);
|
||||
c_shared->arena = arena;
|
||||
c_shared->blob_slots_count = 16384;
|
||||
c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, os_get_system_info()->logical_processor_count);
|
||||
c_shared->blob_slots = push_array(arena, C_BlobSlot, c_shared->blob_slots_count);
|
||||
c_shared->blob_stripes = push_array(arena, C_Stripe, c_shared->blob_stripes_count);
|
||||
c_shared->blob_stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->blob_stripes_count);
|
||||
for(U64 idx = 0; idx < c_shared->blob_stripes_count; idx += 1)
|
||||
{
|
||||
C_Stripe *stripe = &c_shared->blob_stripes[idx];
|
||||
stripe->arena = arena_alloc();
|
||||
stripe->rw_mutex = rw_mutex_alloc();
|
||||
stripe->cv = cond_var_alloc();
|
||||
}
|
||||
c_shared->key_slots_count = 4096;
|
||||
c_shared->key_stripes_count = Min(c_shared->key_slots_count, os_get_system_info()->logical_processor_count);
|
||||
c_shared->key_slots = push_array(arena, C_KeySlot, c_shared->key_slots_count);
|
||||
c_shared->key_stripes = push_array(arena, C_Stripe, c_shared->key_stripes_count);
|
||||
c_shared->key_stripes_free_nodes = push_array(arena, C_KeyNode *, c_shared->key_stripes_count);
|
||||
for(U64 idx = 0; idx < c_shared->key_stripes_count; idx += 1)
|
||||
{
|
||||
C_Stripe *stripe = &c_shared->key_stripes[idx];
|
||||
stripe->arena = arena_alloc();
|
||||
stripe->rw_mutex = rw_mutex_alloc();
|
||||
stripe->cv = cond_var_alloc();
|
||||
}
|
||||
c_shared->root_slots_count = 4096;
|
||||
c_shared->root_stripes_count = Min(c_shared->root_slots_count, os_get_system_info()->logical_processor_count);
|
||||
c_shared->root_slots = push_array(arena, C_RootSlot, c_shared->root_slots_count);
|
||||
c_shared->root_stripes = push_array(arena, C_Stripe, c_shared->root_stripes_count);
|
||||
c_shared->root_stripes_free_nodes = push_array(arena, C_RootNode *, c_shared->root_stripes_count);
|
||||
for(U64 idx = 0; idx < c_shared->root_stripes_count; idx += 1)
|
||||
{
|
||||
C_Stripe *stripe = &c_shared->root_stripes[idx];
|
||||
stripe->arena = arena_alloc();
|
||||
stripe->rw_mutex = rw_mutex_alloc();
|
||||
stripe->cv = cond_var_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Root Allocation/Deallocation
|
||||
|
||||
internal C_Root
|
||||
c_root_alloc(void)
|
||||
{
|
||||
C_Root root = {0};
|
||||
root.u64[0] = ins_atomic_u64_inc_eval(&c_shared->root_id_gen);
|
||||
U64 slot_idx = root.u64[0]%c_shared->root_slots_count;
|
||||
U64 stripe_idx = slot_idx%c_shared->root_stripes_count;
|
||||
C_RootSlot *slot = &c_shared->root_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->root_stripes[stripe_idx];
|
||||
MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
C_RootNode *node = c_shared->root_stripes_free_nodes[stripe_idx];
|
||||
if(node != 0)
|
||||
{
|
||||
SLLStackPop(c_shared->root_stripes_free_nodes[stripe_idx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = push_array(stripe->arena, C_RootNode, 1);
|
||||
}
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
node->root = root;
|
||||
node->arena = arena_alloc();
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
internal void
|
||||
c_root_release(C_Root root)
|
||||
{
|
||||
//- rjf: unpack root
|
||||
U64 slot_idx = root.u64[0]%c_shared->root_slots_count;
|
||||
U64 stripe_idx = slot_idx%c_shared->root_stripes_count;
|
||||
C_RootSlot *slot = &c_shared->root_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->root_stripes[stripe_idx];
|
||||
|
||||
//- rjf: release root node, grab its arena / ID list
|
||||
Arena *root_arena = 0;
|
||||
C_RootIDChunkList root_ids = {0};
|
||||
MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(C_RootNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&root, &n->root))
|
||||
{
|
||||
DLLRemove(slot->first, slot->last, n);
|
||||
root_arena = n->arena;
|
||||
root_ids = n->ids;
|
||||
SLLStackPush(c_shared->root_stripes_free_nodes[stripe_idx], n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: release all IDs
|
||||
for(C_RootIDChunkNode *id_chunk_n = root_ids.first; id_chunk_n != 0; id_chunk_n = id_chunk_n->next)
|
||||
{
|
||||
for EachIndex(chunk_idx, id_chunk_n->count)
|
||||
{
|
||||
C_ID id = id_chunk_n->v[chunk_idx];
|
||||
C_Key key = c_key_make(root, id);
|
||||
c_close_key(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Submission
|
||||
|
||||
internal U128
|
||||
c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
||||
{
|
||||
//- rjf: unpack key
|
||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
|
||||
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
|
||||
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
|
||||
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
|
||||
|
||||
//- rjf: hash data, unpack hash
|
||||
U128 hash = u128_hash_from_str8(data);
|
||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
||||
|
||||
//- rjf: commit to (hash -> data) cache
|
||||
ProfScope("commit to (hash -> data) cache") RWMutexScope(stripe->rw_mutex, 1)
|
||||
{
|
||||
// rjf: find existing node
|
||||
C_BlobNode *node = 0;
|
||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: release duplicate data if node already exists
|
||||
if(node != 0 && data_arena != 0 && *data_arena != 0)
|
||||
{
|
||||
arena_release(*data_arena);
|
||||
}
|
||||
|
||||
// rjf: allocate node if needed
|
||||
if(node == 0)
|
||||
{
|
||||
node = c_shared->blob_stripes_free_nodes[stripe_idx];
|
||||
if(node)
|
||||
{
|
||||
SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = push_array_no_zero(stripe->arena, C_BlobNode, 1);
|
||||
}
|
||||
MemoryZeroStruct(node);
|
||||
node->hash = hash;
|
||||
if(data_arena != 0)
|
||||
{
|
||||
node->arena = *data_arena;
|
||||
}
|
||||
node->data = data;
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
}
|
||||
|
||||
// rjf: bump key ref count
|
||||
node->key_ref_count += 1;
|
||||
|
||||
// rjf "steal" arena from caller
|
||||
if(data_arena != 0)
|
||||
{
|
||||
*data_arena = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: commit to (key -> list(hash)) cache
|
||||
U128 key_expired_hash = {0};
|
||||
ProfScope("commit to (key -> list(hash)) cache") RWMutexScope(key_stripe->rw_mutex, 1)
|
||||
{
|
||||
// rjf: find existing key
|
||||
C_KeyNode *key_node = 0;
|
||||
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(c_key_match(n->key, key))
|
||||
{
|
||||
key_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: create key node if it doesn't exist
|
||||
B32 key_is_new = 0;
|
||||
if(!key_node)
|
||||
{
|
||||
key_is_new = 1;
|
||||
key_node = c_shared->key_stripes_free_nodes[key_stripe_idx];
|
||||
if(key_node)
|
||||
{
|
||||
SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
key_node = push_array_no_zero(key_stripe->arena, C_KeyNode, 1);
|
||||
}
|
||||
MemoryZeroStruct(key_node);
|
||||
key_node->key = key;
|
||||
DLLPushBack(key_slot->first, key_slot->last, key_node);
|
||||
}
|
||||
|
||||
// rjf: push hash into key's history
|
||||
if(key_node)
|
||||
{
|
||||
if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT)
|
||||
{
|
||||
key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)];
|
||||
}
|
||||
key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash;
|
||||
key_node->hash_history_gen += 1;
|
||||
}
|
||||
|
||||
// rjf: key is new -> add this key to the associated root
|
||||
if(key_is_new)
|
||||
{
|
||||
U64 root_hash = u64_hash_from_str8(str8_struct(&key.root));
|
||||
U64 root_slot_idx = root_hash%c_shared->root_slots_count;
|
||||
U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count;
|
||||
C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx];
|
||||
C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx];
|
||||
RWMutexScope(root_stripe->rw_mutex, 1)
|
||||
{
|
||||
for(C_RootNode *n = root_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->root, &key.root))
|
||||
{
|
||||
C_RootIDChunkNode *chunk = n->ids.last;
|
||||
if(chunk == 0 || chunk->count >= chunk->cap)
|
||||
{
|
||||
chunk = push_array(n->arena, C_RootIDChunkNode, 1);
|
||||
SLLQueuePush(n->ids.first, n->ids.last, chunk);
|
||||
n->ids.chunk_count += 1;
|
||||
chunk->cap = 1024;
|
||||
chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap);
|
||||
}
|
||||
chunk->v[chunk->count] = key.id;
|
||||
chunk->count += 1;
|
||||
n->ids.total_count += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: decrement key ref count of expired hash
|
||||
if(!u128_match(key_expired_hash, u128_zero())) ProfScope("decrement key ref count of expired hash")
|
||||
{
|
||||
U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *old_hash_slot = &c_shared->blob_slots[old_hash_slot_idx];
|
||||
C_Stripe *old_hash_stripe = &c_shared->blob_stripes[old_hash_stripe_idx];
|
||||
RWMutexScope(old_hash_stripe->rw_mutex, 0)
|
||||
{
|
||||
for(C_BlobNode *n = old_hash_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, key_expired_hash))
|
||||
{
|
||||
ins_atomic_u64_dec_eval(&n->key_ref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Closing
|
||||
|
||||
internal void
|
||||
c_close_key(C_Key key)
|
||||
{
|
||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
|
||||
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
|
||||
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
|
||||
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
|
||||
RWMutexScope(key_stripe->rw_mutex, 1)
|
||||
{
|
||||
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(c_key_match(n->key, key))
|
||||
{
|
||||
for(U64 history_idx = 0;
|
||||
history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen;
|
||||
history_idx += 1)
|
||||
{
|
||||
U128 hash = n->hash_history[(n->hash_history_gen-1-history_idx) % ArrayCount(n->hash_history)];
|
||||
U64 hash_slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 hash_stripe_idx = hash_slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *hash_slot = &c_shared->blob_slots[hash_slot_idx];
|
||||
C_Stripe *hash_stripe = &c_shared->blob_stripes[hash_stripe_idx];
|
||||
MutexScopeR(hash_stripe->rw_mutex)
|
||||
{
|
||||
for(C_BlobNode *n = hash_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
ins_atomic_u64_dec_eval(&n->key_ref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DLLRemove(key_slot->first, key_slot->last, n);
|
||||
SLLStackPush(c_shared->key_stripes_free_nodes[key_stripe_idx], n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Downstream Accesses
|
||||
|
||||
internal void
|
||||
c_hash_downstream_inc(U128 hash)
|
||||
{
|
||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
||||
MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(hash, n->hash))
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&n->downstream_ref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
c_hash_downstream_dec(U128 hash)
|
||||
{
|
||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
||||
MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(hash, n->hash))
|
||||
{
|
||||
ins_atomic_u64_dec_eval(&n->downstream_ref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookup
|
||||
|
||||
internal U128
|
||||
c_hash_from_key(C_Key key, U64 rewind_count)
|
||||
{
|
||||
U128 result = {0};
|
||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%c_shared->key_slots_count;
|
||||
U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count;
|
||||
C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx];
|
||||
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
|
||||
RWMutexScope(key_stripe->rw_mutex, 0)
|
||||
{
|
||||
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(c_key_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count)
|
||||
{
|
||||
result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
c_data_from_hash(Access *access, U128 hash)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
String8 result = {0};
|
||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
||||
MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
result = n->data;
|
||||
access_touch(access, &n->access_pt, stripe->cv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal void
|
||||
c_async_tick(void)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
//- rjf: garbage collect blobs
|
||||
{
|
||||
Rng1U64 range = lane_range(c_shared->blob_slots_count);
|
||||
for EachInRange(slot_idx, range)
|
||||
{
|
||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
||||
{
|
||||
B32 slot_has_work = 0;
|
||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
||||
{
|
||||
for(C_BlobNode *n = slot->first, *next = 0; n != 0; n = next)
|
||||
{
|
||||
next = n->next;
|
||||
U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count);
|
||||
U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count);
|
||||
if(access_pt_is_expired(&n->access_pt, .time = 5000000) && key_ref_count == 0 && downstream_ref_count == 0)
|
||||
{
|
||||
slot_has_work = 1;
|
||||
if(!write_mode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLLRemove(slot->first, slot->last, n);
|
||||
SLLStackPush(c_shared->blob_stripes_free_nodes[stripe_idx], n);
|
||||
if(n->arena != 0)
|
||||
{
|
||||
arena_release(n->arena);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!slot_has_work)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONTENT_H
|
||||
#define CONTENT_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Hash Store Notes (2025/05/18)
|
||||
//
|
||||
// The hash store is a general-purpose data cache. It offers three layers of
|
||||
// caching: (a) content (hash of data), (b) key (unique identity correllated
|
||||
// with history of hashes), and (c) root (bucket for many keys, manually
|
||||
// allocated / deallocated).
|
||||
//
|
||||
// (a) The "content" level of cache access is a simply hash(data) -> data
|
||||
// mapping. This bypasses all identity/key/root mechanisms and provides a
|
||||
// way to just talk about unique (and deduplicated) blobs of data.
|
||||
//
|
||||
// (b) The "key" level of cache access is used to encode a history of hashes
|
||||
// for some unique "identity", where the "identity" is a concept managed
|
||||
// by the user. One example of an identity would be a particular address
|
||||
// range inside of some process to which the debugger is attached. Another
|
||||
// might be a range inside of some file.
|
||||
//
|
||||
// (c) The "root" level is to provide a top-level allocation/deallocation
|
||||
// mechanism for a large set of keys. It also provides an extra level of
|
||||
// key uniqueness. For instance, each process to which the debugger is
|
||||
// attached might have its own root, and each key might correspond to a
|
||||
// particular address range within that process. This way, when the
|
||||
// process ends, all of its keys can be easily destroyed using a single
|
||||
// deallocation of the root.
|
||||
//
|
||||
// The way this might be generally used inside of the debugger would be that
|
||||
// some evaluation - let's say it's some variable `x` - is mapped (via debug
|
||||
// info) to some address range. If `x` is a `char[4096]`, then it might map
|
||||
// to some address range [&x, &x + 4096). This, together with the process
|
||||
// within which `x` is evaluated, forms both a `root` (for the process) and
|
||||
// a `key` (for the address range). Some asynchronous memory streaming system
|
||||
// can then, together with the root and key, read memory for that range, then
|
||||
// submit that data to the hash store, correllating with the root and key
|
||||
// combo.
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Types
|
||||
|
||||
typedef struct C_Root C_Root;
|
||||
struct C_Root
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct C_ID C_ID;
|
||||
struct C_ID
|
||||
{
|
||||
U128 u128[1];
|
||||
};
|
||||
|
||||
typedef struct C_Key C_Key;
|
||||
struct C_Key
|
||||
{
|
||||
C_Root root;
|
||||
U64 _padding_;
|
||||
C_ID id;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Stripe Type
|
||||
|
||||
typedef struct C_Stripe C_Stripe;
|
||||
struct C_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
RWMutex rw_mutex;
|
||||
CondVar cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Root Cache Types
|
||||
|
||||
typedef struct C_RootIDChunkNode C_RootIDChunkNode;
|
||||
struct C_RootIDChunkNode
|
||||
{
|
||||
C_RootIDChunkNode *next;
|
||||
C_ID *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct C_RootIDChunkList C_RootIDChunkList;
|
||||
struct C_RootIDChunkList
|
||||
{
|
||||
C_RootIDChunkNode *first;
|
||||
C_RootIDChunkNode *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct C_RootNode C_RootNode;
|
||||
struct C_RootNode
|
||||
{
|
||||
C_RootNode *next;
|
||||
C_RootNode *prev;
|
||||
Arena *arena;
|
||||
C_Root root;
|
||||
C_RootIDChunkList ids;
|
||||
};
|
||||
|
||||
typedef struct C_RootSlot C_RootSlot;
|
||||
struct C_RootSlot
|
||||
{
|
||||
C_RootNode *first;
|
||||
C_RootNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Cache Types
|
||||
|
||||
#define C_KEY_HASH_HISTORY_COUNT 64
|
||||
#define C_KEY_HASH_HISTORY_STRONG_REF_COUNT 2
|
||||
|
||||
typedef struct C_KeyNode C_KeyNode;
|
||||
struct C_KeyNode
|
||||
{
|
||||
C_KeyNode *next;
|
||||
C_KeyNode *prev;
|
||||
C_Key key;
|
||||
U128 hash_history[C_KEY_HASH_HISTORY_COUNT];
|
||||
U64 hash_history_gen;
|
||||
};
|
||||
|
||||
typedef struct C_KeySlot C_KeySlot;
|
||||
struct C_KeySlot
|
||||
{
|
||||
C_KeyNode *first;
|
||||
C_KeyNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Content Blob Cache Types
|
||||
|
||||
typedef struct C_BlobNode C_BlobNode;
|
||||
struct C_BlobNode
|
||||
{
|
||||
C_BlobNode *next;
|
||||
C_BlobNode *prev;
|
||||
U128 hash;
|
||||
Arena *arena;
|
||||
String8 data;
|
||||
AccessPt access_pt;
|
||||
U64 key_ref_count;
|
||||
U64 downstream_ref_count;
|
||||
};
|
||||
|
||||
typedef struct C_BlobSlot C_BlobSlot;
|
||||
struct C_BlobSlot
|
||||
{
|
||||
C_BlobNode *first;
|
||||
C_BlobNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct C_Shared C_Shared;
|
||||
struct C_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: main data blob cache
|
||||
U64 blob_slots_count;
|
||||
U64 blob_stripes_count;
|
||||
C_BlobSlot *blob_slots;
|
||||
C_Stripe *blob_stripes;
|
||||
C_BlobNode **blob_stripes_free_nodes;
|
||||
|
||||
// rjf: key cache
|
||||
U64 key_slots_count;
|
||||
U64 key_stripes_count;
|
||||
C_KeySlot *key_slots;
|
||||
C_Stripe *key_stripes;
|
||||
C_KeyNode **key_stripes_free_nodes;
|
||||
|
||||
// rjf: root cache
|
||||
U64 root_slots_count;
|
||||
U64 root_stripes_count;
|
||||
C_RootSlot *root_slots;
|
||||
C_Stripe *root_stripes;
|
||||
C_RootNode **root_stripes_free_nodes;
|
||||
U64 root_id_gen;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global C_Shared *c_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal C_ID c_id_make(U64 u64_0, U64 u64_1);
|
||||
internal B32 c_id_match(C_ID a, C_ID b);
|
||||
internal C_Key c_key_make(C_Root root, C_ID id);
|
||||
internal B32 c_key_match(C_Key a, C_Key b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void c_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Root Allocation/Deallocation
|
||||
|
||||
internal C_Root c_root_alloc(void);
|
||||
internal void c_root_release(C_Root root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Submission
|
||||
|
||||
internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Closing
|
||||
|
||||
internal void c_close_key(C_Key key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Downstream Accesses
|
||||
|
||||
internal void c_hash_downstream_inc(U128 hash);
|
||||
internal void c_hash_downstream_dec(U128 hash);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal U128 c_hash_from_key(C_Key key, U64 rewind_count);
|
||||
internal String8 c_data_from_hash(Access *access, U128 hash);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal void c_async_tick(void);
|
||||
|
||||
#endif // CONTENT_H
|
||||
+35
-142
@@ -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
File diff suppressed because it is too large
Load Diff
+247
-676
File diff suppressed because it is too large
Load Diff
+1
-4
@@ -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
@@ -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,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
@@ -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
@@ -0,0 +1,540 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void
|
||||
dasm_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
dasm_shared = push_array(arena, DASM_Shared, 1);
|
||||
dasm_shared->arena = arena;
|
||||
dasm_shared->entity_map.slots_count = 1024;
|
||||
dasm_shared->entity_map.slots = push_array(arena, DASM_EntitySlot, dasm_shared->entity_map.slots_count);
|
||||
dasm_shared->entity_map_stripes.count = 64;
|
||||
dasm_shared->entity_map_stripes.v = push_array(arena, DASM_Stripe, dasm_shared->entity_map_stripes.count);
|
||||
for(U64 idx = 0; idx < dasm_shared->entity_map_stripes.count; idx += 1)
|
||||
{
|
||||
dasm_shared->entity_map_stripes.v[idx].arena = arena_alloc();
|
||||
dasm_shared->entity_map_stripes.v[idx].rw_mutex = os_rw_mutex_alloc();
|
||||
dasm_shared->entity_map_stripes.v[idx].cv = os_condition_variable_alloc();
|
||||
}
|
||||
dasm_shared->u2d_ring_mutex = os_mutex_alloc();
|
||||
dasm_shared->u2d_ring_cv = os_condition_variable_alloc();
|
||||
dasm_shared->u2d_ring_size = KB(64);
|
||||
dasm_shared->u2d_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2d_ring_size);
|
||||
dasm_shared->decode_thread_count = Max(1, os_logical_core_count()-1);
|
||||
dasm_shared->decode_threads = push_array(arena, OS_Handle, dasm_shared->decode_thread_count);
|
||||
for(U64 idx = 0; idx < dasm_shared->decode_thread_count; idx += 1)
|
||||
{
|
||||
dasm_shared->decode_threads[idx] = os_launch_thread(dasm_decode_thread_entry_point, (void *)idx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64
|
||||
dasm_hash_from_string(String8 string)
|
||||
{
|
||||
U64 result = 5381;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Instruction Type Functions
|
||||
|
||||
internal void
|
||||
dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst)
|
||||
{
|
||||
DASM_InstChunkNode *node = list->last;
|
||||
if(node == 0 || node->count >= node->cap)
|
||||
{
|
||||
node = push_array(arena, DASM_InstChunkNode, 1);
|
||||
node->v = push_array_no_zero(arena, DASM_Inst, cap);
|
||||
node->cap = cap;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->node_count += 1;
|
||||
}
|
||||
MemoryCopyStruct(&node->v[node->count], inst);
|
||||
node->count += 1;
|
||||
list->inst_count += 1;
|
||||
}
|
||||
|
||||
internal DASM_InstArray
|
||||
dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list)
|
||||
{
|
||||
DASM_InstArray array = {0};
|
||||
array.count = list->inst_count;
|
||||
array.v = push_array_no_zero(arena, DASM_Inst, array.count);
|
||||
U64 idx = 0;
|
||||
for(DASM_InstChunkNode *n = list->first; n != 0; n = n->next)
|
||||
{
|
||||
MemoryCopy(array.v+idx, n->v, sizeof(DASM_Inst)*n->count);
|
||||
idx += n->count;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off)
|
||||
{
|
||||
U64 result = 0;
|
||||
for(U64 idx = 0; idx < array->count; idx += 1)
|
||||
{
|
||||
if(array->v[idx].off == off)
|
||||
{
|
||||
result = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx)
|
||||
{
|
||||
U64 off = 0;
|
||||
if(idx < array->count)
|
||||
{
|
||||
off = array->v[idx].off;
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembly Functions
|
||||
|
||||
#include "third_party/udis86/config.h"
|
||||
#include "third_party/udis86/udis86.h"
|
||||
#include "third_party/udis86/libudis86/decode.c"
|
||||
#include "third_party/udis86/libudis86/itab.c"
|
||||
#include "third_party/udis86/libudis86/syn-att.c"
|
||||
#include "third_party/udis86/libudis86/syn-intel.c"
|
||||
#include "third_party/udis86/libudis86/syn.c"
|
||||
#include "third_party/udis86/libudis86/udis86.c"
|
||||
|
||||
internal DASM_InstChunkList
|
||||
dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data)
|
||||
{
|
||||
DASM_InstChunkList inst_list = {0};
|
||||
switch(arch)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: x86/x64 decoding
|
||||
case Architecture_x64:
|
||||
case Architecture_x86:
|
||||
{
|
||||
// rjf: grab context
|
||||
struct ud udc;
|
||||
ud_init(&udc);
|
||||
ud_set_mode(&udc, bit_size_from_arch(arch));
|
||||
ud_set_pc(&udc, addr);
|
||||
ud_set_input_buffer(&udc, data.str, data.size);
|
||||
ud_set_vendor(&udc, UD_VENDOR_ANY);
|
||||
ud_set_syntax(&udc, UD_SYN_INTEL);
|
||||
|
||||
// rjf: disassemble
|
||||
U64 byte_process_start_off = 0;
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
// rjf: disassemble one instruction
|
||||
U64 size = ud_disassemble(&udc);
|
||||
if(size == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: analyze
|
||||
struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0);
|
||||
U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0;
|
||||
|
||||
// rjf: push
|
||||
String8 string = push_str8f(arena, "%s", udc.asm_buf);
|
||||
DASM_Inst inst = {string, off, rel_voff};
|
||||
dasm_inst_chunk_list_push(arena, &inst_list, 1024, &inst);
|
||||
|
||||
// rjf: increment
|
||||
off += size;
|
||||
if(bytes_processed_counter != 0 && (off-byte_process_start_off >= 1000))
|
||||
{
|
||||
ins_atomic_u64_add_eval(bytes_processed_counter, (off-byte_process_start_off));
|
||||
byte_process_start_off = off;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
}
|
||||
return inst_list;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
//- rjf: opening handles & correllation with module
|
||||
|
||||
internal DASM_Handle
|
||||
dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range)
|
||||
{
|
||||
DASM_Handle result = {0};
|
||||
if(machine != 0 && process.u64[0] != 0)
|
||||
{
|
||||
U64 hash = dasm_hash_from_string(str8_struct(&process));
|
||||
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Entity *entity = 0;
|
||||
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||
{
|
||||
if(e->machine_id == machine &&
|
||||
ctrl_handle_match(e->process, process) &&
|
||||
MemoryMatchStruct(&e->vaddr_range, &vaddr_range))
|
||||
{
|
||||
entity = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(entity == 0)
|
||||
{
|
||||
entity = push_array(stripe->arena, DASM_Entity, 1);
|
||||
SLLQueuePush(slot->first, slot->last, entity);
|
||||
entity->machine_id = machine;
|
||||
entity->process = process;
|
||||
entity->vaddr_range= vaddr_range;
|
||||
entity->id = ins_atomic_u64_inc_eval(&dasm_shared->entity_id_gen);
|
||||
entity->decode_inst_arena = arena_alloc__sized(MB(256), KB(64));
|
||||
entity->decode_string_arena = arena_alloc__sized(GB(1), KB(64));
|
||||
}
|
||||
result.u64[0] = hash;
|
||||
result.u64[1] = entity->id;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//- rjf: asking for top-level info of a handle
|
||||
|
||||
internal DASM_BinaryInfo
|
||||
dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle)
|
||||
{
|
||||
DASM_BinaryInfo info = {0};
|
||||
{
|
||||
U64 hash = handle.u64[0];
|
||||
U64 id = handle.u64[1];
|
||||
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Entity *entity = 0;
|
||||
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||
{
|
||||
if(e->id == id)
|
||||
{
|
||||
entity = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(entity != 0)
|
||||
{
|
||||
info.machine_id = entity->machine_id;
|
||||
info.process = entity->process;
|
||||
info.vaddr_range = entity->vaddr_range;
|
||||
info.bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed);
|
||||
info.bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
//- rjf: asking for decoded instructions
|
||||
|
||||
internal DASM_InstArray
|
||||
dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us)
|
||||
{
|
||||
DASM_InstArray result = {0};
|
||||
if(handle.u64[0] != 0 || handle.u64[1] != 0)
|
||||
{
|
||||
U64 hash = handle.u64[0];
|
||||
U64 id = handle.u64[1];
|
||||
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||
B32 sent = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex) for(;;)
|
||||
{
|
||||
DASM_Entity *entity = 0;
|
||||
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||
{
|
||||
if(e->id == id)
|
||||
{
|
||||
entity = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
U64 last_time_sent_us = 0;
|
||||
if(entity != 0)
|
||||
{
|
||||
U64 bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed);
|
||||
U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
|
||||
last_time_sent_us = ins_atomic_u64_eval(&entity->last_time_sent_us);
|
||||
if(bytes_processed == bytes_to_process && bytes_processed != 0)
|
||||
{
|
||||
result.count = entity->decode_inst_array.count;
|
||||
result.v = push_array_no_zero(arena, DASM_Inst, result.count);
|
||||
MemoryCopy(result.v, entity->decode_inst_array.v, sizeof(DASM_Inst)*result.count);
|
||||
for(U64 idx = 0; idx < result.count; idx += 1)
|
||||
{
|
||||
result.v[idx].string = push_str8_copy(arena, result.v[idx].string);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!sent && entity != 0 && last_time_sent_us+10000 <= os_now_microseconds())
|
||||
{
|
||||
DASM_DecodeRequest req = {handle};
|
||||
sent = dasm_u2d_enqueue_request(&req, endt_us);
|
||||
ins_atomic_u64_eval_assign(&entity->last_time_sent_us, os_now_microseconds());
|
||||
}
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Decode Threads
|
||||
|
||||
internal B32
|
||||
dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us)
|
||||
{
|
||||
B32 result = 0;
|
||||
OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos);
|
||||
U64 available_size = (dasm_shared->u2d_ring_size-unconsumed_size);
|
||||
if(available_size >= sizeof(*req))
|
||||
{
|
||||
result = 1;
|
||||
dasm_shared->u2d_ring_write_pos += ring_write_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_write_pos, req);
|
||||
dasm_shared->u2d_ring_write_pos += 7;
|
||||
dasm_shared->u2d_ring_write_pos -= dasm_shared->u2d_ring_write_pos%8;
|
||||
break;
|
||||
}
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, endt_us);
|
||||
}
|
||||
if(result)
|
||||
{
|
||||
os_condition_variable_broadcast(dasm_shared->u2d_ring_cv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal DASM_DecodeRequest
|
||||
dasm_u2d_dequeue_request(void)
|
||||
{
|
||||
DASM_DecodeRequest req = {0};
|
||||
OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos);
|
||||
if(unconsumed_size >= sizeof(DASM_DecodeRequest))
|
||||
{
|
||||
dasm_shared->u2d_ring_read_pos += ring_read_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_read_pos, &req);
|
||||
dasm_shared->u2d_ring_read_pos += 7;
|
||||
dasm_shared->u2d_ring_read_pos -= dasm_shared->u2d_ring_read_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, max_U64);
|
||||
}
|
||||
os_condition_variable_broadcast(dasm_shared->u2d_ring_cv);
|
||||
return req;
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_decode_thread_entry_point(void *p)
|
||||
{
|
||||
TCTX tctx_;
|
||||
tctx_init_and_equip(&tctx_);
|
||||
for(;;)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: get next request & unpack
|
||||
DASM_DecodeRequest req = dasm_u2d_dequeue_request();
|
||||
DASM_Handle handle = req.handle;
|
||||
U64 hash = handle.u64[0];
|
||||
U64 id = handle.u64[1];
|
||||
U64 slot_idx = hash%dasm_shared->entity_map.slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count;
|
||||
DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx];
|
||||
|
||||
//- rjf: request -> ctrl info
|
||||
B32 is_first_to_task = 0;
|
||||
CTRL_MachineID ctrl_machine_id = 0;
|
||||
CTRL_Handle ctrl_process = {0};
|
||||
Rng1U64 vaddr_range = {0};
|
||||
Architecture arch = Architecture_Null;
|
||||
U64 *bytes_processed_counter = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Entity *entity = 0;
|
||||
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||
{
|
||||
if(e->id == id)
|
||||
{
|
||||
entity = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(entity != 0)
|
||||
{
|
||||
U64 initial_working_count = ins_atomic_u32_eval_cond_assign(&entity->working_count, 1, 0);
|
||||
if(initial_working_count == 0)
|
||||
{
|
||||
is_first_to_task = 1;
|
||||
ctrl_machine_id = entity->machine_id;
|
||||
ctrl_process = entity->process;
|
||||
vaddr_range = entity->vaddr_range;
|
||||
arch = ctrl_arch_from_handle(ctrl_machine_id, ctrl_process);
|
||||
bytes_processed_counter = &entity->bytes_processed;
|
||||
U64 bytes_to_process = dim_1u64(vaddr_range);
|
||||
ins_atomic_u64_eval_assign(&entity->bytes_processed, 0);
|
||||
ins_atomic_u64_eval_assign(&entity->bytes_to_process, bytes_to_process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: bad handle or machine id -> bad task
|
||||
B32 good_task = (is_first_to_task && ctrl_process.u64[0] != 0 && ctrl_machine_id != 0 && arch != Architecture_Null && bytes_processed_counter != 0);
|
||||
|
||||
//- rjf: good task -> clear entity's info
|
||||
if(good_task)
|
||||
{
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Entity *entity = 0;
|
||||
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||
{
|
||||
if(e->id == id)
|
||||
{
|
||||
entity = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(entity != 0)
|
||||
{
|
||||
arena_clear(entity->decode_inst_arena);
|
||||
arena_clear(entity->decode_string_arena);
|
||||
MemoryZeroStruct(&entity->decode_inst_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: good task -> read process memory & decode instructions - stop each
|
||||
// 4k and write into cache, so users can read incremental results
|
||||
if(good_task)
|
||||
{
|
||||
U64 chunk_size = KB(4);
|
||||
for(U64 off = 0; vaddr_range.min+off < vaddr_range.max; off += chunk_size)
|
||||
{
|
||||
Rng1U64 chunk_vaddr_range = r1u64(vaddr_range.min+off, vaddr_range.min+off+chunk_size);
|
||||
chunk_vaddr_range.min = ClampTop(chunk_vaddr_range.min, vaddr_range.max);
|
||||
chunk_vaddr_range.max = ClampTop(chunk_vaddr_range.max, vaddr_range.max);
|
||||
|
||||
//- rjf: read next chunk & decode
|
||||
String8 data = {0};
|
||||
DASM_InstChunkList inst_list = {0};
|
||||
if(good_task)
|
||||
{
|
||||
data.str = push_array_no_zero(scratch.arena, U8, dim_1u64(chunk_vaddr_range));
|
||||
data.size = ctrl_process_read(ctrl_machine_id, ctrl_process, chunk_vaddr_range, data.str);
|
||||
if(data.size != 0)
|
||||
{
|
||||
inst_list = dasm_inst_chunk_list_from_arch_addr_data(scratch.arena, bytes_processed_counter, arch, chunk_vaddr_range.min, data);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: write into cache
|
||||
{
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Entity *entity = 0;
|
||||
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||
{
|
||||
if(e->id == id)
|
||||
{
|
||||
entity = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(entity != 0)
|
||||
{
|
||||
DASM_Inst *new_chunk_base = push_array(entity->decode_inst_arena, DASM_Inst, inst_list.inst_count);
|
||||
U64 off = 0;
|
||||
for(DASM_InstChunkNode *node = inst_list.first; node != 0; node = node->next)
|
||||
{
|
||||
MemoryCopy(new_chunk_base+off, node->v, sizeof(DASM_Inst)*node->count);
|
||||
off += node->count;
|
||||
}
|
||||
for(U64 idx = 0; idx < inst_list.inst_count; idx += 1)
|
||||
{
|
||||
new_chunk_base[idx].string = push_str8_copy(entity->decode_string_arena, new_chunk_base[idx].string);
|
||||
}
|
||||
entity->decode_inst_array.count += inst_list.inst_count;
|
||||
if(entity->decode_inst_array.v == 0)
|
||||
{
|
||||
entity->decode_inst_array.v = new_chunk_base;
|
||||
}
|
||||
}
|
||||
}
|
||||
os_condition_variable_broadcast(stripe->cv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: mark task as complete
|
||||
if(good_task)
|
||||
{
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Entity *entity = 0;
|
||||
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
|
||||
{
|
||||
if(e->id == id)
|
||||
{
|
||||
entity = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(entity != 0)
|
||||
{
|
||||
U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process);
|
||||
ins_atomic_u64_eval_assign(&entity->bytes_processed, bytes_to_process);
|
||||
ins_atomic_u64_eval_assign(&entity->working_count, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DASM_H
|
||||
#define DASM_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handle Type
|
||||
|
||||
typedef struct DASM_Handle DASM_Handle;
|
||||
struct DASM_Handle
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Instruction Types
|
||||
|
||||
typedef struct DASM_Inst DASM_Inst;
|
||||
struct DASM_Inst
|
||||
{
|
||||
String8 string;
|
||||
U64 off;
|
||||
U64 addr;
|
||||
};
|
||||
|
||||
typedef struct DASM_InstChunkNode DASM_InstChunkNode;
|
||||
struct DASM_InstChunkNode
|
||||
{
|
||||
DASM_InstChunkNode *next;
|
||||
DASM_Inst *v;
|
||||
U64 cap;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DASM_InstChunkList DASM_InstChunkList;
|
||||
struct DASM_InstChunkList
|
||||
{
|
||||
DASM_InstChunkNode *first;
|
||||
DASM_InstChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 inst_count;
|
||||
};
|
||||
|
||||
typedef struct DASM_InstArray DASM_InstArray;
|
||||
struct DASM_InstArray
|
||||
{
|
||||
DASM_Inst *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Striped Access Types
|
||||
|
||||
typedef struct DASM_Stripe DASM_Stripe;
|
||||
struct DASM_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle cv;
|
||||
OS_Handle rw_mutex;
|
||||
};
|
||||
|
||||
typedef struct DASM_StripeTable DASM_StripeTable;
|
||||
struct DASM_StripeTable
|
||||
{
|
||||
U64 count;
|
||||
DASM_Stripe *v;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Cache Types
|
||||
|
||||
typedef struct DASM_Entity DASM_Entity;
|
||||
struct DASM_Entity
|
||||
{
|
||||
DASM_Entity *next;
|
||||
|
||||
// rjf: key info
|
||||
CTRL_MachineID machine_id;
|
||||
CTRL_Handle process;
|
||||
Rng1U64 vaddr_range;
|
||||
U64 id;
|
||||
|
||||
// rjf: top-level info
|
||||
U64 last_time_sent_us;
|
||||
U64 working_count;
|
||||
U64 bytes_processed;
|
||||
U64 bytes_to_process;
|
||||
|
||||
// rjf: decoded instruction data
|
||||
Arena *decode_inst_arena;
|
||||
Arena *decode_string_arena;
|
||||
DASM_InstArray decode_inst_array;
|
||||
};
|
||||
|
||||
typedef struct DASM_EntitySlot DASM_EntitySlot;
|
||||
struct DASM_EntitySlot
|
||||
{
|
||||
DASM_Entity *first;
|
||||
DASM_Entity *last;
|
||||
};
|
||||
|
||||
typedef struct DASM_EntityMap DASM_EntityMap;
|
||||
struct DASM_EntityMap
|
||||
{
|
||||
U64 slots_count;
|
||||
DASM_EntitySlot *slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Introspection Info Types
|
||||
|
||||
typedef struct DASM_BinaryInfo DASM_BinaryInfo;
|
||||
struct DASM_BinaryInfo
|
||||
{
|
||||
CTRL_MachineID machine_id;
|
||||
CTRL_Handle process;
|
||||
Rng1U64 vaddr_range;
|
||||
U64 bytes_processed;
|
||||
U64 bytes_to_process;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Decode Request Types
|
||||
|
||||
typedef struct DASM_DecodeRequest DASM_DecodeRequest;
|
||||
struct DASM_DecodeRequest
|
||||
{
|
||||
DASM_Handle handle;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct DASM_Shared DASM_Shared;
|
||||
struct DASM_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: entity table
|
||||
DASM_EntityMap entity_map;
|
||||
DASM_StripeTable entity_map_stripes;
|
||||
U64 entity_id_gen;
|
||||
|
||||
// rjf: user -> decode ring
|
||||
OS_Handle u2d_ring_mutex;
|
||||
OS_Handle u2d_ring_cv;
|
||||
U64 u2d_ring_size;
|
||||
U8 *u2d_ring_base;
|
||||
U64 u2d_ring_write_pos;
|
||||
U64 u2d_ring_read_pos;
|
||||
|
||||
// rjf: decode threads
|
||||
U64 decode_thread_count;
|
||||
OS_Handle *decode_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DASM_Shared *dasm_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void dasm_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 dasm_hash_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Instruction Type Functions
|
||||
|
||||
internal void dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst);
|
||||
internal DASM_InstArray dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list);
|
||||
internal U64 dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off);
|
||||
internal U64 dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembly Functions
|
||||
|
||||
internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
//- rjf: opening handles & correllation with module
|
||||
internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range);
|
||||
|
||||
//- rjf: asking for top-level info of a handle
|
||||
internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle);
|
||||
|
||||
//- rjf: asking for decoded instructions
|
||||
internal DASM_InstArray dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Decode Threads
|
||||
|
||||
internal B32 dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us);
|
||||
internal DASM_DecodeRequest dasm_u2d_dequeue_request(void);
|
||||
|
||||
internal void dasm_decode_thread_entry_point(void *p);
|
||||
|
||||
#endif //DASM_H
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Built-In Command Tables
|
||||
|
||||
@table(name ui_vis ipc_docs_vis text_pt_vis text_rng_vis q_expr q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags ctx_filter)
|
||||
// / | | | | | | \___ _________________________________/ | | | | | |
|
||||
// / | | | | | | \ / | | | | | |
|
||||
D_CmdTable: // | | | | | | | | | | | | | |
|
||||
{
|
||||
//- rjf: low-level target control operations
|
||||
{LaunchAndRun 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" }
|
||||
{LaunchAndStepInto 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" }
|
||||
{Kill 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" }
|
||||
{KillAll 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" }
|
||||
{Detach 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" }
|
||||
{Continue 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" }
|
||||
{StepIntoInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" }
|
||||
{StepOverInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" }
|
||||
{StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
|
||||
{StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
|
||||
{StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" "" }
|
||||
{Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
|
||||
{SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
|
||||
{SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
|
||||
|
||||
//- rjf: high-level composite target control operations
|
||||
{RunToLine 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "$text_pt," }
|
||||
{Run 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" }
|
||||
{Restart 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" }
|
||||
{StepInto 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" }
|
||||
{StepOver 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" }
|
||||
|
||||
//- rjf: debug control context management operations
|
||||
{FreezeThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" }
|
||||
{ThawThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" }
|
||||
{FreezeProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" }
|
||||
{ThawProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" }
|
||||
{FreezeMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" }
|
||||
{ThawMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" }
|
||||
{FreezeLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" }
|
||||
{ThawLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" }
|
||||
{FreezeEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" }
|
||||
{ThawEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" }
|
||||
|
||||
//- rjf: entity decoration
|
||||
{SetEntityColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
|
||||
{SetEntityName 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
|
||||
|
||||
//- rjf: attaching
|
||||
{Attach 1 1 0 0 "query:unattached_processes" PID null Nil Null 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" }
|
||||
}
|
||||
|
||||
@enum D_CmdKind:
|
||||
{
|
||||
Null,
|
||||
@expand(D_CmdTable, a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Developer Toggles
|
||||
|
||||
@table(name)
|
||||
D_DevToggleTable:
|
||||
{
|
||||
{always_refresh}
|
||||
{simulate_lag}
|
||||
{draw_ui_text_pos}
|
||||
{draw_ui_focus_debug}
|
||||
{draw_ui_box_heatmap}
|
||||
{eval_compiler_tooltips}
|
||||
{eval_watch_key_tooltips}
|
||||
{cmd_context_tooltips}
|
||||
{updating_indicator}
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
@expand(D_DevToggleTable a) `global B32 DEV_$(a.name) = 0;`
|
||||
}
|
||||
|
||||
@gen
|
||||
{
|
||||
`struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =`;
|
||||
`{`;
|
||||
@expand(D_DevToggleTable a) `{&DEV_$(a.name), str8_lit_comp("$(a.name)")},`
|
||||
`};`;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,438 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DBG_ENGINE_CORE_H
|
||||
#define DBG_ENGINE_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tick Input Types
|
||||
|
||||
typedef struct D_Target D_Target;
|
||||
struct D_Target
|
||||
{
|
||||
String8 exe;
|
||||
String8 args;
|
||||
String8 working_directory;
|
||||
String8 custom_entry_point_name;
|
||||
String8 stdout_path;
|
||||
String8 stderr_path;
|
||||
String8 stdin_path;
|
||||
B32 debug_subprocesses;
|
||||
String8List env;
|
||||
};
|
||||
|
||||
typedef struct D_TargetArray D_TargetArray;
|
||||
struct D_TargetArray
|
||||
{
|
||||
D_Target *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef U32 D_BreakpointFlags;
|
||||
enum
|
||||
{
|
||||
D_BreakpointFlag_BreakOnWrite = (1<<0),
|
||||
D_BreakpointFlag_BreakOnRead = (1<<1),
|
||||
D_BreakpointFlag_BreakOnExecute = (1<<2),
|
||||
};
|
||||
|
||||
typedef struct D_Breakpoint D_Breakpoint;
|
||||
struct D_Breakpoint
|
||||
{
|
||||
D_BreakpointFlags flags;
|
||||
U64 id;
|
||||
String8 file_path;
|
||||
TxtPt pt;
|
||||
String8 vaddr_expr;
|
||||
String8 condition;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct D_BreakpointArray D_BreakpointArray;
|
||||
struct D_BreakpointArray
|
||||
{
|
||||
D_Breakpoint *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct D_PathMap D_PathMap;
|
||||
struct D_PathMap
|
||||
{
|
||||
String8 src;
|
||||
String8 dst;
|
||||
};
|
||||
|
||||
typedef struct D_PathMapArray D_PathMapArray;
|
||||
struct D_PathMapArray
|
||||
{
|
||||
D_PathMap *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Trap Nets
|
||||
|
||||
typedef struct D_TrapNet D_TrapNet;
|
||||
struct D_TrapNet
|
||||
{
|
||||
CTRL_TrapList traps;
|
||||
B32 good_line_info;
|
||||
B32 good_read;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tick Output Types
|
||||
|
||||
typedef enum D_EventKind
|
||||
{
|
||||
D_EventKind_Null,
|
||||
D_EventKind_ModuleLoad,
|
||||
D_EventKind_ProcessEnd,
|
||||
D_EventKind_Stop,
|
||||
D_EventKind_COUNT
|
||||
}
|
||||
D_EventKind;
|
||||
|
||||
typedef enum D_EventCause
|
||||
{
|
||||
D_EventCause_Null,
|
||||
D_EventCause_UserBreakpoint,
|
||||
D_EventCause_Halt,
|
||||
D_EventCause_SoftHalt,
|
||||
D_EventCause_COUNT
|
||||
}
|
||||
D_EventCause;
|
||||
|
||||
typedef struct D_Event D_Event;
|
||||
struct D_Event
|
||||
{
|
||||
D_EventKind kind;
|
||||
D_EventCause cause;
|
||||
CTRL_Handle module;
|
||||
CTRL_Handle thread;
|
||||
U64 vaddr;
|
||||
U64 code;
|
||||
U64 id;
|
||||
};
|
||||
|
||||
typedef struct D_EventNode D_EventNode;
|
||||
struct D_EventNode
|
||||
{
|
||||
D_EventNode *next;
|
||||
D_Event v;
|
||||
};
|
||||
|
||||
typedef struct D_EventList D_EventList;
|
||||
struct D_EventList
|
||||
{
|
||||
D_EventNode *first;
|
||||
D_EventNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Line Info Types
|
||||
|
||||
typedef struct D_Line D_Line;
|
||||
struct D_Line
|
||||
{
|
||||
String8 file_path;
|
||||
TxtPt pt;
|
||||
Rng1U64 voff_range;
|
||||
DI_Key dbgi_key;
|
||||
};
|
||||
|
||||
typedef struct D_LineNode D_LineNode;
|
||||
struct D_LineNode
|
||||
{
|
||||
D_LineNode *next;
|
||||
D_Line v;
|
||||
};
|
||||
|
||||
typedef struct D_LineList D_LineList;
|
||||
struct D_LineList
|
||||
{
|
||||
D_LineNode *first;
|
||||
D_LineNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct D_LineListArray D_LineListArray;
|
||||
struct D_LineListArray
|
||||
{
|
||||
D_LineList *v;
|
||||
U64 count;
|
||||
DI_KeyList dbgi_keys;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Engine Control Communication Types
|
||||
|
||||
typedef enum D_RunKind
|
||||
{
|
||||
D_RunKind_Run,
|
||||
D_RunKind_SingleStep,
|
||||
D_RunKind_Step,
|
||||
D_RunKind_COUNT
|
||||
}
|
||||
D_RunKind;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "dbg_engine/generated/dbg_engine.meta.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Command Types
|
||||
|
||||
typedef struct D_CmdParams D_CmdParams;
|
||||
struct D_CmdParams
|
||||
{
|
||||
CTRL_Handle machine;
|
||||
CTRL_Handle process;
|
||||
CTRL_Handle thread;
|
||||
CTRL_Handle entity;
|
||||
String8 string;
|
||||
String8 file_path;
|
||||
TxtPt cursor;
|
||||
U64 vaddr;
|
||||
B32 prefer_disasm;
|
||||
U32 pid;
|
||||
U32 rgba;
|
||||
D_TargetArray targets;
|
||||
U64 retry_idx;
|
||||
};
|
||||
|
||||
typedef struct D_Cmd D_Cmd;
|
||||
struct D_Cmd
|
||||
{
|
||||
D_CmdKind kind;
|
||||
D_CmdParams params;
|
||||
};
|
||||
|
||||
typedef struct D_CmdNode D_CmdNode;
|
||||
struct D_CmdNode
|
||||
{
|
||||
D_CmdNode *next;
|
||||
D_CmdNode *prev;
|
||||
D_Cmd cmd;
|
||||
};
|
||||
|
||||
typedef struct D_CmdList D_CmdList;
|
||||
struct D_CmdList
|
||||
{
|
||||
D_CmdNode *first;
|
||||
D_CmdNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main State Caches
|
||||
|
||||
//- rjf: per-run tls-base-vaddr cache
|
||||
|
||||
typedef struct D_RunTLSBaseCacheNode D_RunTLSBaseCacheNode;
|
||||
struct D_RunTLSBaseCacheNode
|
||||
{
|
||||
D_RunTLSBaseCacheNode *hash_next;
|
||||
CTRL_Handle process;
|
||||
U64 root_vaddr;
|
||||
U64 rip_vaddr;
|
||||
U64 tls_base_vaddr;
|
||||
};
|
||||
|
||||
typedef struct D_RunTLSBaseCacheSlot D_RunTLSBaseCacheSlot;
|
||||
struct D_RunTLSBaseCacheSlot
|
||||
{
|
||||
D_RunTLSBaseCacheNode *first;
|
||||
D_RunTLSBaseCacheNode *last;
|
||||
};
|
||||
|
||||
typedef struct D_RunTLSBaseCache D_RunTLSBaseCache;
|
||||
struct D_RunTLSBaseCache
|
||||
{
|
||||
Arena *arena;
|
||||
U64 slots_count;
|
||||
D_RunTLSBaseCacheSlot *slots;
|
||||
};
|
||||
|
||||
//- rjf: per-run locals cache
|
||||
|
||||
typedef struct D_RunLocalsCacheNode D_RunLocalsCacheNode;
|
||||
struct D_RunLocalsCacheNode
|
||||
{
|
||||
D_RunLocalsCacheNode *hash_next;
|
||||
DI_Key dbgi_key;
|
||||
U64 voff;
|
||||
E_String2NumMap *locals_map;
|
||||
};
|
||||
|
||||
typedef struct D_RunLocalsCacheSlot D_RunLocalsCacheSlot;
|
||||
struct D_RunLocalsCacheSlot
|
||||
{
|
||||
D_RunLocalsCacheNode *first;
|
||||
D_RunLocalsCacheNode *last;
|
||||
};
|
||||
|
||||
typedef struct D_RunLocalsCache D_RunLocalsCache;
|
||||
struct D_RunLocalsCache
|
||||
{
|
||||
Arena *arena;
|
||||
U64 table_size;
|
||||
D_RunLocalsCacheSlot *table;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main State Types
|
||||
|
||||
typedef struct D_State D_State;
|
||||
struct D_State
|
||||
{
|
||||
// rjf: top-level state
|
||||
Arena *arena;
|
||||
U64 frame_index;
|
||||
|
||||
// rjf: commands
|
||||
Arena *cmds_arena;
|
||||
D_CmdList cmds;
|
||||
|
||||
// rjf: output log key
|
||||
C_Key output_log_key;
|
||||
|
||||
// rjf: per-run caches
|
||||
U64 tls_base_cache_reggen_idx;
|
||||
U64 tls_base_cache_memgen_idx;
|
||||
D_RunTLSBaseCache tls_base_caches[2];
|
||||
U64 tls_base_cache_gen;
|
||||
U64 locals_cache_reggen_idx;
|
||||
D_RunLocalsCache locals_caches[2];
|
||||
U64 locals_cache_gen;
|
||||
U64 member_cache_reggen_idx;
|
||||
D_RunLocalsCache member_caches[2];
|
||||
U64 member_cache_gen;
|
||||
|
||||
// rjf: user -> ctrl driving state
|
||||
Arena *ctrl_last_run_arena;
|
||||
D_RunKind ctrl_last_run_kind;
|
||||
U64 ctrl_last_run_frame_idx;
|
||||
CTRL_Handle ctrl_last_run_thread_handle;
|
||||
CTRL_RunFlags ctrl_last_run_flags;
|
||||
CTRL_TrapList ctrl_last_run_traps;
|
||||
D_BreakpointArray ctrl_last_run_extra_bps;
|
||||
U128 ctrl_last_run_param_state_hash;
|
||||
B32 ctrl_is_running;
|
||||
B32 ctrl_thread_run_state;
|
||||
B32 ctrl_soft_halt_issued;
|
||||
Arena *ctrl_msg_arena;
|
||||
CTRL_MsgList ctrl_msgs;
|
||||
|
||||
// rjf: ctrl -> user reading state
|
||||
CTRL_EntityCtxRWStore *ctrl_entity_store;
|
||||
Arena *ctrl_stop_arena;
|
||||
CTRL_Event ctrl_last_stop_event;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global D_State *d_state = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 d_hash_from_seed_string(U64 seed, String8 string);
|
||||
internal U64 d_hash_from_string(String8 string);
|
||||
internal U64 d_hash_from_seed_string__case_insensitive(U64 seed, String8 string);
|
||||
internal U64 d_hash_from_string__case_insensitive(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Breakpoints
|
||||
|
||||
internal D_BreakpointArray d_breakpoint_array_copy(Arena *arena, D_BreakpointArray *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Path Map Application
|
||||
|
||||
internal String8List d_possible_path_overrides_from_maps_path(Arena *arena, D_PathMapArray *path_maps, String8 file_path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Extraction Type Pure Functions
|
||||
|
||||
internal D_LineList d_line_list_copy(Arena *arena, D_LineList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Command Type Functions
|
||||
|
||||
//- rjf: command parameters
|
||||
internal D_CmdParams d_cmd_params_copy(Arena *arena, D_CmdParams *src);
|
||||
|
||||
//- rjf: command lists
|
||||
internal void d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, D_CmdParams *params);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Stepping "Trap Net" Builders
|
||||
|
||||
internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread);
|
||||
internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread);
|
||||
internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
//- rjf: voff -> line info
|
||||
internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key dbgi_key, U64 voff);
|
||||
|
||||
//- rjf: file:line -> line info
|
||||
// TODO(rjf): this depends on file path maps, needs to move
|
||||
// TODO(rjf): need to clean this up & dedup
|
||||
internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range);
|
||||
internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range);
|
||||
internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num);
|
||||
internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process/Thread/Module Info Lookups
|
||||
|
||||
internal U64 d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Target Controls
|
||||
|
||||
//- rjf: stopped info from the control thread
|
||||
internal CTRL_Event d_ctrl_last_stop_event(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main State Accessors/Mutators
|
||||
|
||||
//- rjf: frame data
|
||||
internal U64 d_frame_index(void);
|
||||
|
||||
//- rjf: control state
|
||||
internal D_RunKind d_ctrl_last_run_kind(void);
|
||||
internal U64 d_ctrl_last_run_frame_idx(void);
|
||||
internal B32 d_ctrl_targets_running(void);
|
||||
|
||||
//- rjf: active entity based queries
|
||||
internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena);
|
||||
|
||||
//- rjf: per-run caches
|
||||
internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread);
|
||||
internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count);
|
||||
internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr);
|
||||
internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
|
||||
internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
|
||||
|
||||
//- rjf: top-level command dispatch
|
||||
internal void d_push_cmd(D_CmdKind kind, D_CmdParams *params);
|
||||
#define d_cmd(kind, ...) d_push_cmd((kind), &(D_CmdParams){.thread = {0}, __VA_ARGS__})
|
||||
|
||||
//- rjf: command iteration
|
||||
internal B32 d_next_cmd(D_Cmd **cmd);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Top-Level Calls
|
||||
|
||||
internal void d_init(void);
|
||||
internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]);
|
||||
|
||||
#endif // DBG_ENGINE_CORE_H
|
||||
@@ -1,4 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "dbg_engine_core.c"
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DBG_ENGINE_INC_H
|
||||
#define DBG_ENGINE_INC_H
|
||||
|
||||
#include "dbg_engine_core.h"
|
||||
|
||||
#endif // DBG_ENGINE_INC_H
|
||||
@@ -1,5 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user