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,30 +1,28 @@
|
||||
name: builds
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build-windows-2022:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: build (vs 2022)
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
call build raddbg msvc debug || exit /b 1
|
||||
call build rdi_from_pdb msvc debug || exit /b 1
|
||||
call build rdi_from_dwarf msvc debug || exit /b 1
|
||||
call build rdi_dump msvc debug || exit /b 1
|
||||
call build raddbg clang debug || exit /b 1
|
||||
call build rdi_from_pdb clang debug || exit /b 1
|
||||
call build rdi_from_dwarf clang debug || exit /b 1
|
||||
call build rdi_dump clang debug || exit /b 1
|
||||
name: builds
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build-windows-2022:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: build (vs 2022)
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
call build raddbg msvc debug || exit /b 1
|
||||
call build 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
|
||||
|
||||
+3
-3
@@ -1,3 +1,3 @@
|
||||
/build/
|
||||
/local/
|
||||
*~
|
||||
/build/
|
||||
/local/
|
||||
*~
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
Copyright (c) 2024 Epic Games Tools
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Copyright (c) 2024 Epic Games Tools
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -1,353 +1,325 @@
|
||||
# The RAD Debugger Project
|
||||
|
||||
_**Note:** This README does not document usage instructions and tips for the
|
||||
debugger itself, and is intended as a technical overview of the project. The
|
||||
debugger's README, which includes usage instructions and tips, can be found
|
||||
packaged along with debugger releases, or within the `build` folder after a
|
||||
local copy has been built._
|
||||
|
||||
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
||||
plans to expand and port in the future. In the future we'll expand to also
|
||||
support native Linux debugging and DWARF debug info.
|
||||
|
||||
The RAD Debugger is currently in *ALPHA*. In order to get the debugger bullet-
|
||||
proof, it'd greatly help out if you submitted the issues you find here, along
|
||||
with any information you can gather, like dump files (along with the build you
|
||||
used), instructions to reproduce, test executables, and so on.
|
||||
|
||||
You can download pre-built binaries for the debugger
|
||||
[here](https://github.com/EpicGamesExt/raddebugger/releases).
|
||||
|
||||
The RAD Debugger project aims to simplify the debugger by simplifying and
|
||||
unifying the underlying debug info format. In that pursuit we've built the RAD
|
||||
Debug Info (RDI) format, which is what the debugger parses and uses. To work
|
||||
with existing toolchains, we convert PDB (and eventually PE/ELF files with
|
||||
embedded DWARF) into the RDI format on-demand.
|
||||
|
||||
The RDI format is currently specified in code, in the files within the
|
||||
`src/lib_rdi_format` folder. The other relevant folders for working with the
|
||||
format are:
|
||||
|
||||
- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info.
|
||||
- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase
|
||||
layer, or built as an executable with a command line interface frontend.
|
||||
- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter.
|
||||
- `rdi_dump`: Our RDI textual dumping utility.
|
||||
|
||||
## Development Setup Instructions
|
||||
|
||||
**Note: Currently, only x64 Windows development is supported.**
|
||||
|
||||
### 1. Installing the Required Tools (MSVC & Windows SDK)
|
||||
|
||||
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
||||
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
||||
the Windows SDK and the MSVC compiler and linker.
|
||||
|
||||
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
||||
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
||||
|
||||
### 2. Build Environment Setup
|
||||
|
||||
Building the codebase can be done in a terminal which is equipped with the
|
||||
ability to call either MSVC or Clang from command line.
|
||||
|
||||
This is generally done by calling `vcvarsall.bat x64`, which is included in the
|
||||
Microsoft C/C++ Build Tools. This script is automatically called by the `x64
|
||||
Native Tools Command Prompt for VS <year>` variant of the vanilla `cmd.exe`. If
|
||||
you've installed the build tools, this command prompt may be easily located by
|
||||
searching for `Native` from the Windows Start Menu search.
|
||||
|
||||
You can ensure that the MSVC compiler is accessible from your command line by
|
||||
running:
|
||||
|
||||
```
|
||||
cl
|
||||
```
|
||||
|
||||
If everything is set up correctly, you should have output very similar to the
|
||||
following:
|
||||
|
||||
```
|
||||
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
|
||||
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
|
||||
usage: cl [ option... ] filename... [ /link linkoption... ]
|
||||
```
|
||||
|
||||
### 3. Building
|
||||
|
||||
Within this terminal, `cd` to the root directory of the codebase, and just run
|
||||
the `build.bat` script:
|
||||
|
||||
```
|
||||
build
|
||||
```
|
||||
|
||||
You should see the following output:
|
||||
|
||||
```
|
||||
[debug mode]
|
||||
[msvc compile]
|
||||
metagen_main.c
|
||||
searching C:\devel\raddebugger/src... 309 files found
|
||||
parsing metadesk... 15 metadesk files parsed
|
||||
gathering tables... 96 tables found
|
||||
generating layer code...
|
||||
raddbg_main.c
|
||||
```
|
||||
|
||||
If everything worked correctly, there will be a `build` folder in the root
|
||||
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
||||
|
||||
## Short-To-Medium-Term Roadmap
|
||||
|
||||
### The Initial Alpha Battle-Testing Phase
|
||||
|
||||
The first priority for the project is to ensure that the most crucial debugger
|
||||
components are functioning extremely reliably for local, x64, Windows
|
||||
debugging. This would include parts like debug info conversion, debug info
|
||||
loading, process control, stepping, evaluation (correct usage of both location
|
||||
info and type info), and a robust frontend which ensures the lower level parts
|
||||
are usable.
|
||||
|
||||
We feel that the debugger has already come a long way in all of these respects,
|
||||
but given the massive set of possible combinations of languages, build
|
||||
settings, toolchains, used language features, and patterns of generated code,
|
||||
there are still cases where the debugger has not been tested, and so there are
|
||||
still issues. So, we feel that the top priority is eliminating these issues,
|
||||
such that the debugging experience is rock solid.
|
||||
|
||||
### Local x64 Linux Debugging Phase
|
||||
|
||||
The next priority for the project is to take the rock solid x64 Windows
|
||||
debugging experience, and port all of the relevant pieces to support local x64
|
||||
Linux debugging also.
|
||||
|
||||
The debugger has been written to abstract over the parts that need to differ on
|
||||
either Linux or Windows, and this is mainly going to be a task in building out
|
||||
different backends for those abstraction layers.
|
||||
|
||||
The major parts of this phase are:
|
||||
|
||||
- Porting the `src/demon` layer to implement the Demon local process control
|
||||
abstraction API.
|
||||
- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer.
|
||||
- Creating a DWARF-to-RDI converter (in the same way that we've built a
|
||||
PDB-to-RDI converter). A partial implementation of this is in
|
||||
`src/rdi_from_dwarf`.
|
||||
- Porting the `src/render` layer to implement all of the rendering features the
|
||||
frontend needs on a Linux-compatible API (the backend used on Windows is D3D11).
|
||||
- Porting the `src/font_provider` layer to a Linux-compatible font
|
||||
rasterization backend, like FreeType (the backend used on Windows is
|
||||
DirectWrite).
|
||||
- Porting the `src/os` layers to Linux. This includes core operating system
|
||||
abstraction (virtual memory allocation, threading and synchronization
|
||||
primitives, and so on), and graphical operating system abstraction (windows,
|
||||
input events, and so on).
|
||||
|
||||
Once the above list is complete, and once every part is rock solid, the Windows
|
||||
debugging experience we'll have worked diligently to create will also be
|
||||
available natively on Linux machines.
|
||||
|
||||
### And Beyond!
|
||||
|
||||
There are several directions we might take after these two major phases,
|
||||
like remote debugging, porting to different architectures, further improving
|
||||
the debugger's features (like improving the visualization engine), and so on.
|
||||
But for now, we're mostly focused on those first two phases.
|
||||
|
||||
## Top-Level Directory Descriptions
|
||||
|
||||
- `data`: Small binary files which are used when building, either to embed
|
||||
within build artifacts, or to package with them.
|
||||
- `src`: All source code.
|
||||
|
||||
After setting up the codebase and building, the following directories will
|
||||
also exist:
|
||||
|
||||
- `build`: All build artifacts. Not checked in to version control.
|
||||
- `local`: Local files, used for local build configuration input files. Not
|
||||
checked in to version control.
|
||||
|
||||
## Codebase Introduction
|
||||
|
||||
The codebase is organized into *layers*. Layers are separated either to isolate
|
||||
certain problems, and to allow inclusion into various builds without needing to
|
||||
pull everything in the codebase into a build. Layers correspond with folders
|
||||
inside of the `src` directory. Sometimes, one folder inside of the `src`
|
||||
directory will include multiple sub-layers, but the structure is intended to be
|
||||
fairly flat.
|
||||
|
||||
Layers correspond roughly 1-to-1 with *namespaces*. The term "namespaces" in
|
||||
this context does not refer to specific namespace language features, but rather
|
||||
a naming convention for C-style namespaces, which are written in the codebase as
|
||||
a short prefix, usually 1-3 characters, followed by an underscore. These
|
||||
namespaces are used such that the layer to which certain code belongs may be
|
||||
quickly understood by glancing at code. The namespaces are generally quite short
|
||||
to ensure that they aren't much of a hassle to write. Sometimes, multiple sub-
|
||||
layers will share a namespace. A few layers do not have a namespace, but most
|
||||
do. Namespaces are either all-caps or lowercase depending on the context in
|
||||
which they're used. For types, enum values, and some macros, they are
|
||||
capitalized. For functions and global variables, they are lowercase.
|
||||
|
||||
Layers depend on other layers, but circular dependencies would break the
|
||||
separability and isolation utility of layers (in effect, forming one big layer),
|
||||
so in other words, layers are arranged into a directed acyclic graph.
|
||||
|
||||
A few layers are built to be used completely independently from the rest of the
|
||||
codebase, as libraries in other codebases and projects. As such, these layers do
|
||||
not depend on any other layers in the codebase. The folders which contain these
|
||||
layers are prefixed with `lib_`, like `lib_rdi_format`.
|
||||
|
||||
A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||
on no other codebase layers.
|
||||
- `codeview` (`CV_`): Code for parsing and/or writing the CodeView format.
|
||||
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||
Format) file format.
|
||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||
asynchronous process control, stepping, and breakpoints for all attached
|
||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||
processes are halted. When attached processes are running, it is halted.
|
||||
Driven by a debugger frontend on another thread.
|
||||
- `dasm_cache` (`DASM_`): An asynchronous disassembly decoder and cache. Users
|
||||
ask for disassembly for some data, with a particular architecture, and other
|
||||
various parameters, and threads implemented in this layer decode and cache the
|
||||
disassembly for that data with those parameters.
|
||||
- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info
|
||||
stored in the RDI format. Users ask for debug info for a particular path, and
|
||||
on separate threads, this layer loads the associated debug info file. If
|
||||
necessary, it will launch a separate conversion process to convert original
|
||||
debug info into the RDI format.
|
||||
- `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 caching layers,
|
||||
and so on.
|
||||
- `demon` (`DMN_`): 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`.
|
||||
- `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.
|
||||
- `eval` (`E_`): Implements 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 the `Watch` view.
|
||||
- `file_stream` (`FS_`): Provides asynchronous file loading, storing the
|
||||
artifacts inside of the cache implemented by the `hash_store` layer, and
|
||||
hot-reloading the contents of files when they change. Allows callers to map
|
||||
file paths to data hashes, which can then be used to obtain the file's data.
|
||||
- `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in
|
||||
CPU-side data for text shaping, and in GPU texture atlases for rasterized
|
||||
glyphs. All cache information is sourced from the `font_provider` abstraction
|
||||
layer.
|
||||
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
||||
and font rasterization backends.
|
||||
- `fuzzy_search` (`FZY_`): Provides a fuzzy searching engine for doing
|
||||
large, asynchronous fuzzy searches. Used by the debugger for implementing
|
||||
things like the symbol lister or the `Procedures` view, which search across
|
||||
all loaded debug info records, using fuzzy matching rules.
|
||||
- `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 visualization.
|
||||
- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a
|
||||
128-bit hash of the data. Also implements a 128-bit key cache on top, where
|
||||
the keys refer to a unique identity, associated with a 128-bit hash, where the
|
||||
hash may change across time. Used as a general data store by other layers.
|
||||
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
|
||||
programs to work with various features in the debugger. Does not depend on
|
||||
`base`, and can be independently relocated to other codebases.
|
||||
- `lib_rdi_format` (`RDI_`): Standalone library which defines the core RDI types
|
||||
and helper functions for reading and writing the RDI debug info file format.
|
||||
Does not depend on `base`, and can be independently relocated to other
|
||||
codebases.
|
||||
- `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.
|
||||
- `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, view rules, and metacode,
|
||||
which is parsed and used to generate code with the `metagen` layer.
|
||||
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
||||
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
||||
generates C code which is then included by hand-written C code. Currently, it
|
||||
does not analyze the codebase's hand-written C code, but in principle this is
|
||||
possible. This allows easier & less-error-prone management of large data
|
||||
tables, which are then used to produce e.g. C `enum`s and a number of
|
||||
associated data tables. There are also a number of other generation features,
|
||||
like embedding binary files or complex multi-line strings into source code.
|
||||
This layer cannot depend on any other layer in the codebase directly,
|
||||
including `base`, because it may be used to generate code for those layers. To
|
||||
still use `base` and `os` layer features in the `metagen` program, a separate,
|
||||
duplicate version of `base` and `os` are included in this layer. They are
|
||||
updated manually, as needed. This is to ensure the stability of the
|
||||
metaprogram.
|
||||
- `msf` (`MSF_`): Code for parsing and/or writing the MSF file format.
|
||||
- `mule` (no namespace): Test executables for battle testing debugger
|
||||
functionality.
|
||||
- `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` view.
|
||||
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
||||
types in other debuggers.
|
||||
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
||||
functionality from the operating system under an abstract API, which is
|
||||
implemented per-target-operating-system.
|
||||
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||
graphical operating system features under an abstract API, which is
|
||||
implemented per-target-operating-system.
|
||||
- `path` (`PATH_`): Small helpers for manipulating file path strings.
|
||||
- `pdb` (`PDB_`): Code for parsing and/or writing the PDB file format.
|
||||
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
|
||||
file format.
|
||||
- `raddbg` (`RD_`): The layer which ties everything together for the main
|
||||
graphical debugger. 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_breakpad_from_pdb` (`P2B_`): Our implementation, using the codebase's RDI
|
||||
technology, for extracting information from PDBs and generating Breakpad text
|
||||
dumps.
|
||||
- `rdi_dump` (no namespace): A dumper utility program for dumping
|
||||
textualizations of RDI debug info files.
|
||||
- `rdi_format` (no namespace): A layer which includes the `lib_rdi_format` 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_dwarf` (`D2R_`): Our in-progress implementation of DWARF-to-RDI
|
||||
conversion.
|
||||
- `rdi_from_pdb` (`P2R_`): Our implementation of PDB-to-RDI conversion.
|
||||
- `rdi_make` (no namespace): A layer which includes the `lib_rdi_make` layer and
|
||||
bundles it with codebase-specific helpers, to easily include the library in
|
||||
codebase programs, and have it be integrated with codebase constructs.
|
||||
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
||||
supported architectures. Used in reading/writing registers in `demon`, or in
|
||||
looking up register metadata.
|
||||
- `render` (`R_`): An abstraction layer providing an abstract API for rendering
|
||||
using various GPU APIs under a common interface. Does not implement a high
|
||||
level drawing API - this layer is strictly for minimally abstracting on an
|
||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||
layer.
|
||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
||||
- `task_system` (`TS_`): Implements a system for kicking off asynchronous tasks
|
||||
and obtaining artifacts from those tasks once they've completed.
|
||||
- `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 visualization.
|
||||
- `text_cache` (`TXT_`): Implements an asynchronously-filled cache for textual
|
||||
analysis data (tokens, line ranges, and so on), filled by data sourced in the
|
||||
`hash_store` layer's cache. Used for asynchronously preparing data for
|
||||
visualization (like for the source code viewer).
|
||||
- `third_party` (no namespace): External code from other projects, which some
|
||||
layers in the codebase depend on. All external code is included and built
|
||||
directly within the codebase.
|
||||
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
||||
core immediate mode hierarchical user interface data structure building
|
||||
API, and has helper layers for building some higher-level widgets.
|
||||
# The RAD Debugger Project
|
||||
|
||||
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
||||
plans to expand and port in the future. In the future we'll expand to also
|
||||
support native Linux debugging and DWARF debug info.
|
||||
|
||||
The RAD Debugger is currently in *ALPHA*. In order to get the debugger bullet-
|
||||
proof, it'd greatly help out if you submitted the issues you find here, along
|
||||
with any information you can gather, like dump files (along with the build you
|
||||
used), instructions to reproduce, test executables, and so on.
|
||||
|
||||
You can download pre-built binaries for the debugger
|
||||
[here](https://github.com/EpicGames/raddebugger/releases).
|
||||
|
||||
The RAD Debugger project aims to simplify the debugger by simplifying and
|
||||
unifying the underlying debug info format. In that pursuit we've built
|
||||
the 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 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:
|
||||
|
||||
- `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.
|
||||
|
||||
## Development Setup Instructions
|
||||
|
||||
**Note: Currently, only x64 Windows development is supported.**
|
||||
|
||||
### 1. Installing the Required Tools (MSVC & Windows SDK)
|
||||
|
||||
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
||||
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
||||
the Windows SDK and the MSVC compiler and linker.
|
||||
|
||||
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
||||
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
||||
|
||||
### 2. Build Environment Setup
|
||||
|
||||
Building the codebase can be done in a terminal which is equipped with the
|
||||
ability to call either MSVC or Clang from command line.
|
||||
|
||||
This is generally done by calling `vcvarsall.bat x64`, which is included in the
|
||||
Microsoft C/C++ Build Tools. This script is automatically called by the `x64
|
||||
Native Tools Command Prompt for VS <year>` variant of the vanilla `cmd.exe`. If
|
||||
you've installed the build tools, this command prompt may be easily located by
|
||||
searching for `Native` from the Windows Start Menu search.
|
||||
|
||||
You can ensure that the MSVC compiler is accessible from your command line by
|
||||
running:
|
||||
|
||||
```
|
||||
cl
|
||||
```
|
||||
|
||||
If everything is set up correctly, you should have output very similar to the
|
||||
following:
|
||||
|
||||
```
|
||||
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
|
||||
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
|
||||
usage: cl [ option... ] filename... [ /link linkoption... ]
|
||||
```
|
||||
|
||||
### 3. Building
|
||||
|
||||
Within this terminal, `cd` to the root directory of the codebase, and just run
|
||||
the `build.bat` script:
|
||||
|
||||
```
|
||||
build
|
||||
```
|
||||
|
||||
You should see the following output:
|
||||
|
||||
```
|
||||
[debug mode]
|
||||
[msvc compile]
|
||||
[default mode, assuming `raddbg` build]
|
||||
metagen_main.c
|
||||
searching C:\devel\raddebugger/src... 299 files found
|
||||
parsing metadesk... 12 metadesk files parsed
|
||||
gathering tables... 37 tables found
|
||||
generating layer code...
|
||||
raddbg.cpp
|
||||
```
|
||||
|
||||
If everything worked correctly, there will be a `build` folder in the root
|
||||
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
||||
|
||||
## Short-To-Medium-Term Roadmap
|
||||
|
||||
### The Initial Alpha Battle-Testing Phase
|
||||
|
||||
The first priority for the project is to ensure that the most crucial debugger
|
||||
components are functioning extremely reliably for local, x64, Windows
|
||||
debugging. This would include parts like debug info conversion, debug info
|
||||
loading, process control, stepping, evaluation (correct usage of both location
|
||||
info and type info), and a robust frontend which ensures the lower level parts
|
||||
are usable.
|
||||
|
||||
We feel that the debugger has already come a long way in all of these respects,
|
||||
but given the massive set of possible combinations of languages, build
|
||||
settings, toolchains, used language features, and patterns of generated code,
|
||||
there are still cases where the debugger has not been tested, and so there are
|
||||
still issues. So, we feel that the top priority is eliminating these issues,
|
||||
such that the debugging experience is rock solid.
|
||||
|
||||
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
|
||||
|
||||
The next priority for the project is to take the rock solid x64 Windows
|
||||
debugging experience, and port all of the relevant pieces to support local x64
|
||||
Linux debugging also.
|
||||
|
||||
The debugger has been written to abstract over the parts that need to differ on
|
||||
either Linux or Windows, and this is mainly going to be a task in building out
|
||||
different backends for those abstraction layers.
|
||||
|
||||
The major parts of this phase are:
|
||||
|
||||
- Porting the `src/demon` layer to implement the Demon local process control
|
||||
abstraction API.
|
||||
- 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
|
||||
rasterization backend, like FreeType (the backend used on Windows is
|
||||
DirectWrite).
|
||||
- Porting the `src/os` layers to Linux. This includes core operating system
|
||||
abstraction (virtual memory allocation, threading and synchronization
|
||||
primitives, and so on), and graphical operating system abstraction (windows,
|
||||
input events, and so on).
|
||||
|
||||
Once the above list is complete, and once every part is rock solid, the Windows
|
||||
debugging experience we'll have worked diligently to create will also be
|
||||
available natively on Linux machines.
|
||||
|
||||
### And Beyond!
|
||||
|
||||
There are several directions we might take after these two major phases,
|
||||
like remote debugging, porting to different architectures, further improving
|
||||
the debugger's features (like improving the visualization engine), and so on.
|
||||
But for now, we're mostly focused on those first two phases.
|
||||
|
||||
## Top-Level Directory Descriptions
|
||||
|
||||
- `data`: Small binary files which are used when building, either to embed
|
||||
within build artifacts, or to package with them.
|
||||
- `src`: All source code.
|
||||
|
||||
After setting up the codebase and building, the following directories will
|
||||
also exist:
|
||||
|
||||
- `build`: All build artifacts. Not checked in to version control.
|
||||
- `local`: Local files, used for local build configuration input files.
|
||||
|
||||
## Codebase Introduction
|
||||
|
||||
The codebase is organized into *layers*. Layers are separated either to isolate
|
||||
certain problems, and to allow inclusion into various builds without needing to
|
||||
pull everything in the codebase into a build. Layers correspond with folders
|
||||
inside of the `src` directory. Sometimes, one folder inside of the `src`
|
||||
directory will include multiple sub-layers, but the structure is intended to be
|
||||
fairly flat.
|
||||
|
||||
Layers correspond roughly 1-to-1 with *namespaces*. The term "namespaces" in
|
||||
this context does not refer to specific namespace language features, but rather
|
||||
a naming convention for C-style namespaces, which are written in the codebase as
|
||||
a short prefix, usually 1-3 characters, followed by an underscore. These
|
||||
namespaces are used such that the layer to which certain code belongs may be
|
||||
quickly understood by glancing at code. The namespaces are generally quite short
|
||||
to ensure that they aren't much of a hassle to write. Sometimes, multiple sub-
|
||||
layers will share a namespace. A few layers do not have a namespace, but most
|
||||
do. Namespaces are either all-caps or lowercase depending on the context in
|
||||
which they're used. For types, enum values, and some macros, they are
|
||||
capitalized. For functions and global variables, they are lowercase.
|
||||
|
||||
Layers depend on other layers, but circular dependencies would break the
|
||||
separability and isolation utility of layers (in effect, forming one big layer),
|
||||
so in other words, layers are arranged into a directed acyclic graph.
|
||||
|
||||
A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||
on no other codebase layers.
|
||||
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||
Format) file format.
|
||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||
asynchronous process control, stepping, and breakpoints for all attached
|
||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||
processes are halted. When attached processes are running, it is halted.
|
||||
Driven by a debugger frontend on another thread.
|
||||
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
|
||||
disassembly for a particular virtual address range in a process, and threads
|
||||
implemented in this layer decode and cache the disassembly for that range.
|
||||
- `dbgi` (`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`.
|
||||
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
|
||||
debugger "entity cache" (where "entities" include processes, threads, modules,
|
||||
breakpoints, source files, targets, and so on). Implements a command loop
|
||||
for driving process control, which is used to implement stepping commands and
|
||||
user breakpoints. Implements extractors and caches for various entity-related
|
||||
data, like full thread unwinds and local variable maps. Also implements core
|
||||
building blocks for evaluation and evaluation visualization.
|
||||
- `df/gfx` (`DF_`): The debugger's graphical frontend. Builds on top of
|
||||
`df/core` to provide all graphical features, including windows, panels, all
|
||||
of the various debugger interfaces, and evaluation visualization.
|
||||
- `draw` (`D_`): Implements a high-level graphics drawing API for the debugger's
|
||||
purposes, using the underlying `render` abstraction layer. Provides high-level
|
||||
APIs for various draw commands, but takes care of batching them, and so on.
|
||||
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
|
||||
evaluation of variables, registers, and so on from debugger-attached processes
|
||||
and/or debug info. Broken into several phases mostly corresponding to
|
||||
traditional compiler phases - lexer, parser, type-checker, IR generation, and
|
||||
IR evaluation.
|
||||
- `font_cache` (`F_`): Implements a cache of rasterized font data, both in CPU-
|
||||
side data for text shaping, and in GPU texture atlases for rasterized glyphs.
|
||||
All cache information is sourced from the `font_provider` abstraction layer.
|
||||
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
||||
and font rasterization backends.
|
||||
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for memory visualization in the debugger.
|
||||
- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a
|
||||
128-bit hash of the data. Used as a general data store by other layers.
|
||||
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
||||
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
||||
generates C code which is then included by hand-written C code. Currently, it
|
||||
does not analyze the codebase's hand-written C code, but in principle this is
|
||||
possible. This allows easier & less-error-prone management of large data
|
||||
tables, which are then used to produce e.g. C `enum`s and a number of
|
||||
associated data tables. There are also a number of other generation features,
|
||||
like embedding binary files or complex multi-line strings into source code.
|
||||
This layer cannot depend on any other layer in the codebase directly,
|
||||
including `base`, because it may be used to generate code for those layers. To
|
||||
still use `base` and `os` layer features in the `metagen` program, a separate,
|
||||
duplicate version of `base` and `os` are included in this layer. They are
|
||||
updated manually, as needed. This is to ensure the stability of the
|
||||
metaprogram.
|
||||
- `mule` (no namespace): Test executables for battle testing debugger
|
||||
functionality.
|
||||
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
||||
types in other debuggers.
|
||||
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
||||
functionality from the operating system under an abstract API, which is
|
||||
implemented per-target-operating-system.
|
||||
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||
graphical operating system features under an abstract API, which is
|
||||
implemented per-target-operating-system.
|
||||
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||
networking operating system features under an abstract API, which is
|
||||
implemented per-target-operating-system.
|
||||
- `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.
|
||||
- `render` (`R_`): An abstraction layer providing an abstract API for rendering
|
||||
using various GPU APIs under a common interface. Does not implement a high
|
||||
level drawing API - this layer is strictly for minimally abstracting on an
|
||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||
layer.
|
||||
- `scratch` (no namespace): Scratch space for small and transient test or sample
|
||||
programs.
|
||||
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for memory visualization in the debugger.
|
||||
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
|
||||
reloaded, asynchronously parsed, and asynchronously mutated source code files.
|
||||
Used by the debugger to visualize source code files. Users ask for text lines,
|
||||
tokens, and metadata, and it is prepared on background threads.
|
||||
- `type_graph` (`TG_`): Code for analyzing and navigating type structures from
|
||||
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,135 +1,120 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /D "%~dp0"
|
||||
|
||||
:: --- 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.
|
||||
::
|
||||
:: 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`
|
||||
::
|
||||
:: For a full list of possible build targets and their build command lines,
|
||||
:: search for @build_targets in this file.
|
||||
::
|
||||
:: Below is a list of all possible non-target command line options:
|
||||
::
|
||||
:: - `asan`: enable address sanitizer
|
||||
:: - `telemetry`: enable RAD telemetry profiling support
|
||||
|
||||
:: --- Unpack Arguments -------------------------------------------------------
|
||||
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]
|
||||
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 "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||
|
||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
||||
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 -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000
|
||||
set 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 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 cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" /pdbaltpath:%%%%_PDB%%%% logo.res
|
||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res -Xlinker /pdbaltpath:%%%%_PDB%%%%
|
||||
set cl_out= /out:
|
||||
set clang_out= -o
|
||||
|
||||
:: --- Per-Build Settings -----------------------------------------------------
|
||||
set link_dll=-DLL
|
||||
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
|
||||
|
||||
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||
if "%msvc%"=="1" set compile_release=%cl_release%
|
||||
if "%msvc%"=="1" set compile_link=%cl_link%
|
||||
if "%msvc%"=="1" set out=%cl_out%
|
||||
if "%clang%"=="1" set compile_debug=%clang_debug%
|
||||
if "%clang%"=="1" set compile_release=%clang_release%
|
||||
if "%clang%"=="1" set compile_link=%clang_link%
|
||||
if "%clang%"=="1" set out=%clang_out%
|
||||
if "%debug%"=="1" set compile=%compile_debug%
|
||||
if "%release%"=="1" set compile=%compile_release%
|
||||
|
||||
:: --- Prep Directories -------------------------------------------------------
|
||||
if not exist build mkdir build
|
||||
if not exist local mkdir local
|
||||
|
||||
:: --- Produce Logo Icon File -------------------------------------------------
|
||||
pushd build
|
||||
%rc% /nologo /fo logo.res ..\data\logo.rc || exit /b 1
|
||||
popd
|
||||
|
||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
||||
|
||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||
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
|
||||
popd
|
||||
)
|
||||
|
||||
:: --- Build Everything (@build_targets) --------------------------------------
|
||||
pushd build
|
||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %out%raddbg.exe || exit /b 1
|
||||
if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1
|
||||
if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
|
||||
if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1
|
||||
if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.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 "%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 "%mule_peb_trample%"=="1" (
|
||||
set didbuild=1
|
||||
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
|
||||
if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb
|
||||
if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi
|
||||
%compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1
|
||||
move mule_peb_trample_new.exe mule_peb_trample.exe
|
||||
)
|
||||
popd
|
||||
|
||||
:: --- Unset ------------------------------------------------------------------
|
||||
for %%a in (%*) do set "%%a=0"
|
||||
set raddbg=
|
||||
set compile=
|
||||
set compile_link=
|
||||
set out=
|
||||
set msvc=
|
||||
set debug=
|
||||
set release=
|
||||
|
||||
:: --- 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
|
||||
)
|
||||
@echo off
|
||||
setlocal
|
||||
cd /D "%~dp0"
|
||||
|
||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||
::
|
||||
:: 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 raddbg_from_pdb`
|
||||
::
|
||||
:: For a full list of possible build targets and their build command lines,
|
||||
:: search for @build_targets in this file.
|
||||
::
|
||||
:: Below is a list of all possible non-target command line options:
|
||||
::
|
||||
:: - `asan`: enable address sanitizer
|
||||
:: - `telemetry`: enable RAD telemetry profiling support
|
||||
|
||||
:: --- Unpack Arguments -------------------------------------------------------
|
||||
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]
|
||||
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
|
||||
|
||||
:: --- 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 "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||
|
||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
||||
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 clang_out= -o
|
||||
|
||||
:: --- Per-Build Settings -----------------------------------------------------
|
||||
set gfx=-DOS_FEATURE_GRAPHICAL=1
|
||||
set net=-DOS_FEATURE_SOCKET=1
|
||||
set link_dll=-DLL
|
||||
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 rc=rc.exe
|
||||
if "%clang%"=="1" set rc=llvm-rc.exe
|
||||
|
||||
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||
if "%msvc%"=="1" set compile_release=%cl_release%
|
||||
if "%msvc%"=="1" set compile_link=%cl_link%
|
||||
if "%msvc%"=="1" set out=%cl_out%
|
||||
if "%clang%"=="1" set compile_debug=%clang_debug%
|
||||
if "%clang%"=="1" set compile_release=%clang_release%
|
||||
if "%clang%"=="1" set compile_link=%clang_link%
|
||||
if "%clang%"=="1" set out=%clang_out%
|
||||
if "%debug%"=="1" set compile=%compile_debug%
|
||||
if "%release%"=="1" set compile=%compile_release%
|
||||
|
||||
:: --- Prep Directories -------------------------------------------------------
|
||||
if not exist build mkdir build
|
||||
if not exist local mkdir local
|
||||
|
||||
:: --- Produce Logo Icon File -------------------------------------------------
|
||||
pushd build
|
||||
%rc% /nologo /fo logo.res ..\data\logo.rc || exit /b 1
|
||||
popd
|
||||
|
||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DRADDBG_GIT=\"%%i\"
|
||||
|
||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||
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
|
||||
popd
|
||||
)
|
||||
|
||||
:: --- Build Everything (@build_targets) --------------------------------------
|
||||
pushd build
|
||||
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
|
||||
|
||||
:: --- Unset ------------------------------------------------------------------
|
||||
for %%a in (%*) do set "%%a=0"
|
||||
set raddbg=
|
||||
set compile=
|
||||
set compile_link=
|
||||
set out=
|
||||
set msvc=
|
||||
set debug=
|
||||
|
||||
@@ -1,74 +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=''
|
||||
|
||||
# --- Compile/Link Line Definitions -------------------------------------------
|
||||
clang_common='-I../src/ -I../local/ -g -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 -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"
|
||||
|
||||
# --- 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 $out raddbg; 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 $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
|
||||
+145
-96
@@ -1,96 +1,145 @@
|
||||
version(2);
|
||||
project_name = "The RAD Debugger";
|
||||
|
||||
indent_width = "2";
|
||||
default_tab_width = "2";
|
||||
|
||||
patterns =
|
||||
{
|
||||
"*.c",
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"*.inc",
|
||||
"*.hpp",
|
||||
"*.bat",
|
||||
"*.sh",
|
||||
"*.4coder",
|
||||
"*.glsl",
|
||||
"*.bfs",
|
||||
"*.html",
|
||||
"*.txt",
|
||||
"*.md",
|
||||
"*.mdesk",
|
||||
"*.asm",
|
||||
};
|
||||
|
||||
blacklist_patterns =
|
||||
{
|
||||
".*",
|
||||
"metagen_base_*",
|
||||
"metagen_os_*",
|
||||
};
|
||||
|
||||
paths =
|
||||
{
|
||||
{ .path = ".", .recursive = false, .relative = true, },
|
||||
{ .path = "src", .recursive = true , .relative = true, },
|
||||
{ .path = "local", .recursive = true , .relative = true, },
|
||||
};
|
||||
|
||||
load_paths =
|
||||
{
|
||||
.win = paths,
|
||||
.linux = paths,
|
||||
};
|
||||
|
||||
commands =
|
||||
{
|
||||
//- rjf: fkey command slots (change locally but do not commit)
|
||||
.f1 = { .win = "build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f2 = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f3 = { .win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --project:local_dev.raddbg_project --xuto_run && popd",.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, },
|
||||
};
|
||||
|
||||
fkey_command =
|
||||
{
|
||||
.F1 = "f1",
|
||||
.F2 = "f2",
|
||||
.F3 = "f3",
|
||||
};
|
||||
|
||||
fkey_command_override =
|
||||
{
|
||||
.rjf =
|
||||
{
|
||||
.F1 = "f1",
|
||||
.F2 = "f2",
|
||||
.F3 = "f3",
|
||||
},
|
||||
};
|
||||
version(2);
|
||||
project_name = "The RAD Debugger";
|
||||
|
||||
indent_width = "2";
|
||||
default_tab_width = "2";
|
||||
|
||||
patterns =
|
||||
{
|
||||
"*.c",
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"*.inc",
|
||||
"*.hpp",
|
||||
"*.bat",
|
||||
"*.sh",
|
||||
"*.4coder",
|
||||
"*.glsl",
|
||||
"*.bfs",
|
||||
"*.html",
|
||||
"*.txt",
|
||||
"*.md",
|
||||
"*.mdesk",
|
||||
"*.asm",
|
||||
};
|
||||
|
||||
blacklist_patterns =
|
||||
{
|
||||
".*",
|
||||
"metagen_base_*",
|
||||
"metagen_os_*",
|
||||
};
|
||||
|
||||
paths =
|
||||
{
|
||||
{ .path = ".", .recursive = false, .relative = true, },
|
||||
{ .path = "src", .recursive = true , .relative = true, },
|
||||
{ .path = "local", .recursive = true , .relative = true, },
|
||||
};
|
||||
|
||||
load_paths =
|
||||
{
|
||||
.win = paths,
|
||||
.linux = paths,
|
||||
};
|
||||
|
||||
commands =
|
||||
{
|
||||
.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 = "build_raddbg",
|
||||
.F3 = "run_raddbg",
|
||||
};
|
||||
|
||||
fkey_command_override =
|
||||
{
|
||||
.rjf =
|
||||
{
|
||||
.F1 = "rjf_f1",
|
||||
.F2 = "rjf_f2",
|
||||
.F3 = "rjf_f3",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Clear-Host
|
||||
|
||||
$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
|
||||
}
|
||||
|
||||
Push-Location $path_root
|
||||
|
||||
$build_bat = Join-Path $path_root 'build.bat'
|
||||
& $build_bat @args
|
||||
|
||||
Pop-Location
|
||||
@@ -0,0 +1,10 @@
|
||||
Clear-Host
|
||||
$path_root = git rev-parse --show-toplevel
|
||||
$build_dir = Join-Path $path_root 'build'
|
||||
|
||||
if (Test-Path $build_dir) {
|
||||
Get-ChildItem -Path $build_dir -Recurse | Remove-Item -Force -Recurse
|
||||
Write-Host "Build directory cleaned."
|
||||
} else {
|
||||
Write-Host "Build directory does not exist."
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
if ($env:VCINSTALLDIR) {
|
||||
return
|
||||
}
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Use vswhere to find the latest Visual Studio installation
|
||||
$vswhere_out = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath
|
||||
if ($null -eq $vswhere_out) {
|
||||
Write-Host "ERROR: Visual Studio installation not found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find Launch-VsDevShell.ps1 in the Visual Studio installation
|
||||
$vs_path = $vswhere_out
|
||||
$vs_devshell = Join-Path $vs_path "\Common7\Tools\Launch-VsDevShell.ps1"
|
||||
|
||||
if ( -not (Test-Path $vs_devshell) ) {
|
||||
Write-Host "ERROR: Launch-VsDevShell.ps1 not found in Visual Studio installation"
|
||||
Write-Host Tested path: $vs_devshell
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Launch the Visual Studio Developer Shell
|
||||
Push-Location
|
||||
write-host @args
|
||||
& $vs_devshell @args
|
||||
Pop-Location
|
||||
+315
-204
@@ -1,204 +1,315 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arena Functions
|
||||
|
||||
//- rjf: arena creation/destruction
|
||||
|
||||
internal Arena *
|
||||
arena_alloc_(ArenaParams *params)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
// rjf: reserve/commit initial block
|
||||
void *base = params->optional_backing_buffer;
|
||||
if(base == 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
// rjf: extract arena header & fill
|
||||
Arena *arena = (Arena *)base;
|
||||
arena->current = arena;
|
||||
arena->flags = params->flags;
|
||||
arena->cmt_size = (U32)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;
|
||||
AsanPoisonMemoryRegion(base, commit_size);
|
||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: arena push/pop core functions
|
||||
|
||||
internal void *
|
||||
arena_push(Arena *arena, U64 size, U64 align)
|
||||
{
|
||||
Arena *current = arena->current;
|
||||
U64 pos_pre = AlignPow2(current->pos, align);
|
||||
U64 pos_pst = pos_pre + size;
|
||||
|
||||
// rjf: chain, if needed
|
||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
||||
{
|
||||
U64 res_size = current->res_size;
|
||||
U64 cmt_size = current->cmt_size;
|
||||
if(size + ARENA_HEADER_SIZE > res_size)
|
||||
{
|
||||
res_size = size + ARENA_HEADER_SIZE;
|
||||
cmt_size = size + ARENA_HEADER_SIZE;
|
||||
}
|
||||
Arena *new_block = arena_alloc(.reserve_size = res_size,
|
||||
.commit_size = cmt_size,
|
||||
.flags = current->flags);
|
||||
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: 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);
|
||||
}
|
||||
|
||||
// rjf: panic on failure
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
if(Unlikely(result == 0))
|
||||
{
|
||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||
os_abort(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
arena_pos(Arena *arena)
|
||||
{
|
||||
Arena *current = arena->current;
|
||||
U64 pos = current->base_pos + current->pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_pop_to(Arena *arena, U64 pos)
|
||||
{
|
||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
||||
Arena *current = arena->current;
|
||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
||||
{
|
||||
prev = current->prev;
|
||||
os_release(current, current->res);
|
||||
}
|
||||
arena->current = current;
|
||||
U64 new_pos = big_pos - current->base_pos;
|
||||
AssertAlways(new_pos <= current->pos);
|
||||
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
||||
current->pos = new_pos;
|
||||
}
|
||||
|
||||
//- rjf: arena push/pop helpers
|
||||
|
||||
internal void
|
||||
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)
|
||||
{
|
||||
U64 pos = arena_pos(arena);
|
||||
Temp temp = {arena, pos};
|
||||
return temp;
|
||||
}
|
||||
|
||||
internal void
|
||||
temp_end(Temp temp)
|
||||
{
|
||||
arena_pop_to(temp.arena, temp.pos);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// Implementation
|
||||
|
||||
internal Arena *
|
||||
arena_alloc__sized(U64 init_res, U64 init_cmt)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res);
|
||||
|
||||
void *memory = 0;
|
||||
U64 res = 0;
|
||||
U64 cmt = 0;
|
||||
B32 large_pages = os_large_pages_enabled();
|
||||
if(large_pages)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Arena *arena = (Arena*)memory;
|
||||
if(arena)
|
||||
{
|
||||
AsanPoisonMemoryRegion(memory, cmt);
|
||||
AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE);
|
||||
arena->prev = 0;
|
||||
arena->current = arena;
|
||||
arena->base_pos = 0;
|
||||
arena->pos = ARENA_HEADER_SIZE;
|
||||
arena->cmt = cmt;
|
||||
arena->res = res;
|
||||
arena->align = 8;
|
||||
#if ENABLE_DEV
|
||||
arena->dev = 0;
|
||||
#endif
|
||||
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 *node = arena->current, *prev = 0; node != 0; node = prev) {
|
||||
prev = node->prev;
|
||||
os_release(node, node->res);
|
||||
}
|
||||
}
|
||||
|
||||
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__impl(Arena *arena, U64 size)
|
||||
{
|
||||
Arena *current = arena->current;
|
||||
U64 pos_mem = AlignPow2(current->pos, arena->align);
|
||||
U64 pos_new = pos_mem + size;
|
||||
|
||||
if (current->res < pos_new && arena->grow) {
|
||||
Arena *new_block;
|
||||
|
||||
// normal growth path
|
||||
if (size < arena_huge_push_threshold()) {
|
||||
new_block = arena_alloc();
|
||||
}
|
||||
// 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_mem = AlignPow2(current->pos, current->align);
|
||||
pos_new = pos_mem + size;
|
||||
}
|
||||
}
|
||||
|
||||
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(memory == 0))
|
||||
{
|
||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||
os_exit_process(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
internal U64
|
||||
arena_pos(Arena *arena)
|
||||
{
|
||||
Arena *current = arena->current;
|
||||
U64 pos = current->base_pos + current->pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_pop_to(Arena *arena, U64 big_pos_unclamped)
|
||||
{
|
||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped);
|
||||
|
||||
// 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
arena_pop_to(arena, 0);
|
||||
}
|
||||
|
||||
internal Temp
|
||||
temp_begin(Arena *arena)
|
||||
{
|
||||
U64 pos = arena_pos(arena);
|
||||
Temp temp = {arena, pos};
|
||||
return temp;
|
||||
}
|
||||
|
||||
internal void
|
||||
temp_end(Temp temp)
|
||||
{
|
||||
arena_pop_to(temp.arena, temp.pos);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): "Mini-Arena" Helper
|
||||
|
||||
internal B32
|
||||
ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){
|
||||
B32 result = 0;
|
||||
U8 *cmt = (U8*)*cmtptr;
|
||||
if (cmt < (U8*)pos){
|
||||
U64 cmt_size_raw = (U8*)pos - cmt;
|
||||
U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size);
|
||||
if (os_commit(cmt, cmt_size)){
|
||||
*cmtptr = cmt + cmt_size;
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
result = 1;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
+94
-87
@@ -1,87 +1,94 @@
|
||||
// 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: Constants
|
||||
|
||||
#define ARENA_HEADER_SIZE 64
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Types
|
||||
|
||||
typedef U32 ArenaFlags;
|
||||
enum
|
||||
{
|
||||
ArenaFlag_NoChain = (1<<0),
|
||||
ArenaFlag_LargePages = (1<<1),
|
||||
};
|
||||
|
||||
typedef struct ArenaParams ArenaParams;
|
||||
struct ArenaParams
|
||||
{
|
||||
ArenaFlags flags;
|
||||
U64 reserve_size;
|
||||
U64 commit_size;
|
||||
void *optional_backing_buffer;
|
||||
};
|
||||
|
||||
typedef struct Arena Arena;
|
||||
struct Arena
|
||||
{
|
||||
Arena *prev; // previous arena in chain
|
||||
Arena *current; // current arena in chain
|
||||
ArenaFlags flags;
|
||||
U32 cmt_size;
|
||||
U64 res_size;
|
||||
U64 base_pos;
|
||||
U64 pos;
|
||||
U64 cmt;
|
||||
U64 res;
|
||||
};
|
||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
||||
|
||||
typedef struct Temp Temp;
|
||||
struct Temp
|
||||
{
|
||||
Arena *arena;
|
||||
U64 pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Global Defaults
|
||||
|
||||
global U64 arena_default_reserve_size = MB(64);
|
||||
global U64 arena_default_commit_size = KB(64);
|
||||
global ArenaFlags arena_default_flags = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arena Functions
|
||||
|
||||
//- 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, __VA_ARGS__})
|
||||
internal void arena_release(Arena *arena);
|
||||
|
||||
//- rjf: arena push/pop/pos core functions
|
||||
internal void *arena_push(Arena *arena, U64 size, U64 align);
|
||||
internal U64 arena_pos(Arena *arena);
|
||||
internal void arena_pop_to(Arena *arena, U64 pos);
|
||||
|
||||
//- rjf: arena push/pop helpers
|
||||
internal void arena_clear(Arena *arena);
|
||||
internal void arena_pop(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))
|
||||
#define push_array_aligned(a, T, c, align) (T *)MemoryZero(push_array_no_zero_aligned(a, T, c, align), sizeof(T)*(c))
|
||||
#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)))
|
||||
|
||||
#endif // BASE_ARENA_H
|
||||
// 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: Constants
|
||||
|
||||
#define ARENA_HEADER_SIZE 128
|
||||
|
||||
#ifndef ARENA_RESERVE_SIZE
|
||||
# define ARENA_RESERVE_SIZE MB(64)
|
||||
#endif
|
||||
#ifndef ARENA_COMMIT_SIZE
|
||||
# define ARENA_COMMIT_SIZE KB(64)
|
||||
#endif
|
||||
|
||||
#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
|
||||
{
|
||||
struct Arena *prev;
|
||||
struct Arena *current;
|
||||
U64 base_pos;
|
||||
U64 pos;
|
||||
U64 cmt;
|
||||
U64 res;
|
||||
U64 align;
|
||||
struct ArenaDev *dev;
|
||||
B8 grow;
|
||||
B8 large_pages;
|
||||
};
|
||||
|
||||
typedef struct Temp Temp;
|
||||
struct Temp
|
||||
{
|
||||
Arena *arena;
|
||||
U64 pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// Implementation
|
||||
|
||||
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt);
|
||||
|
||||
internal Arena* arena_alloc(void);
|
||||
internal void arena_release(Arena *arena);
|
||||
|
||||
internal void* arena_push__impl(Arena *arena, U64 size);
|
||||
internal U64 arena_pos(Arena *arena);
|
||||
internal void arena_pop_to(Arena *arena, U64 pos);
|
||||
|
||||
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_push_align(Arena *arena, U64 align);
|
||||
internal void arena_put_back(Arena *arena, U64 amt);
|
||||
|
||||
internal Temp temp_begin(Arena *arena);
|
||||
internal void temp_end(Temp temp);
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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
|
||||
+229
-232
@@ -1,232 +1,229 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64
|
||||
cmd_line_hash_from_string(String8 string)
|
||||
{
|
||||
U64 result = 5381;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CmdLineOpt **
|
||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||
{
|
||||
CmdLineOpt **slot = 0;
|
||||
if(cmd_line->option_table_size != 0)
|
||||
{
|
||||
U64 hash = cmd_line_hash_from_string(string);
|
||||
U64 bucket = hash % cmd_line->option_table_size;
|
||||
slot = &cmd_line->option_table[bucket];
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string)
|
||||
{
|
||||
CmdLineOpt *result = 0;
|
||||
for(CmdLineOpt *var = *slot; var; var = var->hash_next)
|
||||
{
|
||||
if(str8_match(string, var->string, 0))
|
||||
{
|
||||
result = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, var);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values)
|
||||
{
|
||||
CmdLineOpt *var = 0;
|
||||
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
|
||||
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
|
||||
if(existing_var != 0)
|
||||
{
|
||||
var = existing_var;
|
||||
}
|
||||
else
|
||||
{
|
||||
var = push_array(arena, CmdLineOpt, 1);
|
||||
var->hash_next = *slot;
|
||||
var->hash = cmd_line_hash_from_string(string);
|
||||
var->string = push_str8_copy(arena, string);
|
||||
var->value_strings = values;
|
||||
StringJoin join = {0};
|
||||
join.pre = str8_lit("");
|
||||
join.sep = str8_lit(",");
|
||||
join.post = str8_lit("");
|
||||
var->value_string = str8_list_join(arena, &var->value_strings, &join);
|
||||
*slot = var;
|
||||
cmd_line_push_opt(&cmd_line->options, var);
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
internal CmdLine
|
||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
{
|
||||
CmdLine parsed = {0};
|
||||
parsed.exe_name = command_line.first->string;
|
||||
|
||||
// NOTE(rjf): Set up config option table.
|
||||
{
|
||||
parsed.option_table_size = 4096;
|
||||
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Parse command line.
|
||||
B32 after_passthrough_option = 0;
|
||||
B32 first_passthrough = 1;
|
||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
String8 option_name = node->string;
|
||||
|
||||
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's
|
||||
// a flag option. All arguments after a single "--" (with no trailing string
|
||||
// on the command line will be considered as input files.
|
||||
B32 is_option = 1;
|
||||
if(after_passthrough_option == 0)
|
||||
{
|
||||
if(str8_match(node->string, str8_lit("--"), 0))
|
||||
{
|
||||
after_passthrough_option = 1;
|
||||
is_option = 0;
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 2);
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
|
||||
// NOTE(rjf): This string is an option.
|
||||
if(is_option)
|
||||
{
|
||||
B32 has_arguments = 0;
|
||||
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||
if(arg_signifier_position < option_name.size)
|
||||
{
|
||||
has_arguments = 1;
|
||||
}
|
||||
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||
|
||||
String8List arguments = {0};
|
||||
|
||||
// NOTE(rjf): Parse arguments.
|
||||
if(has_arguments)
|
||||
{
|
||||
for(String8Node *n = node; n; n = n->next)
|
||||
{
|
||||
next = n->next;
|
||||
|
||||
String8 string = n->string;
|
||||
if(n == node)
|
||||
{
|
||||
string = arg_portion_this_string;
|
||||
}
|
||||
|
||||
U8 splits[] = { ',' };
|
||||
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||
{
|
||||
str8_list_push(arena, &arguments, sub_arg->string);
|
||||
}
|
||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||
(n != node || arg_portion_this_string.size != 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(rjf): Register config variable.
|
||||
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||
// handled by tool-specific code.
|
||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
||||
{
|
||||
str8_list_push(arena, &parsed.inputs, node->string);
|
||||
after_passthrough_option = 1;
|
||||
first_passthrough = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name);
|
||||
}
|
||||
|
||||
internal String8List
|
||||
cmd_line_strings(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8List result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_strings;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cmd_line_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8 result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_string;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0);
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0 && var->value_strings.node_count > 0);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64
|
||||
cmd_line_hash_from_string(String8 string)
|
||||
{
|
||||
U64 result = 5381;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CmdLineOpt **
|
||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||
{
|
||||
CmdLineOpt **slot = 0;
|
||||
if(cmd_line->option_table_size != 0)
|
||||
{
|
||||
U64 hash = cmd_line_hash_from_string(string);
|
||||
U64 bucket = hash % cmd_line->option_table_size;
|
||||
slot = &cmd_line->option_table[bucket];
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string)
|
||||
{
|
||||
CmdLineOpt *result = 0;
|
||||
for(CmdLineOpt *var = *slot; var; var = var->hash_next)
|
||||
{
|
||||
if(str8_match(string, var->string, 0))
|
||||
{
|
||||
result = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, var);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values)
|
||||
{
|
||||
CmdLineOpt *var = 0;
|
||||
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
|
||||
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
|
||||
if(existing_var != 0)
|
||||
{
|
||||
var = existing_var;
|
||||
}
|
||||
else
|
||||
{
|
||||
var = push_array(arena, CmdLineOpt, 1);
|
||||
var->hash_next = *slot;
|
||||
var->hash = cmd_line_hash_from_string(string);
|
||||
var->string = push_str8_copy(arena, string);
|
||||
var->value_strings = values;
|
||||
StringJoin join = {0};
|
||||
join.pre = str8_lit("");
|
||||
join.sep = str8_lit(",");
|
||||
join.post = str8_lit("");
|
||||
var->value_string = str8_list_join(arena, &var->value_strings, &join);
|
||||
*slot = var;
|
||||
cmd_line_push_opt(&cmd_line->options, var);
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
internal CmdLine
|
||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
{
|
||||
CmdLine parsed = {0};
|
||||
|
||||
// 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;
|
||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
String8 option_name = node->string;
|
||||
|
||||
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's
|
||||
// a flag option. All arguments after a single "--" (with no trailing string
|
||||
// on the command line will be considered as input files.
|
||||
B32 is_option = 1;
|
||||
if(after_passthrough_option == 0)
|
||||
{
|
||||
if(str8_match(node->string, str8_lit("--"), 0))
|
||||
{
|
||||
after_passthrough_option = 1;
|
||||
is_option = 0;
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 2);
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
|
||||
// NOTE(rjf): This string is an option.
|
||||
if(is_option)
|
||||
{
|
||||
B32 has_arguments = 0;
|
||||
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||
if(arg_signifier_position < option_name.size)
|
||||
{
|
||||
has_arguments = 1;
|
||||
}
|
||||
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||
|
||||
String8List arguments = {0};
|
||||
|
||||
// NOTE(rjf): Parse arguments.
|
||||
if(has_arguments)
|
||||
{
|
||||
for(String8Node *n = node; n; n = n->next)
|
||||
{
|
||||
next = n->next;
|
||||
|
||||
String8 string = n->string;
|
||||
if(n == node)
|
||||
{
|
||||
string = arg_portion_this_string;
|
||||
}
|
||||
|
||||
U8 splits[] = { ',' };
|
||||
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||
{
|
||||
str8_list_push(arena, &arguments, sub_arg->string);
|
||||
}
|
||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||
(n != node || arg_portion_this_string.size != 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(rjf): Register config variable.
|
||||
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||
// handled by tool-specific code.
|
||||
else if(!str8_match(node->string, str8_lit("--"), 0))
|
||||
{
|
||||
str8_list_push(arena, &parsed.inputs, node->string);
|
||||
after_passthrough_option = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name);
|
||||
}
|
||||
|
||||
internal String8List
|
||||
cmd_line_strings(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8List result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_strings;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cmd_line_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8 result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_string;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0);
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0 && var->value_strings.node_count > 0);
|
||||
}
|
||||
|
||||
@@ -1,54 +1,53 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_COMMAND_LINE_H
|
||||
#define BASE_COMMAND_LINE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsed Command Line Types
|
||||
|
||||
typedef struct CmdLineOpt CmdLineOpt;
|
||||
struct CmdLineOpt
|
||||
{
|
||||
CmdLineOpt *next;
|
||||
CmdLineOpt *hash_next;
|
||||
U64 hash;
|
||||
String8 string;
|
||||
String8List value_strings;
|
||||
String8 value_string;
|
||||
};
|
||||
|
||||
typedef struct CmdLineOptList CmdLineOptList;
|
||||
struct CmdLineOptList
|
||||
{
|
||||
U64 count;
|
||||
CmdLineOpt *first;
|
||||
CmdLineOpt *last;
|
||||
};
|
||||
|
||||
typedef struct CmdLine CmdLine;
|
||||
struct CmdLine
|
||||
{
|
||||
String8 exe_name;
|
||||
CmdLineOptList options;
|
||||
String8List inputs;
|
||||
U64 option_table_size;
|
||||
CmdLineOpt **option_table;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64 cmd_line_hash_from_string(String8 string);
|
||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||
internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values);
|
||||
internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments);
|
||||
internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name);
|
||||
internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name);
|
||||
internal String8 cmd_line_string(CmdLine *cmd_line, String8 name);
|
||||
internal B32 cmd_line_has_flag(CmdLine *cmd_line, String8 name);
|
||||
internal B32 cmd_line_has_argument(CmdLine *cmd_line, String8 name);
|
||||
|
||||
#endif // BASE_COMMAND_LINE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_COMMAND_LINE_H
|
||||
#define BASE_COMMAND_LINE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsed Command Line Types
|
||||
|
||||
typedef struct CmdLineOpt CmdLineOpt;
|
||||
struct CmdLineOpt
|
||||
{
|
||||
CmdLineOpt *next;
|
||||
CmdLineOpt *hash_next;
|
||||
U64 hash;
|
||||
String8 string;
|
||||
String8List value_strings;
|
||||
String8 value_string;
|
||||
};
|
||||
|
||||
typedef struct CmdLineOptList CmdLineOptList;
|
||||
struct CmdLineOptList
|
||||
{
|
||||
U64 count;
|
||||
CmdLineOpt *first;
|
||||
CmdLineOpt *last;
|
||||
};
|
||||
|
||||
typedef struct CmdLine CmdLine;
|
||||
struct CmdLine
|
||||
{
|
||||
CmdLineOptList options;
|
||||
String8List inputs;
|
||||
U64 option_table_size;
|
||||
CmdLineOpt **option_table;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64 cmd_line_hash_from_string(String8 string);
|
||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||
internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values);
|
||||
internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments);
|
||||
internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name);
|
||||
internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name);
|
||||
internal String8 cmd_line_string(CmdLine *cmd_line, String8 name);
|
||||
internal B32 cmd_line_has_flag(CmdLine *cmd_line, String8 name);
|
||||
internal B32 cmd_line_has_argument(CmdLine *cmd_line, String8 name);
|
||||
|
||||
#endif // BASE_COMMAND_LINE_H
|
||||
|
||||
+144
-247
@@ -1,247 +1,144 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_CONTEXT_CRACKING_H
|
||||
#define BASE_CONTEXT_CRACKING_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Clang OS/Arch Cracking
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSVC OS/Arch Cracking
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
# define COMPILER_MSVC 1
|
||||
|
||||
# if _MSC_VER >= 1920
|
||||
# define COMPILER_MSVC_YEAR 2019
|
||||
# elif _MSC_VER >= 1910
|
||||
# define COMPILER_MSVC_YEAR 2017
|
||||
# elif _MSC_VER >= 1900
|
||||
# define COMPILER_MSVC_YEAR 2015
|
||||
# elif _MSC_VER >= 1800
|
||||
# define COMPILER_MSVC_YEAR 2013
|
||||
# elif _MSC_VER >= 1700
|
||||
# define COMPILER_MSVC_YEAR 2012
|
||||
# elif _MSC_VER >= 1600
|
||||
# define COMPILER_MSVC_YEAR 2010
|
||||
# elif _MSC_VER >= 1500
|
||||
# define COMPILER_MSVC_YEAR 2008
|
||||
# elif _MSC_VER >= 1400
|
||||
# define COMPILER_MSVC_YEAR 2005
|
||||
# else
|
||||
# define COMPILER_MSVC_YEAR 0
|
||||
# endif
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(_M_IX86)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(_M_ARM64)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(_M_ARM)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: GCC OS/Arch Cracking
|
||||
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
|
||||
# define COMPILER_GCC 1
|
||||
|
||||
# if defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error Compiler not supported.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arch Cracking
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
# define ARCH_64BIT 1
|
||||
#elif defined(ARCH_X86)
|
||||
# define ARCH_32BIT 1
|
||||
#endif
|
||||
|
||||
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
||||
# define ARCH_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# error Endianness of this architecture not understood by context cracker.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Language Cracking
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CPP 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Option Cracking
|
||||
|
||||
#if !defined(BUILD_DEBUG)
|
||||
# define BUILD_DEBUG 1
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_ENTRY_DEFINING_UNIT)
|
||||
# define BUILD_ENTRY_DEFINING_UNIT 1
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_CONSOLE_INTERFACE)
|
||||
# define BUILD_CONSOLE_INTERFACE 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_MAJOR)
|
||||
# define BUILD_VERSION_MAJOR 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_MINOR)
|
||||
# define BUILD_VERSION_MINOR 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 0
|
||||
#endif
|
||||
|
||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
||||
#if BUILD_DEBUG
|
||||
# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]"
|
||||
#else
|
||||
# define BUILD_MODE_STRING_LITERAL_APPEND ""
|
||||
#endif
|
||||
#if defined(BUILD_GIT_HASH)
|
||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]"
|
||||
#else
|
||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND ""
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_TITLE)
|
||||
# define BUILD_TITLE "Untitled"
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL)
|
||||
# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
|
||||
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGamesExt/raddebugger/issues"
|
||||
#endif
|
||||
|
||||
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zero All Undefined Options
|
||||
|
||||
#if !defined(ARCH_32BIT)
|
||||
# define ARCH_32BIT 0
|
||||
#endif
|
||||
#if !defined(ARCH_64BIT)
|
||||
# define ARCH_64BIT 0
|
||||
#endif
|
||||
#if !defined(ARCH_X64)
|
||||
# define ARCH_X64 0
|
||||
#endif
|
||||
#if !defined(ARCH_X86)
|
||||
# define ARCH_X86 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM64)
|
||||
# define ARCH_ARM64 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM32)
|
||||
# define ARCH_ARM32 0
|
||||
#endif
|
||||
#if !defined(COMPILER_MSVC)
|
||||
# define COMPILER_MSVC 0
|
||||
#endif
|
||||
#if !defined(COMPILER_GCC)
|
||||
# define COMPILER_GCC 0
|
||||
#endif
|
||||
#if !defined(COMPILER_CLANG)
|
||||
# define COMPILER_CLANG 0
|
||||
#endif
|
||||
#if !defined(OS_WINDOWS)
|
||||
# define OS_WINDOWS 0
|
||||
#endif
|
||||
#if !defined(OS_LINUX)
|
||||
# define OS_LINUX 0
|
||||
#endif
|
||||
#if !defined(OS_MAC)
|
||||
# define OS_MAC 0
|
||||
#endif
|
||||
#if !defined(LANG_CPP)
|
||||
# define LANG_CPP 0
|
||||
#endif
|
||||
#if !defined(LANG_C)
|
||||
# define LANG_C 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unsupported Errors
|
||||
|
||||
#if ARCH_X86
|
||||
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
|
||||
#endif
|
||||
#if !ARCH_X64
|
||||
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
|
||||
#endif
|
||||
|
||||
#endif // BASE_CONTEXT_CRACKING_H
|
||||
// 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
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error This compiler/platform combo is not supported yet
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error architecture not supported yet
|
||||
# endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
# define COMPILER_CL 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error This compiler/platform combo is not supported yet
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(_M_IX86)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(_M_ARM64)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(_M_ARM)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error architecture not supported yet
|
||||
# endif
|
||||
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
|
||||
# define COMPILER_GCC 1
|
||||
|
||||
# if defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# else
|
||||
# error This compiler/platform combo is not supported yet
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error architecture not supported yet
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error This compiler is not supported yet
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
# define ARCH_64BIT 1
|
||||
#elif defined(ARCH_X86)
|
||||
# define ARCH_32BIT 1
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CPP 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
// zeroify
|
||||
|
||||
#if !defined(ARCH_32BIT)
|
||||
# define ARCH_32BIT 0
|
||||
#endif
|
||||
#if !defined(ARCH_64BIT)
|
||||
# define ARCH_64BIT 0
|
||||
#endif
|
||||
#if !defined(ARCH_X64)
|
||||
# define ARCH_X64 0
|
||||
#endif
|
||||
#if !defined(ARCH_X86)
|
||||
# define ARCH_X86 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM64)
|
||||
# define ARCH_ARM64 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM32)
|
||||
# define ARCH_ARM32 0
|
||||
#endif
|
||||
#if !defined(COMPILER_CL)
|
||||
# define COMPILER_CL 0
|
||||
#endif
|
||||
#if !defined(COMPILER_GCC)
|
||||
# define COMPILER_GCC 0
|
||||
#endif
|
||||
#if !defined(COMPILER_CLANG)
|
||||
# define COMPILER_CLANG 0
|
||||
#endif
|
||||
#if !defined(OS_WINDOWS)
|
||||
# define OS_WINDOWS 0
|
||||
#endif
|
||||
#if !defined(OS_LINUX)
|
||||
# define OS_LINUX 0
|
||||
#endif
|
||||
#if !defined(OS_MAC)
|
||||
# define OS_MAC 0
|
||||
#endif
|
||||
#if !defined(LANG_CPP)
|
||||
# define LANG_CPP 0
|
||||
#endif
|
||||
#if !defined(LANG_C)
|
||||
# define LANG_C 0
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
ThreadNameF("[main thread]");
|
||||
|
||||
//- rjf: set up telemetry
|
||||
#if PROFILE_TELEMETRY
|
||||
local_persist U8 tm_data[MB(64)];
|
||||
tmLoadLibrary(TM_RELEASE);
|
||||
tmSetMaxThreadCount(256);
|
||||
tmInitialize(sizeof(tm_data), (char *)tm_data);
|
||||
#endif
|
||||
|
||||
//- rjf: parse command line
|
||||
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments);
|
||||
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]);
|
||||
}
|
||||
|
||||
//- rjf: initialize all included layers
|
||||
#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL)
|
||||
ts_init();
|
||||
#endif
|
||||
#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL)
|
||||
hs_init();
|
||||
#endif
|
||||
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
|
||||
fs_init();
|
||||
#endif
|
||||
#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL)
|
||||
txt_init();
|
||||
#endif
|
||||
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
|
||||
mtx_init();
|
||||
#endif
|
||||
#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL)
|
||||
dasm_init();
|
||||
#endif
|
||||
#if defined(DBGI_H) && !defined(DBGI_INIT_MANUAL)
|
||||
di_init();
|
||||
#endif
|
||||
#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL)
|
||||
fzy_init();
|
||||
#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(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL)
|
||||
tex_init();
|
||||
#endif
|
||||
#if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL)
|
||||
geo_init();
|
||||
#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: call into entry point
|
||||
entry_point(&cmdline);
|
||||
|
||||
//- 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_init_and_equip(&tctx);
|
||||
entry_point(params);
|
||||
tctx_release();
|
||||
}
|
||||
|
||||
internal B32
|
||||
update(void)
|
||||
{
|
||||
ProfTick(0);
|
||||
#if defined(TEXT_CACHE_H)
|
||||
txt_user_clock_tick();
|
||||
#endif
|
||||
#if defined(DASM_CACHE_H)
|
||||
dasm_user_clock_tick();
|
||||
#endif
|
||||
#if defined(GEO_CACHE_H)
|
||||
geo_user_clock_tick();
|
||||
#endif
|
||||
#if defined(TEXTURE_CACHE_H)
|
||||
tex_user_clock_tick();
|
||||
#endif
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
B32 result = frame();
|
||||
#else
|
||||
B32 result = 0;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_ENTRY_POINT_H
|
||||
#define BASE_ENTRY_POINT_H
|
||||
|
||||
internal void main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count);
|
||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||
internal B32 update(void);
|
||||
|
||||
#endif // BASE_ENTRY_POINT_H
|
||||
+18
-20
@@ -1,20 +1,18 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#undef MARKUP_LAYER_COLOR
|
||||
#define MARKUP_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||
|
||||
#include "base_core.c"
|
||||
#include "base_profile.c"
|
||||
#include "base_arena.c"
|
||||
#include "base_math.c"
|
||||
#include "base_strings.c"
|
||||
#include "base_thread_context.c"
|
||||
#include "base_command_line.c"
|
||||
#include "base_markup.c"
|
||||
#include "base_meta.c"
|
||||
#include "base_log.c"
|
||||
#include "base_entry_point.c"
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#undef RADDBG_LAYER_COLOR
|
||||
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||
|
||||
#include "base_types.c"
|
||||
#include "base_markup.c"
|
||||
#include "base_arena.c"
|
||||
#include "base_math.c"
|
||||
#include "base_string.c"
|
||||
#include "base_thread_context.c"
|
||||
#include "base_command_line.c"
|
||||
#include "base_arena_dev.c"
|
||||
#include "base_bits.c"
|
||||
|
||||
+23
-24
@@ -1,24 +1,23 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_INC_H
|
||||
#define BASE_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#include "base_context_cracking.h"
|
||||
|
||||
#include "base_core.h"
|
||||
#include "base_profile.h"
|
||||
#include "base_arena.h"
|
||||
#include "base_math.h"
|
||||
#include "base_strings.h"
|
||||
#include "base_thread_context.h"
|
||||
#include "base_command_line.h"
|
||||
#include "base_markup.h"
|
||||
#include "base_meta.h"
|
||||
#include "base_log.h"
|
||||
#include "base_entry_point.h"
|
||||
|
||||
#endif // BASE_INC_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_INC_H
|
||||
#define BASE_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#include "base_context_cracking.h"
|
||||
#include "base_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_string.h"
|
||||
#include "base_thread_context.h"
|
||||
#include "base_command_line.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) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals/Thread-Locals
|
||||
|
||||
C_LINKAGE thread_static Log *log_active;
|
||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||
C_LINKAGE thread_static Log *log_active = 0;
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Creation/Selection
|
||||
|
||||
internal Log *
|
||||
log_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
Log *log = push_array(arena, Log, 1);
|
||||
log->arena = arena;
|
||||
return log;
|
||||
}
|
||||
|
||||
internal void
|
||||
log_release(Log *log)
|
||||
{
|
||||
arena_release(log->arena);
|
||||
}
|
||||
|
||||
internal void
|
||||
log_select(Log *log)
|
||||
{
|
||||
log_active = log;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Building/Clearing
|
||||
|
||||
internal void
|
||||
log_msg(LogMsgKind kind, String8 string)
|
||||
{
|
||||
if(log_active != 0 && log_active->top_scope != 0)
|
||||
{
|
||||
String8 string_copy = push_str8_copy(log_active->arena, string);
|
||||
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
log_msgf(LogMsgKind kind, char *fmt, ...)
|
||||
{
|
||||
if(log_active != 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
log_msg(kind, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Scopes
|
||||
|
||||
internal void
|
||||
log_scope_begin(void)
|
||||
{
|
||||
if(log_active != 0)
|
||||
{
|
||||
U64 pos = arena_pos(log_active->arena);
|
||||
LogScope *scope = push_array(log_active->arena, LogScope, 1);
|
||||
scope->pos = pos;
|
||||
SLLStackPush(log_active->top_scope, scope);
|
||||
}
|
||||
}
|
||||
|
||||
internal LogScopeResult
|
||||
log_scope_end(Arena *arena)
|
||||
{
|
||||
LogScopeResult result = {0};
|
||||
if(log_active != 0)
|
||||
{
|
||||
LogScope *scope = log_active->top_scope;
|
||||
if(scope != 0)
|
||||
{
|
||||
SLLStackPop(log_active->top_scope);
|
||||
if(arena != 0)
|
||||
{
|
||||
for EachEnumVal(LogMsgKind, kind)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
|
||||
result.strings[kind] = indented_from_string(arena, result_unindented);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
arena_pop_to(log_active->arena, scope->pos);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) 2024 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(fmt, ...) log_msgf(LogMsgKind_Info, (fmt), __VA_ARGS__)
|
||||
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
|
||||
#define log_user_errorf(fmt, ...) log_msgf(LogMsgKind_UserError, (fmt), __VA_ARGS__)
|
||||
|
||||
#define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
|
||||
#define LogInfoNamedBlockF(fmt, ...) DeferLoop((log_infof(fmt, __VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Scopes
|
||||
|
||||
internal void log_scope_begin(void);
|
||||
internal LogScopeResult log_scope_end(Arena *arena);
|
||||
|
||||
#endif // BASE_LOG_H
|
||||
+2
-21
@@ -1,21 +1,2 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
set_thread_name(String8 string)
|
||||
{
|
||||
ProfThreadName("%.*s", str8_varg(string));
|
||||
os_set_thread_name(string);
|
||||
}
|
||||
|
||||
internal void
|
||||
set_thread_namef(char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
set_thread_name(string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
+79
-12
@@ -1,12 +1,79 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_MARKUP_H
|
||||
#define BASE_MARKUP_H
|
||||
|
||||
internal void set_thread_name(String8 string);
|
||||
internal void set_thread_namef(char *fmt, ...);
|
||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__))
|
||||
#define ThreadName(str) (set_thread_name(str))
|
||||
|
||||
#endif // BASE_MARKUP_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_MARKUP_H
|
||||
#define BASE_MARKUP_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zero Settings
|
||||
|
||||
#if !defined(PROFILE_TELEMETRY)
|
||||
# define PROFILE_TELEMETRY 0
|
||||
#endif
|
||||
|
||||
#if !defined(MARKUP_LAYER_COLOR)
|
||||
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# include "rad_tm.h"
|
||||
# if OS_WINDOWS
|
||||
# pragma comment(lib, "rad_tm_win64.lib")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Telemetry Profile Defines
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
||||
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
||||
# define ProfTick(...) tmTick(0)
|
||||
# define ProfIsCapturing(...) tmRunning()
|
||||
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
||||
# define ProfEndCapture(...) tmClose(0)
|
||||
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
||||
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
||||
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||
# define ProfColor(color) tmZoneColorSticky(color)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zeroify Undefined Defines
|
||||
|
||||
#if !defined(ProfBegin)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helper Wrappers
|
||||
|
||||
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
||||
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: General Markup
|
||||
|
||||
#define ThreadName(...) (ProfThreadName(__VA_ARGS__))
|
||||
|
||||
#endif // BASE_MARKUP_H
|
||||
|
||||
+616
-616
File diff suppressed because it is too large
Load Diff
+649
-649
File diff suppressed because it is too large
Load Diff
@@ -1,422 +0,0 @@
|
||||
// Copyright (c) 2024 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:
|
||||
if(!(t->type->flags & TypeFlag_IsExternal))
|
||||
{
|
||||
*(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,274 +0,0 @@
|
||||
// Copyright (c) 2024 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_IsExternal = (1<<0),
|
||||
TypeFlag_IsPlainText = (1<<1),
|
||||
TypeFlag_IsCodeText = (1<<2),
|
||||
TypeFlag_IsPathText = (1<<3),
|
||||
};
|
||||
|
||||
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")};
|
||||
|
||||
//- 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,74 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_PROFILE_H
|
||||
#define BASE_PROFILE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zero Settings
|
||||
|
||||
#if !defined(PROFILE_TELEMETRY)
|
||||
# define PROFILE_TELEMETRY 0
|
||||
#endif
|
||||
|
||||
#if !defined(MARKUP_LAYER_COLOR)
|
||||
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# include "rad_tm.h"
|
||||
# if OS_WINDOWS
|
||||
# pragma comment(lib, "rad_tm_win64.lib")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Telemetry Profile Defines
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
||||
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
||||
# define ProfTick(...) tmTick(0)
|
||||
# define ProfIsCapturing(...) tmRunning()
|
||||
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
||||
# define ProfEndCapture(...) tmClose(0)
|
||||
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
||||
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
||||
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||
# define ProfColor(color) tmZoneColorSticky(color)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zeroify Undefined Defines
|
||||
|
||||
#if !defined(ProfBegin)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helper Wrappers
|
||||
|
||||
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
||||
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
||||
|
||||
#endif // BASE_PROFILE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,381 +1,371 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_STRINGS_H
|
||||
#define BASE_STRINGS_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||
#include "third_party/stb/stb_sprintf.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Types
|
||||
|
||||
typedef struct String8 String8;
|
||||
struct String8
|
||||
{
|
||||
U8 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String16 String16;
|
||||
struct String16
|
||||
{
|
||||
U16 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String32 String32;
|
||||
struct String32
|
||||
{
|
||||
U32 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List & Array Types
|
||||
|
||||
typedef struct String8Node String8Node;
|
||||
struct String8Node
|
||||
{
|
||||
String8Node *next;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct String8MetaNode String8MetaNode;
|
||||
struct String8MetaNode
|
||||
{
|
||||
String8MetaNode *next;
|
||||
String8Node *node;
|
||||
};
|
||||
|
||||
typedef struct String8List String8List;
|
||||
struct String8List
|
||||
{
|
||||
String8Node *first;
|
||||
String8Node *last;
|
||||
U64 node_count;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
typedef struct String8Array String8Array;
|
||||
struct String8Array
|
||||
{
|
||||
String8 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching, Splitting, & Joining Types
|
||||
|
||||
typedef U32 StringMatchFlags;
|
||||
enum
|
||||
{
|
||||
StringMatchFlag_CaseInsensitive = (1 << 0),
|
||||
StringMatchFlag_RightSideSloppy = (1 << 1),
|
||||
StringMatchFlag_SlashInsensitive = (1 << 2),
|
||||
};
|
||||
|
||||
typedef U32 StringSplitFlags;
|
||||
enum
|
||||
{
|
||||
StringSplitFlag_KeepEmpties = (1 << 0),
|
||||
};
|
||||
|
||||
typedef enum PathStyle
|
||||
{
|
||||
PathStyle_Relative,
|
||||
PathStyle_WindowsAbsolute,
|
||||
PathStyle_UnixAbsolute,
|
||||
|
||||
#if OS_WINDOWS
|
||||
PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute
|
||||
#elif OS_LINUX
|
||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||
#else
|
||||
# error "absolute path style is undefined for this OS"
|
||||
#endif
|
||||
}
|
||||
PathStyle;
|
||||
|
||||
typedef struct StringJoin StringJoin;
|
||||
struct StringJoin
|
||||
{
|
||||
String8 pre;
|
||||
String8 sep;
|
||||
String8 post;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Pair Types
|
||||
|
||||
typedef struct String8TxtPtPair String8TxtPtPair;
|
||||
struct String8TxtPtPair
|
||||
{
|
||||
String8 string;
|
||||
TxtPt pt;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF Decoding Types
|
||||
|
||||
typedef struct UnicodeDecode UnicodeDecode;
|
||||
struct UnicodeDecode
|
||||
{
|
||||
U32 inc;
|
||||
U32 codepoint;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching Types
|
||||
|
||||
typedef struct FuzzyMatchRangeNode FuzzyMatchRangeNode;
|
||||
struct FuzzyMatchRangeNode
|
||||
{
|
||||
FuzzyMatchRangeNode *next;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct FuzzyMatchRangeList FuzzyMatchRangeList;
|
||||
struct FuzzyMatchRangeList
|
||||
{
|
||||
FuzzyMatchRangeNode *first;
|
||||
FuzzyMatchRangeNode *last;
|
||||
U64 count;
|
||||
U64 needle_part_count;
|
||||
U64 total_dim;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Character Classification & Conversion Functions
|
||||
|
||||
internal B32 char_is_space(U8 c);
|
||||
internal B32 char_is_upper(U8 c);
|
||||
internal B32 char_is_lower(U8 c);
|
||||
internal B32 char_is_alpha(U8 c);
|
||||
internal B32 char_is_slash(U8 c);
|
||||
internal B32 char_is_digit(U8 c, U32 base);
|
||||
internal U8 char_to_lower(U8 c);
|
||||
internal U8 char_to_upper(U8 c);
|
||||
internal U8 char_to_correct_slash(U8 c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String Measurement
|
||||
|
||||
internal U64 cstring8_length(U8 *c);
|
||||
internal U64 cstring16_length(U16 *c);
|
||||
internal U64 cstring32_length(U32 *c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Constructors
|
||||
|
||||
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
||||
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
|
||||
#define str8_varg(S) (int)((S).size), ((S).str)
|
||||
|
||||
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
||||
#define str8_array_fixed(S) str8((U8*)(S), sizeof(S))
|
||||
#define str8_struct(S) str8((U8*)(S), sizeof(*(S)))
|
||||
|
||||
internal String8 str8(U8 *str, U64 size);
|
||||
internal String8 str8_range(U8 *first, U8 *one_past_last);
|
||||
internal String8 str8_zero(void);
|
||||
internal String16 str16(U16 *str, U64 size);
|
||||
internal String16 str16_range(U16 *first, U16 *one_past_last);
|
||||
internal String16 str16_zero(void);
|
||||
internal String32 str32(U32 *str, U64 size);
|
||||
internal String32 str32_range(U32 *first, U32 *one_past_last);
|
||||
internal String32 str32_zero(void);
|
||||
internal String8 str8_cstring(char *c);
|
||||
internal String16 str16_cstring(U16 *c);
|
||||
internal String32 str32_cstring(U32 *c);
|
||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Stylization
|
||||
|
||||
internal String8 upper_from_str8(Arena *arena, String8 string);
|
||||
internal String8 lower_from_str8(Arena *arena, String8 string);
|
||||
internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching
|
||||
|
||||
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Slicing
|
||||
|
||||
internal String8 str8_substr(String8 str, Rng1U64 range);
|
||||
internal String8 str8_prefix(String8 str, U64 size);
|
||||
internal String8 str8_skip(String8 str, U64 amt);
|
||||
internal String8 str8_postfix(String8 str, U64 size);
|
||||
internal String8 str8_chop(String8 str, U64 amt);
|
||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Formatting & Copying
|
||||
|
||||
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||
internal String8 push_str8_copy(Arena *arena, String8 s);
|
||||
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
||||
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Integer Conversions
|
||||
|
||||
//- rjf: string -> integer
|
||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||
|
||||
//- rjf: integer -> string
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Float Conversions
|
||||
|
||||
internal F64 f64_from_str8(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List Construction Functions
|
||||
|
||||
internal String8Node* str8_list_push_node(String8List *list, String8Node *node);
|
||||
internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
||||
internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node);
|
||||
internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
||||
internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string);
|
||||
internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
||||
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
||||
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Splitting & Joining
|
||||
|
||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
||||
internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
||||
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf; String Arrays
|
||||
|
||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Path Helpers
|
||||
|
||||
internal String8 str8_chop_last_slash(String8 string);
|
||||
internal String8 str8_skip_last_slash(String8 string);
|
||||
internal String8 str8_chop_last_dot(String8 string);
|
||||
internal String8 str8_skip_last_dot(String8 string);
|
||||
|
||||
internal PathStyle path_style_from_str8(String8 string);
|
||||
internal String8List str8_split_path(Arena *arena, String8 string);
|
||||
internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style);
|
||||
internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style);
|
||||
|
||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||
|
||||
internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unicode String Conversions
|
||||
|
||||
internal String8 str8_from_16(Arena *arena, String16 in);
|
||||
internal String16 str16_from_8(Arena *arena, String8 in);
|
||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
internal String8 string_from_dimension(Dimension dimension);
|
||||
internal String8 string_from_side(Side side);
|
||||
internal String8 string_from_operating_system(OperatingSystem os);
|
||||
internal String8 string_from_architecture(Architecture arch);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Types -> String
|
||||
|
||||
internal String8 string_from_week_day(WeekDay week_day);
|
||||
internal String8 string_from_month(Month month);
|
||||
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
internal String8 indented_from_string(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Wrapping
|
||||
|
||||
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <-> Color
|
||||
|
||||
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
||||
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching
|
||||
|
||||
internal FuzzyMatchRangeList fuzzy_match_find(Arena *arena, String8 needle, String8 haystack);
|
||||
internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Serialization Helpers
|
||||
|
||||
internal void str8_serial_begin(Arena *arena, String8List *srl);
|
||||
internal String8 str8_serial_end(Arena *arena, String8List *srl);
|
||||
internal void str8_serial_write_to_dst(String8List *srl, void *out);
|
||||
internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 align);
|
||||
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
||||
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
||||
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
||||
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
||||
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
||||
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
||||
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
||||
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
||||
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
||||
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Deserialization Helpers
|
||||
|
||||
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
||||
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
||||
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
||||
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
||||
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
||||
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
|
||||
|
||||
#endif // BASE_STRINGS_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_STRING_H
|
||||
#define BASE_STRING_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||
#include "third_party/stb/stb_sprintf.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Types
|
||||
|
||||
typedef struct String8 String8;
|
||||
struct String8
|
||||
{
|
||||
U8 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String16 String16;
|
||||
struct String16
|
||||
{
|
||||
U16 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String32 String32;
|
||||
struct String32
|
||||
{
|
||||
U32 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List & Array Types
|
||||
|
||||
typedef struct String8Node String8Node;
|
||||
struct String8Node
|
||||
{
|
||||
String8Node *next;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct String8MetaNode String8MetaNode;
|
||||
struct String8MetaNode
|
||||
{
|
||||
String8MetaNode *next;
|
||||
String8Node *node;
|
||||
};
|
||||
|
||||
typedef struct String8List String8List;
|
||||
struct String8List
|
||||
{
|
||||
String8Node *first;
|
||||
String8Node *last;
|
||||
U64 node_count;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
typedef struct String8Array String8Array;
|
||||
struct String8Array
|
||||
{
|
||||
String8 *strings;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching, Splitting, & Joining Types
|
||||
|
||||
typedef U32 StringMatchFlags;
|
||||
enum
|
||||
{
|
||||
StringMatchFlag_CaseInsensitive = (1 << 0),
|
||||
StringMatchFlag_RightSideSloppy = (1 << 1),
|
||||
StringMatchFlag_SlashInsensitive = (1 << 2),
|
||||
};
|
||||
|
||||
typedef U32 StringSplitFlags;
|
||||
enum
|
||||
{
|
||||
StringSplitFlag_KeepEmpties = (1 << 0),
|
||||
};
|
||||
|
||||
typedef enum PathStyle
|
||||
{
|
||||
PathStyle_Relative,
|
||||
PathStyle_WindowsAbsolute,
|
||||
PathStyle_UnixAbsolute,
|
||||
|
||||
#if OS_WINDOWS
|
||||
PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute
|
||||
#elif OS_LINUX
|
||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||
#else
|
||||
# error "absolute path style is undefined for this OS"
|
||||
#endif
|
||||
}
|
||||
PathStyle;
|
||||
|
||||
typedef struct StringJoin StringJoin;
|
||||
struct StringJoin
|
||||
{
|
||||
String8 pre;
|
||||
String8 sep;
|
||||
String8 post;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Pair Types
|
||||
|
||||
typedef struct String8TxtPtPair String8TxtPtPair;
|
||||
struct String8TxtPtPair
|
||||
{
|
||||
String8 string;
|
||||
TxtPt pt;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF Decoding Types
|
||||
|
||||
typedef struct UnicodeDecode UnicodeDecode;
|
||||
struct UnicodeDecode
|
||||
{
|
||||
U32 inc;
|
||||
U32 codepoint;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching Types
|
||||
|
||||
typedef struct FuzzyMatchRangeNode FuzzyMatchRangeNode;
|
||||
struct FuzzyMatchRangeNode
|
||||
{
|
||||
FuzzyMatchRangeNode *next;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct FuzzyMatchRangeList FuzzyMatchRangeList;
|
||||
struct FuzzyMatchRangeList
|
||||
{
|
||||
FuzzyMatchRangeNode *first;
|
||||
FuzzyMatchRangeNode *last;
|
||||
U64 count;
|
||||
U64 needle_part_count;
|
||||
U64 total_dim;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Character Classification & Conversion Functions
|
||||
|
||||
internal B32 char_is_space(U8 c);
|
||||
internal B32 char_is_upper(U8 c);
|
||||
internal B32 char_is_lower(U8 c);
|
||||
internal B32 char_is_alpha(U8 c);
|
||||
internal B32 char_is_slash(U8 c);
|
||||
internal B32 char_is_digit(U8 c, U32 base);
|
||||
internal U8 char_to_lower(U8 c);
|
||||
internal U8 char_to_upper(U8 c);
|
||||
internal U8 char_to_correct_slash(U8 c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String Measurement
|
||||
|
||||
internal U64 cstring8_length(U8 *c);
|
||||
internal U64 cstring16_length(U16 *c);
|
||||
internal U64 cstring32_length(U32 *c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Constructors
|
||||
|
||||
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
||||
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
|
||||
#define str8_varg(S) (int)((S).size), ((S).str)
|
||||
|
||||
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
||||
#define str8_array_fixed(S) str8((U8*)(S), sizeof(S))
|
||||
#define str8_struct(S) str8((U8*)(S), sizeof(*(S)))
|
||||
|
||||
internal String8 str8(U8 *str, U64 size);
|
||||
internal String8 str8_range(U8 *first, U8 *one_past_last);
|
||||
internal String8 str8_zero(void);
|
||||
internal String16 str16(U16 *str, U64 size);
|
||||
internal String16 str16_range(U16 *first, U16 *one_past_last);
|
||||
internal String16 str16_zero(void);
|
||||
internal String32 str32(U32 *str, U64 size);
|
||||
internal String32 str32_range(U32 *first, U32 *one_past_last);
|
||||
internal String32 str32_zero(void);
|
||||
internal String8 str8_cstring(char *c);
|
||||
internal String16 str16_cstring(U16 *c);
|
||||
internal String32 str32_cstring(U32 *c);
|
||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Stylization
|
||||
|
||||
internal String8 upper_from_str8(Arena *arena, String8 string);
|
||||
internal String8 lower_from_str8(Arena *arena, String8 string);
|
||||
internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching
|
||||
|
||||
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Slicing
|
||||
|
||||
internal String8 str8_substr(String8 str, Rng1U64 range);
|
||||
internal String8 str8_prefix(String8 str, U64 size);
|
||||
internal String8 str8_skip(String8 str, U64 amt);
|
||||
internal String8 str8_postfix(String8 str, U64 size);
|
||||
internal String8 str8_chop(String8 str, U64 amt);
|
||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Formatting & Copying
|
||||
|
||||
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||
internal String8 push_str8_copy(Arena *arena, String8 s);
|
||||
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
||||
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Integer Conversions
|
||||
|
||||
//- rjf: string -> integer
|
||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||
|
||||
//- rjf: integer -> string
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Float Conversions
|
||||
|
||||
internal F64 f64_from_str8(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List Construction Functions
|
||||
|
||||
internal String8Node* str8_list_push_node(String8List *list, String8Node *node);
|
||||
internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
||||
internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node);
|
||||
internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
||||
internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string);
|
||||
internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
||||
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
||||
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Splitting & Joining
|
||||
|
||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
||||
internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
||||
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf; String Arrays
|
||||
|
||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Path Helpers
|
||||
|
||||
internal String8 str8_chop_last_slash(String8 string);
|
||||
internal String8 str8_skip_last_slash(String8 string);
|
||||
internal String8 str8_chop_last_dot(String8 string);
|
||||
internal String8 str8_skip_last_dot(String8 string);
|
||||
|
||||
internal PathStyle path_style_from_str8(String8 string);
|
||||
internal String8List str8_split_path(Arena *arena, String8 string);
|
||||
internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style);
|
||||
internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style);
|
||||
|
||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||
|
||||
internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unicode String Conversions
|
||||
|
||||
internal String8 str8_from_16(Arena *arena, String16 in);
|
||||
internal String16 str16_from_8(Arena *arena, String8 in);
|
||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
internal String8 string_from_dimension(Dimension dimension);
|
||||
internal String8 string_from_side(Side side);
|
||||
internal String8 string_from_operating_system(OperatingSystem os);
|
||||
internal String8 string_from_architecture(Architecture arch);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Types -> String
|
||||
|
||||
internal String8 string_from_week_day(WeekDay week_day);
|
||||
internal String8 string_from_month(Month month);
|
||||
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <-> Color
|
||||
|
||||
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
||||
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching
|
||||
|
||||
internal FuzzyMatchRangeList fuzzy_match_find(Arena *arena, String8 needle, String8 haystack);
|
||||
internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Serialization Helpers
|
||||
|
||||
internal void str8_serial_begin(Arena *arena, String8List *srl);
|
||||
internal String8 str8_serial_end(Arena *arena, String8List *srl);
|
||||
internal void str8_serial_write_to_dst(String8List *srl, void *out);
|
||||
internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 align);
|
||||
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
||||
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
||||
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
||||
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
||||
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
||||
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
||||
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
||||
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
||||
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
||||
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Deserialization Helpers
|
||||
|
||||
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
||||
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
||||
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
||||
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
||||
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
||||
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
|
||||
|
||||
#endif // BASE_STRING_H
|
||||
@@ -1,87 +1,78 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||
#endif
|
||||
|
||||
internal void
|
||||
tctx_init_and_equip(TCTX *tctx){
|
||||
MemoryZeroStruct(tctx);
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
*arena_ptr = arena_alloc();
|
||||
}
|
||||
tctx_thread_local = tctx;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_release(void)
|
||||
{
|
||||
for(U64 i = 0; i < ArrayCount(tctx_thread_local->arenas); i += 1)
|
||||
{
|
||||
arena_release(tctx_thread_local->arenas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal TCTX*
|
||||
tctx_get_equipped(void){
|
||||
return(tctx_thread_local);
|
||||
}
|
||||
|
||||
internal Arena*
|
||||
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
|
||||
Arena *result = 0;
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
Arena **conflict_ptr = conflicts;
|
||||
B32 has_conflict = 0;
|
||||
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||
if (*arena_ptr == *conflict_ptr){
|
||||
has_conflict = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_conflict){
|
||||
result = *arena_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_set_thread_name(String8 string){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
||||
MemoryCopy(tctx->thread_name, string.str, size);
|
||||
tctx->thread_name_size = size;
|
||||
}
|
||||
|
||||
internal String8
|
||||
tctx_get_thread_name(void){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
tctx->file_name = file_name;
|
||||
tctx->line_number = line_number;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
*file_name = tctx->file_name;
|
||||
*line_number = tctx->line_number;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||
#if !SUPPLEMENT_UNIT
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||
#endif
|
||||
|
||||
internal void
|
||||
tctx_init_and_equip(TCTX *tctx){
|
||||
MemoryZeroStruct(tctx);
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
*arena_ptr = arena_alloc();
|
||||
}
|
||||
tctx_thread_local = tctx;
|
||||
}
|
||||
|
||||
internal TCTX*
|
||||
tctx_get_equipped(void){
|
||||
return(tctx_thread_local);
|
||||
}
|
||||
|
||||
internal Arena*
|
||||
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
|
||||
Arena *result = 0;
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
Arena **conflict_ptr = conflicts;
|
||||
B32 has_conflict = 0;
|
||||
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||
if (*arena_ptr == *conflict_ptr){
|
||||
has_conflict = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_conflict){
|
||||
result = *arena_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_set_thread_name(String8 string){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
||||
MemoryCopy(tctx->thread_name, string.str, size);
|
||||
tctx->thread_name_size = size;
|
||||
}
|
||||
|
||||
internal String8
|
||||
tctx_get_thread_name(void){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
tctx->file_name = file_name;
|
||||
tctx->line_number = line_number;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
*file_name = tctx->file_name;
|
||||
*line_number = tctx->line_number;
|
||||
}
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
// 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
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context
|
||||
|
||||
typedef struct TCTX TCTX;
|
||||
struct TCTX
|
||||
{
|
||||
Arena *arenas[2];
|
||||
|
||||
U8 thread_name[32];
|
||||
U64 thread_name_size;
|
||||
|
||||
char *file_name;
|
||||
U64 line_number;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
internal void tctx_init_and_equip(TCTX *tctx);
|
||||
internal void tctx_release(void);
|
||||
internal TCTX* tctx_get_equipped(void);
|
||||
|
||||
internal Arena* tctx_get_scratch(Arena **conflicts, U64 countt);
|
||||
|
||||
internal void tctx_set_thread_name(String8 name);
|
||||
internal String8 tctx_get_thread_name(void);
|
||||
|
||||
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__)
|
||||
|
||||
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
||||
#define scratch_end(scratch) temp_end(scratch)
|
||||
|
||||
#endif // BASE_THREAD_CONTEXT_H
|
||||
// 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
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context
|
||||
|
||||
typedef struct TCTX TCTX;
|
||||
struct TCTX
|
||||
{
|
||||
Arena *arenas[2];
|
||||
|
||||
U8 thread_name[32];
|
||||
U64 thread_name_size;
|
||||
|
||||
char *file_name;
|
||||
U64 line_number;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
internal void tctx_init_and_equip(TCTX *tctx);
|
||||
internal TCTX* tctx_get_equipped(void);
|
||||
|
||||
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
|
||||
|
||||
internal void tctx_set_thread_name(String8 name);
|
||||
internal String8 tctx_get_thread_name(void);
|
||||
|
||||
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__)
|
||||
|
||||
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
||||
#define scratch_end(scratch) temp_end(scratch)
|
||||
|
||||
#endif //BASE_THREAD_CONTEXT_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,637 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Generated Code
|
||||
|
||||
#include "generated/codeview.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Common Decoding Helper Functions
|
||||
|
||||
internal U64
|
||||
cv_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 U64
|
||||
cv_hash_from_item_id(CV_ItemId item_id)
|
||||
{
|
||||
U64 result = cv_hash_from_string(str8_struct(&item_id));
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CV_NumericParsed
|
||||
cv_numeric_from_data_range(U8 *first, U8 *opl)
|
||||
{
|
||||
CV_NumericParsed result = {0};
|
||||
if(first + 2 <= opl)
|
||||
{
|
||||
U16 x = *(U16*)first;
|
||||
if(x < 0x8000)
|
||||
{
|
||||
result.kind = CV_NumericKind_USHORT;
|
||||
result.val = first;
|
||||
result.encoded_size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 val_size = 0;
|
||||
switch(x)
|
||||
{
|
||||
case CV_NumericKind_CHAR: val_size = 1; break;
|
||||
case CV_NumericKind_SHORT:
|
||||
case CV_NumericKind_USHORT: val_size = 2; break;
|
||||
case CV_NumericKind_LONG:
|
||||
case CV_NumericKind_ULONG: val_size = 4; break;
|
||||
case CV_NumericKind_FLOAT32: val_size = 4; break;
|
||||
case CV_NumericKind_FLOAT64: val_size = 8; break;
|
||||
case CV_NumericKind_FLOAT80: val_size = 10; break;
|
||||
case CV_NumericKind_FLOAT128: val_size = 16; break;
|
||||
case CV_NumericKind_QUADWORD:
|
||||
case CV_NumericKind_UQUADWORD: val_size = 8; break;
|
||||
case CV_NumericKind_FLOAT48: val_size = 6; break;
|
||||
case CV_NumericKind_COMPLEX32: val_size = 8; break;
|
||||
case CV_NumericKind_COMPLEX64: val_size = 16; break;
|
||||
case CV_NumericKind_COMPLEX80: val_size = 20; break;
|
||||
case CV_NumericKind_COMPLEX128:val_size = 32; break;
|
||||
case CV_NumericKind_VARSTRING: val_size = 0; break; // TODO: ???
|
||||
case CV_NumericKind_OCTWORD:
|
||||
case CV_NumericKind_UOCTWORD: val_size = 16; break;
|
||||
case CV_NumericKind_DECIMAL: val_size = 0; break; // TODO: ???
|
||||
case CV_NumericKind_DATE: val_size = 0; break; // TODO: ???
|
||||
case CV_NumericKind_UTF8STRING:val_size = 0; break; // TODO: ???
|
||||
case CV_NumericKind_FLOAT16: val_size = 2; break;
|
||||
}
|
||||
if(first + 2 + val_size <= opl)
|
||||
{
|
||||
result.kind = x;
|
||||
result.val = (first + 2);
|
||||
result.encoded_size = 2 + val_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cv_numeric_fits_in_u64(CV_NumericParsed *num)
|
||||
{
|
||||
B32 result = 0;
|
||||
switch(num->kind)
|
||||
{
|
||||
case CV_NumericKind_USHORT:
|
||||
case CV_NumericKind_ULONG:
|
||||
case CV_NumericKind_UQUADWORD:
|
||||
{
|
||||
result = 1;
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cv_numeric_fits_in_s64(CV_NumericParsed *num)
|
||||
{
|
||||
B32 result = 0;
|
||||
switch(num->kind)
|
||||
{
|
||||
case CV_NumericKind_CHAR:
|
||||
case CV_NumericKind_SHORT:
|
||||
case CV_NumericKind_LONG:
|
||||
case CV_NumericKind_QUADWORD:
|
||||
{
|
||||
result = 1;
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cv_numeric_fits_in_f64(CV_NumericParsed *num)
|
||||
{
|
||||
B32 result = 0;
|
||||
switch(num->kind)
|
||||
{
|
||||
case CV_NumericKind_FLOAT32:
|
||||
case CV_NumericKind_FLOAT64:
|
||||
{
|
||||
result = 1;
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
cv_u64_from_numeric(CV_NumericParsed *num)
|
||||
{
|
||||
U64 result = 0;
|
||||
switch(num->kind)
|
||||
{
|
||||
case CV_NumericKind_USHORT: {result = *(U16*)num->val;}break;
|
||||
case CV_NumericKind_ULONG: {result = *(U32*)num->val;}break;
|
||||
case CV_NumericKind_UQUADWORD:{result = *(U64*)num->val;}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal S64
|
||||
cv_s64_from_numeric(CV_NumericParsed *num)
|
||||
{
|
||||
S64 result = 0;
|
||||
switch(num->kind)
|
||||
{
|
||||
case CV_NumericKind_CHAR: {result = *(S8*)num->val;}break;
|
||||
case CV_NumericKind_SHORT: {result = *(S16*)num->val;}break;
|
||||
case CV_NumericKind_LONG: {result = *(S32*)num->val;}break;
|
||||
case CV_NumericKind_QUADWORD: {result = *(S64*)num->val;}break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal F64
|
||||
cv_f64_from_numeric(CV_NumericParsed *num)
|
||||
{
|
||||
F64 result = 0;
|
||||
switch(num->kind)
|
||||
{
|
||||
case CV_NumericKind_FLOAT32:{result = *(F32*)num->val;}break;
|
||||
case CV_NumericKind_FLOAT64:{result = *(F64*)num->val;}break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal U64
|
||||
cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value)
|
||||
{
|
||||
U64 cursor = offset;
|
||||
|
||||
// rjf: read header
|
||||
U8 header = 0;
|
||||
cursor += str8_deserial_read_struct(data, cursor, &header);
|
||||
|
||||
// rjf: decode value
|
||||
U32 value = 0;
|
||||
{
|
||||
// 1 byte
|
||||
if((header & 0x80) == 0)
|
||||
{
|
||||
value = header;
|
||||
}
|
||||
|
||||
// 2 bytes
|
||||
else if((header & 0xC0) == 0x80 && cursor+2 <= data.size)
|
||||
{
|
||||
U8 second_byte;
|
||||
cursor += str8_deserial_read_struct(data, cursor, &second_byte);
|
||||
value = ((header & 0x3F) << 8) | second_byte;
|
||||
}
|
||||
|
||||
// 4 bytes
|
||||
else if((header & 0xE0) == 0xC0 && cursor+3 <= data.size)
|
||||
{
|
||||
U8 second_byte, third_byte, fourth_byte;
|
||||
cursor += str8_deserial_read_struct(data, cursor, &second_byte);
|
||||
cursor += str8_deserial_read_struct(data, cursor, &third_byte);
|
||||
cursor += str8_deserial_read_struct(data, cursor, &fourth_byte);
|
||||
value = (((U32)header & 0x1F) << 24) | ((U32)second_byte << 16) | ((U32)third_byte << 8) | (U32)fourth_byte;
|
||||
}
|
||||
|
||||
// bad encode
|
||||
else if((header & 0xE0) == 0xE0)
|
||||
{
|
||||
value = max_U32;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: output results
|
||||
if(out_value)
|
||||
{
|
||||
*out_value = value;
|
||||
}
|
||||
|
||||
U64 read_size = cursor - offset;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value)
|
||||
{
|
||||
U32 value;
|
||||
U64 read_size = cv_decode_inline_annot_u32(data, offset, &value);
|
||||
if(value & 1)
|
||||
{
|
||||
value = -(value >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = value >> 1;
|
||||
}
|
||||
*out_value = (S32)value;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal S32
|
||||
cv_inline_annot_signed_from_unsigned_operand(U32 value)
|
||||
{
|
||||
if(value & 1)
|
||||
{
|
||||
value = -(value >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = value >> 1;
|
||||
}
|
||||
S32 result = (S32)value;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Parsing Functions
|
||||
|
||||
//- rjf: record range stream parsing
|
||||
|
||||
internal CV_RecRangeStream*
|
||||
cv_rec_range_stream_from_data(Arena *arena, String8 sym_data, U64 sym_align)
|
||||
{
|
||||
Assert(1 <= sym_align && IsPow2OrZero(sym_align));
|
||||
CV_RecRangeStream *result = push_array(arena, CV_RecRangeStream, 1);
|
||||
U8 *data = sym_data.str;
|
||||
U64 cursor = 0;
|
||||
U64 cap = sym_data.size;
|
||||
for(;cursor + sizeof(CV_RecHeader) <= cap;)
|
||||
{
|
||||
// setup a new chunk
|
||||
CV_RecRangeChunk *cur_chunk = push_array_aligned(arena, CV_RecRangeChunk, 1, 64);
|
||||
SLLQueuePush(result->first_chunk, result->last_chunk, cur_chunk);
|
||||
U64 partial_count = 0;
|
||||
for(;partial_count < CV_REC_RANGE_CHUNK_SIZE && cursor + sizeof(CV_RecHeader) <= cap; partial_count += 1)
|
||||
{
|
||||
// compute cap
|
||||
CV_RecHeader *hdr = (CV_RecHeader*)(data + cursor);
|
||||
U64 symbol_cap_unclamped = cursor + 2 + hdr->size;
|
||||
U64 symbol_cap = ClampTop(symbol_cap_unclamped, cap);
|
||||
|
||||
// push on range
|
||||
cur_chunk->ranges[partial_count].off = cursor + 2;
|
||||
cur_chunk->ranges[partial_count].hdr = *hdr;
|
||||
|
||||
// update cursor
|
||||
U32 next_pos = AlignPow2(symbol_cap, sym_align);
|
||||
cursor = next_pos;
|
||||
}
|
||||
result->total_count += partial_count;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CV_RecRangeArray
|
||||
cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream)
|
||||
{
|
||||
U64 total_count = stream->total_count;
|
||||
CV_RecRange *ranges = push_array_no_zero_aligned(arena, CV_RecRange, total_count, 8);
|
||||
U64 idx = 0;
|
||||
for(CV_RecRangeChunk *chunk = stream->first_chunk; chunk != 0; chunk = chunk->next)
|
||||
{
|
||||
U64 copy_count_raw = total_count - idx;
|
||||
U64 copy_count = ClampTop(copy_count_raw, CV_REC_RANGE_CHUNK_SIZE);
|
||||
MemoryCopy(ranges + idx, chunk->ranges, copy_count*sizeof(CV_RecRange));
|
||||
idx += copy_count;
|
||||
}
|
||||
CV_RecRangeArray result = {0};
|
||||
result.ranges = ranges;
|
||||
result.count = total_count;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- rjf: sym stream parsing
|
||||
|
||||
internal CV_SymParsed *
|
||||
cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align)
|
||||
{
|
||||
Assert(1 <= sym_align && IsPow2OrZero(sym_align));
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
//- rjf: gather symbols
|
||||
CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, sym_data, sym_align);
|
||||
|
||||
//- rjf: convert to result, fill basics
|
||||
CV_SymParsed *result = push_array(arena, CV_SymParsed, 1);
|
||||
result->data = sym_data;
|
||||
result->sym_align = sym_align;
|
||||
result->sym_ranges = cv_rec_range_array_from_stream(arena, stream);
|
||||
|
||||
//- rjf: extract top-level-info
|
||||
{
|
||||
CV_RecRange *range = result->sym_ranges.ranges;
|
||||
CV_RecRange *opl = range + result->sym_ranges.count;
|
||||
for(;range < opl; range += 1)
|
||||
{
|
||||
U8 *first = sym_data.str + range->off + 2;
|
||||
U64 cap = range->hdr.size - 2;
|
||||
switch(range->hdr.kind)
|
||||
{
|
||||
case CV_SymKind_COMPILE:
|
||||
if(sizeof(CV_SymCompile) <= cap)
|
||||
{
|
||||
CV_SymCompile *compile = (CV_SymCompile*)first;
|
||||
String8 ver_str = str8_cstring_capped((char*)(compile + 1), (char *)(first + cap));
|
||||
result->info.arch = compile->machine;
|
||||
result->info.language = CV_CompileFlags_ExtractLanguage(compile->flags);;
|
||||
result->info.compiler_name = ver_str;
|
||||
}break;
|
||||
case CV_SymKind_COMPILE2:
|
||||
if(sizeof(CV_SymCompile2) <= cap)
|
||||
{
|
||||
CV_SymCompile2 *compile2 = (CV_SymCompile2*)first;
|
||||
String8 ver_str = str8_cstring_capped((char*)(compile2 + 1), (char*)(first + cap));
|
||||
String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u",
|
||||
str8_varg(ver_str),
|
||||
compile2->ver_major,
|
||||
compile2->ver_minor,
|
||||
compile2->ver_build);
|
||||
result->info.arch = compile2->machine;
|
||||
result->info.language = CV_Compile2Flags_ExtractLanguage(compile2->flags);;
|
||||
result->info.compiler_name = compiler_name;
|
||||
}break;
|
||||
case CV_SymKind_COMPILE3:
|
||||
if(sizeof(CV_SymCompile3) <= cap)
|
||||
{
|
||||
CV_SymCompile3 *compile3 = (CV_SymCompile3*)first;
|
||||
String8 ver_str = str8_cstring_capped((char*)(compile3 + 1), (char *)(first + cap));
|
||||
String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u",
|
||||
str8_varg(ver_str),
|
||||
compile3->ver_major,
|
||||
compile3->ver_minor,
|
||||
compile3->ver_build);
|
||||
result->info.arch = compile3->machine;
|
||||
result->info.language = CV_Compile3Flags_ExtractLanguage(compile3->flags);;
|
||||
result->info.compiler_name = compiler_name;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
//- rjf: leaf stream parsing
|
||||
|
||||
internal CV_LeafParsed *
|
||||
cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId itype_first)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// gather up symbols
|
||||
CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, leaf_data, 1);
|
||||
|
||||
// convert to result
|
||||
CV_LeafParsed *result = push_array(arena, CV_LeafParsed, 1);
|
||||
result->data = leaf_data;
|
||||
result->itype_first = itype_first;
|
||||
result->itype_opl = itype_first + stream->total_count;
|
||||
result->leaf_ranges = cv_rec_range_array_from_stream(arena, stream);
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView C13 Parser Functions
|
||||
|
||||
internal CV_C13Parsed *
|
||||
cv_c13_parsed_from_data(Arena *arena, String8 c13_data, PDB_Strtbl *strtbl, PDB_CoffSectionArray *sections)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather c13 sub-sections
|
||||
//
|
||||
CV_C13SubSectionNode *file_chksms = 0;
|
||||
CV_C13SubSectionNode *first = 0;
|
||||
CV_C13SubSectionNode *last = 0;
|
||||
U64 count = 0;
|
||||
{
|
||||
U32 cursor = 0;
|
||||
for(; cursor + sizeof(CV_C13SubSectionHeader) <= c13_data.size;)
|
||||
{
|
||||
// read header
|
||||
CV_C13SubSectionHeader *hdr = (CV_C13SubSectionHeader*)(c13_data.str + cursor);
|
||||
|
||||
// get sub section info
|
||||
U32 sub_section_off = cursor + sizeof(*hdr);
|
||||
U32 sub_section_size_raw = hdr->size;
|
||||
U32 after_sub_section_off_unclamped = sub_section_off + sub_section_size_raw;
|
||||
U32 after_sub_section_off = ClampTop(after_sub_section_off_unclamped, c13_data.size);
|
||||
U32 sub_section_size = after_sub_section_off - sub_section_off;
|
||||
|
||||
// emit sub section
|
||||
if(!(hdr->kind & CV_C13SubSectionKind_IgnoreFlag))
|
||||
{
|
||||
CV_C13SubSectionNode *node = push_array(arena, CV_C13SubSectionNode, 1);
|
||||
SLLQueuePush(first, last, node);
|
||||
count += 1;
|
||||
node->kind = hdr->kind;
|
||||
node->off = sub_section_off;
|
||||
node->size = sub_section_size;
|
||||
if(hdr->kind == CV_C13SubSectionKind_FileChksms)
|
||||
{
|
||||
file_chksms = node;
|
||||
}
|
||||
}
|
||||
|
||||
// move cursor
|
||||
cursor = AlignPow2(after_sub_section_off, 4);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: parse each sub-section
|
||||
//
|
||||
U64 inlinee_lines_parsed_slots_count = 4096;
|
||||
CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots = push_array(arena, CV_C13InlineeLinesParsedNode *, inlinee_lines_parsed_slots_count);
|
||||
for(CV_C13SubSectionNode *node = first;
|
||||
node != 0;
|
||||
node = node->next)
|
||||
{
|
||||
U8 *first = c13_data.str + node->off;
|
||||
U32 cap = node->size;
|
||||
switch(node->kind)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: line info sub-section
|
||||
//
|
||||
case CV_C13SubSectionKind_Lines:
|
||||
if(sizeof(CV_C13SubSecLinesHeader) <= cap)
|
||||
{
|
||||
// read header
|
||||
U32 read_off = 0;
|
||||
U64 read_off_opl = node->size;
|
||||
CV_C13SubSecLinesHeader *hdr = (CV_C13SubSecLinesHeader*)(first + read_off);
|
||||
read_off += sizeof(*hdr);
|
||||
|
||||
// extract top level info
|
||||
U32 sec_idx = hdr->sec;
|
||||
B32 has_cols = !!(hdr->flags & CV_C13SubSecLinesFlag_HasColumns);
|
||||
U64 secrel_off = hdr->sec_off;
|
||||
U64 secrel_opl = secrel_off + hdr->len;
|
||||
U64 sec_base_off = sections->sections[sec_idx - 1].voff;
|
||||
|
||||
// rjf: bad section index -> skip
|
||||
if(sec_idx < 1 || sections->count < sec_idx)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// read files
|
||||
for(;read_off+sizeof(CV_C13File) <= read_off_opl;)
|
||||
{
|
||||
// rjf: grab next file header
|
||||
CV_C13File *file = (CV_C13File*)(first + read_off);
|
||||
U32 file_off = file->file_off;
|
||||
U32 line_count_unclamped = file->num_lines;
|
||||
U32 block_size = file->block_size;
|
||||
|
||||
// file_name from file_off
|
||||
String8 file_name = {0};
|
||||
if(file_off + sizeof(CV_C13Checksum) <= file_chksms->size)
|
||||
{
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = pdb_strtbl_string_from_off(strtbl, name_off);
|
||||
}
|
||||
|
||||
// array layouts
|
||||
U32 line_item_size = sizeof(CV_C13Line);
|
||||
if (has_cols){
|
||||
line_item_size += sizeof(CV_C13Column);
|
||||
}
|
||||
|
||||
U32 line_array_off = read_off + sizeof(*file);
|
||||
U32 line_count_max = (read_off_opl - line_array_off) / line_item_size;
|
||||
U32 line_count = ClampTop(line_count_unclamped, line_count_max);
|
||||
|
||||
U32 col_array_off = line_array_off + line_count*sizeof(CV_C13Line);
|
||||
|
||||
// parse lines
|
||||
U64 *voffs = push_array_no_zero(arena, U64, line_count + 1);
|
||||
U32 *line_nums = push_array_no_zero(arena, U32, line_count);
|
||||
|
||||
{
|
||||
CV_C13Line *line_ptr = (CV_C13Line*)(first + line_array_off);
|
||||
CV_C13Line *line_opl = line_ptr + line_count;
|
||||
|
||||
// TODO(allen): check order correctness here
|
||||
|
||||
U32 i = 0;
|
||||
for (; line_ptr < line_opl; line_ptr += 1, i += 1){
|
||||
voffs[i] = line_ptr->off + secrel_off + sec_base_off;
|
||||
line_nums[i] = CV_C13LineFlags_ExtractLineNumber(line_ptr->flags);
|
||||
}
|
||||
voffs[i] = secrel_opl + sec_base_off;
|
||||
}
|
||||
|
||||
// emit parsed lines
|
||||
CV_C13LinesParsedNode *lines_parsed_node = push_array(arena, CV_C13LinesParsedNode, 1);
|
||||
CV_C13LinesParsed *lines_parsed = &lines_parsed_node->v;
|
||||
lines_parsed->sec_idx = sec_idx;
|
||||
lines_parsed->file_off = file_off;
|
||||
lines_parsed->secrel_base_off = secrel_off;
|
||||
lines_parsed->file_name = file_name;
|
||||
lines_parsed->voffs = voffs;
|
||||
lines_parsed->line_nums = line_nums;
|
||||
lines_parsed->line_count = line_count;
|
||||
SLLQueuePush(node->lines_first, node->lines_last, lines_parsed_node);
|
||||
|
||||
// rjf: advance
|
||||
read_off += sizeof(*file);
|
||||
read_off += line_item_size*line_count;
|
||||
}
|
||||
}break;
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: inlinee line info sub-section
|
||||
//
|
||||
case CV_C13SubSectionKind_InlineeLines:
|
||||
if(sizeof(CV_C13InlineeLinesSig) <= cap)
|
||||
{
|
||||
// rjf: read sig
|
||||
U32 read_off = 0;
|
||||
U64 read_off_opl = node->size;
|
||||
CV_C13InlineeLinesSig *sig = (CV_C13InlineeLinesSig *)(first + read_off);
|
||||
read_off += sizeof(*sig);
|
||||
|
||||
// rjf: read source lines
|
||||
for(;read_off + sizeof(CV_C13InlineeSourceLineHeader) <= read_off_opl;)
|
||||
{
|
||||
// rjf: read next header
|
||||
CV_C13InlineeSourceLineHeader *hdr = (CV_C13InlineeSourceLineHeader *)(first + read_off);
|
||||
read_off += sizeof(*hdr);
|
||||
|
||||
// rjf: file_off -> file_name
|
||||
String8 file_name = {0};
|
||||
if(hdr->file_off + sizeof(CV_C13Checksum) <= file_chksms->size)
|
||||
{
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = pdb_strtbl_string_from_off(strtbl, name_off);
|
||||
}
|
||||
|
||||
// rjf: parse extra files
|
||||
U32 extra_file_count = 0;
|
||||
U32 *extra_files = 0;
|
||||
if(*sig == CV_C13InlineeLinesSig_EXTRA_FILES && read_off+sizeof(U32) <= read_off_opl)
|
||||
{
|
||||
U32 *extra_file_count_ptr = (U32 *)(first + read_off);
|
||||
read_off += sizeof(*extra_file_count_ptr);
|
||||
U32 max_extra_file_count = (read_off_opl-read_off)/sizeof(U32);
|
||||
extra_file_count = Min(*extra_file_count_ptr, max_extra_file_count);
|
||||
extra_files = (U32 *)(first + read_off);
|
||||
read_off += sizeof(*extra_files)*extra_file_count;
|
||||
}
|
||||
|
||||
// rjf: push node for this inlinee lines parsed into this subsection's list
|
||||
CV_C13InlineeLinesParsedNode *n = push_array(arena, CV_C13InlineeLinesParsedNode, 1);
|
||||
SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n);
|
||||
n->v.inlinee = hdr->inlinee;
|
||||
n->v.file_name = file_name;
|
||||
n->v.first_source_ln = hdr->first_source_ln;
|
||||
n->v.extra_file_count = extra_file_count;
|
||||
n->v.extra_files = extra_files;
|
||||
|
||||
// rjf: push node into inlinee parse hash table
|
||||
U64 hash = cv_hash_from_item_id(hdr->inlinee);
|
||||
U64 slot_idx = hash%inlinee_lines_parsed_slots_count;
|
||||
SLLStackPush_N(inlinee_lines_parsed_slots[slot_idx], n, hash_next);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: fill output
|
||||
//
|
||||
CV_C13Parsed *result = push_array(arena, CV_C13Parsed, 1);
|
||||
result->data = c13_data;
|
||||
result->first_sub_section = first;
|
||||
result->last_sub_section = last;
|
||||
result->sub_section_count = count;
|
||||
result->file_chksms_sub_section = file_chksms;
|
||||
result->inlinee_lines_parsed_slots = inlinee_lines_parsed_slots;
|
||||
result->inlinee_lines_parsed_slots_count = inlinee_lines_parsed_slots_count;
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,622 +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 "S16" }
|
||||
{LONG 0x12 "S32" }
|
||||
{QUAD 0x13 "S64" }
|
||||
{OCT 0x14 "S128" }
|
||||
{UCHAR 0x20 "UCHAR" }
|
||||
{USHORT 0x21 "U16" }
|
||||
{ULONG 0x22 "U32" }
|
||||
{UQUAD 0x23 "U64" }
|
||||
{UOCT 0x24 "U128" }
|
||||
{BOOL8 0x30 "B8" }
|
||||
{BOOL16 0x31 "B16" }
|
||||
{BOOL32 0x32 "B32" }
|
||||
{BOOL64 0x33 "B64" }
|
||||
{FLOAT32 0x40 "F32" }
|
||||
{FLOAT64 0x41 "F64" }
|
||||
{FLOAT80 0x42 "F80" }
|
||||
{FLOAT128 0x43 "F128" }
|
||||
{FLOAT48 0x44 "F48" }
|
||||
{FLOAT32PP 0x45 "F32PP" }
|
||||
{FLOAT16 0x46 "F16" }
|
||||
{COMPLEX32 0x50 "ComplexF32" }
|
||||
{COMPLEX64 0x51 "ComplexF64" }
|
||||
{COMPLEX80 0x52 "ComplexF80" }
|
||||
{COMPLEX128 0x53 "ComplexF128" }
|
||||
{BIT 0x60 "" }
|
||||
{PASCHAR 0x61 "" }
|
||||
{BOOL32FF 0x62 "B32FF" }
|
||||
{INT8 0x68 "S8" }
|
||||
{UINT8 0x69 "U8" }
|
||||
{RCHAR 0x70 "char" }
|
||||
{WCHAR 0x71 "WCHAR" }
|
||||
{INT16 0x72 "S16" }
|
||||
{UINT16 0x73 "U16" }
|
||||
{INT32 0x74 "S32" }
|
||||
{UINT32 0x75 "U32" }
|
||||
{INT64 0x76 "S64" }
|
||||
{UINT64 0x77 "U64" }
|
||||
{INT128 0x78 "S128" }
|
||||
{UINT128 0x79 "U128" }
|
||||
{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:
|
||||
{
|
||||
{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}
|
||||
{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,82 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CODEVIEW_STRINGIZE_H
|
||||
#define CODEVIEW_STRINGIZE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Stringize Helper Types
|
||||
|
||||
typedef struct CV_StringizeSymParams{
|
||||
CV_Arch arch;
|
||||
} CV_StringizeSymParams;
|
||||
|
||||
typedef struct CV_StringizeLeafParams{
|
||||
U32 dummy;
|
||||
} CV_StringizeLeafParams;
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Common Stringize Functions
|
||||
|
||||
internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num);
|
||||
|
||||
internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out,
|
||||
CV_LvarAddrRange *range);
|
||||
internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap);
|
||||
internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out,
|
||||
void *first, void *opl);
|
||||
|
||||
internal String8 cv_string_from_basic_type(CV_BasicType basic_type);
|
||||
internal String8 cv_string_from_c13_sub_section_kind(CV_C13SubSectionKind kind);
|
||||
internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg);
|
||||
internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind);
|
||||
internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode);
|
||||
internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind);
|
||||
internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Flags Stringize Functions
|
||||
|
||||
internal void cv_stringize_modifier_flags(Arena *arena, String8List *out,
|
||||
U32 indent, CV_ModifierFlags flags);
|
||||
|
||||
internal void cv_stringize_type_props(Arena *arena, String8List *out,
|
||||
U32 indent, CV_TypeProps props);
|
||||
|
||||
internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out,
|
||||
U32 indent, CV_PointerAttribs attribs);
|
||||
|
||||
internal void cv_stringize_local_flags(Arena *arena, String8List *out,
|
||||
U32 indent, CV_LocalFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Sym Stringize Functions
|
||||
|
||||
internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym);
|
||||
|
||||
internal void cv_stringize_sym_range(Arena *arena, String8List *out,
|
||||
CV_RecRange *range, String8 data,
|
||||
CV_StringizeSymParams *p);
|
||||
internal void cv_stringize_sym_array(Arena *arena, String8List *out,
|
||||
CV_RecRangeArray *ranges, String8 data,
|
||||
CV_StringizeSymParams *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView Leaf Stringize Functions
|
||||
|
||||
internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf);
|
||||
|
||||
internal void cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
CV_RecRange *range, CV_TypeId itype, String8 data,
|
||||
CV_StringizeLeafParams *p);
|
||||
internal void cv_stringize_leaf_array(Arena *arena, String8List *out,
|
||||
CV_RecRangeArray *ranges, CV_TypeId itype_first,
|
||||
String8 data,
|
||||
CV_StringizeLeafParams *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CodeView C13 Stringize Functions
|
||||
|
||||
internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13);
|
||||
|
||||
#endif // CODEVIEW_STRINGIZE_H
|
||||
@@ -1,703 +0,0 @@
|
||||
// Copyright (c) 2024 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("S16");}break;
|
||||
case CV_BasicType_LONG:{result = str8_lit("S32");}break;
|
||||
case CV_BasicType_QUAD:{result = str8_lit("S64");}break;
|
||||
case CV_BasicType_OCT:{result = str8_lit("S128");}break;
|
||||
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
|
||||
case CV_BasicType_USHORT:{result = str8_lit("U16");}break;
|
||||
case CV_BasicType_ULONG:{result = str8_lit("U32");}break;
|
||||
case CV_BasicType_UQUAD:{result = str8_lit("U64");}break;
|
||||
case CV_BasicType_UOCT:{result = str8_lit("U128");}break;
|
||||
case CV_BasicType_BOOL8:{result = str8_lit("B8");}break;
|
||||
case CV_BasicType_BOOL16:{result = str8_lit("B16");}break;
|
||||
case CV_BasicType_BOOL32:{result = str8_lit("B32");}break;
|
||||
case CV_BasicType_BOOL64:{result = str8_lit("B64");}break;
|
||||
case CV_BasicType_FLOAT32:{result = str8_lit("F32");}break;
|
||||
case CV_BasicType_FLOAT64:{result = str8_lit("F64");}break;
|
||||
case CV_BasicType_FLOAT80:{result = str8_lit("F80");}break;
|
||||
case CV_BasicType_FLOAT128:{result = str8_lit("F128");}break;
|
||||
case CV_BasicType_FLOAT48:{result = str8_lit("F48");}break;
|
||||
case CV_BasicType_FLOAT32PP:{result = str8_lit("F32PP");}break;
|
||||
case CV_BasicType_FLOAT16:{result = str8_lit("F16");}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("B32FF");}break;
|
||||
case CV_BasicType_INT8:{result = str8_lit("S8");}break;
|
||||
case CV_BasicType_UINT8:{result = str8_lit("U8");}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("S16");}break;
|
||||
case CV_BasicType_UINT16:{result = str8_lit("U16");}break;
|
||||
case CV_BasicType_INT32:{result = str8_lit("S32");}break;
|
||||
case CV_BasicType_UINT32:{result = str8_lit("U32");}break;
|
||||
case CV_BasicType_INT64:{result = str8_lit("S64");}break;
|
||||
case CV_BasicType_UINT64:{result = str8_lit("U64");}break;
|
||||
case CV_BasicType_INT128:{result = str8_lit("S128");}break;
|
||||
case CV_BasicType_UINT128:{result = str8_lit("U128");}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_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_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_CLASS2:{result = sizeof(CV_LeafStruct2);}break;
|
||||
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,520 +0,0 @@
|
||||
// Copyright (c) 2024 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_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_CLASS2 = 0x1608,
|
||||
CV_LeafKind_STRUCT2 = 0x1609,
|
||||
} CV_LeafKindEnum;
|
||||
|
||||
internal String8 cv_string_from_numeric_kind(CV_NumericKind v);
|
||||
internal String8 cv_string_from_arch(CV_Arch v);
|
||||
internal String8 cv_string_from_sym_kind(CV_SymKind v);
|
||||
internal String8 cv_string_from_basic_type(CV_BasicType v);
|
||||
internal String8 cv_type_name_from_basic_type(CV_BasicType v);
|
||||
internal String8 cv_string_from_leaf_kind(CV_LeafKind v);
|
||||
internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);
|
||||
internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);
|
||||
#endif // CODEVIEW_META_H
|
||||
+1119
-1119
File diff suppressed because it is too large
Load Diff
+1
-11
@@ -11,16 +11,6 @@ typedef U32 COFF_TimeStamp;
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct COFF_Guid COFF_Guid;
|
||||
struct COFF_Guid
|
||||
{
|
||||
U32 data1;
|
||||
U16 data2;
|
||||
U16 data3;
|
||||
U32 data4;
|
||||
U32 data5;
|
||||
};
|
||||
|
||||
typedef U16 COFF_Flags;
|
||||
enum
|
||||
{
|
||||
@@ -48,7 +38,7 @@ enum
|
||||
COFF_MachineType_UNKNOWN = 0x0,
|
||||
COFF_MachineType_X86 = 0x14c,
|
||||
COFF_MachineType_X64 = 0x8664,
|
||||
COFF_MachineType_AM33 = 0x1d3,
|
||||
COFF_MachineType_ARM33 = 0x1d3,
|
||||
COFF_MachineType_ARM = 0x1c0,
|
||||
COFF_MachineType_ARM64 = 0xaa64,
|
||||
COFF_MachineType_ARMNT = 0x1c4,
|
||||
|
||||
+85
-106
@@ -1,106 +1,85 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Kinds
|
||||
|
||||
@table(name display_string)
|
||||
CTRL_EntityKindTable:
|
||||
{
|
||||
{Root "Root" }
|
||||
{Machine "Machine" }
|
||||
{Process "Process" }
|
||||
{Thread "Thread" }
|
||||
{Module "Module" }
|
||||
{EntryPoint "Entry Point" }
|
||||
{DebugInfoPath "Debug Info Path" }
|
||||
}
|
||||
|
||||
@enum CTRL_EntityKind:
|
||||
{
|
||||
Null,
|
||||
@expand(CTRL_EntityKindTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@data(String8) ctrl_entity_kind_display_string_table:
|
||||
{
|
||||
`{0}`,
|
||||
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.display_name)")`
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Exception Codes
|
||||
|
||||
@table(name lower_name code default display_string)
|
||||
CTRL_ExceptionCodeKindTable:
|
||||
{
|
||||
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
|
||||
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
|
||||
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
|
||||
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
|
||||
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
|
||||
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
|
||||
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
|
||||
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
|
||||
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
|
||||
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
|
||||
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
|
||||
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
|
||||
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
|
||||
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
|
||||
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
|
||||
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
|
||||
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
|
||||
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
|
||||
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
|
||||
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
|
||||
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
|
||||
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
|
||||
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
|
||||
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
|
||||
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
|
||||
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
|
||||
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
|
||||
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
|
||||
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
|
||||
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
|
||||
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
|
||||
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
|
||||
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
|
||||
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
|
||||
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
|
||||
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
|
||||
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
||||
}
|
||||
|
||||
@enum CTRL_ExceptionCodeKind:
|
||||
{
|
||||
Null,
|
||||
@expand(CTRL_ExceptionCodeKindTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@data(U32) ctrl_exception_code_kind_code_table:
|
||||
{
|
||||
`0`;
|
||||
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code)`;
|
||||
}
|
||||
|
||||
@data(String8) ctrl_exception_code_kind_display_string_table:
|
||||
{
|
||||
`{0}`;
|
||||
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`;
|
||||
}
|
||||
|
||||
@data(String8) ctrl_exception_code_kind_lowercase_code_string_table:
|
||||
{
|
||||
`{0}`;
|
||||
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`;
|
||||
}
|
||||
|
||||
@data(B8) ctrl_exception_code_kind_default_enable_table:
|
||||
{
|
||||
`0`;
|
||||
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default)`;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tables
|
||||
|
||||
@table(name lower_name code default display_string)
|
||||
CTRL_ExceptionCodeKindTable:
|
||||
{
|
||||
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
|
||||
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
|
||||
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
|
||||
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
|
||||
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
|
||||
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
|
||||
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
|
||||
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
|
||||
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
|
||||
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
|
||||
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
|
||||
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
|
||||
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
|
||||
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
|
||||
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
|
||||
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
|
||||
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
|
||||
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
|
||||
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
|
||||
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
|
||||
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
|
||||
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
|
||||
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
|
||||
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
|
||||
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
|
||||
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
|
||||
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
|
||||
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
|
||||
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
|
||||
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
|
||||
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
|
||||
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
|
||||
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
|
||||
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
|
||||
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
|
||||
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
|
||||
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@table_gen_enum CTRL_ExceptionCodeKind:
|
||||
{
|
||||
`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),`;
|
||||
}
|
||||
|
||||
+3406
-5809
File diff suppressed because it is too large
Load Diff
+603
-1149
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "ctrl_core.c"
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "ctrl_core.c"
|
||||
|
||||
+77
-77
@@ -1,77 +1,77 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CTRL_INC_H
|
||||
#define CTRL_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
|
||||
//
|
||||
// This layer's purpose is to provide access to the asynchronously-running, low
|
||||
// level parts of a debugger, running on the debugger client. This primarily
|
||||
// consists of process control, using the Demon layer (the lower level
|
||||
// abstraction layer for process control, across multiple OSes), but including
|
||||
// higher-level concepts, like stepping, breakpoint resolution, conditional
|
||||
// breakpoint evaluation, and so on. Right now, this just includes process
|
||||
// control *local to the debugger client machine*. But in the future, this can
|
||||
// also include communication to multiple target machines, all running their
|
||||
// own process controller, using the Demon layer.
|
||||
//
|
||||
// This part of a debugger must run asynchronously to prevent blocking the UI -
|
||||
// ideally our debugger is designed such that, if targets are running, the
|
||||
// debugger frontend is still usable for a variety of purposes. So, in short,
|
||||
// the asynchronously-running "control thread", implemented by this layer, is
|
||||
// tasked with communicating with a separately executing "user thread". This
|
||||
// communication happens in two directions - `user -> ctrl`, and the reverse,
|
||||
// `ctrl -> user`.
|
||||
//
|
||||
// In the case of `user -> ctrl` communication, this is done with a ring buffer
|
||||
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
|
||||
// include commands like: launching targets, attaching to targets, killing
|
||||
// targets, detaching from targets, stepping/running, or single stepping.
|
||||
//
|
||||
// In the case of `ctrl -> user` communication, this is done with a ring buffer
|
||||
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
|
||||
// include information about what happened during the execution of targets -
|
||||
// including: process/module/thread creation, process/module/thread deletion,
|
||||
// debug strings, thread name events, memory allocation events, and stop events
|
||||
// (where stops can be caused by: user breakpoints, traps set for stepping,
|
||||
// exceptions, halts, or errors).
|
||||
//
|
||||
// The various stepping algorithms are implemented with two concepts: (a) the
|
||||
// "trap net", and (b) "spoofs".
|
||||
//
|
||||
// A "trap net" is a term which refers to a set of addresses paired with a set
|
||||
// of behavioral flags. Before targets run, trap instructions are written to
|
||||
// these addresses. After targets stop, these addresses are reset to their
|
||||
// original bytes. These trap instructions cause the debugger's targets to
|
||||
// stop executing, and based on which behavioral flags are associated with
|
||||
// the instruction causing the stop, the control thread may adjust parameters
|
||||
// used for running, then continue execution, or it will not resume target
|
||||
// execution, and will report stopped events. These behavioral flags can
|
||||
// include: single-stepping the stopped thread to execute the instruction at
|
||||
// the trap location, saving a stack pointer "check value" (where this check
|
||||
// value is compared against when making decisions about whether to continue
|
||||
// running or not), and so on. It's complicated to unpack why exactly these
|
||||
// behaviors are useful, but the TL;DR of it is that they are used for a
|
||||
// variety of stepping behaviors. For example, when doing a "step into" step,
|
||||
// a `call` instruction can have a trap set at it, and will be marked with
|
||||
// a "single-step-after" trap flag, as well as the "end stepping" trap flag,
|
||||
// such that the step operation will complete after the `call` has executed.
|
||||
//
|
||||
// A "spoof" is a feature the control layer uses to detect when some thread
|
||||
// returns from a particular sub-callstack. This is useful when implementing
|
||||
// "step over" in functions that may be recursive. In short, unlike a trap,
|
||||
// which writes a trap instruction (like `int3`) into an instruction stream,
|
||||
// a spoof overwrites a *return address* on some thread's *stack*. This return
|
||||
// address is not a valid address for executing code -- it is simply a value
|
||||
// that the debugger can recognize, such that it is notified when the thread
|
||||
// returns from some level in a callstack. When the thread exits some function,
|
||||
// it will return to the "spoofed" address, and it will immediately hit an
|
||||
// exception, because the spoofed address will not be a valid address for
|
||||
// code execution. At that point, the debugger can move the thread back to
|
||||
// the pre-spoof return address, and resume execution.
|
||||
|
||||
#include "ctrl_core.h"
|
||||
|
||||
#endif // CTRL_INC_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CTRL_INC_H
|
||||
#define CTRL_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
|
||||
//
|
||||
// This layer's purpose is to provide access to the asynchronously-running, low
|
||||
// level parts of a debugger, running on the debugger client. This primarily
|
||||
// consists of process control, using the Demon layer (the lower level
|
||||
// abstraction layer for process control, across multiple OSes), but including
|
||||
// higher-level concepts, like stepping, breakpoint resolution, conditional
|
||||
// breakpoint evaluation, and so on. Right now, this just includes process
|
||||
// control *local to the debugger client machine*. But in the future, this can
|
||||
// also include communication to multiple target machines, all running their
|
||||
// own process controller, using the Demon layer.
|
||||
//
|
||||
// This part of a debugger must run asynchronously to prevent blocking the UI -
|
||||
// ideally our debugger is designed such that, if targets are running, the
|
||||
// debugger frontend is still usable for a variety of purposes. So, in short,
|
||||
// the asynchronously-running "control thread", implemented by this layer, is
|
||||
// tasked with communicating with a separately executing "user thread". This
|
||||
// communication happens in two directions - `user -> ctrl`, and the reverse,
|
||||
// `ctrl -> user`.
|
||||
//
|
||||
// In the case of `user -> ctrl` communication, this is done with a ring buffer
|
||||
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
|
||||
// include commands like: launching targets, attaching to targets, killing
|
||||
// targets, detaching from targets, stepping/running, or single stepping.
|
||||
//
|
||||
// In the case of `ctrl -> user` communication, this is done with a ring buffer
|
||||
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
|
||||
// include information about what happened during the execution of targets -
|
||||
// including: process/module/thread creation, process/module/thread deletion,
|
||||
// debug strings, thread name events, memory allocation events, and stop events
|
||||
// (where stops can be caused by: user breakpoints, traps set for stepping,
|
||||
// exceptions, halts, or errors).
|
||||
//
|
||||
// The various stepping algorithms are implemented with two concepts: (a) the
|
||||
// "trap net", and (b) "spoofs".
|
||||
//
|
||||
// A "trap net" is a term which refers to a set of addresses paired with a set
|
||||
// of behavioral flags. Before targets run, trap instructions are written to
|
||||
// these addresses. After targets stop, these addresses are reset to their
|
||||
// original bytes. These trap instructions cause the debugger's targets to
|
||||
// stop executing, and based on which behavioral flags are associated with
|
||||
// the instruction causing the stop, the control thread may adjust parameters
|
||||
// used for running, then continue execution, or it will not resume target
|
||||
// execution, and will report stopped events. These behavioral flags can
|
||||
// include: single-stepping the stopped thread to execute the instruction at
|
||||
// the trap location, saving a stack pointer "check value" (where this check
|
||||
// value is compared against when making decisions about whether to continue
|
||||
// running or not), and so on. It's complicated to unpack why exactly these
|
||||
// behaviors are useful, but the TL;DR of it is that they are used for a
|
||||
// variety of stepping behaviors. For example, when doing a "step into" step,
|
||||
// a `call` instruction can have a trap set at it, and will be marked with
|
||||
// a "single-step-after" trap flag, as well as the "end stepping" trap flag,
|
||||
// such that the step operation will complete after the `call` has executed.
|
||||
//
|
||||
// A "spoof" is a feature the control layer uses to detect when some thread
|
||||
// returns from a particular sub-callstack. This is useful when implementing
|
||||
// "step over" in functions that may be recursive. In short, unlike a trap,
|
||||
// which writes a trap instruction (like `int3`) into an instruction stream,
|
||||
// a spoof overwrites a *return address* on some thread's *stack*. This return
|
||||
// address is not a valid address for executing code -- it is simply a value
|
||||
// that the debugger can recognize, such that it is notified when the thread
|
||||
// returns from some level in a callstack. When the thread exits some function,
|
||||
// it will return to the "spoofed" address, and it will immediately hit an
|
||||
// exception, because the spoofed address will not be a valid address for
|
||||
// code execution. At that point, the debugger can move the thread back to
|
||||
// the pre-spoof return address, and resume execution.
|
||||
|
||||
#include "ctrl_core.h"
|
||||
|
||||
#endif //CTRL_INC_H
|
||||
|
||||
@@ -1,188 +1,5 @@
|
||||
// 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_display_string_table[8] =
|
||||
{
|
||||
{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"),
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
|
||||
+221
-74
@@ -1,74 +1,221 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef CTRL_META_H
|
||||
#define CTRL_META_H
|
||||
|
||||
typedef enum CTRL_EntityKind
|
||||
{
|
||||
CTRL_EntityKind_Null,
|
||||
CTRL_EntityKind_Root,
|
||||
CTRL_EntityKind_Machine,
|
||||
CTRL_EntityKind_Process,
|
||||
CTRL_EntityKind_Thread,
|
||||
CTRL_EntityKind_Module,
|
||||
CTRL_EntityKind_EntryPoint,
|
||||
CTRL_EntityKind_DebugInfoPath,
|
||||
CTRL_EntityKind_COUNT,
|
||||
} CTRL_EntityKind;
|
||||
|
||||
typedef enum CTRL_ExceptionCodeKind
|
||||
{
|
||||
CTRL_ExceptionCodeKind_Null,
|
||||
CTRL_ExceptionCodeKind_Win32CtrlC,
|
||||
CTRL_ExceptionCodeKind_Win32CtrlBreak,
|
||||
CTRL_ExceptionCodeKind_Win32WinRTOriginateError,
|
||||
CTRL_ExceptionCodeKind_Win32WinRTTransformError,
|
||||
CTRL_ExceptionCodeKind_Win32RPCCallCancelled,
|
||||
CTRL_ExceptionCodeKind_Win32DatatypeMisalignment,
|
||||
CTRL_ExceptionCodeKind_Win32AccessViolation,
|
||||
CTRL_ExceptionCodeKind_Win32InPageError,
|
||||
CTRL_ExceptionCodeKind_Win32InvalidHandle,
|
||||
CTRL_ExceptionCodeKind_Win32NotEnoughQuota,
|
||||
CTRL_ExceptionCodeKind_Win32IllegalInstruction,
|
||||
CTRL_ExceptionCodeKind_Win32CannotContinueException,
|
||||
CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition,
|
||||
CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointOverflow,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow,
|
||||
CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero,
|
||||
CTRL_ExceptionCodeKind_Win32IntegerOverflow,
|
||||
CTRL_ExceptionCodeKind_Win32PrivilegedInstruction,
|
||||
CTRL_ExceptionCodeKind_Win32StackOverflow,
|
||||
CTRL_ExceptionCodeKind_Win32UnableToLocateDLL,
|
||||
CTRL_ExceptionCodeKind_Win32OrdinalNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32EntryPointNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32DLLInitializationFailed,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps,
|
||||
CTRL_ExceptionCodeKind_Win32AssertionFailed,
|
||||
CTRL_ExceptionCodeKind_Win32ModuleNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
|
||||
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
|
||||
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
|
||||
CTRL_ExceptionCodeKind_COUNT,
|
||||
} CTRL_ExceptionCodeKind;
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
extern String8 ctrl_entity_kind_display_string_table[8];
|
||||
extern U32 ctrl_exception_code_kind_code_table[38];
|
||||
extern String8 ctrl_exception_code_kind_display_string_table[38];
|
||||
extern String8 ctrl_exception_code_kind_lowercase_code_string_table[38];
|
||||
extern B8 ctrl_exception_code_kind_default_enable_table[38];
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
#endif // CTRL_META_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef CTRL_META_H
|
||||
#define CTRL_META_H
|
||||
|
||||
typedef enum CTRL_ExceptionCodeKind
|
||||
{
|
||||
CTRL_ExceptionCodeKind_Null,
|
||||
CTRL_ExceptionCodeKind_Win32CtrlC,
|
||||
CTRL_ExceptionCodeKind_Win32CtrlBreak,
|
||||
CTRL_ExceptionCodeKind_Win32WinRTOriginateError,
|
||||
CTRL_ExceptionCodeKind_Win32WinRTTransformError,
|
||||
CTRL_ExceptionCodeKind_Win32RPCCallCancelled,
|
||||
CTRL_ExceptionCodeKind_Win32DatatypeMisalignment,
|
||||
CTRL_ExceptionCodeKind_Win32AccessViolation,
|
||||
CTRL_ExceptionCodeKind_Win32InPageError,
|
||||
CTRL_ExceptionCodeKind_Win32InvalidHandle,
|
||||
CTRL_ExceptionCodeKind_Win32NotEnoughQuota,
|
||||
CTRL_ExceptionCodeKind_Win32IllegalInstruction,
|
||||
CTRL_ExceptionCodeKind_Win32CannotContinueException,
|
||||
CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition,
|
||||
CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointOverflow,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow,
|
||||
CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero,
|
||||
CTRL_ExceptionCodeKind_Win32IntegerOverflow,
|
||||
CTRL_ExceptionCodeKind_Win32PrivilegedInstruction,
|
||||
CTRL_ExceptionCodeKind_Win32StackOverflow,
|
||||
CTRL_ExceptionCodeKind_Win32UnableToLocateDLL,
|
||||
CTRL_ExceptionCodeKind_Win32OrdinalNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32EntryPointNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32DLLInitializationFailed,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults,
|
||||
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps,
|
||||
CTRL_ExceptionCodeKind_Win32AssertionFailed,
|
||||
CTRL_ExceptionCodeKind_Win32ModuleNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
|
||||
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
|
||||
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
|
||||
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
|
||||
CTRL_ExceptionCodeKind_COUNT
|
||||
} CTRL_ExceptionCodeKind;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
#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,875 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Instruction Decoding/Disassembling Type Functions
|
||||
|
||||
#if !defined(ZYDIS_H)
|
||||
#include "third_party/zydis/zydis.h"
|
||||
#include "third_party/zydis/zydis.c"
|
||||
#endif
|
||||
|
||||
internal DASM_Inst
|
||||
dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Syntax syntax)
|
||||
{
|
||||
DASM_Inst inst = {0};
|
||||
switch(arch)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: x86/x64 disassembly
|
||||
case Arch_x86:
|
||||
case Arch_x64:
|
||||
{
|
||||
// rjf: determine zydis formatter style
|
||||
ZydisFormatterStyle style = ZYDIS_FORMATTER_STYLE_INTEL;
|
||||
switch(syntax)
|
||||
{
|
||||
default:{}break;
|
||||
case DASM_Syntax_Intel:{style = ZYDIS_FORMATTER_STYLE_INTEL;}break;
|
||||
case DASM_Syntax_ATT: {style = ZYDIS_FORMATTER_STYLE_ATT;}break;
|
||||
}
|
||||
|
||||
// rjf: disassemble one instruction
|
||||
ZydisDisassembledInstruction zinst = {0};
|
||||
ZyanStatus status = ZydisDisassemble(ZYDIS_MACHINE_MODE_LONG_64, vaddr, code.str, code.size, &zinst, style);
|
||||
|
||||
// rjf: analyze
|
||||
DASM_InstFlags flags = 0;
|
||||
U64 jump_dest_vaddr = 0;
|
||||
{
|
||||
ZydisDecodedOperand *first_visible_op = (zinst.info.operand_count_visible > 0 ? &zinst.operands[0] : 0);
|
||||
ZydisDecodedOperand *first_op = (zinst.info.operand_count > 0 ? &zinst.operands[0] : 0);
|
||||
ZydisDecodedOperand *second_op = (zinst.info.operand_count > 1 ? &zinst.operands[1] : 0);
|
||||
if(first_visible_op != 0)
|
||||
{
|
||||
ZydisCalcAbsoluteAddress(&zinst.info, first_visible_op, vaddr, &jump_dest_vaddr);
|
||||
}
|
||||
if(first_op != 0 && second_op != 0 && first_op->type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
(first_op->reg.value == ZYDIS_REGISTER_RSP ||
|
||||
first_op->reg.value == ZYDIS_REGISTER_ESP ||
|
||||
first_op->reg.value == ZYDIS_REGISTER_SP))
|
||||
{
|
||||
flags |= DASM_InstFlag_ChangesStackPointer;
|
||||
if(second_op->type != ZYDIS_OPERAND_TYPE_IMMEDIATE)
|
||||
{
|
||||
flags |= DASM_InstFlag_ChangesStackPointerVariably;
|
||||
}
|
||||
}
|
||||
if(zinst.info.attributes & (ZYDIS_ATTRIB_HAS_REP|
|
||||
ZYDIS_ATTRIB_HAS_REPE|
|
||||
ZYDIS_ATTRIB_HAS_REPZ|
|
||||
ZYDIS_ATTRIB_HAS_REPNZ|
|
||||
ZYDIS_ATTRIB_HAS_REPNE))
|
||||
{
|
||||
flags |= DASM_InstFlag_Repeats;
|
||||
}
|
||||
switch(zinst.info.mnemonic)
|
||||
{
|
||||
case ZYDIS_MNEMONIC_CALL:
|
||||
{
|
||||
flags |= DASM_InstFlag_Call;
|
||||
}break;
|
||||
|
||||
case ZYDIS_MNEMONIC_JB:
|
||||
case ZYDIS_MNEMONIC_JBE:
|
||||
case ZYDIS_MNEMONIC_JCXZ:
|
||||
case ZYDIS_MNEMONIC_JECXZ:
|
||||
case ZYDIS_MNEMONIC_JKNZD:
|
||||
case ZYDIS_MNEMONIC_JKZD:
|
||||
case ZYDIS_MNEMONIC_JL:
|
||||
case ZYDIS_MNEMONIC_JLE:
|
||||
case ZYDIS_MNEMONIC_JNB:
|
||||
case ZYDIS_MNEMONIC_JNBE:
|
||||
case ZYDIS_MNEMONIC_JNL:
|
||||
case ZYDIS_MNEMONIC_JNLE:
|
||||
case ZYDIS_MNEMONIC_JNO:
|
||||
case ZYDIS_MNEMONIC_JNP:
|
||||
case ZYDIS_MNEMONIC_JNS:
|
||||
case ZYDIS_MNEMONIC_JNZ:
|
||||
case ZYDIS_MNEMONIC_JO:
|
||||
case ZYDIS_MNEMONIC_JP:
|
||||
case ZYDIS_MNEMONIC_JRCXZ:
|
||||
case ZYDIS_MNEMONIC_JS:
|
||||
case ZYDIS_MNEMONIC_JZ:
|
||||
case ZYDIS_MNEMONIC_LOOP:
|
||||
case ZYDIS_MNEMONIC_LOOPE:
|
||||
case ZYDIS_MNEMONIC_LOOPNE:
|
||||
{
|
||||
flags |= DASM_InstFlag_Branch;
|
||||
}break;
|
||||
|
||||
case ZYDIS_MNEMONIC_JMP:
|
||||
{
|
||||
flags |= DASM_InstFlag_UnconditionalJump;
|
||||
}break;
|
||||
|
||||
case ZYDIS_MNEMONIC_RET:
|
||||
{
|
||||
flags |= DASM_InstFlag_Return;
|
||||
}break;
|
||||
|
||||
case ZYDIS_MNEMONIC_PUSH:
|
||||
case ZYDIS_MNEMONIC_POP:
|
||||
{
|
||||
flags |= DASM_InstFlag_ChangesStackPointer;
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
flags |= DASM_InstFlag_NonFlow;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: convert
|
||||
{
|
||||
inst.flags = flags;
|
||||
inst.size = zinst.info.length;
|
||||
inst.string = push_str8_copy(arena, str8_cstring(zinst.text));
|
||||
inst.jump_dest_vaddr = jump_dest_vaddr;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Control Flow Analysis
|
||||
|
||||
internal DASM_CtrlFlowInfo
|
||||
dasm_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DASM_InstFlags exit_points_mask, Arch arch, U64 vaddr, String8 code)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
DASM_CtrlFlowInfo info = {0};
|
||||
for(U64 offset = 0; offset < code.size;)
|
||||
{
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, arch, vaddr+offset, str8_skip(code, offset), DASM_Syntax_Intel);
|
||||
U64 inst_vaddr = vaddr+offset;
|
||||
offset += inst.size;
|
||||
info.total_size += inst.size;
|
||||
if(inst.flags & exit_points_mask)
|
||||
{
|
||||
DASM_CtrlFlowPoint point = {0};
|
||||
point.inst_flags = inst.flags;
|
||||
point.vaddr = inst_vaddr;
|
||||
point.jump_dest_vaddr = inst.jump_dest_vaddr;
|
||||
DASM_CtrlFlowPointNode *node = push_array(arena, DASM_CtrlFlowPointNode, 1);
|
||||
node->v = point;
|
||||
SLLQueuePush(info.exit_points.first, info.exit_points.last, node);
|
||||
info.exit_points.count += 1;
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return info;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parameter Type Functions
|
||||
|
||||
internal B32
|
||||
dasm_params_match(DASM_Params *a, DASM_Params *b)
|
||||
{
|
||||
B32 result = (a->vaddr == b->vaddr &&
|
||||
a->arch == b->arch &&
|
||||
a->style_flags == b->style_flags &&
|
||||
a->syntax == b->syntax &&
|
||||
a->base_vaddr == b->base_vaddr &&
|
||||
di_key_match(&a->dbgi_key, &b->dbgi_key));
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Line Type Functions
|
||||
|
||||
internal void
|
||||
dasm_line_chunk_list_push(Arena *arena, DASM_LineChunkList *list, U64 cap, DASM_Line *inst)
|
||||
{
|
||||
DASM_LineChunkNode *node = list->last;
|
||||
if(node == 0 || node->count >= node->cap)
|
||||
{
|
||||
node = push_array(arena, DASM_LineChunkNode, 1);
|
||||
node->v = push_array_no_zero(arena, DASM_Line, cap);
|
||||
node->cap = cap;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->node_count += 1;
|
||||
}
|
||||
MemoryCopyStruct(&node->v[node->count], inst);
|
||||
node->count += 1;
|
||||
list->line_count += 1;
|
||||
}
|
||||
|
||||
internal DASM_LineArray
|
||||
dasm_line_array_from_chunk_list(Arena *arena, DASM_LineChunkList *list)
|
||||
{
|
||||
DASM_LineArray array = {0};
|
||||
array.count = list->line_count;
|
||||
array.v = push_array_no_zero(arena, DASM_Line, array.count);
|
||||
U64 idx = 0;
|
||||
for(DASM_LineChunkNode *n = list->first; n != 0; n = n->next)
|
||||
{
|
||||
MemoryCopy(array.v+idx, n->v, sizeof(DASM_Line)*n->count);
|
||||
idx += n->count;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dasm_line_array_idx_from_code_off__linear_scan(DASM_LineArray *array, U64 off)
|
||||
{
|
||||
U64 result = 0;
|
||||
for(U64 idx = 0; idx < array->count; idx += 1)
|
||||
{
|
||||
U64 next_off = (idx+1 < array->count ? array->v[idx+1].code_off : max_U64);
|
||||
if(array->v[idx].code_off <= off && off < next_off)
|
||||
{
|
||||
result = idx;
|
||||
if(!(array->v[idx].flags & DASM_LineFlag_Decorative))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx)
|
||||
{
|
||||
U64 off = 0;
|
||||
if(idx < array->count)
|
||||
{
|
||||
off = array->v[idx].code_off;
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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->slots_count = 1024;
|
||||
dasm_shared->stripes_count = Min(dasm_shared->slots_count, os_get_system_info()->logical_processor_count);
|
||||
dasm_shared->slots = push_array(arena, DASM_Slot, dasm_shared->slots_count);
|
||||
dasm_shared->stripes = push_array(arena, DASM_Stripe, dasm_shared->stripes_count);
|
||||
for(U64 idx = 0; idx < dasm_shared->stripes_count; idx += 1)
|
||||
{
|
||||
dasm_shared->stripes[idx].arena = arena_alloc();
|
||||
dasm_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
|
||||
dasm_shared->stripes[idx].cv = os_condition_variable_alloc();
|
||||
}
|
||||
dasm_shared->u2p_ring_size = KB(64);
|
||||
dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size);
|
||||
dasm_shared->u2p_ring_cv = os_condition_variable_alloc();
|
||||
dasm_shared->u2p_ring_mutex = os_mutex_alloc();
|
||||
dasm_shared->parse_thread_count = 1;
|
||||
dasm_shared->parse_threads = push_array(arena, OS_Handle, dasm_shared->parse_thread_count);
|
||||
for(U64 idx = 0; idx < dasm_shared->parse_thread_count; idx += 1)
|
||||
{
|
||||
dasm_shared->parse_threads[idx] = os_thread_launch(dasm_parse_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
dasm_shared->evictor_detector_thread = os_thread_launch(dasm_evictor_detector_thread__entry_point, 0, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void
|
||||
dasm_user_clock_tick(void)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&dasm_shared->user_clock_idx);
|
||||
}
|
||||
|
||||
internal U64
|
||||
dasm_user_clock_idx(void)
|
||||
{
|
||||
U64 idx = ins_atomic_u64_eval(&dasm_shared->user_clock_idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
internal DASM_Scope *
|
||||
dasm_scope_open(void)
|
||||
{
|
||||
if(dasm_tctx == 0)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
dasm_tctx = push_array(arena, DASM_TCTX, 1);
|
||||
dasm_tctx->arena = arena;
|
||||
}
|
||||
U64 base_pos = arena_pos(dasm_tctx->arena);
|
||||
DASM_Scope *scope = push_array(dasm_tctx->arena, DASM_Scope, 1);
|
||||
scope->base_pos = base_pos;
|
||||
return scope;
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_scope_close(DASM_Scope *scope)
|
||||
{
|
||||
for(DASM_Touch *t = scope->top_touch, *next = 0; t != 0; t = next)
|
||||
{
|
||||
next = t->next;
|
||||
U64 slot_idx = t->hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(t->hash, n->hash) && dasm_params_match(&t->params, &n->params))
|
||||
{
|
||||
ins_atomic_u64_dec_eval(&n->scope_ref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
arena_pop_to(dasm_tctx->arena, scope->base_pos);
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node)
|
||||
{
|
||||
DASM_Touch *touch = push_array(dasm_tctx->arena, DASM_Touch, 1);
|
||||
ins_atomic_u64_inc_eval(&node->scope_ref_count);
|
||||
ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx());
|
||||
touch->hash = node->hash;
|
||||
MemoryCopyStruct(&touch->params, &node->params);
|
||||
touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key);
|
||||
SLLStackPush(scope->top_touch, touch);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal DASM_Info
|
||||
dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
|
||||
{
|
||||
DASM_Info info = {0};
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
U64 slot_idx = hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
B32 found = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(hash, n->hash) && dasm_params_match(params, &n->params))
|
||||
{
|
||||
MemoryCopyStruct(&info, &n->info);
|
||||
found = 1;
|
||||
dasm_scope_touch_node__stripe_r_guarded(scope, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
B32 node_is_new = 0;
|
||||
if(!found)
|
||||
{
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Node *node = 0;
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(hash, n->hash) && dasm_params_match(params, &n->params))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
LogInfoNamedBlockF("dasm_new_node")
|
||||
{
|
||||
log_infof("hash: [0x%I64x 0x%I64x]\n", hash.u64[0], hash.u64[1]);
|
||||
log_infof("vaddr: 0x%I64x\n", params->vaddr);
|
||||
log_infof("arch: %S\n", string_from_arch(params->arch));
|
||||
log_infof("style_flags: 0x%x\n", params->style_flags);
|
||||
log_infof("syntax: %i\n", params->syntax);
|
||||
log_infof("base_vaddr: 0x%I64x\n", params->base_vaddr);
|
||||
log_infof("dbgi_key: [%S 0x%I64x]\n", params->dbgi_key.path, params->dbgi_key.min_timestamp);
|
||||
}
|
||||
node = stripe->free_node;
|
||||
if(node)
|
||||
{
|
||||
SLLStackPop(stripe->free_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = push_array_no_zero(stripe->arena, DASM_Node, 1);
|
||||
}
|
||||
MemoryZeroStruct(node);
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
node->hash = hash;
|
||||
MemoryCopyStruct(&node->params, params);
|
||||
// TODO(rjf): need to make this releasable - currently all exe_paths just leak
|
||||
node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key);
|
||||
node_is_new = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node_is_new)
|
||||
{
|
||||
dasm_u2p_enqueue_req(hash, params, max_U64);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
internal DASM_Info
|
||||
dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128 *hash_out)
|
||||
{
|
||||
DASM_Info result = {0};
|
||||
for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
|
||||
{
|
||||
U128 hash = hs_hash_from_key(key, rewind_idx);
|
||||
result = dasm_info_from_hash_params(scope, hash, params);
|
||||
if(result.lines.count != 0)
|
||||
{
|
||||
if(hash_out)
|
||||
{
|
||||
*hash_out = hash;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32
|
||||
dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us)
|
||||
{
|
||||
B32 good = 0;
|
||||
OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos;
|
||||
U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64))
|
||||
{
|
||||
good = 1;
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &hash);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->vaddr);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->arch);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->style_flags);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->syntax);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->base_vaddr);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbgi_key.path.str, params->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.min_timestamp);
|
||||
dasm_shared->u2p_ring_write_pos += 7;
|
||||
dasm_shared->u2p_ring_write_pos -= dasm_shared->u2p_ring_write_pos%8;
|
||||
break;
|
||||
}
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, endt_us);
|
||||
}
|
||||
if(good)
|
||||
{
|
||||
os_condition_variable_broadcast(dasm_shared->u2p_ring_cv);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
|
||||
{
|
||||
OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+sizeof(U64))
|
||||
{
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, hash_out);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->vaddr);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->arch);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->style_flags);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->syntax);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->base_vaddr);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.path.size);
|
||||
params_out->dbgi_key.path.str = push_array(arena, U8, params_out->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbgi_key.path.str, params_out->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.min_timestamp);
|
||||
dasm_shared->u2p_ring_read_pos += 7;
|
||||
dasm_shared->u2p_ring_read_pos -= dasm_shared->u2p_ring_read_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64);
|
||||
}
|
||||
os_condition_variable_broadcast(dasm_shared->u2p_ring_cv);
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_parse_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[dasm] parse thread #%I64u", (U64)p);
|
||||
for(;;)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
TXT_Scope *txt_scope = txt_scope_open();
|
||||
|
||||
//- rjf: get next request
|
||||
U128 hash = {0};
|
||||
DASM_Params params = {0};
|
||||
dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms);
|
||||
U64 change_gen = fs_change_gen();
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: get dbg info
|
||||
RDI_Parsed *rdi = &di_rdi_parsed_nil;
|
||||
if(got_task && params.dbgi_key.path.size != 0)
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(hs_scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data * arch * addr * dbg -> decode artifacts
|
||||
DASM_LineChunkList line_list = {0};
|
||||
String8List inst_strings = {0};
|
||||
if(got_task)
|
||||
{
|
||||
switch(params.arch)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: x86/x64 decoding
|
||||
case Arch_x64:
|
||||
case Arch_x86:
|
||||
{
|
||||
// rjf: disassemble
|
||||
RDI_SourceFile *last_file = &rdi_nil_element_union.source_file;
|
||||
RDI_Line *last_line = 0;
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
// rjf: disassemble one instruction
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax);
|
||||
if(inst.size == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: push strings derived from voff -> line info
|
||||
if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines))
|
||||
{
|
||||
if(rdi != &di_rdi_parsed_nil)
|
||||
{
|
||||
U64 voff = (params.vaddr+off) - params.base_vaddr;
|
||||
U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff);
|
||||
RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx);
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
RDI_ParsedLineTable unit_line_info = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &unit_line_info);
|
||||
U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff);
|
||||
if(line_info_idx < unit_line_info.count)
|
||||
{
|
||||
RDI_Line *line = &unit_line_info.lines[line_info_idx];
|
||||
RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx);
|
||||
String8 file_normalized_full_path = {0};
|
||||
file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size);
|
||||
if(file != last_file)
|
||||
{
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames &&
|
||||
file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0)
|
||||
{
|
||||
String8 inst_string = str8_lit(">");
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
last_file = file;
|
||||
}
|
||||
if(line && line != last_line && file->normal_full_path_string_idx != 0 &&
|
||||
params.style_flags & DASM_StyleFlag_SourceLines &&
|
||||
file_normalized_full_path.size != 0)
|
||||
{
|
||||
FileProperties props = os_properties_from_file_path(file_normalized_full_path);
|
||||
if(props.modified != 0)
|
||||
{
|
||||
// TODO(rjf): need redirection path - this may map to a different path on the local machine,
|
||||
// need frontend to communicate path remapping info to this layer
|
||||
U128 key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64));
|
||||
TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path);
|
||||
U64 endt_us = max_U64;
|
||||
U128 hash = {0};
|
||||
TXT_TextInfo text_info = {0};
|
||||
for(;os_now_microseconds() <= endt_us;)
|
||||
{
|
||||
text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash);
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(0 < line->line_num && line->line_num < text_info.lines_count)
|
||||
{
|
||||
String8 data = hs_data_from_hash(hs_scope, hash);
|
||||
String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1]));
|
||||
if(line_text.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", line_text);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_line = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push line
|
||||
String8 addr_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_Addresses)
|
||||
{
|
||||
addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &di_rdi_parsed_nil ? " " : "", params.vaddr+off);
|
||||
}
|
||||
String8 code_bytes_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_CodeBytes)
|
||||
{
|
||||
String8List code_bytes_strings = {0};
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{"));
|
||||
for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1)
|
||||
{
|
||||
if(byte_idx < inst.size)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : "");
|
||||
}
|
||||
else if(byte_idx < 8)
|
||||
{
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
}
|
||||
}
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0);
|
||||
}
|
||||
String8 symbol_part = {0};
|
||||
if(inst.jump_dest_vaddr != 0 && rdi != &di_rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames)
|
||||
{
|
||||
RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr);
|
||||
if(scope_idx != 0)
|
||||
{
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx);
|
||||
RDI_U32 procedure_idx = scope->proc_idx;
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx);
|
||||
String8 procedure_name = {0};
|
||||
procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size);
|
||||
if(procedure_name.size != 0)
|
||||
{
|
||||
symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part);
|
||||
DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
|
||||
// rjf: increment
|
||||
off += inst.size;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: artifacts -> value bundle
|
||||
Arena *info_arena = 0;
|
||||
DASM_Info info = {0};
|
||||
if(got_task)
|
||||
{
|
||||
//- rjf: produce joined text
|
||||
Arena *text_arena = arena_alloc();
|
||||
StringJoin text_join = {0};
|
||||
text_join.sep = str8_lit("\n");
|
||||
String8 text = str8_list_join(text_arena, &inst_strings, &text_join);
|
||||
|
||||
//- rjf: produce unique key for this disassembly's text
|
||||
U128 text_key = {0};
|
||||
{
|
||||
U64 hash_data[] =
|
||||
{
|
||||
hash.u64[0],
|
||||
hash.u64[1],
|
||||
params.vaddr,
|
||||
(U64)params.arch,
|
||||
(U64)params.style_flags,
|
||||
(U64)params.syntax,
|
||||
(U64)rdi,
|
||||
0x4d534144,
|
||||
};
|
||||
text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data)));
|
||||
}
|
||||
|
||||
//- rjf: submit text data to hash store
|
||||
U128 text_hash = hs_submit_data(text_key, &text_arena, text);
|
||||
|
||||
//- rjf: produce value bundle
|
||||
info_arena = arena_alloc();
|
||||
info.text_key = text_key;
|
||||
info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
n->info_arena = info_arena;
|
||||
MemoryCopyStruct(&n->info, &info);
|
||||
if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames))
|
||||
{
|
||||
n->change_gen = change_gen;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->change_gen = 0;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txt_scope_close(txt_scope);
|
||||
di_scope_close(di_scope);
|
||||
hs_scope_close(hs_scope);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor/Detector Thread
|
||||
|
||||
internal void
|
||||
dasm_evictor_detector_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[dasm] evictor/detector thread");
|
||||
for(;;)
|
||||
{
|
||||
U64 change_gen = fs_change_gen();
|
||||
U64 check_time_us = os_now_microseconds();
|
||||
U64 check_time_user_clocks = dasm_user_clock_idx();
|
||||
U64 evict_threshold_us = 10*1000000;
|
||||
U64 retry_threshold_us = 1*1000000;
|
||||
U64 evict_threshold_user_clocks = 10;
|
||||
U64 retry_threshold_user_clocks = 10;
|
||||
for(U64 slot_idx = 0; slot_idx < dasm_shared->slots_count; slot_idx += 1)
|
||||
{
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
B32 slot_has_work = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->scope_ref_count == 0 &&
|
||||
n->last_time_touched_us+evict_threshold_us <= check_time_us &&
|
||||
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
|
||||
n->load_count != 0 &&
|
||||
n->is_working == 0)
|
||||
{
|
||||
slot_has_work = 1;
|
||||
break;
|
||||
}
|
||||
if(n->change_gen != 0 && n->change_gen != change_gen &&
|
||||
n->last_time_requested_us+retry_threshold_us <= check_time_us &&
|
||||
n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks)
|
||||
{
|
||||
slot_has_work = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first, *next = 0; n != 0; n = next)
|
||||
{
|
||||
next = n->next;
|
||||
if(n->scope_ref_count == 0 &&
|
||||
n->last_time_touched_us+evict_threshold_us <= check_time_us &&
|
||||
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
|
||||
n->load_count != 0 &&
|
||||
n->is_working == 0)
|
||||
{
|
||||
DLLRemove(slot->first, slot->last, n);
|
||||
if(n->info_arena != 0)
|
||||
{
|
||||
arena_release(n->info_arena);
|
||||
}
|
||||
SLLStackPush(stripe->free_node, n);
|
||||
}
|
||||
if(n->change_gen != 0 && n->change_gen != change_gen &&
|
||||
n->last_time_requested_us+retry_threshold_us <= check_time_us &&
|
||||
n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks)
|
||||
{
|
||||
if(dasm_u2p_enqueue_req(n->hash, &n->params, max_U64))
|
||||
{
|
||||
n->last_time_requested_us = os_now_microseconds();
|
||||
n->last_user_clock_idx_requested = check_time_user_clocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
os_sleep_milliseconds(100);
|
||||
}
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DASM_CACHE_H
|
||||
#define DASM_CACHE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembly Syntax Types
|
||||
|
||||
typedef enum DASM_Syntax
|
||||
{
|
||||
DASM_Syntax_Intel,
|
||||
DASM_Syntax_ATT,
|
||||
DASM_Syntax_COUNT
|
||||
}
|
||||
DASM_Syntax;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembly Instruction Info Types
|
||||
|
||||
typedef U32 DASM_InstFlags;
|
||||
enum
|
||||
{
|
||||
DASM_InstFlag_Call = (1<<0),
|
||||
DASM_InstFlag_Branch = (1<<1),
|
||||
DASM_InstFlag_UnconditionalJump = (1<<2),
|
||||
DASM_InstFlag_Return = (1<<3),
|
||||
DASM_InstFlag_NonFlow = (1<<4),
|
||||
DASM_InstFlag_Repeats = (1<<5),
|
||||
DASM_InstFlag_ChangesStackPointer = (1<<6),
|
||||
DASM_InstFlag_ChangesStackPointerVariably = (1<<7),
|
||||
};
|
||||
|
||||
typedef struct DASM_Inst DASM_Inst;
|
||||
struct DASM_Inst
|
||||
{
|
||||
DASM_InstFlags flags;
|
||||
U32 size;
|
||||
String8 string;
|
||||
U64 jump_dest_vaddr;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Control Flow Analysis Types
|
||||
|
||||
typedef struct DASM_CtrlFlowPoint DASM_CtrlFlowPoint;
|
||||
struct DASM_CtrlFlowPoint
|
||||
{
|
||||
U64 vaddr;
|
||||
U64 jump_dest_vaddr;
|
||||
DASM_InstFlags inst_flags;
|
||||
};
|
||||
|
||||
typedef struct DASM_CtrlFlowPointNode DASM_CtrlFlowPointNode;
|
||||
struct DASM_CtrlFlowPointNode
|
||||
{
|
||||
DASM_CtrlFlowPointNode *next;
|
||||
DASM_CtrlFlowPoint v;
|
||||
};
|
||||
|
||||
typedef struct DASM_CtrlFlowPointList DASM_CtrlFlowPointList;
|
||||
struct DASM_CtrlFlowPointList
|
||||
{
|
||||
DASM_CtrlFlowPointNode *first;
|
||||
DASM_CtrlFlowPointNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DASM_CtrlFlowInfo DASM_CtrlFlowInfo;
|
||||
struct DASM_CtrlFlowInfo
|
||||
{
|
||||
DASM_CtrlFlowPointList exit_points;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembly Text Decoration Types
|
||||
|
||||
typedef U32 DASM_StyleFlags;
|
||||
enum
|
||||
{
|
||||
DASM_StyleFlag_Addresses = (1<<0),
|
||||
DASM_StyleFlag_CodeBytes = (1<<1),
|
||||
DASM_StyleFlag_SourceFilesNames = (1<<2),
|
||||
DASM_StyleFlag_SourceLines = (1<<3),
|
||||
DASM_StyleFlag_SymbolNames = (1<<4),
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembling Parameters Bundle
|
||||
|
||||
typedef struct DASM_Params DASM_Params;
|
||||
struct DASM_Params
|
||||
{
|
||||
U64 vaddr;
|
||||
Arch arch;
|
||||
DASM_StyleFlags style_flags;
|
||||
DASM_Syntax syntax;
|
||||
U64 base_vaddr;
|
||||
DI_Key dbgi_key;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembly Text Line Types
|
||||
|
||||
typedef U32 DASM_LineFlags;
|
||||
enum
|
||||
{
|
||||
DASM_LineFlag_Decorative = (1<<0),
|
||||
};
|
||||
|
||||
typedef struct DASM_Line DASM_Line;
|
||||
struct DASM_Line
|
||||
{
|
||||
U32 code_off;
|
||||
DASM_LineFlags flags;
|
||||
U64 addr;
|
||||
Rng1U64 text_range;
|
||||
};
|
||||
|
||||
typedef struct DASM_LineChunkNode DASM_LineChunkNode;
|
||||
struct DASM_LineChunkNode
|
||||
{
|
||||
DASM_LineChunkNode *next;
|
||||
DASM_Line *v;
|
||||
U64 cap;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DASM_LineChunkList DASM_LineChunkList;
|
||||
struct DASM_LineChunkList
|
||||
{
|
||||
DASM_LineChunkNode *first;
|
||||
DASM_LineChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 line_count;
|
||||
};
|
||||
|
||||
typedef struct DASM_LineArray DASM_LineArray;
|
||||
struct DASM_LineArray
|
||||
{
|
||||
DASM_Line *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Disassembly Result Bundle
|
||||
|
||||
typedef struct DASM_Result DASM_Result;
|
||||
struct DASM_Result
|
||||
{
|
||||
String8 text;
|
||||
DASM_LineArray lines;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Value Bundle Type
|
||||
|
||||
typedef struct DASM_Info DASM_Info;
|
||||
struct DASM_Info
|
||||
{
|
||||
U128 text_key;
|
||||
DASM_LineArray lines;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct DASM_Node DASM_Node;
|
||||
struct DASM_Node
|
||||
{
|
||||
// rjf: links
|
||||
DASM_Node *next;
|
||||
DASM_Node *prev;
|
||||
|
||||
// rjf: key
|
||||
U128 hash;
|
||||
DASM_Params params;
|
||||
|
||||
// rjf: generations
|
||||
U64 change_gen;
|
||||
|
||||
// rjf: value
|
||||
Arena *info_arena;
|
||||
DASM_Info info;
|
||||
|
||||
// rjf: metadata
|
||||
B32 is_working;
|
||||
U64 scope_ref_count;
|
||||
U64 last_time_touched_us;
|
||||
U64 last_user_clock_idx_touched;
|
||||
U64 load_count;
|
||||
U64 last_time_requested_us;
|
||||
U64 last_user_clock_idx_requested;
|
||||
};
|
||||
|
||||
typedef struct DASM_Slot DASM_Slot;
|
||||
struct DASM_Slot
|
||||
{
|
||||
DASM_Node *first;
|
||||
DASM_Node *last;
|
||||
};
|
||||
|
||||
typedef struct DASM_Stripe DASM_Stripe;
|
||||
struct DASM_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
DASM_Node *free_node;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct DASM_Touch DASM_Touch;
|
||||
struct DASM_Touch
|
||||
{
|
||||
DASM_Touch *next;
|
||||
U128 hash;
|
||||
DASM_Params params;
|
||||
};
|
||||
|
||||
typedef struct DASM_Scope DASM_Scope;
|
||||
struct DASM_Scope
|
||||
{
|
||||
DASM_Scope *next;
|
||||
DASM_Touch *top_touch;
|
||||
U64 base_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Context
|
||||
|
||||
typedef struct DASM_TCTX DASM_TCTX;
|
||||
struct DASM_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct DASM_Shared DASM_Shared;
|
||||
struct DASM_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user clock
|
||||
U64 user_clock_idx;
|
||||
|
||||
// rjf: cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
DASM_Slot *slots;
|
||||
DASM_Stripe *stripes;
|
||||
|
||||
// rjf: user -> parse thread
|
||||
U64 u2p_ring_size;
|
||||
U8 *u2p_ring_base;
|
||||
U64 u2p_ring_write_pos;
|
||||
U64 u2p_ring_read_pos;
|
||||
OS_Handle u2p_ring_cv;
|
||||
OS_Handle u2p_ring_mutex;
|
||||
|
||||
// rjf: parse threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
|
||||
// rjf: evictor/detector thread
|
||||
OS_Handle evictor_detector_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static DASM_TCTX *dasm_tctx = 0;
|
||||
global DASM_Shared *dasm_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Instruction Decoding/Disassembling Type Functions
|
||||
|
||||
internal DASM_Inst dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Syntax syntax);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Control Flow Analysis
|
||||
|
||||
internal DASM_CtrlFlowInfo dasm_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DASM_InstFlags exit_points_mask, Arch arch, U64 vaddr, String8 code);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parameter Type Functions
|
||||
|
||||
internal B32 dasm_params_match(DASM_Params *a, DASM_Params *b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Line Type Functions
|
||||
|
||||
internal void dasm_line_chunk_list_push(Arena *arena, DASM_LineChunkList *list, U64 cap, DASM_Line *line);
|
||||
internal DASM_LineArray dasm_line_array_from_chunk_list(Arena *arena, DASM_LineChunkList *list);
|
||||
internal U64 dasm_line_array_idx_from_code_off__linear_scan(DASM_LineArray *array, U64 off);
|
||||
internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void dasm_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void dasm_user_clock_tick(void);
|
||||
internal U64 dasm_user_clock_idx(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
internal DASM_Scope *dasm_scope_open(void);
|
||||
internal void dasm_scope_close(DASM_Scope *scope);
|
||||
internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal DASM_Info dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params);
|
||||
internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128 *hash_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32 dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us);
|
||||
internal void dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out);
|
||||
internal void dasm_parse_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor/Detector Thread
|
||||
|
||||
internal void dasm_evictor_detector_thread__entry_point(void *p);
|
||||
|
||||
#endif // DASM_CACHE_H
|
||||
@@ -1,133 +0,0 @@
|
||||
// Copyright (c) 2024 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 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_required canonical_icon string display_name desc search_tags )
|
||||
// / | | | \___ _________________________________/ | | | | |
|
||||
// / | | | \ / | | | | |
|
||||
D_CmdTable: // | | | | | | | | | |
|
||||
{
|
||||
//- rjf: low-level target control operations
|
||||
{LaunchAndRun 1 1 Entity null Target Null 0 0 0 0 0 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" }
|
||||
{LaunchAndInit 1 1 Entity null Target Null 0 0 0 0 0 1 PlayStepForward "launch_and_init" "Launch and Initialize" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" }
|
||||
{Kill 1 1 Process null Nil Process 0 0 0 0 0 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" }
|
||||
{KillAll 1 1 Null null Nil Null 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" }
|
||||
{Detach 1 1 Process null Nil Process 0 0 0 0 0 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" }
|
||||
{Continue 1 1 Null null Nil Null 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" }
|
||||
{StepIntoInst 1 1 Null null Nil Null 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 Null null Nil Null 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 Null null Nil Null 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 Null null Nil Null 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 Null null Nil Null 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 Null null Nil Null 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" }
|
||||
{SoftHaltRefresh 1 1 Null null Nil Null 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" }
|
||||
{SetThreadIP 0 1 Vaddr null Nil Null 0 0 0 0 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 0 1 Null null Nil Null 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" }
|
||||
{RunToAddress 1 1 Vaddr null Nil Null 0 0 0 0 1 1 PlayStepForward "run_to_address" "Run To Address" "Runs until a particular address is hit." "" }
|
||||
{Run 1 1 Null null Nil Null 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 Null null Nil Null 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then restarts the targets which were used to launch all current processes (if any).""restart,retry" }
|
||||
{StepInto 1 1 Null null Nil Null 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" }
|
||||
{StepOver 1 1 Null null Nil Null 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 Thread null Nil Thread 0 0 0 0 0 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" }
|
||||
{ThawThread 1 1 Thread null Nil Thread 0 0 0 0 0 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" }
|
||||
{FreezeProcess 1 1 Process null Nil Process 0 0 0 0 0 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" }
|
||||
{ThawProcess 1 1 Process null Nil Process 0 0 0 0 0 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" }
|
||||
{FreezeMachine 0 1 Machine null Nil Machine 0 0 0 0 0 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" }
|
||||
{ThawMachine 0 1 Machine null Nil Machine 0 0 0 0 0 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" }
|
||||
{FreezeLocalMachine 1 1 Null null Nil Null 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" }
|
||||
{ThawLocalMachine 1 1 Null null Nil Null 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" }
|
||||
{FreezeEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "freeze_entity" "Freeze Entity" "Freezes an entity." "" }
|
||||
{ThawEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "thaw_entity" "Thaw Entity" "Thaws an entity." "" }
|
||||
|
||||
//- rjf: entity decoration
|
||||
{SetEntityColor 0 0 Null null Nil Null 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" }
|
||||
{SetEntityName 0 0 Null null Nil Null 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" }
|
||||
|
||||
//- rjf: attaching
|
||||
{Attach 1 1 PID null Nil Null 0 0 0 0 0 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: Built-In VieNull w Rules
|
||||
|
||||
@table(coverage_check name name_lower string ih ex xp vb display_name docs schema description)
|
||||
D_ViewRuleTable:
|
||||
{
|
||||
{x Default default "default" - - - x "Default" - "" "" }
|
||||
{x Array array "array" - - x - "Array" x "x:{expr}" "Specifies that a pointer points to N elements, rather than only 1." }
|
||||
{x Slice slice "slice" - - x - "Slice" x "" "Specifies that a pointer within a struct, also containing an integer, points to the number of elements encoded by the integer." }
|
||||
{- List list "list" - - - x "List" - "x:{member}" "Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list." }
|
||||
{x ByteSwap bswap "bswap" x - x - "Byte Swap" x "" "Specifies that all integral evaluations should be byte-swapped, such that their endianness is reversed." }
|
||||
{x Cast cast "cast" - - x - "Cast" x "x:{type}" "Specifies that the expression to which the view rule is applied should be casted to the provided type." }
|
||||
{- BaseDec base_dec "dec" x - - - "Decimal Base (Base 10)" x "" "Specifies that all integral evaluations should appear in base-10 form." }
|
||||
{- BaseBin base_bin "bin" x - - - "Binary Base (Base 2)" x "" "Specifies that all integral evaluations should appear in base-2 form." }
|
||||
{- BaseOct base_oct "oct" x - - - "Octal Base (Base 8)" x "" "Specifies that all integral evaluations should appear in base-8 form." }
|
||||
{- BaseHex base_hex "hex" x - - - "Hexadecimal Base (Base 16)" x "" "Specifies that all integral evaluations should appear in base-16 form." }
|
||||
{- Only only "only" x - - x "Only Specified Members" x "x:{member}" "Specifies that only the specified members should appear in struct, union, or class evaluations." }
|
||||
{- Omit omit "omit" x - - x "Omit Specified Members" x "x:{member}" "Omits a list of member names from appearing in struct, union, or class evaluations." }
|
||||
{- NoAddr no_addr "no_addr" x - - - "Disable Address Values" x "" "Displays only what pointers point to, if possible, without the pointer's address value." }
|
||||
{x Checkbox checkbox "checkbox" - - - - "Checkbox" x "" "Displays simple integer values as checkboxes, encoding zero or nonzero values." }
|
||||
{- ColorRGBA color_rgba "color_rgba" - x - x "Color (RGBA)" x "" "Displays as a color, interpreting the data as encoding R, G, B, and A values." }
|
||||
{x Text text "text" - x - x "Text" x "x:{'lang':lang, 'size':expr}" "Displays as text." }
|
||||
{x Disasm disasm "disasm" - x - x "Disassembly" x "x:{'arch':arch, 'size':expr}" "Displays as disassembled instructions, interpreting the data as raw machine code." }
|
||||
{x Memory memory "memory" - x - x "Memory" x "x:{'size':expr}" "Displays as a raw memory grid." }
|
||||
{- Graph graph "graph" - x - x "Graph" x "" "Displays as a pointer graph, visualizing nodes and edges formed by pointers directly." }
|
||||
{x Bitmap bitmap "bitmap" - x - x "Bitmap" x "x:{'w':expr, 'h':expr, 'fmt':tex2dformat}" "Displays as a bitmap, interpreting the data as raw pixel data." }
|
||||
{- Geo3D geo3d "geo3d" - x - x "Geometry (3D)" x "x:{'count':expr, 'vtx':expr, 'vtx_size':expr}" "Displays as geometry, interpreting the data as index or vertex data." }
|
||||
}
|
||||
|
||||
@enum D_ViewRuleKind:
|
||||
{
|
||||
@expand(D_ViewRuleTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@data(D_ViewRuleSpecInfo) @c_file d_core_view_rule_spec_info_table:
|
||||
{
|
||||
@expand(D_ViewRuleTable a)
|
||||
```{str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.schema)"), str8_lit_comp("$(a.description)"), (D_ViewRuleSpecInfoFlag_Inherited*$(a.ih == "x"))|(D_ViewRuleSpecInfoFlag_Expandable*$(a.ex == "x"))|(D_ViewRuleSpecInfoFlag_ExprResolution*$(a.xp == "x"))|(D_ViewRuleSpecInfoFlag_VizBlockProd*$(a.vb == "x")), }```;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Developer Toggles
|
||||
|
||||
@table(name)
|
||||
D_DevToggleTable:
|
||||
{
|
||||
{telemetry_capture}
|
||||
{simulate_lag}
|
||||
{draw_ui_text_pos}
|
||||
{draw_ui_focus_debug}
|
||||
{draw_ui_box_heatmap}
|
||||
{eval_compiler_tooltips}
|
||||
{eval_watch_key_tooltips}
|
||||
{cmd_context_tooltips}
|
||||
{scratch_mouse_draw}
|
||||
{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,492 +0,0 @@
|
||||
// Copyright (c) 2024 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;
|
||||
String8List env;
|
||||
};
|
||||
|
||||
typedef struct D_TargetArray D_TargetArray;
|
||||
struct D_TargetArray
|
||||
{
|
||||
D_Target *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct D_Breakpoint D_Breakpoint;
|
||||
struct D_Breakpoint
|
||||
{
|
||||
String8 file_path;
|
||||
TxtPt pt;
|
||||
String8 symbol_name;
|
||||
U64 vaddr;
|
||||
String8 condition;
|
||||
};
|
||||
|
||||
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: Tick Output Types
|
||||
|
||||
typedef enum D_EventKind
|
||||
{
|
||||
D_EventKind_Null,
|
||||
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_COUNT
|
||||
}
|
||||
D_EventCause;
|
||||
|
||||
typedef struct D_Event D_Event;
|
||||
struct D_Event
|
||||
{
|
||||
D_EventKind kind;
|
||||
D_EventCause cause;
|
||||
CTRL_Handle thread;
|
||||
U64 vaddr;
|
||||
U64 code;
|
||||
};
|
||||
|
||||
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: View Rules
|
||||
|
||||
typedef U32 D_ViewRuleSpecInfoFlags; // NOTE(rjf): see @view_rule_info
|
||||
enum
|
||||
{
|
||||
D_ViewRuleSpecInfoFlag_Inherited = (1<<0),
|
||||
D_ViewRuleSpecInfoFlag_Expandable = (1<<1),
|
||||
D_ViewRuleSpecInfoFlag_ExprResolution = (1<<2),
|
||||
D_ViewRuleSpecInfoFlag_VizBlockProd = (1<<3),
|
||||
};
|
||||
|
||||
typedef struct D_ViewRuleSpecInfo D_ViewRuleSpecInfo;
|
||||
struct D_ViewRuleSpecInfo
|
||||
{
|
||||
String8 string;
|
||||
String8 display_string;
|
||||
String8 schema;
|
||||
String8 description;
|
||||
D_ViewRuleSpecInfoFlags flags;
|
||||
};
|
||||
|
||||
typedef struct D_ViewRuleSpecInfoArray D_ViewRuleSpecInfoArray;
|
||||
struct D_ViewRuleSpecInfoArray
|
||||
{
|
||||
D_ViewRuleSpecInfo *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct D_ViewRuleSpec D_ViewRuleSpec;
|
||||
struct D_ViewRuleSpec
|
||||
{
|
||||
D_ViewRuleSpec *hash_next;
|
||||
D_ViewRuleSpecInfo info;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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;
|
||||
};
|
||||
|
||||
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-thread unwind cache
|
||||
|
||||
typedef struct D_UnwindCacheNode D_UnwindCacheNode;
|
||||
struct D_UnwindCacheNode
|
||||
{
|
||||
D_UnwindCacheNode *next;
|
||||
D_UnwindCacheNode *prev;
|
||||
U64 reggen;
|
||||
U64 memgen;
|
||||
Arena *arena;
|
||||
CTRL_Handle thread;
|
||||
CTRL_Unwind unwind;
|
||||
};
|
||||
|
||||
typedef struct D_UnwindCacheSlot D_UnwindCacheSlot;
|
||||
struct D_UnwindCacheSlot
|
||||
{
|
||||
D_UnwindCacheNode *first;
|
||||
D_UnwindCacheNode *last;
|
||||
};
|
||||
|
||||
typedef struct D_UnwindCache D_UnwindCache;
|
||||
struct D_UnwindCache
|
||||
{
|
||||
U64 slots_count;
|
||||
D_UnwindCacheSlot *slots;
|
||||
D_UnwindCacheNode *free_node;
|
||||
};
|
||||
|
||||
//- 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;
|
||||
U64 frame_eval_memread_endt_us;
|
||||
|
||||
// rjf: commands
|
||||
Arena *cmds_arena;
|
||||
D_CmdList cmds;
|
||||
|
||||
// rjf: output log key
|
||||
U128 output_log_key;
|
||||
|
||||
// rjf: per-run caches
|
||||
D_UnwindCache unwind_cache;
|
||||
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: view rule specification table
|
||||
U64 view_rule_spec_table_size;
|
||||
D_ViewRuleSpec **view_rule_spec_table;
|
||||
|
||||
// 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_EntityStore *ctrl_entity_store;
|
||||
Arena *ctrl_stop_arena;
|
||||
CTRL_Event ctrl_last_stop_event;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global D_ViewRuleSpec d_nil_core_view_rule_spec = {0};
|
||||
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: View Rule Spec Stateful Functions
|
||||
|
||||
internal void d_register_view_rule_specs(D_ViewRuleSpecInfoArray specs);
|
||||
internal D_ViewRuleSpec *d_view_rule_spec_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Stepping "Trap Net" Builders
|
||||
|
||||
internal CTRL_TrapList d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread);
|
||||
internal CTRL_TrapList d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread);
|
||||
internal CTRL_TrapList d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
//- rjf: voff|vaddr -> symbol lookups
|
||||
internal String8 d_symbol_name_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff, B32 decorated);
|
||||
internal String8 d_symbol_name_from_process_vaddr(Arena *arena, CTRL_Entity *process, U64 vaddr, B32 decorated);
|
||||
|
||||
//- rjf: symbol -> voff lookups
|
||||
internal U64 d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name);
|
||||
internal U64 d_type_num_from_dbgi_key_name(DI_Key *dbgi_key, String8 name);
|
||||
|
||||
//- 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
|
||||
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_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 CTRL_Unwind d_query_cached_unwind_from_thread(CTRL_Entity *thread);
|
||||
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], CTRL_MetaEvalArray *meta_evals);
|
||||
|
||||
#endif // DBG_ENGINE_CORE_H
|
||||
@@ -1,4 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "dbg_engine_core.c"
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright (c) 2024 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,33 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
D_ViewRuleSpecInfo d_core_view_rule_spec_info_table[21] =
|
||||
{
|
||||
{str8_lit_comp("default"), str8_lit_comp("Default"), str8_lit_comp(""), str8_lit_comp(""), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("array"), str8_lit_comp("Array"), str8_lit_comp("x:{expr}"), str8_lit_comp("Specifies that a pointer points to N elements, rather than only 1."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("slice"), str8_lit_comp("Slice"), str8_lit_comp(""), str8_lit_comp("Specifies that a pointer within a struct, also containing an integer, points to the number of elements encoded by the integer."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("list"), str8_lit_comp("List"), str8_lit_comp("x:{member}"), str8_lit_comp("Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("bswap"), str8_lit_comp("Byte Swap"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should be byte-swapped, such that their endianness is reversed."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("cast"), str8_lit_comp("Cast"), str8_lit_comp("x:{type}"), str8_lit_comp("Specifies that the expression to which the view rule is applied should be casted to the provided type."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("dec"), str8_lit_comp("Decimal Base (Base 10)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-10 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("bin"), str8_lit_comp("Binary Base (Base 2)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-2 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("oct"), str8_lit_comp("Octal Base (Base 8)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-8 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("hex"), str8_lit_comp("Hexadecimal Base (Base 16)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-16 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("only"), str8_lit_comp("Only Specified Members"), str8_lit_comp("x:{member}"), str8_lit_comp("Specifies that only the specified members should appear in struct, union, or class evaluations."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("omit"), str8_lit_comp("Omit Specified Members"), str8_lit_comp("x:{member}"), str8_lit_comp("Omits a list of member names from appearing in struct, union, or class evaluations."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("no_addr"), str8_lit_comp("Disable Address Values"), str8_lit_comp(""), str8_lit_comp("Displays only what pointers point to, if possible, without the pointer's address value."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("checkbox"), str8_lit_comp("Checkbox"), str8_lit_comp(""), str8_lit_comp("Displays simple integer values as checkboxes, encoding zero or nonzero values."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), },
|
||||
{str8_lit_comp("color_rgba"), str8_lit_comp("Color (RGBA)"), str8_lit_comp(""), str8_lit_comp("Displays as a color, interpreting the data as encoding R, G, B, and A values."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("text"), str8_lit_comp("Text"), str8_lit_comp("x:{'lang':lang, 'size':expr}"), str8_lit_comp("Displays as text."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), str8_lit_comp("x:{'arch':arch, 'size':expr}"), str8_lit_comp("Displays as disassembled instructions, interpreting the data as raw machine code."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("memory"), str8_lit_comp("Memory"), str8_lit_comp("x:{'size':expr}"), str8_lit_comp("Displays as a raw memory grid."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("graph"), str8_lit_comp("Graph"), str8_lit_comp(""), str8_lit_comp("Displays as a pointer graph, visualizing nodes and edges formed by pointers directly."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("bitmap"), str8_lit_comp("Bitmap"), str8_lit_comp("x:{'w':expr, 'h':expr, 'fmt':tex2dformat}"), str8_lit_comp("Displays as a bitmap, interpreting the data as raw pixel data."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
{str8_lit_comp("geo3d"), str8_lit_comp("Geometry (3D)"), str8_lit_comp("x:{'count':expr, 'vtx':expr, 'vtx_size':expr}"), str8_lit_comp("Displays as geometry, interpreting the data as index or vertex data."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), },
|
||||
};
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef DBG_ENGINE_META_H
|
||||
#define DBG_ENGINE_META_H
|
||||
|
||||
typedef enum D_CmdKind
|
||||
{
|
||||
D_CmdKind_Null,
|
||||
D_CmdKind_LaunchAndRun,
|
||||
D_CmdKind_LaunchAndInit,
|
||||
D_CmdKind_Kill,
|
||||
D_CmdKind_KillAll,
|
||||
D_CmdKind_Detach,
|
||||
D_CmdKind_Continue,
|
||||
D_CmdKind_StepIntoInst,
|
||||
D_CmdKind_StepOverInst,
|
||||
D_CmdKind_StepIntoLine,
|
||||
D_CmdKind_StepOverLine,
|
||||
D_CmdKind_StepOut,
|
||||
D_CmdKind_Halt,
|
||||
D_CmdKind_SoftHaltRefresh,
|
||||
D_CmdKind_SetThreadIP,
|
||||
D_CmdKind_RunToLine,
|
||||
D_CmdKind_RunToAddress,
|
||||
D_CmdKind_Run,
|
||||
D_CmdKind_Restart,
|
||||
D_CmdKind_StepInto,
|
||||
D_CmdKind_StepOver,
|
||||
D_CmdKind_FreezeThread,
|
||||
D_CmdKind_ThawThread,
|
||||
D_CmdKind_FreezeProcess,
|
||||
D_CmdKind_ThawProcess,
|
||||
D_CmdKind_FreezeMachine,
|
||||
D_CmdKind_ThawMachine,
|
||||
D_CmdKind_FreezeLocalMachine,
|
||||
D_CmdKind_ThawLocalMachine,
|
||||
D_CmdKind_FreezeEntity,
|
||||
D_CmdKind_ThawEntity,
|
||||
D_CmdKind_SetEntityColor,
|
||||
D_CmdKind_SetEntityName,
|
||||
D_CmdKind_Attach,
|
||||
D_CmdKind_COUNT,
|
||||
} D_CmdKind;
|
||||
|
||||
typedef enum D_ViewRuleKind
|
||||
{
|
||||
D_ViewRuleKind_Default,
|
||||
D_ViewRuleKind_Array,
|
||||
D_ViewRuleKind_Slice,
|
||||
D_ViewRuleKind_List,
|
||||
D_ViewRuleKind_ByteSwap,
|
||||
D_ViewRuleKind_Cast,
|
||||
D_ViewRuleKind_BaseDec,
|
||||
D_ViewRuleKind_BaseBin,
|
||||
D_ViewRuleKind_BaseOct,
|
||||
D_ViewRuleKind_BaseHex,
|
||||
D_ViewRuleKind_Only,
|
||||
D_ViewRuleKind_Omit,
|
||||
D_ViewRuleKind_NoAddr,
|
||||
D_ViewRuleKind_Checkbox,
|
||||
D_ViewRuleKind_ColorRGBA,
|
||||
D_ViewRuleKind_Text,
|
||||
D_ViewRuleKind_Disasm,
|
||||
D_ViewRuleKind_Memory,
|
||||
D_ViewRuleKind_Graph,
|
||||
D_ViewRuleKind_Bitmap,
|
||||
D_ViewRuleKind_Geo3D,
|
||||
D_ViewRuleKind_COUNT,
|
||||
} D_ViewRuleKind;
|
||||
|
||||
global B32 DEV_telemetry_capture = 0;
|
||||
global B32 DEV_simulate_lag = 0;
|
||||
global B32 DEV_draw_ui_text_pos = 0;
|
||||
global B32 DEV_draw_ui_focus_debug = 0;
|
||||
global B32 DEV_draw_ui_box_heatmap = 0;
|
||||
global B32 DEV_eval_compiler_tooltips = 0;
|
||||
global B32 DEV_eval_watch_key_tooltips = 0;
|
||||
global B32 DEV_cmd_context_tooltips = 0;
|
||||
global B32 DEV_scratch_mouse_draw = 0;
|
||||
global B32 DEV_updating_indicator = 0;
|
||||
struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =
|
||||
{
|
||||
{&DEV_telemetry_capture, str8_lit_comp("telemetry_capture")},
|
||||
{&DEV_simulate_lag, str8_lit_comp("simulate_lag")},
|
||||
{&DEV_draw_ui_text_pos, str8_lit_comp("draw_ui_text_pos")},
|
||||
{&DEV_draw_ui_focus_debug, str8_lit_comp("draw_ui_focus_debug")},
|
||||
{&DEV_draw_ui_box_heatmap, str8_lit_comp("draw_ui_box_heatmap")},
|
||||
{&DEV_eval_compiler_tooltips, str8_lit_comp("eval_compiler_tooltips")},
|
||||
{&DEV_eval_watch_key_tooltips, str8_lit_comp("eval_watch_key_tooltips")},
|
||||
{&DEV_cmd_context_tooltips, str8_lit_comp("cmd_context_tooltips")},
|
||||
{&DEV_scratch_mouse_draw, str8_lit_comp("scratch_mouse_draw")},
|
||||
{&DEV_updating_indicator, str8_lit_comp("updating_indicator")},
|
||||
};
|
||||
#endif // DBG_ENGINE_META_H
|
||||
+1341
-891
File diff suppressed because it is too large
Load Diff
+431
-255
@@ -1,255 +1,431 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DBGI_H
|
||||
#define DBGI_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Key Type
|
||||
|
||||
typedef struct DI_Key DI_Key;
|
||||
struct DI_Key
|
||||
{
|
||||
String8 path;
|
||||
U64 min_timestamp;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyNode DI_KeyNode;
|
||||
struct DI_KeyNode
|
||||
{
|
||||
DI_KeyNode *next;
|
||||
DI_Key v;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyList DI_KeyList;
|
||||
struct DI_KeyList
|
||||
{
|
||||
DI_KeyNode *first;
|
||||
DI_KeyNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DI_KeyArray DI_KeyArray;
|
||||
struct DI_KeyArray
|
||||
{
|
||||
DI_Key *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Types
|
||||
|
||||
typedef enum DI_EventKind
|
||||
{
|
||||
DI_EventKind_Null,
|
||||
DI_EventKind_ConversionStarted,
|
||||
DI_EventKind_ConversionEnded,
|
||||
DI_EventKind_ConversionFailureUnsupportedFormat,
|
||||
DI_EventKind_COUNT
|
||||
}
|
||||
DI_EventKind;
|
||||
|
||||
typedef struct DI_Event DI_Event;
|
||||
struct DI_Event
|
||||
{
|
||||
DI_EventKind kind;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct DI_EventNode DI_EventNode;
|
||||
struct DI_EventNode
|
||||
{
|
||||
DI_EventNode *next;
|
||||
DI_Event v;
|
||||
};
|
||||
|
||||
typedef struct DI_EventList DI_EventList;
|
||||
struct DI_EventList
|
||||
{
|
||||
DI_EventNode *first;
|
||||
DI_EventNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct DI_StringChunkNode DI_StringChunkNode;
|
||||
struct DI_StringChunkNode
|
||||
{
|
||||
DI_StringChunkNode *next;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct DI_Node DI_Node;
|
||||
struct DI_Node
|
||||
{
|
||||
// rjf: links
|
||||
DI_Node *next;
|
||||
DI_Node *prev;
|
||||
|
||||
// rjf: metadata
|
||||
U64 ref_count;
|
||||
U64 touch_count;
|
||||
U64 is_working;
|
||||
U64 last_time_requested_us;
|
||||
|
||||
// rjf: key
|
||||
DI_Key key;
|
||||
|
||||
// rjf: file handles
|
||||
OS_Handle file;
|
||||
OS_Handle file_map;
|
||||
void *file_base;
|
||||
FileProperties file_props;
|
||||
|
||||
// rjf: parse artifacts
|
||||
Arena *arena;
|
||||
RDI_Parsed rdi;
|
||||
B32 parse_done;
|
||||
};
|
||||
|
||||
typedef struct DI_Slot DI_Slot;
|
||||
struct DI_Slot
|
||||
{
|
||||
DI_Node *first;
|
||||
DI_Node *last;
|
||||
};
|
||||
|
||||
typedef struct DI_Stripe DI_Stripe;
|
||||
struct DI_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Node *free_node;
|
||||
DI_StringChunkNode *free_string_chunks[8];
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct DI_Touch DI_Touch;
|
||||
struct DI_Touch
|
||||
{
|
||||
DI_Touch *next;
|
||||
DI_Node *node;
|
||||
};
|
||||
|
||||
typedef struct DI_Scope DI_Scope;
|
||||
struct DI_Scope
|
||||
{
|
||||
DI_Scope *next;
|
||||
DI_Touch *first_touch;
|
||||
DI_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct DI_TCTX DI_TCTX;
|
||||
struct DI_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Scope *free_scope;
|
||||
DI_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
typedef struct DI_Shared DI_Shared;
|
||||
struct DI_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: node cache
|
||||
U64 slots_count;
|
||||
DI_Slot *slots;
|
||||
U64 stripes_count;
|
||||
DI_Stripe *stripes;
|
||||
|
||||
// rjf: user -> parse ring
|
||||
OS_Handle u2p_ring_mutex;
|
||||
OS_Handle u2p_ring_cv;
|
||||
U64 u2p_ring_size;
|
||||
U8 *u2p_ring_base;
|
||||
U64 u2p_ring_write_pos;
|
||||
U64 u2p_ring_read_pos;
|
||||
|
||||
// rjf: parse -> user event ring
|
||||
OS_Handle p2u_ring_mutex;
|
||||
OS_Handle p2u_ring_cv;
|
||||
U64 p2u_ring_size;
|
||||
U8 *p2u_ring_base;
|
||||
U64 p2u_ring_write_pos;
|
||||
U64 p2u_ring_read_pos;
|
||||
|
||||
// rjf: threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DI_Shared *di_shared = 0;
|
||||
thread_static DI_TCTX *di_tctx = 0;
|
||||
global RDI_Parsed di_rdi_parsed_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_key(DI_Key *k);
|
||||
internal DI_Key di_key_zero(void);
|
||||
internal B32 di_key_match(DI_Key *a, DI_Key *b);
|
||||
internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
|
||||
internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src);
|
||||
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key);
|
||||
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void di_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal DI_Scope *di_scope_open(void);
|
||||
internal void di_scope_close(DI_Scope *scope);
|
||||
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Slot Functions
|
||||
|
||||
internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Stripe Functions
|
||||
|
||||
internal U64 di_string_bucket_idx_from_string_size(U64 size);
|
||||
internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Opening/Closing
|
||||
|
||||
internal void di_open(DI_Key *key);
|
||||
internal void di_close(DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
|
||||
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
|
||||
internal void di_p2u_push_event(DI_Event *event);
|
||||
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||
|
||||
internal void di_parse_thread__entry_point(void *p);
|
||||
|
||||
#endif // DBGI_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DBGI_H
|
||||
#define DBGI_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Info Bundle Types
|
||||
|
||||
typedef struct DBGI_Parse DBGI_Parse;
|
||||
struct DBGI_Parse
|
||||
{
|
||||
U64 gen;
|
||||
Arena *arena;
|
||||
void *exe_base;
|
||||
FileProperties exe_props;
|
||||
String8 dbg_path;
|
||||
void *dbg_base;
|
||||
FileProperties dbg_props;
|
||||
PE_BinInfo pe;
|
||||
RADDBG_Parsed rdbg;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Exe -> Debug Forced Override Cache Types
|
||||
|
||||
typedef struct DBGI_ForceNode DBGI_ForceNode;
|
||||
struct DBGI_ForceNode
|
||||
{
|
||||
DBGI_ForceNode *next;
|
||||
String8 exe_path;
|
||||
U64 dbg_path_cap;
|
||||
U64 dbg_path_size;
|
||||
U8 *dbg_path_base;
|
||||
};
|
||||
|
||||
typedef struct DBGI_ForceSlot DBGI_ForceSlot;
|
||||
struct DBGI_ForceSlot
|
||||
{
|
||||
DBGI_ForceNode *first;
|
||||
DBGI_ForceNode *last;
|
||||
};
|
||||
|
||||
typedef struct DBGI_ForceStripe DBGI_ForceStripe;
|
||||
struct DBGI_ForceStripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Binary Cache State Types
|
||||
|
||||
typedef U32 DBGI_BinaryFlags;
|
||||
enum
|
||||
{
|
||||
DBGI_BinaryFlag_ParseInFlight = (1<<0),
|
||||
};
|
||||
|
||||
typedef struct DBGI_Binary DBGI_Binary;
|
||||
struct DBGI_Binary
|
||||
{
|
||||
// rjf: links & metadata
|
||||
DBGI_Binary *next;
|
||||
String8 exe_path;
|
||||
U64 refcount;
|
||||
U64 scope_touch_count;
|
||||
U64 last_time_enqueued_for_parse_us;
|
||||
DBGI_BinaryFlags flags;
|
||||
U64 gen;
|
||||
|
||||
// rjf: exe handles
|
||||
OS_Handle exe_file;
|
||||
OS_Handle exe_file_map;
|
||||
|
||||
// rjf: debug handles
|
||||
OS_Handle dbg_file;
|
||||
OS_Handle dbg_file_map;
|
||||
|
||||
// rjf: analysis results
|
||||
DBGI_Parse parse;
|
||||
};
|
||||
|
||||
typedef struct DBGI_BinarySlot DBGI_BinarySlot;
|
||||
struct DBGI_BinarySlot
|
||||
{
|
||||
DBGI_Binary *first;
|
||||
DBGI_Binary *last;
|
||||
};
|
||||
|
||||
typedef struct DBGI_BinaryStripe DBGI_BinaryStripe;
|
||||
struct DBGI_BinaryStripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Fuzzy Search Cache Types
|
||||
|
||||
typedef enum DBGI_FuzzySearchTarget
|
||||
{
|
||||
DBGI_FuzzySearchTarget_Procedures,
|
||||
DBGI_FuzzySearchTarget_GlobalVariables,
|
||||
DBGI_FuzzySearchTarget_ThreadVariables,
|
||||
DBGI_FuzzySearchTarget_UDTs,
|
||||
DBGI_FuzzySearchTarget_COUNT
|
||||
}
|
||||
DBGI_FuzzySearchTarget;
|
||||
|
||||
typedef struct DBGI_FuzzySearchItem DBGI_FuzzySearchItem;
|
||||
struct DBGI_FuzzySearchItem
|
||||
{
|
||||
U64 idx;
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchItemChunk DBGI_FuzzySearchItemChunk;
|
||||
struct DBGI_FuzzySearchItemChunk
|
||||
{
|
||||
DBGI_FuzzySearchItemChunk *next;
|
||||
DBGI_FuzzySearchItem *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchItemChunkList DBGI_FuzzySearchItemChunkList;
|
||||
struct DBGI_FuzzySearchItemChunkList
|
||||
{
|
||||
DBGI_FuzzySearchItemChunk *first;
|
||||
DBGI_FuzzySearchItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchItemArray DBGI_FuzzySearchItemArray;
|
||||
struct DBGI_FuzzySearchItemArray
|
||||
{
|
||||
DBGI_FuzzySearchItem *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchBucket DBGI_FuzzySearchBucket;
|
||||
struct DBGI_FuzzySearchBucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 exe_path;
|
||||
String8 query;
|
||||
DBGI_FuzzySearchTarget target;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchNode DBGI_FuzzySearchNode;
|
||||
struct DBGI_FuzzySearchNode
|
||||
{
|
||||
DBGI_FuzzySearchNode *next;
|
||||
U128 key;
|
||||
U64 scope_touch_count;
|
||||
U64 last_time_submitted_us;
|
||||
DBGI_FuzzySearchBucket buckets[3];
|
||||
U64 gen;
|
||||
U64 submit_gen;
|
||||
DBGI_FuzzySearchItemArray gen_items;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchSlot DBGI_FuzzySearchSlot;
|
||||
struct DBGI_FuzzySearchSlot
|
||||
{
|
||||
DBGI_FuzzySearchNode *first;
|
||||
DBGI_FuzzySearchNode *last;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchStripe DBGI_FuzzySearchStripe;
|
||||
struct DBGI_FuzzySearchStripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
typedef struct DBGI_FuzzySearchThread DBGI_FuzzySearchThread;
|
||||
struct DBGI_FuzzySearchThread
|
||||
{
|
||||
OS_Handle thread;
|
||||
OS_Handle u2f_ring_mutex;
|
||||
OS_Handle u2f_ring_cv;
|
||||
U64 u2f_ring_size;
|
||||
U8 *u2f_ring_base;
|
||||
U64 u2f_ring_write_pos;
|
||||
U64 u2f_ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Weak Access Scope Types
|
||||
|
||||
typedef struct DBGI_TouchedBinary DBGI_TouchedBinary;
|
||||
struct DBGI_TouchedBinary
|
||||
{
|
||||
DBGI_TouchedBinary *next;
|
||||
DBGI_Binary *binary;
|
||||
};
|
||||
|
||||
typedef struct DBGI_TouchedFuzzySearch DBGI_TouchedFuzzySearch;
|
||||
struct DBGI_TouchedFuzzySearch
|
||||
{
|
||||
DBGI_TouchedFuzzySearch *next;
|
||||
DBGI_FuzzySearchNode *node;
|
||||
};
|
||||
|
||||
typedef struct DBGI_Scope DBGI_Scope;
|
||||
struct DBGI_Scope
|
||||
{
|
||||
DBGI_Scope *next;
|
||||
DBGI_TouchedBinary *first_tb;
|
||||
DBGI_TouchedBinary *last_tb;
|
||||
DBGI_TouchedFuzzySearch *first_tfs;
|
||||
DBGI_TouchedFuzzySearch *last_tfs;
|
||||
};
|
||||
|
||||
typedef struct DBGI_ThreadCtx DBGI_ThreadCtx;
|
||||
struct DBGI_ThreadCtx
|
||||
{
|
||||
Arena *arena;
|
||||
DBGI_Scope *free_scope;
|
||||
DBGI_TouchedBinary *free_tb;
|
||||
DBGI_TouchedFuzzySearch *free_tfs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Types
|
||||
|
||||
typedef enum DBGI_EventKind
|
||||
{
|
||||
DBGI_EventKind_Null,
|
||||
DBGI_EventKind_ConversionStarted,
|
||||
DBGI_EventKind_ConversionEnded,
|
||||
DBGI_EventKind_ConversionFailureUnsupportedFormat,
|
||||
DBGI_EventKind_COUNT
|
||||
}
|
||||
DBGI_EventKind;
|
||||
|
||||
typedef struct DBGI_Event DBGI_Event;
|
||||
struct DBGI_Event
|
||||
{
|
||||
DBGI_EventKind kind;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct DBGI_EventNode DBGI_EventNode;
|
||||
struct DBGI_EventNode
|
||||
{
|
||||
DBGI_EventNode *next;
|
||||
DBGI_Event v;
|
||||
};
|
||||
|
||||
typedef struct DBGI_EventList DBGI_EventList;
|
||||
struct DBGI_EventList
|
||||
{
|
||||
DBGI_EventNode *first;
|
||||
DBGI_EventNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cross-Thread Shared State
|
||||
|
||||
typedef struct DBGI_Shared DBGI_Shared;
|
||||
struct DBGI_Shared
|
||||
{
|
||||
// rjf: arena
|
||||
Arena *arena;
|
||||
|
||||
// rjf: forced override table
|
||||
U64 force_slots_count;
|
||||
U64 force_stripes_count;
|
||||
DBGI_ForceSlot *force_slots;
|
||||
DBGI_ForceStripe *force_stripes;
|
||||
|
||||
// rjf: binary table
|
||||
U64 binary_slots_count;
|
||||
U64 binary_stripes_count;
|
||||
DBGI_BinarySlot *binary_slots;
|
||||
DBGI_BinaryStripe *binary_stripes;
|
||||
|
||||
// rjf: fuzzy search cache table
|
||||
U64 fuzzy_search_slots_count;
|
||||
U64 fuzzy_search_stripes_count;
|
||||
DBGI_FuzzySearchSlot *fuzzy_search_slots;
|
||||
DBGI_FuzzySearchStripe *fuzzy_search_stripes;
|
||||
|
||||
// rjf: user -> parse ring
|
||||
OS_Handle u2p_ring_mutex;
|
||||
OS_Handle u2p_ring_cv;
|
||||
U64 u2p_ring_size;
|
||||
U8 *u2p_ring_base;
|
||||
U64 u2p_ring_write_pos;
|
||||
U64 u2p_ring_read_pos;
|
||||
|
||||
// rjf: parse -> user event ring
|
||||
OS_Handle p2u_ring_mutex;
|
||||
OS_Handle p2u_ring_cv;
|
||||
U64 p2u_ring_size;
|
||||
U8 *p2u_ring_base;
|
||||
U64 p2u_ring_write_pos;
|
||||
U64 p2u_ring_read_pos;
|
||||
|
||||
// rjf: threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
U64 fuzzy_thread_count;
|
||||
DBGI_FuzzySearchThread *fuzzy_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DBGI_Shared *dbgi_shared = 0;
|
||||
thread_static DBGI_ThreadCtx *dbgi_tctx = 0;
|
||||
global DBGI_Parse dbgi_parse_nil =
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{0},
|
||||
{0},
|
||||
0,
|
||||
{0},
|
||||
{0},
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{0},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&raddbg_binary_section_nil, 1,
|
||||
&raddbg_file_path_node_nil, 1,
|
||||
&raddbg_source_file_nil, 1,
|
||||
&raddbg_unit_nil, 1,
|
||||
&raddbg_vmap_entry_nil, 1,
|
||||
&raddbg_type_node_nil, 1,
|
||||
&raddbg_udt_nil, 1,
|
||||
&raddbg_member_nil, 1,
|
||||
&raddbg_enum_member_nil, 1,
|
||||
&raddbg_global_variable_nil, 1,
|
||||
&raddbg_vmap_entry_nil, 1,
|
||||
&raddbg_thread_variable_nil, 1,
|
||||
&raddbg_procedure_nil, 1,
|
||||
&raddbg_scope_nil, 1,
|
||||
&raddbg_voff_nil, 1,
|
||||
&raddbg_vmap_entry_nil, 1,
|
||||
&raddbg_local_nil, 1,
|
||||
&raddbg_location_block_nil, 1,
|
||||
0, 0,
|
||||
0, 0,
|
||||
},
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void dbgi_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread-Context Idempotent Initialization
|
||||
|
||||
internal void dbgi_ensure_tctx_inited(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64 dbgi_hash_from_string(String8 string);
|
||||
internal U64 dbgi_fuzzy_item_num_from_array_element_idx__linear_search(DBGI_FuzzySearchItemArray *array, U64 element_idx);
|
||||
internal String8 dbgi_fuzzy_item_string_from_rdbg_target_element_idx(RADDBG_Parsed *rdbg, DBGI_FuzzySearchTarget target, U64 element_idx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Forced Override Cache Functions
|
||||
|
||||
internal void dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path);
|
||||
internal String8 dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal DBGI_Scope *dbgi_scope_open(void);
|
||||
internal void dbgi_scope_close(DBGI_Scope *scope);
|
||||
internal void dbgi_scope_touch_binary__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_Binary *binary);
|
||||
internal void dbgi_scope_touch_fuzzy_search__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_FuzzySearchNode *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Binary Cache Functions
|
||||
|
||||
internal void dbgi_binary_open(String8 exe_path);
|
||||
internal void dbgi_binary_close(String8 exe_path);
|
||||
internal DBGI_Parse *dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Fuzzy Search Cache Functions
|
||||
|
||||
internal DBGI_FuzzySearchItemArray dbgi_fuzzy_search_items_from_key_exe_query(DBGI_Scope *scope, U128 key, String8 exe_path, String8 query, DBGI_FuzzySearchTarget target, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32 dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us);
|
||||
internal String8 dbgi_u2p_dequeue_exe_path(Arena *arena);
|
||||
|
||||
internal void dbgi_p2u_push_event(DBGI_Event *event);
|
||||
internal DBGI_EventList dbgi_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||
|
||||
internal void dbgi_parse_thread_entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Fuzzy Searching Threads
|
||||
|
||||
internal B32 dbgi_u2f_enqueue_req(U128 key, U64 endt_us);
|
||||
internal void dbgi_u2f_dequeue_req(Arena *arena, DBGI_FuzzySearchThread *thread, U128 *key_out);
|
||||
|
||||
internal int dbgi_qsort_compare_fuzzy_search_items(DBGI_FuzzySearchItem *a, DBGI_FuzzySearchItem *b);
|
||||
|
||||
internal void dbgi_fuzzy_thread__entry_point(void *p);
|
||||
|
||||
#endif //DBGI_H
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//- allen: Acceleration Layer Functions
|
||||
|
||||
//- accel helpers
|
||||
internal DEMON_AccelModule*
|
||||
demon_accel_module_alloc(void){
|
||||
DEMON_AccelModule *result = demon_free_module_accel;
|
||||
if (result != 0){
|
||||
SLLStackPop(demon_free_module_accel);
|
||||
}
|
||||
else{
|
||||
result = push_array_no_zero(demon_ent_arena, DEMON_AccelModule, 1);
|
||||
}
|
||||
MemoryZeroStruct(result);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_accel_module_free(DEMON_AccelModule *module){
|
||||
SLLStackPush(demon_free_module_accel, module);
|
||||
}
|
||||
|
||||
internal DEMON_AccelThread*
|
||||
demon_accel_thread_alloc(void){
|
||||
DEMON_AccelThread *result = demon_free_thread_accel;
|
||||
if (result != 0){
|
||||
SLLStackPop(demon_free_thread_accel);
|
||||
}
|
||||
else{
|
||||
result = push_array_no_zero(demon_ent_arena, DEMON_AccelThread, 1);
|
||||
}
|
||||
MemoryZeroStruct(result);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_accel_thread_free(DEMON_AccelThread *thread){
|
||||
SLLStackPush(demon_free_thread_accel, thread);
|
||||
}
|
||||
|
||||
internal DEMON_AccelThread*
|
||||
demon_accel_from_thread(DEMON_Entity *thread){
|
||||
DEMON_AccelThread *accel = (DEMON_AccelThread*)thread->accel;
|
||||
if (accel == 0){
|
||||
accel = demon_accel_thread_alloc();
|
||||
thread->accel = accel;
|
||||
}
|
||||
return(accel);
|
||||
}
|
||||
|
||||
//- operations on demon objects
|
||||
internal String8
|
||||
demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module){
|
||||
DEMON_AccelModule *accel = (DEMON_AccelModule*)module->accel;
|
||||
|
||||
String8 result = {0};
|
||||
|
||||
// first time
|
||||
if (accel == 0){
|
||||
result = demon_os_full_path_from_module(arena, module);
|
||||
|
||||
// build chain
|
||||
DEMON_AccelModule *last_accel = 0;
|
||||
|
||||
U8 *ptr = result.str;
|
||||
U8 *opl = result.str + result.size;
|
||||
for (;ptr < opl;){
|
||||
U64 size = (U64)(ptr - opl);
|
||||
U64 clamped_size = ClampTop(result.size, sizeof(Member(DEMON_AccelModule, buf)));
|
||||
|
||||
DEMON_AccelModule *node = demon_accel_module_alloc();
|
||||
SLLQueuePush(accel, last_accel, node);
|
||||
node->total_size = result.size;
|
||||
MemoryCopy(node->buf, ptr, clamped_size);
|
||||
|
||||
ptr += clamped_size;
|
||||
}
|
||||
|
||||
// store in module
|
||||
module->accel = accel;
|
||||
}
|
||||
|
||||
// read from accel
|
||||
else{
|
||||
U64 size = accel->total_size;
|
||||
U8 *str = push_array_no_zero(arena, U8, size + 1);
|
||||
|
||||
// copy chain contents to buffer
|
||||
U8 *ptr = str;
|
||||
for (DEMON_AccelModule *node = accel;
|
||||
node != 0;
|
||||
node = node->next){
|
||||
U64 total_size = node->total_size;
|
||||
U64 clamped_size = ClampTop(total_size, sizeof(node->buf));
|
||||
MemoryCopy(ptr, node->buf, clamped_size);
|
||||
ptr += clamped_size;
|
||||
}
|
||||
*ptr = 0;
|
||||
|
||||
// fill result
|
||||
result.str = str;
|
||||
result.size = size;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal U64
|
||||
demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread){
|
||||
// get accel data
|
||||
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
|
||||
|
||||
// fill stack base
|
||||
if (!accel->has_stack_base){
|
||||
accel->has_stack_base = 1;
|
||||
accel->stack_base = demon_os_stack_base_vaddr_from_thread(thread);
|
||||
}
|
||||
|
||||
return(accel->stack_base);
|
||||
}
|
||||
|
||||
internal U64
|
||||
demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread){
|
||||
// get accel data
|
||||
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
|
||||
|
||||
// fill tls root
|
||||
if (!accel->has_tls_root){
|
||||
accel->has_tls_root = 1;
|
||||
accel->tls_root = demon_os_tls_root_vaddr_from_thread(thread);
|
||||
}
|
||||
|
||||
return(accel->tls_root);
|
||||
}
|
||||
|
||||
internal void*
|
||||
demon_accel_read_regs(DEMON_Entity *thread){
|
||||
// get accel data
|
||||
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
|
||||
|
||||
// update reg cache
|
||||
if (accel->reg_cache_time != demon_time){
|
||||
accel->reg_cache_time = demon_time;
|
||||
B32 success = demon_os_read_regs(thread, &accel->regs);
|
||||
if (!success){
|
||||
MemoryZeroStruct(&accel->regs);
|
||||
}
|
||||
}
|
||||
|
||||
return(&accel->regs);
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_accel_write_regs(DEMON_Entity *thread, void *data){
|
||||
// get accel data
|
||||
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
|
||||
|
||||
// low level write
|
||||
B32 success = 0;
|
||||
U64 data_size = 0;
|
||||
switch (thread->arch){
|
||||
case Architecture_x86:
|
||||
{
|
||||
data_size = sizeof(REGS_RegBlockX86);
|
||||
success = demon_os_write_regs_x86(thread, (REGS_RegBlockX86*)data);
|
||||
}break;
|
||||
case Architecture_x64:
|
||||
{
|
||||
data_size = sizeof(REGS_RegBlockX64);
|
||||
success = demon_os_write_regs_x64(thread, (REGS_RegBlockX64*)data);
|
||||
}break;
|
||||
}
|
||||
|
||||
// update cache
|
||||
if (success){
|
||||
accel->reg_cache_time = demon_time;
|
||||
MemoryCopy(&accel->regs, data, data_size);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_accel_low_level_write_regs(DEMON_Entity *thread){
|
||||
// NOTE(allen): This is a tricky one. It's just a way to enable some internal
|
||||
// optimizations. Instead of forcing the user to pass in register data
|
||||
// to write out and copy to the cache, the "user" is other demon code that
|
||||
// knows what it's doing. So it grabs the cache memory (through a call to
|
||||
// `demon_accel_read_regs`) modifies it in place and then calls this.
|
||||
// So we just have to write the cache contents directly out to OS.
|
||||
|
||||
// get accel data
|
||||
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
|
||||
switch (thread->arch){
|
||||
case Architecture_x86:
|
||||
{
|
||||
demon_os_write_regs_x86(thread, &accel->regs.x86);
|
||||
}break;
|
||||
case Architecture_x64:
|
||||
{
|
||||
demon_os_write_regs_x64(thread, &accel->regs.x64);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//- entity accel free
|
||||
internal void
|
||||
demon_accel_free(DEMON_Entity *entity){
|
||||
switch (entity->kind){
|
||||
case DEMON_EntityKind_Module:
|
||||
{
|
||||
if (entity->accel != 0){
|
||||
for (DEMON_AccelModule *node = (DEMON_AccelModule*)entity->accel, *next = 0;
|
||||
node != 0;
|
||||
node = next){
|
||||
next = node->next;
|
||||
demon_accel_module_free(node);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
case DEMON_EntityKind_Thread:
|
||||
{
|
||||
if (entity->accel != 0){
|
||||
demon_accel_thread_free((DEMON_AccelThread*)entity->accel);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_ACCEL_H
|
||||
#define DEMON_ACCEL_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Acceleration Data
|
||||
|
||||
typedef struct DEMON_AccelModule DEMON_AccelModule;
|
||||
struct DEMON_AccelModule
|
||||
{
|
||||
DEMON_AccelModule *next;
|
||||
U64 total_size;
|
||||
U8 buf[240];
|
||||
};
|
||||
|
||||
typedef union DEMON_AccelThread DEMON_AccelThread;
|
||||
union DEMON_AccelThread
|
||||
{
|
||||
DEMON_AccelThread *next;
|
||||
struct{
|
||||
B32 has_stack_base;
|
||||
B32 has_tls_root;
|
||||
U64 stack_base;
|
||||
U64 tls_root;
|
||||
|
||||
U64 reg_cache_time;
|
||||
union{
|
||||
REGS_RegBlockX64 x64;
|
||||
REGS_RegBlockX86 x86;
|
||||
} regs;
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Acceleration Globals
|
||||
|
||||
global DEMON_AccelModule *demon_free_module_accel = 0;
|
||||
global DEMON_AccelThread *demon_free_thread_accel = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Acceleration Layer Functions
|
||||
|
||||
//- accel helpers
|
||||
internal DEMON_AccelModule *demon_accel_module_alloc(void);
|
||||
internal void demon_accel_module_free(DEMON_AccelModule *module);
|
||||
|
||||
internal DEMON_AccelThread *demon_accel_thread_alloc(void);
|
||||
internal void demon_accel_thread_free(DEMON_AccelThread *thread);
|
||||
internal DEMON_AccelThread *demon_accel_from_thread(DEMON_Entity *thread);
|
||||
|
||||
//- operations on demon objects
|
||||
internal String8 demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module);
|
||||
internal U64 demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread);
|
||||
internal U64 demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread);
|
||||
|
||||
internal void* demon_accel_read_regs(DEMON_Entity *thread);
|
||||
internal void demon_accel_write_regs(DEMON_Entity *thread, void *data);
|
||||
|
||||
internal void demon_accel_low_level_write_regs(DEMON_Entity *thread);
|
||||
|
||||
//- entity accel free
|
||||
internal void demon_accel_free(DEMON_Entity *entity);
|
||||
|
||||
#endif //DEMON_ACCEL_H
|
||||
@@ -0,0 +1,270 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): State Safety Helper
|
||||
|
||||
internal B32
|
||||
demon_access_begin(void){
|
||||
B32 result = 0;
|
||||
if (demon_primary_thread){
|
||||
Assert(demon_run_state);
|
||||
result = 1;
|
||||
}
|
||||
else{
|
||||
os_mutex_take(demon_state_mutex);
|
||||
if (demon_run_state){
|
||||
os_mutex_drop(demon_state_mutex);
|
||||
}
|
||||
else{
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_access_end(void){
|
||||
if (!demon_primary_thread){
|
||||
os_mutex_drop(demon_state_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Entity System
|
||||
|
||||
internal void
|
||||
demon_common_init(void){
|
||||
// access control mechanism
|
||||
demon_state_mutex = os_mutex_alloc();
|
||||
|
||||
// time
|
||||
demon_time = 1;
|
||||
|
||||
// setup arena
|
||||
demon_ent_arena = arena_alloc();
|
||||
|
||||
// setup map
|
||||
demon_ent_map = push_array(demon_ent_arena, DEMON_Map, 1);
|
||||
demon_ent_map->bucket_count = 4093;
|
||||
demon_ent_map->buckets = push_array(demon_ent_arena, DEMON_MapSlot*, demon_ent_map->bucket_count);
|
||||
|
||||
// setup entity memory
|
||||
U64 reserve_size_unaligned = (DEMON_ENTITY_CAP)*sizeof(DEMON_Entity);
|
||||
U64 reserve_size = AlignPow2(reserve_size_unaligned, DEMON_ENTITY_CMT_SIZE);
|
||||
demon_ent_cmt = demon_ent_pos = demon_ent_base = (DEMON_Entity*)os_reserve(reserve_size);
|
||||
demon_ent_opl = demon_ent_base + (reserve_size/sizeof(DEMON_Entity));
|
||||
|
||||
Assert(demon_ent_base != 0);
|
||||
|
||||
// setup root
|
||||
demon_ent_root = demon_ent_alloc();
|
||||
demon_ent_root->kind = DEMON_EntityKind_Root;
|
||||
}
|
||||
|
||||
internal DEMON_Entity*
|
||||
demon_ent_alloc(void){
|
||||
DEMON_Entity *result = demon_ent_free;
|
||||
if (result != 0){
|
||||
SLLStackPop(demon_ent_free);
|
||||
}
|
||||
else{
|
||||
if (demon_ent_pos < demon_ent_opl){
|
||||
if (ensure_commit(&demon_ent_cmt, demon_ent_pos + 1, DEMON_ENTITY_CMT_SIZE)){
|
||||
result = demon_ent_pos;
|
||||
demon_ent_pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != 0){
|
||||
U32 gen = result->gen;
|
||||
MemoryZeroStruct(result);
|
||||
result->gen = gen;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
//- handle <-> entity pointer
|
||||
|
||||
internal DEMON_Entity*
|
||||
demon_ent_ptr_from_handle(DEMON_Handle handle){
|
||||
Assert(demon_ent_base != 0);
|
||||
DEMON_Entity *result = 0;
|
||||
U32 index = (U32)(handle & 0xFFFFFFFF);
|
||||
U64 count = (U64)(demon_ent_pos - demon_ent_base);
|
||||
if (0 < index && index < count){
|
||||
DEMON_Entity *entity = demon_ent_base + index;
|
||||
U32 gen = (U32)(handle >> 32);
|
||||
if (gen == entity->gen){
|
||||
result = entity;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal DEMON_Handle
|
||||
demon_ent_handle_from_ptr(DEMON_Entity *entity){
|
||||
Assert(demon_ent_base != 0);
|
||||
DEMON_Handle result = {0};
|
||||
if (demon_ent_base < entity && entity < demon_ent_pos){
|
||||
U32 index = (U32)(entity - demon_ent_base);
|
||||
U64 gen = entity->gen;
|
||||
result = (gen << 32) | index;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
//- high level entity alloc,init,release
|
||||
|
||||
internal DEMON_Entity*
|
||||
demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id){
|
||||
Assert(demon_ent_base != 0);
|
||||
DEMON_Entity *result = demon_ent_alloc();
|
||||
if (result != 0){
|
||||
result->kind = kind;
|
||||
result->id = id;
|
||||
result->arch = parent->arch;
|
||||
result->parent = parent;
|
||||
DLLPushBack(parent->first, parent->last, result);
|
||||
demon_ent_map_save(kind, id, result);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_ent_release_single(DEMON_Entity *entity){
|
||||
switch (entity->kind){
|
||||
case DEMON_EntityKind_Process: demon_proc_count -= 1; break;
|
||||
case DEMON_EntityKind_Thread: demon_thread_count -= 1; break;
|
||||
case DEMON_EntityKind_Module: demon_module_count -= 1; break;
|
||||
}
|
||||
demon_accel_free(entity);
|
||||
demon_os_entity_cleanup(entity);
|
||||
DEMON_MapRef ref = demon_ent_map_find(entity->kind, entity->id);
|
||||
demon_ent_map_erase(ref);
|
||||
entity->gen += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_ent_release_children(DEMON_Entity *root){
|
||||
Assert(demon_ent_base != 0);
|
||||
if (root->first != 0){
|
||||
for (DEMON_Entity *node = root->first;
|
||||
node != 0;
|
||||
node = node->next){
|
||||
demon_ent_release_children(node);
|
||||
demon_ent_release_single(node);
|
||||
}
|
||||
root->last->next = demon_ent_free;
|
||||
demon_ent_free = root->first;
|
||||
root->first = 0;
|
||||
root->last = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_ent_release_root_and_children(DEMON_Entity *root){
|
||||
Assert(demon_ent_base != 0);
|
||||
Assert(root->parent != 0);
|
||||
|
||||
// release children
|
||||
demon_ent_release_children(root);
|
||||
|
||||
// release root
|
||||
DEMON_Entity *parent = root->parent;
|
||||
demon_ent_release_single(root);
|
||||
DLLRemove(parent->first, parent->last, root);
|
||||
SLLStackPush(demon_ent_free, root);
|
||||
}
|
||||
|
||||
//- entity map
|
||||
|
||||
internal U64
|
||||
demon_ent_map_hash(U16 kind, U64 id){
|
||||
U64 result = ((U64)kind << 32) ^ id;
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity){
|
||||
Assert(demon_ent_base != 0);
|
||||
DEMON_Map *map = demon_ent_map;
|
||||
|
||||
// allocate a new slot
|
||||
DEMON_MapSlot *slot = map->free_slots;
|
||||
if (slot != 0){
|
||||
SLLStackPop(map->free_slots);
|
||||
}
|
||||
else{
|
||||
slot = push_array_no_zero(demon_ent_arena, DEMON_MapSlot, 1);
|
||||
}
|
||||
|
||||
// fill slot
|
||||
slot->kind = kind;
|
||||
slot->id = id;
|
||||
slot->entity = entity;
|
||||
|
||||
// insert into bucket
|
||||
U64 hash = demon_ent_map_hash(kind, id);
|
||||
U64 bucket_index = hash%map->bucket_count;
|
||||
SLLStackPush(map->buckets[bucket_index], slot);
|
||||
}
|
||||
|
||||
internal DEMON_MapRef
|
||||
demon_ent_map_find(U16 kind, U64 id){
|
||||
Assert(demon_ent_base != 0);
|
||||
DEMON_Map *map = demon_ent_map;
|
||||
|
||||
// scan bucket
|
||||
DEMON_MapRef result = {0};
|
||||
U64 hash = demon_ent_map_hash(kind, id);
|
||||
U64 bucket_index = hash%map->bucket_count;
|
||||
for (DEMON_MapSlot **ptr = &map->buckets[bucket_index], *slot = 0;
|
||||
*ptr != 0;
|
||||
ptr = &slot->next){
|
||||
slot = *ptr;
|
||||
if (slot->kind == kind && slot->id == id){
|
||||
result.slot = slot;
|
||||
result.ptr_to_slot = ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal DEMON_Entity*
|
||||
demon_ent_map_entity_from_id(U16 kind, U64 id){
|
||||
DEMON_Entity *result = 0;
|
||||
DEMON_MapRef ref = demon_ent_map_find(kind, id);
|
||||
if (ref.slot != 0){
|
||||
result = ref.slot->entity;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
demon_ent_map_erase(DEMON_MapRef ref){
|
||||
Assert(demon_ent_base != 0);
|
||||
DEMON_Map *map = demon_ent_map;
|
||||
|
||||
// move slot to free list
|
||||
if (ref.slot != 0){
|
||||
*ref.ptr_to_slot = ref.slot->next;
|
||||
SLLStackPush(map->free_slots, ref.slot);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Event Helpers
|
||||
|
||||
internal DEMON_Event*
|
||||
demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind){
|
||||
DEMON_EventNode *n = push_array(arena, DEMON_EventNode, 1);
|
||||
DEMON_Event *result = &n->v;
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
result->kind = kind;
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_COMMON_H
|
||||
#define DEMON_COMMON_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: DEMON Entity System
|
||||
|
||||
typedef enum DEMON_EntityKind
|
||||
{
|
||||
DEMON_EntityKind_NULL,
|
||||
|
||||
DEMON_EntityKind_Root,
|
||||
DEMON_EntityKind_Process,
|
||||
DEMON_EntityKind_Thread,
|
||||
DEMON_EntityKind_Module,
|
||||
|
||||
DEMON_EntityKind_COUNT
|
||||
}
|
||||
DEMON_EntityKind;
|
||||
|
||||
typedef struct DEMON_Entity DEMON_Entity;
|
||||
struct DEMON_Entity
|
||||
{
|
||||
// TODO(allen): these could be U32s
|
||||
DEMON_Entity *next;
|
||||
DEMON_Entity *prev;
|
||||
DEMON_Entity *parent;
|
||||
DEMON_Entity *first;
|
||||
DEMON_Entity *last;
|
||||
|
||||
DEMON_EntityKind kind;
|
||||
Architecture arch;
|
||||
U32 gen;
|
||||
U64 id;
|
||||
U64 addr_range_dim;
|
||||
|
||||
// each OS backend decides how to use `ext` for each entity kind
|
||||
union{
|
||||
void *ext;
|
||||
U64 ext_u64;
|
||||
};
|
||||
|
||||
// the accel layer attaches some extra information to some entities
|
||||
void *accel;
|
||||
};
|
||||
|
||||
//- id -> entity map
|
||||
typedef struct DEMON_MapSlot DEMON_MapSlot;
|
||||
struct DEMON_MapSlot
|
||||
{
|
||||
DEMON_MapSlot *next;
|
||||
U16 kind;
|
||||
U64 id;
|
||||
DEMON_Entity *entity;
|
||||
};
|
||||
|
||||
typedef struct DEMON_Map DEMON_Map;
|
||||
struct DEMON_Map
|
||||
{
|
||||
DEMON_MapSlot **buckets;
|
||||
U64 bucket_count;
|
||||
DEMON_MapSlot *free_slots;
|
||||
};
|
||||
|
||||
typedef struct DEMON_MapRef DEMON_MapRef;
|
||||
struct DEMON_MapRef
|
||||
{
|
||||
DEMON_MapSlot *slot;
|
||||
DEMON_MapSlot **ptr_to_slot;
|
||||
};
|
||||
|
||||
//- rjf: entity extrusive list
|
||||
|
||||
typedef struct DEMON_EntityNode DEMON_EntityNode;
|
||||
struct DEMON_EntityNode
|
||||
{
|
||||
DEMON_EntityNode *next;
|
||||
DEMON_Entity *entity;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Demon Globals
|
||||
|
||||
thread_static B32 demon_primary_thread = 0;
|
||||
global B32 demon_run_state = 0;
|
||||
global OS_Handle demon_state_mutex = {0};
|
||||
|
||||
global U64 demon_time = 0;
|
||||
|
||||
global Arena *demon_ent_arena = 0;
|
||||
global DEMON_Map *demon_ent_map = 0;
|
||||
|
||||
global DEMON_Entity *demon_ent_free = 0;
|
||||
global DEMON_Entity *demon_ent_root = 0;
|
||||
|
||||
global DEMON_Entity *demon_ent_base = 0;
|
||||
global DEMON_Entity *demon_ent_pos = 0;
|
||||
global DEMON_Entity *demon_ent_opl = 0;
|
||||
global void *demon_ent_cmt = 0;
|
||||
|
||||
global U64 demon_proc_count = 0;
|
||||
global U64 demon_thread_count = 0;
|
||||
global U64 demon_module_count = 0;
|
||||
|
||||
#if !defined(DEMON_ENTITY_CMT_SIZE)
|
||||
# define DEMON_ENTITY_CMT_SIZE KB(64)
|
||||
#endif
|
||||
#if !defined(DEMON_ENTITY_CAP)
|
||||
# define DEMON_ENTITY_CAP 65536
|
||||
#endif
|
||||
|
||||
StaticAssert(IsPow2(DEMON_ENTITY_CMT_SIZE), check_demon_entity_cmt_size);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: State Safety Helper
|
||||
|
||||
internal B32 demon_access_begin(void);
|
||||
internal void demon_access_end(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Entity System
|
||||
|
||||
internal void demon_common_init(void);
|
||||
internal DEMON_Entity* demon_ent_alloc(void);
|
||||
|
||||
//- handle <-> entity pointer
|
||||
internal DEMON_Entity* demon_ent_ptr_from_handle(DEMON_Handle handle);
|
||||
internal DEMON_Handle demon_ent_handle_from_ptr(DEMON_Entity *entity);
|
||||
|
||||
//- high level entity alloc,init,release
|
||||
internal DEMON_Entity* demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id);
|
||||
internal void demon_ent_release_single(DEMON_Entity *entity);
|
||||
internal void demon_ent_release_children(DEMON_Entity *root);
|
||||
internal void demon_ent_release_root_and_children(DEMON_Entity *root);
|
||||
|
||||
//- entity map
|
||||
internal U64 demon_ent_map_hash(U16 kind, U64 id);
|
||||
internal void demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity);
|
||||
internal DEMON_MapRef demon_ent_map_find(U16 kind, U64 id);
|
||||
internal DEMON_Entity* demon_ent_map_entity_from_id(U16 kind, U64 id);
|
||||
internal void demon_ent_map_erase(DEMON_MapRef map_ref);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Event Helpers
|
||||
|
||||
internal DEMON_Event* demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind);
|
||||
|
||||
#endif //DEMON_COMMON_H
|
||||
+871
-158
File diff suppressed because it is too large
Load Diff
+293
-242
@@ -1,242 +1,293 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_H
|
||||
#define DEMON_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Control-Thread-Only Context
|
||||
//
|
||||
// An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only
|
||||
// used by the thread which called it. All APIs which can ONLY run on the
|
||||
// control thread, which blocks to control & receive events, will take this
|
||||
// parameter. All other APIs can be called from any thread.
|
||||
|
||||
typedef struct DMN_CtrlCtx DMN_CtrlCtx;
|
||||
struct DMN_CtrlCtx
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handle Types
|
||||
|
||||
typedef union DMN_Handle DMN_Handle;
|
||||
union DMN_Handle
|
||||
{
|
||||
U32 u32[2];
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct DMN_HandleNode DMN_HandleNode;
|
||||
struct DMN_HandleNode
|
||||
{
|
||||
DMN_HandleNode *next;
|
||||
DMN_Handle v;
|
||||
};
|
||||
|
||||
typedef struct DMN_HandleList DMN_HandleList;
|
||||
struct DMN_HandleList
|
||||
{
|
||||
DMN_HandleNode *first;
|
||||
DMN_HandleNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DMN_HandleArray DMN_HandleArray;
|
||||
struct DMN_HandleArray
|
||||
{
|
||||
DMN_Handle *handles;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/demon.meta.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Types
|
||||
|
||||
typedef struct DMN_Event DMN_Event;
|
||||
struct DMN_Event
|
||||
{
|
||||
DMN_EventKind kind;
|
||||
DMN_ErrorKind error_kind;
|
||||
DMN_MemoryEventKind memory_kind;
|
||||
DMN_ExceptionKind exception_kind;
|
||||
DMN_Handle process;
|
||||
DMN_Handle thread;
|
||||
DMN_Handle module;
|
||||
Arch arch;
|
||||
U64 address;
|
||||
U64 size;
|
||||
String8 string;
|
||||
U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully)
|
||||
U32 flags;
|
||||
S32 signo;
|
||||
S32 sigcode;
|
||||
U64 instruction_pointer;
|
||||
U64 stack_pointer;
|
||||
U64 user_data;
|
||||
B32 exception_repeated;
|
||||
};
|
||||
|
||||
typedef struct DMN_EventNode DMN_EventNode;
|
||||
struct DMN_EventNode
|
||||
{
|
||||
DMN_EventNode *next;
|
||||
DMN_Event v;
|
||||
};
|
||||
|
||||
typedef struct DMN_EventList DMN_EventList;
|
||||
struct DMN_EventList
|
||||
{
|
||||
DMN_EventNode *first;
|
||||
DMN_EventNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Run Control Types
|
||||
|
||||
typedef struct DMN_Trap DMN_Trap;
|
||||
struct DMN_Trap
|
||||
{
|
||||
DMN_Handle process;
|
||||
U64 vaddr;
|
||||
U64 id;
|
||||
};
|
||||
|
||||
typedef struct DMN_TrapChunkNode DMN_TrapChunkNode;
|
||||
struct DMN_TrapChunkNode
|
||||
{
|
||||
DMN_TrapChunkNode *next;
|
||||
DMN_Trap *v;
|
||||
U64 cap;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DMN_TrapChunkList DMN_TrapChunkList;
|
||||
struct DMN_TrapChunkList
|
||||
{
|
||||
DMN_TrapChunkNode *first;
|
||||
DMN_TrapChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 trap_count;
|
||||
};
|
||||
|
||||
typedef struct DMN_RunCtrls DMN_RunCtrls;
|
||||
struct DMN_RunCtrls
|
||||
{
|
||||
DMN_Handle single_step_thread;
|
||||
B8 ignore_previous_exception;
|
||||
B8 run_entities_are_unfrozen;
|
||||
B8 run_entities_are_processes;
|
||||
DMN_Handle *run_entities;
|
||||
U64 run_entity_count;
|
||||
DMN_TrapChunkList traps;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: System Process Listing Types
|
||||
|
||||
typedef struct DMN_ProcessIter DMN_ProcessIter;
|
||||
struct DMN_ProcessIter
|
||||
{
|
||||
U64 v[2];
|
||||
};
|
||||
|
||||
typedef struct DMN_ProcessInfo DMN_ProcessInfo;
|
||||
struct DMN_ProcessInfo
|
||||
{
|
||||
String8 name;
|
||||
U32 pid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
|
||||
|
||||
//- rjf: handles
|
||||
internal DMN_Handle dmn_handle_zero(void);
|
||||
internal B32 dmn_handle_match(DMN_Handle a, DMN_Handle b);
|
||||
|
||||
//- rjf: trap chunk lists
|
||||
internal void dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap);
|
||||
internal void dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
|
||||
internal void dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
|
||||
|
||||
//- rjf: handle lists
|
||||
internal void dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle);
|
||||
internal DMN_HandleArray dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list);
|
||||
internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src);
|
||||
|
||||
//- rjf: event list building
|
||||
internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
|
||||
|
||||
internal U64 dmn_rip_from_thread(DMN_Handle thread);
|
||||
internal U64 dmn_rsp_from_thread(DMN_Handle thread);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
|
||||
|
||||
internal void dmn_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS)
|
||||
|
||||
internal DMN_CtrlCtx *dmn_ctrl_begin(void);
|
||||
internal void dmn_ctrl_exclusive_access_begin(void);
|
||||
internal void dmn_ctrl_exclusive_access_end(void);
|
||||
#define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end())
|
||||
internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params);
|
||||
internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid);
|
||||
internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code);
|
||||
internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process);
|
||||
internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS)
|
||||
|
||||
internal void dmn_halt(U64 code, U64 user_data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
|
||||
|
||||
//- rjf: run/memory/register counters
|
||||
internal U64 dmn_run_gen(void);
|
||||
internal U64 dmn_mem_gen(void);
|
||||
internal U64 dmn_reg_gen(void);
|
||||
|
||||
//- rjf: non-blocking-control-thread access barriers
|
||||
internal B32 dmn_access_open(void);
|
||||
internal void dmn_access_close(void);
|
||||
#define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close())
|
||||
|
||||
//- rjf: processes
|
||||
internal U64 dmn_process_memory_reserve(DMN_Handle process, U64 vaddr, U64 size);
|
||||
internal void dmn_process_memory_commit(DMN_Handle process, U64 vaddr, U64 size);
|
||||
internal void dmn_process_memory_decommit(DMN_Handle process, U64 vaddr, U64 size);
|
||||
internal void dmn_process_memory_release(DMN_Handle process, U64 vaddr, U64 size);
|
||||
internal void dmn_process_memory_protect(DMN_Handle process, U64 vaddr, U64 size, OS_AccessFlags flags);
|
||||
internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
|
||||
#define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
#define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
|
||||
//- rjf: threads
|
||||
internal Arch dmn_arch_from_thread(DMN_Handle handle);
|
||||
internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle);
|
||||
internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle);
|
||||
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
|
||||
internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block);
|
||||
|
||||
//- rjf: system process listing
|
||||
internal void dmn_process_iter_begin(DMN_ProcessIter *iter);
|
||||
internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out);
|
||||
internal void dmn_process_iter_end(DMN_ProcessIter *iter);
|
||||
|
||||
#endif // DEMON_CORE_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_H
|
||||
#define DEMON_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Demon Low Level Entities
|
||||
|
||||
typedef U64 DEMON_Handle;
|
||||
|
||||
typedef struct DEMON_HandleNode DEMON_HandleNode;
|
||||
struct DEMON_HandleNode
|
||||
{
|
||||
DEMON_HandleNode *next;
|
||||
DEMON_Handle v;
|
||||
};
|
||||
|
||||
typedef struct DEMON_HandleList DEMON_HandleList;
|
||||
struct DEMON_HandleList
|
||||
{
|
||||
DEMON_HandleNode *first;
|
||||
DEMON_HandleNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DEMON_HandleArray DEMON_HandleArray;
|
||||
struct DEMON_HandleArray
|
||||
{
|
||||
DEMON_Handle *handles;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Memory Protection Flags
|
||||
|
||||
typedef U32 DEMON_MemoryProtectFlags;
|
||||
enum{
|
||||
DEMON_MemoryProtectFlag_Read = (1<<0),
|
||||
DEMON_MemoryProtectFlag_Write = (1<<1),
|
||||
DEMON_MemoryProtectFlag_Execute = (1<<2),
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Demon Event Types
|
||||
|
||||
typedef enum DEMON_EventKind
|
||||
{
|
||||
DEMON_EventKind_Null,
|
||||
DEMON_EventKind_Error,
|
||||
DEMON_EventKind_HandshakeComplete,
|
||||
DEMON_EventKind_CreateProcess,
|
||||
DEMON_EventKind_ExitProcess,
|
||||
DEMON_EventKind_CreateThread,
|
||||
DEMON_EventKind_ExitThread,
|
||||
DEMON_EventKind_LoadModule,
|
||||
DEMON_EventKind_UnloadModule,
|
||||
DEMON_EventKind_Breakpoint,
|
||||
DEMON_EventKind_Trap,
|
||||
DEMON_EventKind_SingleStep,
|
||||
DEMON_EventKind_Exception,
|
||||
DEMON_EventKind_Halt,
|
||||
DEMON_EventKind_Memory,
|
||||
DEMON_EventKind_DebugString,
|
||||
DEMON_EventKind_SetThreadName,
|
||||
DEMON_EventKind_COUNT
|
||||
}
|
||||
DEMON_EventKind;
|
||||
|
||||
typedef enum DEMON_ErrorKind
|
||||
{
|
||||
DEMON_ErrorKind_Null,
|
||||
DEMON_ErrorKind_NotInitialized,
|
||||
DEMON_ErrorKind_NotAttached,
|
||||
DEMON_ErrorKind_UnexpectedFailure,
|
||||
DEMON_ErrorKind_InvalidHandle,
|
||||
}
|
||||
DEMON_ErrorKind;
|
||||
|
||||
typedef enum DEMON_MemoryEventKind
|
||||
{
|
||||
DEMON_MemoryEventKind_Null,
|
||||
DEMON_MemoryEventKind_Commit,
|
||||
DEMON_MemoryEventKind_Reserve,
|
||||
DEMON_MemoryEventKind_Decommit,
|
||||
DEMON_MemoryEventKind_Release,
|
||||
DEMON_MemoryEventKind_COUNT
|
||||
}
|
||||
DEMON_MemoryEventKind;
|
||||
|
||||
typedef enum DEMON_ExceptionKind
|
||||
{
|
||||
DEMON_ExceptionKind_Null,
|
||||
DEMON_ExceptionKind_MemoryRead,
|
||||
DEMON_ExceptionKind_MemoryWrite,
|
||||
DEMON_ExceptionKind_MemoryExecute,
|
||||
DEMON_ExceptionKind_CppThrow,
|
||||
DEMON_ExceptionKind_COUNT
|
||||
}
|
||||
DEMON_ExceptionKind;
|
||||
|
||||
typedef struct DEMON_Event DEMON_Event;
|
||||
struct DEMON_Event
|
||||
{
|
||||
// TODO(allen): condense
|
||||
DEMON_EventKind kind;
|
||||
DEMON_ErrorKind error_kind;
|
||||
DEMON_MemoryEventKind memory_kind;
|
||||
DEMON_ExceptionKind exception_kind;
|
||||
DEMON_Handle process;
|
||||
DEMON_Handle thread;
|
||||
DEMON_Handle module;
|
||||
U64 address;
|
||||
U64 size;
|
||||
String8 string;
|
||||
U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully)
|
||||
U32 flags;
|
||||
S32 signo;
|
||||
S32 sigcode;
|
||||
U64 instruction_pointer;
|
||||
U64 stack_pointer;
|
||||
U64 user_data;
|
||||
B32 exception_repeated;
|
||||
};
|
||||
|
||||
typedef struct DEMON_EventNode DEMON_EventNode;
|
||||
struct DEMON_EventNode
|
||||
{
|
||||
DEMON_EventNode *next;
|
||||
DEMON_Event v;
|
||||
};
|
||||
|
||||
typedef struct DEMON_EventList DEMON_EventList;
|
||||
struct DEMON_EventList
|
||||
{
|
||||
DEMON_EventNode *first;
|
||||
DEMON_EventNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Demon Run Control Types
|
||||
|
||||
typedef struct DEMON_Trap DEMON_Trap;
|
||||
struct DEMON_Trap
|
||||
{
|
||||
DEMON_Handle process;
|
||||
U64 address;
|
||||
U64 id;
|
||||
};
|
||||
|
||||
typedef struct DEMON_TrapChunkNode DEMON_TrapChunkNode;
|
||||
struct DEMON_TrapChunkNode
|
||||
{
|
||||
DEMON_TrapChunkNode *next;
|
||||
DEMON_Trap *v;
|
||||
U64 cap;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DEMON_TrapChunkList DEMON_TrapChunkList;
|
||||
struct DEMON_TrapChunkList
|
||||
{
|
||||
DEMON_TrapChunkNode *first;
|
||||
DEMON_TrapChunkNode *last;
|
||||
U64 node_count;
|
||||
U64 trap_count;
|
||||
};
|
||||
|
||||
typedef struct DEMON_RunCtrls DEMON_RunCtrls;
|
||||
struct DEMON_RunCtrls
|
||||
{
|
||||
DEMON_Handle single_step_thread;
|
||||
B8 ignore_previous_exception;
|
||||
B8 run_entities_are_unfrozen;
|
||||
B8 run_entities_are_processes;
|
||||
DEMON_Handle *run_entities;
|
||||
U64 run_entity_count;
|
||||
DEMON_TrapChunkList traps;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Demon Process Listing
|
||||
|
||||
typedef struct DEMON_ProcessIter DEMON_ProcessIter;
|
||||
struct DEMON_ProcessIter
|
||||
{
|
||||
U64 v[2];
|
||||
};
|
||||
|
||||
typedef struct DEMON_ProcessInfo DEMON_ProcessInfo;
|
||||
struct DEMON_ProcessInfo
|
||||
{
|
||||
String8 name;
|
||||
U32 pid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void demon_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
|
||||
//- rjf: stringizing
|
||||
internal String8 demon_string_from_event_kind(DEMON_EventKind kind);
|
||||
internal String8 demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind);
|
||||
internal String8 demon_string_from_exception_kind(DEMON_ExceptionKind kind);
|
||||
internal void demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event);
|
||||
|
||||
//- rjf: trap chunk lists
|
||||
internal void demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap);
|
||||
internal void demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push);
|
||||
internal void demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push);
|
||||
|
||||
//- rjf: handle lists
|
||||
internal void demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle);
|
||||
internal DEMON_HandleArray demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list);
|
||||
internal DEMON_HandleArray demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Primary Thread & Exclusive Mode Controls
|
||||
|
||||
internal void demon_primary_thread_begin(void);
|
||||
internal void demon_exclusive_mode_begin(void);
|
||||
internal void demon_exclusive_mode_end(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Running/Halting
|
||||
|
||||
internal DEMON_EventList demon_run(Arena *arena, DEMON_RunCtrls *ctrls);
|
||||
internal void demon_halt(U64 code, U64 user_data);
|
||||
internal U64 demon_get_time_counter(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting
|
||||
|
||||
internal U32 demon_launch_process(OS_LaunchOptions *options);
|
||||
internal B32 demon_attach_process(U32 pid);
|
||||
internal B32 demon_kill_process(DEMON_Handle process, U32 exit_code);
|
||||
internal B32 demon_detach_process(DEMON_Handle process);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Functions
|
||||
|
||||
//- rjf: basics
|
||||
internal B32 demon_object_exists(DEMON_Handle object);
|
||||
|
||||
//- rjf: introspection
|
||||
internal Architecture demon_arch_from_object(DEMON_Handle object);
|
||||
internal U64 demon_base_vaddr_from_module(DEMON_Handle module);
|
||||
internal Rng1U64 demon_vaddr_range_from_module(DEMON_Handle module);
|
||||
internal String8 demon_full_path_from_module(Arena *arena, DEMON_Handle module);
|
||||
internal U64 demon_stack_base_vaddr_from_thread(DEMON_Handle thread);
|
||||
internal U64 demon_tls_root_vaddr_from_thread(DEMON_Handle thread);
|
||||
internal DEMON_HandleArray demon_all_processes(Arena *arena);
|
||||
internal DEMON_HandleArray demon_threads_from_process(Arena *arena, DEMON_Handle process);
|
||||
internal DEMON_HandleArray demon_modules_from_process(Arena *arena, DEMON_Handle process);
|
||||
|
||||
//- rjf: target process memory allocation/protection
|
||||
internal U64 demon_reserve_memory(DEMON_Handle process, U64 size);
|
||||
internal B32 demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags);
|
||||
internal B32 demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size);
|
||||
|
||||
//- rjf: target process memory reading/writing
|
||||
internal U64 demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size);
|
||||
internal B32 demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size);
|
||||
internal U64 demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size);
|
||||
internal U64 demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size);
|
||||
|
||||
//- rjf: thread registers reading/writing
|
||||
// IMPORTANT(allen): This API is _trusting_ you. You should never modify the data pointed
|
||||
// at by that void pointer! It is pointing to the internal cache of the registers, so it
|
||||
// will become invalid after a call to demon_write_regs, or demon_run. Use it to read
|
||||
// what you need and be done ASAP and we can avoid an extra copy baked into the API.
|
||||
internal void *demon_read_regs(DEMON_Handle thread);
|
||||
internal B32 demon_write_regs(DEMON_Handle thread, void *data);
|
||||
// TODO(allen): These might be a bad idea when we try to extend to ARM
|
||||
// They make sense for x86/x64 abstraction, which often needs identical
|
||||
// code paths except for these parts. Revisit this when ARM is integrated.
|
||||
internal U64 demon_read_ip(DEMON_Handle thread);
|
||||
internal U64 demon_read_sp(DEMON_Handle thread);
|
||||
internal void demon_write_ip(DEMON_Handle thread, U64 ip);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Listing
|
||||
|
||||
internal void demon_proc_iter_begin(DEMON_ProcessIter *iter);
|
||||
internal B32 demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out);
|
||||
internal void demon_proc_iter_end(DEMON_ProcessIter *iter);
|
||||
|
||||
#endif //DEMON_CORE_H
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Kind Tables
|
||||
|
||||
@table(name)
|
||||
DMN_EventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Error}
|
||||
{HandshakeComplete}
|
||||
{CreateProcess}
|
||||
{ExitProcess}
|
||||
{CreateThread}
|
||||
{ExitThread}
|
||||
{LoadModule}
|
||||
{UnloadModule}
|
||||
{Breakpoint}
|
||||
{Trap}
|
||||
{SingleStep}
|
||||
{Exception}
|
||||
{Halt}
|
||||
{Memory}
|
||||
{DebugString}
|
||||
{SetThreadName}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ErrorKindTable:
|
||||
{
|
||||
{Null}
|
||||
{NotAttached}
|
||||
{UnexpectedFailure}
|
||||
{InvalidHandle}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_MemoryEventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Commit}
|
||||
{Reserve}
|
||||
{Decommit}
|
||||
{Release}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ExceptionKindTable:
|
||||
{
|
||||
{Null}
|
||||
{MemoryRead}
|
||||
{MemoryWrite}
|
||||
{MemoryExecute}
|
||||
{CppThrow}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@enum DMN_EventKind:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_event_kind_string_table:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
@enum DMN_ErrorKind:
|
||||
{
|
||||
@expand(DMN_ErrorKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_MemoryEventKind:
|
||||
{
|
||||
@expand(DMN_MemoryEventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_ExceptionKind:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_exception_kind_string_table:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
+15
-12
@@ -1,12 +1,15 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "demon/demon_core.c"
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "demon/win32/demon_core_win32.c"
|
||||
#elif OS_LINUX
|
||||
# include "demon/linux/demon_core_linux.c"
|
||||
#else
|
||||
# error Demon layer backend not defined for this operating system.
|
||||
#endif
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "demon_core.c"
|
||||
#include "demon_common.c"
|
||||
#include "demon_accel.c"
|
||||
#include "demon_os.c"
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "win32/demon_os_win32.c"
|
||||
#elif OS_LINUX
|
||||
# include "linux/demon_os_linux.c"
|
||||
#else
|
||||
# error No Demon Implementation for This OS
|
||||
#endif
|
||||
|
||||
+20
-17
@@ -1,17 +1,20 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_INC_H
|
||||
#define DEMON_INC_H
|
||||
|
||||
#include "demon/demon_core.h"
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "demon/win32/demon_core_win32.h"
|
||||
#elif OS_LINUX
|
||||
# include "demon/linux/demon_core_linux.h"
|
||||
#else
|
||||
# error Demon layer backend not defined for this operating system.
|
||||
#endif
|
||||
|
||||
#endif // DEMON_INC_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_INC_H
|
||||
#define DEMON_INC_H
|
||||
|
||||
#include "demon_core.h"
|
||||
#include "demon_common.h"
|
||||
#include "demon_accel.h"
|
||||
#include "demon_os.h"
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "win32/demon_os_win32.h"
|
||||
#elif OS_LINUX
|
||||
# include "linux/demon_os_linux.h"
|
||||
#else
|
||||
# error No Demon Implementation for This OS
|
||||
#endif
|
||||
|
||||
#endif //DEMON_INC_H
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal B32
|
||||
demon_os_read_regs(DEMON_Entity *thread, void *dst)
|
||||
{
|
||||
B32 result = 0;
|
||||
switch(thread->arch)
|
||||
{
|
||||
default:{}break;
|
||||
case Architecture_x86:{result = demon_os_read_regs_x86(thread, (REGS_RegBlockX86 *)dst);}break;
|
||||
case Architecture_x64:{result = demon_os_read_regs_x64(thread, (REGS_RegBlockX64 *)dst);}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
demon_os_write_regs(DEMON_Entity *thread, void *src)
|
||||
{
|
||||
B32 result = 0;
|
||||
switch(thread->arch)
|
||||
{
|
||||
default:{}break;
|
||||
case Architecture_x86:{result = demon_os_write_regs_x86(thread, (REGS_RegBlockX86 *)src);}break;
|
||||
case Architecture_x64:{result = demon_os_write_regs_x64(thread, (REGS_RegBlockX64 *)src);}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_OS_H
|
||||
#define DEMON_OS_H
|
||||
|
||||
// NOTE(allen):
|
||||
// These are the functions that the OS backends actually implement.
|
||||
// Demon objects go through a handle validation layer but it is a lot more
|
||||
// convenient in the OS backends to implement these versions which take the
|
||||
// already validated DEMON_Entity*. These are also more convenient to call from
|
||||
// the backend layer, which lets us avoid converting back and forth between
|
||||
// handles and pointers a lot.
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Demon OS Run Control Types
|
||||
|
||||
typedef struct DEMON_OS_Trap DEMON_OS_Trap;
|
||||
struct DEMON_OS_Trap
|
||||
{
|
||||
DEMON_Entity *process;
|
||||
U64 address;
|
||||
};
|
||||
|
||||
typedef struct DEMON_OS_RunCtrls DEMON_OS_RunCtrls;
|
||||
struct DEMON_OS_RunCtrls
|
||||
{
|
||||
DEMON_Entity *single_step_thread;
|
||||
B8 ignore_previous_exception;
|
||||
B8 run_entities_are_unfrozen;
|
||||
B8 run_entities_are_processes;
|
||||
DEMON_Entity **run_entities;
|
||||
U64 run_entity_count;
|
||||
DEMON_OS_Trap *traps;
|
||||
U64 trap_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal B32 demon_os_read_regs(DEMON_Entity *thread, void *dst);
|
||||
internal B32 demon_os_write_regs(DEMON_Entity *thread, void *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @demon_os_hooks Main Layer Initialization
|
||||
|
||||
internal void demon_os_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @demon_os_hooks Running/Halting
|
||||
|
||||
internal DEMON_EventList demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls);
|
||||
internal void demon_os_halt(U64 code, U64 user_data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @demon_os_hooks Target Process Launching/Attaching/Killing/Detaching/Halting
|
||||
|
||||
internal U32 demon_os_launch_process(OS_LaunchOptions *options);
|
||||
internal B32 demon_os_attach_process(U32 pid);
|
||||
internal B32 demon_os_kill_process(DEMON_Entity *process, U32 exit_code);
|
||||
internal B32 demon_os_detach_process(DEMON_Entity *process);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @demon_os_hooks Entity Functions
|
||||
|
||||
//- rjf: cleanup
|
||||
internal void demon_os_entity_cleanup(DEMON_Entity *entity);
|
||||
|
||||
//- rjf: introspection
|
||||
internal String8 demon_os_full_path_from_module(Arena *arena, DEMON_Entity *module);
|
||||
internal U64 demon_os_stack_base_vaddr_from_thread(DEMON_Entity *thread);
|
||||
internal U64 demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread);
|
||||
|
||||
//- rjf: target process memory allocation/protection
|
||||
internal U64 demon_os_reserve_memory(DEMON_Entity *process, U64 size);
|
||||
internal void demon_os_set_memory_protect_flags(DEMON_Entity *process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags);
|
||||
internal void demon_os_release_memory(DEMON_Entity *process, U64 vaddr, U64 size);
|
||||
|
||||
//- rjf: target process memory reading/writing
|
||||
internal U64 demon_os_read_memory(DEMON_Entity *process, void *dst, U64 src_address, U64 size);
|
||||
internal B32 demon_os_write_memory(DEMON_Entity *process, U64 dst_address, void *src, U64 size);
|
||||
#define demon_os_read_struct(p,dst,src) demon_os_read_memory((p), (dst), (src), sizeof(*(dst)))
|
||||
#define demon_os_write_struct(p,dst,src) demon_os_write_memory((p), (dst), (src), sizeof(*(src)))
|
||||
|
||||
//- rjf: thread registers reading/writing
|
||||
internal B32 demon_os_read_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *dst);
|
||||
internal B32 demon_os_write_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *src);
|
||||
internal B32 demon_os_read_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *dst);
|
||||
internal B32 demon_os_write_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @demon_os_hooks Process Listing
|
||||
|
||||
internal void demon_os_proc_iter_begin(DEMON_ProcessIter *iter);
|
||||
internal B32 demon_os_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out);
|
||||
internal void demon_os_proc_iter_end(DEMON_ProcessIter *iter);
|
||||
|
||||
#endif //DEMON_OS_H
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
String8 dmn_event_kind_string_table[17] =
|
||||
{
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("Error"),
|
||||
str8_lit_comp("HandshakeComplete"),
|
||||
str8_lit_comp("CreateProcess"),
|
||||
str8_lit_comp("ExitProcess"),
|
||||
str8_lit_comp("CreateThread"),
|
||||
str8_lit_comp("ExitThread"),
|
||||
str8_lit_comp("LoadModule"),
|
||||
str8_lit_comp("UnloadModule"),
|
||||
str8_lit_comp("Breakpoint"),
|
||||
str8_lit_comp("Trap"),
|
||||
str8_lit_comp("SingleStep"),
|
||||
str8_lit_comp("Exception"),
|
||||
str8_lit_comp("Halt"),
|
||||
str8_lit_comp("Memory"),
|
||||
str8_lit_comp("DebugString"),
|
||||
str8_lit_comp("SetThreadName"),
|
||||
};
|
||||
|
||||
String8 dmn_exception_kind_string_table[5] =
|
||||
{
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("MemoryRead"),
|
||||
str8_lit_comp("MemoryWrite"),
|
||||
str8_lit_comp("MemoryExecute"),
|
||||
str8_lit_comp("CppThrow"),
|
||||
};
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef DEMON_META_H
|
||||
#define DEMON_META_H
|
||||
|
||||
typedef enum DMN_EventKind
|
||||
{
|
||||
DMN_EventKind_Null,
|
||||
DMN_EventKind_Error,
|
||||
DMN_EventKind_HandshakeComplete,
|
||||
DMN_EventKind_CreateProcess,
|
||||
DMN_EventKind_ExitProcess,
|
||||
DMN_EventKind_CreateThread,
|
||||
DMN_EventKind_ExitThread,
|
||||
DMN_EventKind_LoadModule,
|
||||
DMN_EventKind_UnloadModule,
|
||||
DMN_EventKind_Breakpoint,
|
||||
DMN_EventKind_Trap,
|
||||
DMN_EventKind_SingleStep,
|
||||
DMN_EventKind_Exception,
|
||||
DMN_EventKind_Halt,
|
||||
DMN_EventKind_Memory,
|
||||
DMN_EventKind_DebugString,
|
||||
DMN_EventKind_SetThreadName,
|
||||
DMN_EventKind_COUNT,
|
||||
} DMN_EventKind;
|
||||
|
||||
typedef enum DMN_ErrorKind
|
||||
{
|
||||
DMN_ErrorKind_Null,
|
||||
DMN_ErrorKind_NotAttached,
|
||||
DMN_ErrorKind_UnexpectedFailure,
|
||||
DMN_ErrorKind_InvalidHandle,
|
||||
DMN_ErrorKind_COUNT,
|
||||
} DMN_ErrorKind;
|
||||
|
||||
typedef enum DMN_MemoryEventKind
|
||||
{
|
||||
DMN_MemoryEventKind_Null,
|
||||
DMN_MemoryEventKind_Commit,
|
||||
DMN_MemoryEventKind_Reserve,
|
||||
DMN_MemoryEventKind_Decommit,
|
||||
DMN_MemoryEventKind_Release,
|
||||
DMN_MemoryEventKind_COUNT,
|
||||
} DMN_MemoryEventKind;
|
||||
|
||||
typedef enum DMN_ExceptionKind
|
||||
{
|
||||
DMN_ExceptionKind_Null,
|
||||
DMN_ExceptionKind_MemoryRead,
|
||||
DMN_ExceptionKind_MemoryWrite,
|
||||
DMN_ExceptionKind_MemoryExecute,
|
||||
DMN_ExceptionKind_CppThrow,
|
||||
DMN_ExceptionKind_COUNT,
|
||||
} DMN_ExceptionKind;
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
extern String8 dmn_event_kind_string_table[17];
|
||||
extern String8 dmn_exception_kind_string_table[5];
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
#endif // DEMON_META_H
|
||||
@@ -1,174 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
|
||||
|
||||
internal void
|
||||
dmn_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS)
|
||||
|
||||
internal DMN_CtrlCtx *
|
||||
dmn_ctrl_begin(void)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_ctrl_exclusive_access_begin(void)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_ctrl_exclusive_access_end(void)
|
||||
{
|
||||
}
|
||||
|
||||
internal U32
|
||||
dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
|
||||
{
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid)
|
||||
{
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code)
|
||||
{
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process)
|
||||
{
|
||||
}
|
||||
|
||||
internal DMN_EventList
|
||||
dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS)
|
||||
|
||||
internal void
|
||||
dmn_halt(U64 code, U64 user_data)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
|
||||
|
||||
//- rjf: run/memory/register counters
|
||||
|
||||
internal U64
|
||||
dmn_run_gen(void)
|
||||
{
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_mem_gen(void)
|
||||
{
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_reg_gen(void)
|
||||
{
|
||||
}
|
||||
|
||||
//- rjf: non-blocking-control-thread access barriers
|
||||
|
||||
internal B32
|
||||
dmn_access_open(void)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_access_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
//- rjf: processes
|
||||
|
||||
internal U64
|
||||
dmn_process_memory_reserve(DMN_Handle process, U64 vaddr, U64 size)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_process_memory_commit(DMN_Handle process, U64 vaddr, U64 size)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_process_memory_decommit(DMN_Handle process, U64 vaddr, U64 size)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_process_memory_release(DMN_Handle process, U64 vaddr, U64 size)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_process_memory_protect(DMN_Handle process, U64 vaddr, U64 size, OS_AccessFlags flags)
|
||||
{
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst)
|
||||
{
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_process_write(DMN_Handle process, Rng1U64 range, void *src)
|
||||
{
|
||||
}
|
||||
|
||||
//- rjf: threads
|
||||
|
||||
internal Arch
|
||||
dmn_arch_from_thread(DMN_Handle handle)
|
||||
{
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_stack_base_vaddr_from_thread(DMN_Handle handle)
|
||||
{
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_tls_root_vaddr_from_thread(DMN_Handle handle)
|
||||
{
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block)
|
||||
{
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block)
|
||||
{
|
||||
}
|
||||
|
||||
//- rjf: system process listing
|
||||
|
||||
internal void
|
||||
dmn_process_iter_begin(DMN_ProcessIter *iter)
|
||||
{
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_process_iter_end(DMN_ProcessIter *iter)
|
||||
{
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_LINUX_H
|
||||
#define DEMON_CORE_LINUX_H
|
||||
|
||||
#endif // DEMON_CORE_LINUX_H
|
||||
+2106
-2106
File diff suppressed because it is too large
Load Diff
+222
-222
@@ -1,222 +1,222 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_OS_LINUX_H
|
||||
#define DEMON_OS_LINUX_H
|
||||
|
||||
// TODO(allen): Potential Upgrades:
|
||||
//
|
||||
// memory fd upgrade - Right now for each process we hold open a file
|
||||
// descriptor for the process's memory (/proc/%d/mem) for the entire lifetime
|
||||
// of the process; it could be opened and closed with some kind of LRU cache
|
||||
// to put a finite cap on the number of handles the demon holds
|
||||
//
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Get The Linux Includes
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Types
|
||||
|
||||
//- entities
|
||||
|
||||
// Demon Linux Entity Extensions
|
||||
// Process: ext_u64 set to memory file descriptor
|
||||
// Thread : ext_u64 cast to DEMON_LNX_ThreadExt
|
||||
// Module : ext_u64 set to U64 (address of name)
|
||||
|
||||
struct DEMON_LNX_ThreadExt{
|
||||
B32 expecting_dummy_sigstop;
|
||||
};
|
||||
StaticAssert(sizeof(DEMON_LNX_ThreadExt) <= sizeof(Member(DEMON_Entity, ext_u64)), check_demon_lnx_thread_ext);
|
||||
|
||||
//- helpers
|
||||
|
||||
struct DEMON_LNX_AttachNode{
|
||||
DEMON_LNX_AttachNode *next;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ProcessAux{
|
||||
B32 filled;
|
||||
U64 phnum;
|
||||
U64 phent;
|
||||
U64 phdr;
|
||||
U64 execfn;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_PhdrInfo{
|
||||
Rng1U64 range;
|
||||
U64 dynamic;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ModuleNode{
|
||||
DEMON_LNX_ModuleNode *next;
|
||||
U64 vaddr;
|
||||
U64 size;
|
||||
U64 name;
|
||||
U64 already_known;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_EntityNode{
|
||||
DEMON_LNX_EntityNode *next;
|
||||
DEMON_Entity *entity;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Register Layouts
|
||||
|
||||
// these are defined in <sys/user.h> but only for one architecture at a time
|
||||
// (and we can't really trick it into giving us both in any obvious way)
|
||||
// we define them here so that we have them all "at once"
|
||||
|
||||
struct DEMON_LNX_UserRegsX64{
|
||||
U64 r15;
|
||||
U64 r14;
|
||||
U64 r13;
|
||||
U64 r12;
|
||||
U64 rbp;
|
||||
U64 rbx;
|
||||
U64 r11;
|
||||
U64 r10;
|
||||
U64 r9;
|
||||
U64 r8;
|
||||
U64 rax;
|
||||
U64 rcx;
|
||||
U64 rdx;
|
||||
U64 rsi;
|
||||
U64 rdi;
|
||||
U64 orig_rax;
|
||||
U64 rip;
|
||||
U64 cs;
|
||||
U64 rflags;
|
||||
U64 rsp;
|
||||
U64 ss;
|
||||
U64 fsbase;
|
||||
U64 gsbase;
|
||||
U64 ds;
|
||||
U64 es;
|
||||
U64 fs;
|
||||
U64 gs;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX64{
|
||||
DEMON_LNX_UserRegsX64 regs;
|
||||
S32 u_fpvalid, _pad0;
|
||||
SYMS_XSaveLegacy i387;
|
||||
U64 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
U64 signal;
|
||||
S32 reserved, _pad1;
|
||||
U64 u_ar0, u_fpstate;
|
||||
U64 magic;
|
||||
U8 u_comm[32];
|
||||
U64 u_debugreg[8];
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserRegsX86{
|
||||
U32 ebx;
|
||||
U32 ecx;
|
||||
U32 edx;
|
||||
U32 esi;
|
||||
U32 edi;
|
||||
U32 ebp;
|
||||
U32 eax;
|
||||
U32 ds;
|
||||
U32 es;
|
||||
U32 fs;
|
||||
U32 gs;
|
||||
U32 orig_eax;
|
||||
U32 eip;
|
||||
U32 cs;
|
||||
U32 eflags;
|
||||
U32 sp;
|
||||
U32 ss;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX86{
|
||||
DEMON_LNX_UserRegsX86 regs;
|
||||
S32 u_fpvalid;
|
||||
SYMS_FSave i387;
|
||||
U32 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
S32 signal, reserved;
|
||||
U32 u_ar0, u_fpstate;
|
||||
U32 magic;
|
||||
U8 u_comm[32];
|
||||
U32 u_debugreg[8];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_PermFlags_Read = (1 << 0),
|
||||
DEMON_LNX_PermFlags_Write = (1 << 1),
|
||||
DEMON_LNX_PermFlags_Exec = (1 << 2),
|
||||
DEMON_LNX_PermFlags_Private = (1 << 3)
|
||||
};
|
||||
typedef int DEMON_LNX_PermFlags;
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_MapsEntryType_Null,
|
||||
DEMON_LNX_MapsEntryType_Path,
|
||||
DEMON_LNX_MapsEntryType_Heap,
|
||||
DEMON_LNX_MapsEntryType_Stack,
|
||||
DEMON_LNX_MapsEntryType_VDSO,
|
||||
};
|
||||
typedef int DEMON_LNX_MapsEntryType;
|
||||
|
||||
struct DEMON_LNX_MapsEntry
|
||||
{
|
||||
U64 address_lo;
|
||||
U64 address_hi;
|
||||
DEMON_LNX_PermFlags perms;
|
||||
U64 offset;
|
||||
U32 dev_major;
|
||||
U32 dev_minor;
|
||||
U64 inode;
|
||||
String8 pathname;
|
||||
DEMON_LNX_MapsEntryType type;
|
||||
pid_t stack_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DEMON_LNX_ThreadExt* demon_lnx_thread_ext(DEMON_Entity *entity);
|
||||
|
||||
internal B32 demon_lnx_attach_pid(Arena *arena, pid_t pid, DEMON_LNX_AttachNode **new_node);
|
||||
|
||||
internal String8 demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid);
|
||||
internal int demon_lnx_open_memory_fd_for_pid(pid_t pid);
|
||||
|
||||
internal Arch demon_lnx_arch_from_pid(pid_t pid);
|
||||
internal DEMON_LNX_ProcessAux demon_lnx_aux_from_pid(pid_t pid, Arch arch);
|
||||
internal DEMON_LNX_PhdrInfo demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit,
|
||||
U64 phvaddr, U64 phstride, U64 phcount);
|
||||
internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process);
|
||||
|
||||
internal U64 demon_lnx_read_memory(int memory_fd, void *dst, U64 src, U64 size);
|
||||
internal B32 demon_lnx_write_memory(int memory_fd, U64 dst, void *src, U64 size);
|
||||
internal String8 demon_lnx_read_memory_str(Arena *arena, int memory_fd, U64 address);
|
||||
|
||||
internal void demon_lnx_regs_x64_from_usr_regs_x64(SYMS_RegX64 *dst, DEMON_LNX_UserRegsX64 *src);
|
||||
internal void demon_lnx_usr_regs_x64_from_regs_x64(DEMON_LNX_UserRegsX64 *dst, SYMS_RegX64 *src);
|
||||
|
||||
internal String8 demon_lnx_read_int_string(int fd);
|
||||
internal B32 demon_lnx_read_expect(int fd, char expect);
|
||||
internal int demon_lnx_read_whitespace(int fd);
|
||||
internal String8 demon_lnx_read_string(Arena *arena, int fd);
|
||||
|
||||
internal int demon_lnx_open_maps(pid_t pid);
|
||||
internal B32 demon_lnx_next_map(Arena *arena, int maps, DEMON_LNX_MapsEntry *entry_out);
|
||||
|
||||
#endif //DEMON_OS_LINUX_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_OS_LINUX_H
|
||||
#define DEMON_OS_LINUX_H
|
||||
|
||||
// TODO(allen): Potential Upgrades:
|
||||
//
|
||||
// memory fd upgrade - Right now for each process we hold open a file
|
||||
// descriptor for the process's memory (/proc/%d/mem) for the entire lifetime
|
||||
// of the process; it could be opened and closed with some kind of LRU cache
|
||||
// to put a finite cap on the number of handles the demon holds
|
||||
//
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Get The Linux Includes
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Types
|
||||
|
||||
//- entities
|
||||
|
||||
// Demon Linux Entity Extensions
|
||||
// Process: ext_u64 set to memory file descriptor
|
||||
// Thread : ext_u64 cast to DEMON_LNX_ThreadExt
|
||||
// Module : ext_u64 set to U64 (address of name)
|
||||
|
||||
struct DEMON_LNX_ThreadExt{
|
||||
B32 expecting_dummy_sigstop;
|
||||
};
|
||||
StaticAssert(sizeof(DEMON_LNX_ThreadExt) <= sizeof(Member(DEMON_Entity, ext_u64)), check_demon_lnx_thread_ext);
|
||||
|
||||
//- helpers
|
||||
|
||||
struct DEMON_LNX_AttachNode{
|
||||
DEMON_LNX_AttachNode *next;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ProcessAux{
|
||||
B32 filled;
|
||||
U64 phnum;
|
||||
U64 phent;
|
||||
U64 phdr;
|
||||
U64 execfn;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_PhdrInfo{
|
||||
Rng1U64 range;
|
||||
U64 dynamic;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_ModuleNode{
|
||||
DEMON_LNX_ModuleNode *next;
|
||||
U64 vaddr;
|
||||
U64 size;
|
||||
U64 name;
|
||||
U64 already_known;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_EntityNode{
|
||||
DEMON_LNX_EntityNode *next;
|
||||
DEMON_Entity *entity;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Linux Demon Register Layouts
|
||||
|
||||
// these are defined in <sys/user.h> but only for one architecture at a time
|
||||
// (and we can't really trick it into giving us both in any obvious way)
|
||||
// we define them here so that we have them all "at once"
|
||||
|
||||
struct DEMON_LNX_UserRegsX64{
|
||||
U64 r15;
|
||||
U64 r14;
|
||||
U64 r13;
|
||||
U64 r12;
|
||||
U64 rbp;
|
||||
U64 rbx;
|
||||
U64 r11;
|
||||
U64 r10;
|
||||
U64 r9;
|
||||
U64 r8;
|
||||
U64 rax;
|
||||
U64 rcx;
|
||||
U64 rdx;
|
||||
U64 rsi;
|
||||
U64 rdi;
|
||||
U64 orig_rax;
|
||||
U64 rip;
|
||||
U64 cs;
|
||||
U64 rflags;
|
||||
U64 rsp;
|
||||
U64 ss;
|
||||
U64 fsbase;
|
||||
U64 gsbase;
|
||||
U64 ds;
|
||||
U64 es;
|
||||
U64 fs;
|
||||
U64 gs;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX64{
|
||||
DEMON_LNX_UserRegsX64 regs;
|
||||
S32 u_fpvalid, _pad0;
|
||||
SYMS_XSaveLegacy i387;
|
||||
U64 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
U64 signal;
|
||||
S32 reserved, _pad1;
|
||||
U64 u_ar0, u_fpstate;
|
||||
U64 magic;
|
||||
U8 u_comm[32];
|
||||
U64 u_debugreg[8];
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserRegsX86{
|
||||
U32 ebx;
|
||||
U32 ecx;
|
||||
U32 edx;
|
||||
U32 esi;
|
||||
U32 edi;
|
||||
U32 ebp;
|
||||
U32 eax;
|
||||
U32 ds;
|
||||
U32 es;
|
||||
U32 fs;
|
||||
U32 gs;
|
||||
U32 orig_eax;
|
||||
U32 eip;
|
||||
U32 cs;
|
||||
U32 eflags;
|
||||
U32 sp;
|
||||
U32 ss;
|
||||
};
|
||||
|
||||
struct DEMON_LNX_UserX86{
|
||||
DEMON_LNX_UserRegsX86 regs;
|
||||
S32 u_fpvalid;
|
||||
SYMS_FSave i387;
|
||||
U32 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
S32 signal, reserved;
|
||||
U32 u_ar0, u_fpstate;
|
||||
U32 magic;
|
||||
U8 u_comm[32];
|
||||
U32 u_debugreg[8];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_PermFlags_Read = (1 << 0),
|
||||
DEMON_LNX_PermFlags_Write = (1 << 1),
|
||||
DEMON_LNX_PermFlags_Exec = (1 << 2),
|
||||
DEMON_LNX_PermFlags_Private = (1 << 3)
|
||||
};
|
||||
typedef int DEMON_LNX_PermFlags;
|
||||
|
||||
enum
|
||||
{
|
||||
DEMON_LNX_MapsEntryType_Null,
|
||||
DEMON_LNX_MapsEntryType_Path,
|
||||
DEMON_LNX_MapsEntryType_Heap,
|
||||
DEMON_LNX_MapsEntryType_Stack,
|
||||
DEMON_LNX_MapsEntryType_VDSO,
|
||||
};
|
||||
typedef int DEMON_LNX_MapsEntryType;
|
||||
|
||||
struct DEMON_LNX_MapsEntry
|
||||
{
|
||||
U64 address_lo;
|
||||
U64 address_hi;
|
||||
DEMON_LNX_PermFlags perms;
|
||||
U64 offset;
|
||||
U32 dev_major;
|
||||
U32 dev_minor;
|
||||
U64 inode;
|
||||
String8 pathname;
|
||||
DEMON_LNX_MapsEntryType type;
|
||||
pid_t stack_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DEMON_LNX_ThreadExt* demon_lnx_thread_ext(DEMON_Entity *entity);
|
||||
|
||||
internal B32 demon_lnx_attach_pid(Arena *arena, pid_t pid, DEMON_LNX_AttachNode **new_node);
|
||||
|
||||
internal String8 demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid);
|
||||
internal int demon_lnx_open_memory_fd_for_pid(pid_t pid);
|
||||
|
||||
internal Architecture demon_lnx_arch_from_pid(pid_t pid);
|
||||
internal DEMON_LNX_ProcessAux demon_lnx_aux_from_pid(pid_t pid, Architecture arch);
|
||||
internal DEMON_LNX_PhdrInfo demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit,
|
||||
U64 phvaddr, U64 phstride, U64 phcount);
|
||||
internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process);
|
||||
|
||||
internal U64 demon_lnx_read_memory(int memory_fd, void *dst, U64 src, U64 size);
|
||||
internal B32 demon_lnx_write_memory(int memory_fd, U64 dst, void *src, U64 size);
|
||||
internal String8 demon_lnx_read_memory_str(Arena *arena, int memory_fd, U64 address);
|
||||
|
||||
internal void demon_lnx_regs_x64_from_usr_regs_x64(SYMS_RegX64 *dst, DEMON_LNX_UserRegsX64 *src);
|
||||
internal void demon_lnx_usr_regs_x64_from_regs_x64(DEMON_LNX_UserRegsX64 *dst, SYMS_RegX64 *src);
|
||||
|
||||
internal String8 demon_lnx_read_int_string(int fd);
|
||||
internal B32 demon_lnx_read_expect(int fd, char expect);
|
||||
internal int demon_lnx_read_whitespace(int fd);
|
||||
internal String8 demon_lnx_read_string(Arena *arena, int fd);
|
||||
|
||||
internal int demon_lnx_open_maps(pid_t pid);
|
||||
internal B32 demon_lnx_next_map(Arena *arena, int maps, DEMON_LNX_MapsEntry *entry_out);
|
||||
|
||||
#endif //DEMON_OS_LINUX_H
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
// exe //
|
||||
|
||||
#include "base/base_inc.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "demon/demon_inc.h"
|
||||
#include "syms_helpers/syms_internal_overrides.h"
|
||||
#include "syms/syms_inc.h"
|
||||
#include "syms_helpers/syms_helpers.h"
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "demon/demon_inc.c"
|
||||
#include "syms_helpers/syms_internal_overrides.c"
|
||||
#include "syms/syms_inc.c"
|
||||
#include "syms_helpers/syms_helpers.c"
|
||||
|
||||
int
|
||||
main(int argument_count, char **arguments)
|
||||
{
|
||||
os_init(argument_count, arguments);
|
||||
Arena *arena = arena_alloc();
|
||||
demon_init();
|
||||
|
||||
//- rjf: find PID of mule_loop.exe
|
||||
String8 attach_process_name = str8_lit("mule_loop.exe");
|
||||
U32 pid = 0;
|
||||
{
|
||||
DEMON_ProcessIter it = {0};
|
||||
demon_proc_iter_begin(&it);
|
||||
for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(arena, &it, &info);)
|
||||
{
|
||||
if(str8_match(info.name, attach_process_name, 0))
|
||||
{
|
||||
pid = info.pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
demon_proc_iter_end(&it);
|
||||
}
|
||||
|
||||
//- rjf: attach
|
||||
B32 attach_good = demon_attach_process(pid);
|
||||
|
||||
//- rjf: get events
|
||||
DEMON_RunCtrls ctrls = {0};
|
||||
DEMON_EventList events = demon_run(arena, ctrls);
|
||||
for(DEMON_Event *event = events.first; event != 0; event = event->next)
|
||||
{
|
||||
int x = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//- rjf: try to break in the loop
|
||||
DEMON_RunCtrls ctrls = {0};
|
||||
DEMON_Trap trap = {0};
|
||||
{
|
||||
U64 loop_bp = 0x0000000140001074;
|
||||
ctrls.trap_count = 1;
|
||||
ctrls.traps = &trap;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "base/base_inc.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "demon/demon_inc.h"
|
||||
#include "syms_helpers/syms_internal_overrides.h"
|
||||
#include "syms/syms_inc.h"
|
||||
#include "syms_helpers/syms_helpers.h"
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "demon/demon_inc.c"
|
||||
#include "syms_helpers/syms_internal_overrides.c"
|
||||
#include "syms/syms_inc.c"
|
||||
#include "syms_helpers/syms_helpers.c"
|
||||
|
||||
internal SYMS_String8
|
||||
file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){
|
||||
String8 data = os_read_file(arena, str8_from_syms(file_name));
|
||||
SYMS_String8 result = syms_from_str8(data);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argument_count, char **arguments)
|
||||
{
|
||||
os_init(argument_count, arguments);
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// setup
|
||||
demon_init();
|
||||
|
||||
// parse arguments
|
||||
String8 executable_file_name = {0};
|
||||
U64 bp_address = 0;
|
||||
|
||||
{
|
||||
String8List command_line_arguments = os_get_command_line_arguments();
|
||||
CmdLine cmd_line = cmd_line_from_string_list(scratch.arena, command_line_arguments);
|
||||
if (cmd_line.inputs.first != 0){
|
||||
executable_file_name = cmd_line.inputs.first->string;
|
||||
}
|
||||
String8 bp_string = cmd_line_string(cmd_line, str8_lit("bp"));
|
||||
try_u64_from_str8_c_rules(bp_string, &bp_address);
|
||||
}
|
||||
|
||||
// check parameters
|
||||
if (bp_address == 0 || executable_file_name.size == 0){
|
||||
printf("bad parameters\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// demon launch
|
||||
OS_LaunchOptions launch_opts = {0};
|
||||
str8_list_push(scratch.arena, &launch_opts.cmd_line, executable_file_name);
|
||||
launch_opts.path = os_get_path(scratch.arena, OS_SystemPath_Current);
|
||||
U32 process_id = demon_launch_process(&launch_opts);
|
||||
if (process_id == 0){
|
||||
printf("could not launch: '%.*s'\n", str8_varg(executable_file_name));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// demon loop
|
||||
{
|
||||
DEMON_Handle process = 0;
|
||||
DEMON_Handle thread = 0;
|
||||
|
||||
B32 hit_bp = false;
|
||||
U64 single_step_counter = 0;
|
||||
|
||||
U64 counter = 0;
|
||||
for (;;){
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
|
||||
DEMON_RunCtrls run_controls = {0};
|
||||
DEMON_Trap traps[1];
|
||||
|
||||
if (!hit_bp){
|
||||
if (process != 0){
|
||||
run_controls.trap_count = 1;
|
||||
run_controls.traps = traps;
|
||||
run_controls.traps[0].process = process;
|
||||
run_controls.traps[0].address = bp_address;
|
||||
}
|
||||
}
|
||||
else{
|
||||
run_controls.single_step_thread = thread;
|
||||
}
|
||||
|
||||
DEMON_EventList events = demon_run(temp.arena, run_controls);
|
||||
|
||||
for (DEMON_Event *event = events.first;
|
||||
event != 0;
|
||||
event = event->next, counter += 1){
|
||||
// update tracking state
|
||||
switch (event->kind){
|
||||
case DEMON_EventKind_CreateProcess:
|
||||
{
|
||||
process = event->process;
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_ExitProcess:
|
||||
{
|
||||
if (event->process == process){
|
||||
process = 0;
|
||||
}
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_CreateThread:
|
||||
{
|
||||
thread = event->thread;
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_Breakpoint:
|
||||
{
|
||||
hit_bp = true;
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_SingleStep:
|
||||
{
|
||||
single_step_counter += 1;
|
||||
|
||||
SYMS_RegX64 regs1 = {0};
|
||||
demon_read_x64_regs(thread, ®s1);
|
||||
demon_write_x64_regs(thread, ®s1);
|
||||
SYMS_RegX64 regs2 = {0};
|
||||
demon_read_x64_regs(thread, ®s2);
|
||||
if (!MemoryMatchStruct(®s1, ®s2)){
|
||||
printf("mismatch at single_step_counter=%llu\n", single_step_counter);
|
||||
}
|
||||
|
||||
if (single_step_counter == 1000){
|
||||
goto end_loop;
|
||||
}
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_NotAttached:
|
||||
{
|
||||
fprintf(stderr, "not attached - exiting\n");
|
||||
goto end_loop;
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_NotInitialized:
|
||||
case DEMON_EventKind_UnexpectedFailure:
|
||||
{
|
||||
fprintf(stderr, "unexpected error - exiting\n");
|
||||
goto end_loop;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
goto end_it;
|
||||
end_loop:
|
||||
temp_end(temp);
|
||||
goto loop_exit;
|
||||
end_it:;
|
||||
}
|
||||
|
||||
loop_exit:;
|
||||
}
|
||||
|
||||
printf("[done]\n");
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "base/base_inc.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "demon/demon_inc.h"
|
||||
#include "syms_helpers/syms_internal_overrides.h"
|
||||
#include "syms/syms_inc.h"
|
||||
#include "syms_helpers/syms_helpers.h"
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "demon/demon_inc.c"
|
||||
#include "syms_helpers/syms_internal_overrides.c"
|
||||
#include "syms/syms_inc.c"
|
||||
#include "syms_helpers/syms_helpers.c"
|
||||
|
||||
internal SYMS_String8
|
||||
file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){
|
||||
String8 data = os_read_file(arena, str8_from_syms(file_name));
|
||||
SYMS_String8 result = syms_from_str8(data);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argument_count, char **arguments)
|
||||
{
|
||||
os_init(argument_count, arguments);
|
||||
demon_init();
|
||||
|
||||
String8Node node[2];
|
||||
|
||||
#define TARGET_EXE "C:\\devel\\projects\\debugger\\build\\mule_unwind_20210511_clang11_lldlink.exe"
|
||||
|
||||
OS_LaunchOptions options = {0};
|
||||
#if OS_WINDOWS
|
||||
str8_list_push(&options.cmd_line, &node[0], str8_lit(TARGET_EXE));
|
||||
options.path = str8_lit("C:\\devel\\projects\\debugger\\build\\");
|
||||
#else
|
||||
str8_list_push(&options.cmd_line, &node[0], str8_lit("/home/allenw/projects_copy/debugger/build/mule_main"));
|
||||
options.path = str8_lit("/home/allenw/projects_copy/debugger/build/");
|
||||
#endif
|
||||
U32 process_id = demon_launch_process(&options);
|
||||
if (process_id == 0){
|
||||
printf("Could not launch process\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if OS_WINDOWS
|
||||
U64 bp_addr = 0x140001134;
|
||||
#else
|
||||
U64 bp_addr = 0x400918;
|
||||
#endif
|
||||
|
||||
DEMON_Handle process = 0;
|
||||
DEMON_Handle thread = 0;
|
||||
DEMON_Handle module = 0;
|
||||
U64 module_base = 0;
|
||||
SYMS_Group *group = 0;
|
||||
|
||||
B32 hit_bp = false;
|
||||
U64 counter = 0;
|
||||
|
||||
for (;;){
|
||||
DEMON_RunCtrls run_controls = {0};
|
||||
DEMON_Trap trap_memory[2];
|
||||
|
||||
DEMON_Trap *trap_ptr = trap_memory;
|
||||
if (process != 0 && !hit_bp){
|
||||
trap_ptr->process = process;
|
||||
trap_ptr->address = bp_addr;
|
||||
trap_ptr += 1;
|
||||
}
|
||||
run_controls.traps = trap_memory;
|
||||
run_controls.trap_count = (U64)(trap_ptr - trap_memory);
|
||||
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
DEMON_EventList events = demon_run(scratch.arena, run_controls);
|
||||
|
||||
for (DEMON_Event *event = events.first;
|
||||
event != 0;
|
||||
event = event->next){
|
||||
printf("STEP[%05llx] -- ", counter);
|
||||
counter += 1;
|
||||
|
||||
switch (event->kind){
|
||||
case DEMON_EventKind_NotInitialized:
|
||||
{
|
||||
printf("Not Initialized\n");
|
||||
exit(1);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_NotAttached:
|
||||
{
|
||||
printf("Not Attached\n");
|
||||
exit(1);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_UnexpectedFailure:
|
||||
{
|
||||
printf("Unexpected Failure\n");
|
||||
exit(1);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_CreateProcess:
|
||||
{
|
||||
printf("Create Process\n");
|
||||
if (process == 0){
|
||||
process = event->process;
|
||||
}
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_CreateThread:
|
||||
{
|
||||
printf("Create Thread\n");
|
||||
if (thread == 0){
|
||||
thread = event->thread;
|
||||
}
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_LoadModule:
|
||||
{
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
String8 file_name = demon_full_path_from_module(scratch.arena, event->module);
|
||||
printf("Load Module: %.*s\n", str8_varg(file_name));
|
||||
if (module == 0 && str8_match(file_name, str8_lit(TARGET_EXE), 0)){
|
||||
module = event->module;
|
||||
module_base = event->address;
|
||||
|
||||
// setup syms group
|
||||
group = syms_group_alloc();
|
||||
|
||||
SYMS_FileLoadCtx ctx = {0};
|
||||
ctx.file_load_func = file_load_func_for_syms;
|
||||
|
||||
SYMS_String8List file_names = {0};
|
||||
syms_string_list_push(group->arena, &file_names, syms_from_str8(file_name));
|
||||
|
||||
SYMS_FileInfOptions opts = {0};
|
||||
|
||||
SYMS_FileInfResult inf_result = syms_file_inf_infer_from_file_list(group->arena, ctx, file_names, &opts);
|
||||
syms_group_init(group, &inf_result.data_parsed);
|
||||
}
|
||||
temp_end(temp);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_ExitProcess:
|
||||
{
|
||||
printf("Exit Process\n");
|
||||
exit(0);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_ExitThread:
|
||||
{
|
||||
printf("Exit Thread\n");
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_UnloadModule:
|
||||
{
|
||||
printf("Unload Module\n");
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_Breakpoint:
|
||||
{
|
||||
Architecture arch = demon_arch_from_object(event->process);
|
||||
U64 ip = event->instruction_pointer;
|
||||
printf("Breakpoint: %llx\n", ip);
|
||||
|
||||
hit_bp = true;
|
||||
|
||||
//- unwind
|
||||
|
||||
// setup bin
|
||||
SYMS_String8 bin_data = group->bin_data;
|
||||
SYMS_BinAccel *generic_bin = group->bin;
|
||||
SYMS_PeBinAccel *pe_bin = 0;
|
||||
if (generic_bin->format == SYMS_FileFormat_PE){
|
||||
pe_bin = (SYMS_PeBinAccel*)generic_bin;
|
||||
}
|
||||
|
||||
if (pe_bin != 0){
|
||||
// read regs
|
||||
SYMS_RegX64 regs = {0};
|
||||
demon_read_x64_regs(event->thread, ®s);
|
||||
|
||||
// read stack
|
||||
SYMS_U64 sp = regs.rsp.u64;
|
||||
SYMS_U64 sp_rounded_down = sp&~(KB(4) - 1);
|
||||
|
||||
SYMS_String8 stack_memory = {0};
|
||||
stack_memory.size = KB(8);
|
||||
stack_memory.str = push_array_no_zero(scratch.arena, U8, stack_memory.size);
|
||||
|
||||
SYMS_U64 stack_memory_addr = sp_rounded_down;
|
||||
stack_memory.size = demon_read_memory_amap(event->process, stack_memory.str,
|
||||
stack_memory_addr, stack_memory.size);
|
||||
|
||||
// unwind loop
|
||||
U64 counter = 1;
|
||||
for (;; counter += 1){
|
||||
printf("%02llu: ip=%llx; sp=%llx\n", counter, regs.rip.u64, regs.rsp.u64);
|
||||
SYMS_MemoryView memview = syms_memory_view_make(stack_memory, stack_memory_addr);
|
||||
SYMS_UnwindResult unwind_result = syms_unwind_pe_x64(bin_data, pe_bin, module_base, &memview, ®s);
|
||||
if (unwind_result.dead){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_Trap:
|
||||
{
|
||||
Architecture arch = demon_arch_from_object(event->process);
|
||||
U64 ip = event->instruction_pointer;
|
||||
printf("Trap: %llx\n", ip);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_SingleStep:
|
||||
{
|
||||
printf("Single Step: %llx\n", event->instruction_pointer);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_Exception:
|
||||
{
|
||||
printf("Exception: %llx\n", event->instruction_pointer);
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_Halt:
|
||||
{
|
||||
printf("Halt\n");
|
||||
}break;
|
||||
|
||||
case DEMON_EventKind_Memory:
|
||||
{
|
||||
printf("Memory\n");
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
printf("Unhandled Event\n");
|
||||
exit(1);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
printf("Done\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,935 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
// NOTE(rjf): (18 October 2021) Notes on Win32 process halting via
|
||||
// DebugBreakProcess:
|
||||
//
|
||||
// Calling DebugBreakProcess seems to cause a few events to come back:
|
||||
// 1. Thread Creation Event
|
||||
// 2. Breakpoint Event (with the thread matching that of #1)
|
||||
// 3. Thread Exiting Event (matching #1)
|
||||
//
|
||||
// Having done this experiment on a single-threaded program (mule_loop.exe),
|
||||
// I can only infer that what is happening here is that when DebugBreakProcess
|
||||
// is called, it first injects a thread into the target process that runs
|
||||
// code with an int3. This is very similar to the old approach that Demon
|
||||
// took.
|
||||
//
|
||||
// It's going to be difficult to distinguish between these CreateThreads and
|
||||
// ExitThreads from others (not caused by halting), even though we can match
|
||||
// the hit breakpoint to the associated thread.
|
||||
//
|
||||
// What could be possible (in order to distinguish the hit breakpoint as a
|
||||
// halt event, instead of an arbitrary breakpoint) is looking at the breakpoint
|
||||
// address. This injected thread has a breakpoint that's different from the
|
||||
// initial breakpoint that the kernel automatically hits when a process is
|
||||
// first being debugged.
|
||||
//
|
||||
// With DebugBreakProcess:
|
||||
// - first breakpoint that is hit: 0x7ff8ad9806b0 in kernel code
|
||||
// - last breakpoint that is hit: 0x7ff8ad950860 in kernel code (halt)
|
||||
//
|
||||
// Without DebugBreakProcess:
|
||||
// - first breakpoint that is hit: 0x7ff8ad9806b0
|
||||
//
|
||||
|
||||
// NOTE(rjf): (18 October 2021) Notes on suspending processes via
|
||||
// NtSuspendProcess:
|
||||
//
|
||||
// NtSuspendProcess is an undocumented API that is exported by ntdll. It is
|
||||
// fairly simple but could be unstable. To call it, the main trick is that
|
||||
// you need a handle with certain privileges (PROCESS_SUSPEND_RESUME), so
|
||||
// you can't just take any handle and use it.
|
||||
//
|
||||
// To use it, we can manually load it from ntdll, grab an elevated handle
|
||||
// for a given process HANDLE, and then call it. We can resume, then, with
|
||||
// NtResumeProcess.
|
||||
//
|
||||
// Other than this, our options seem to more-or-less lie in individually
|
||||
// suspending all of the threads in the process-to-be-halted.
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/base_inc.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "syms_helpers/syms_internal_overrides.h"
|
||||
#include "syms/syms_inc.h"
|
||||
#include "syms_helpers/syms_helpers.h"
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "syms_helpers/syms_internal_overrides.c"
|
||||
#include "syms/syms_inc.c"
|
||||
#include "syms_helpers/syms_helpers.c"
|
||||
|
||||
typedef LONG NtSuspendProcessFunction(HANDLE ProcessHandle);
|
||||
global NtSuspendProcessFunction *NtSuspendProcess = 0;
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Win32 Demon Exceptions
|
||||
|
||||
#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Win32 Demon Register API Codes
|
||||
|
||||
#define DEMON_W32_CTX_X86 0x00010000
|
||||
#define DEMON_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DEMON_W32_CTX_INTEL_CONTROL 0x0001
|
||||
#define DEMON_W32_CTX_INTEL_INTEGER 0x0002
|
||||
#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004
|
||||
#define DEMON_W32_CTX_INTEL_FLOATS 0x0008
|
||||
#define DEMON_W32_CTX_INTEL_DEBUG 0x0010
|
||||
#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DEMON_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \
|
||||
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
|
||||
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \
|
||||
DEMON_W32_CTX_INTEL_EXTENDED)
|
||||
#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \
|
||||
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
|
||||
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \
|
||||
DEMON_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
struct TEST_DebugEvent
|
||||
{
|
||||
String8 name;
|
||||
U64 process_id;
|
||||
U64 thread_id;
|
||||
HANDLE process;
|
||||
HANDLE thread;
|
||||
U64 addr;
|
||||
DEBUG_EVENT evt;
|
||||
};
|
||||
|
||||
struct TEST_Trap
|
||||
{
|
||||
HANDLE process;
|
||||
U64 address;
|
||||
};
|
||||
|
||||
internal U16
|
||||
test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave)
|
||||
{
|
||||
U16 result = 0;
|
||||
U32 top = (fxsave->StatusWord >> 11) & 7;
|
||||
for (U32 fpr = 0; fpr < 8; fpr += 1){
|
||||
U32 tag = 3;
|
||||
if (fxsave->TagWord & (1 << fpr)){
|
||||
U32 st = (fpr - top)&7;
|
||||
|
||||
SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16];
|
||||
U16 exponent = fp->sign1_exp15 & bitmask15;
|
||||
U64 integer_part = fp->int1_frac63 >> 63;
|
||||
U64 fraction_part = fp->int1_frac63 & bitmask63;
|
||||
|
||||
// tag: 0 - normal; 1 - zero; 2 - special
|
||||
tag = 2;
|
||||
if (exponent == 0){
|
||||
if (integer_part == 0 && fraction_part == 0){
|
||||
tag = 1;
|
||||
}
|
||||
}
|
||||
else if (exponent != bitmask15 && integer_part != 0){
|
||||
tag = 0;
|
||||
}
|
||||
}
|
||||
result |= tag << (2 * fpr);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal U16
|
||||
test_w32_xsave_tag_word_from_real_tag_word(U16 ftw)
|
||||
{
|
||||
U16 compact = 0;
|
||||
for (U32 fpr = 0; fpr < 8; fpr++){
|
||||
U32 tag = (ftw >> (fpr * 2)) & 3;
|
||||
if (tag != 3){
|
||||
compact |= (1 << fpr);
|
||||
}
|
||||
}
|
||||
return(compact);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// NOTE(allen): Check available features
|
||||
U32 feature_mask = GetEnabledXStateFeatures();
|
||||
B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX);
|
||||
|
||||
// NOTE(allen): Setup the context
|
||||
CONTEXT *ctx = 0;
|
||||
U32 ctx_flags = DEMON_W32_CTX_X64_ALL;
|
||||
if (avx_enabled){
|
||||
ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE;
|
||||
}
|
||||
DWORD size = 0;
|
||||
InitializeContext(0, ctx_flags, 0, &size);
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
|
||||
void *ctx_memory = push_array(scratch.arena, U8, size);
|
||||
if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){
|
||||
ctx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
B32 avx_available = false;
|
||||
|
||||
if (ctx != 0){
|
||||
// NOTE(allen): Finish Context Setup
|
||||
if (avx_enabled){
|
||||
SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX);
|
||||
}
|
||||
|
||||
// NOTE(allen): Determine what features are available on this particular ctx
|
||||
// TODO(allen): Experiment carefully with this nonsense.
|
||||
// Does avx_enabled = avx_available in all circumstances or not?
|
||||
DWORD64 xstate_flags = 0;
|
||||
if (GetXStateFeaturesMask(ctx, &xstate_flags)){
|
||||
if (xstate_flags & XSTATE_MASK_AVX){
|
||||
avx_available = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get thread context
|
||||
HANDLE thread_handle = thread;
|
||||
if (!GetThreadContext(thread_handle, ctx)){
|
||||
ctx = 0;
|
||||
}
|
||||
|
||||
B32 result = false;
|
||||
if (ctx != 0){
|
||||
result = true;
|
||||
|
||||
// NOTE(allen): Convert CONTEXT -> SYMS_RegX64
|
||||
dst->rax.u64 = ctx->Rax;
|
||||
dst->rcx.u64 = ctx->Rcx;
|
||||
dst->rdx.u64 = ctx->Rdx;
|
||||
dst->rbx.u64 = ctx->Rbx;
|
||||
dst->rsp.u64 = ctx->Rsp;
|
||||
dst->rbp.u64 = ctx->Rbp;
|
||||
dst->rsi.u64 = ctx->Rsi;
|
||||
dst->rdi.u64 = ctx->Rdi;
|
||||
dst->r8.u64 = ctx->R8;
|
||||
dst->r9.u64 = ctx->R9;
|
||||
dst->r10.u64 = ctx->R10;
|
||||
dst->r11.u64 = ctx->R11;
|
||||
dst->r12.u64 = ctx->R12;
|
||||
dst->r13.u64 = ctx->R13;
|
||||
dst->r14.u64 = ctx->R14;
|
||||
dst->r15.u64 = ctx->R15;
|
||||
dst->rip.u64 = ctx->Rip;
|
||||
dst->cs.u16 = ctx->SegCs;
|
||||
dst->ds.u16 = ctx->SegDs;
|
||||
dst->es.u16 = ctx->SegEs;
|
||||
dst->fs.u16 = ctx->SegFs;
|
||||
dst->gs.u16 = ctx->SegGs;
|
||||
dst->ss.u16 = ctx->SegSs;
|
||||
dst->dr0.u32 = ctx->Dr0;
|
||||
dst->dr1.u32 = ctx->Dr1;
|
||||
dst->dr2.u32 = ctx->Dr2;
|
||||
dst->dr3.u32 = ctx->Dr3;
|
||||
dst->dr6.u32 = ctx->Dr6;
|
||||
dst->dr7.u32 = ctx->Dr7;
|
||||
|
||||
// NOTE(allen): This bit is "supposed to always be 1" I guess.
|
||||
// TODO(allen): Not sure what this is all about but I haven't investigated it yet.
|
||||
// This might be totally not necessary or something.
|
||||
dst->rflags.u64 = ctx->EFlags | 0x2;
|
||||
|
||||
XSAVE_FORMAT *xsave = &ctx->FltSave;
|
||||
dst->fcw.u16 = xsave->ControlWord;
|
||||
dst->fsw.u16 = xsave->StatusWord;
|
||||
dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave);
|
||||
dst->fop.u16 = xsave->ErrorOpcode;
|
||||
dst->fcs.u16 = xsave->ErrorSelector;
|
||||
dst->fds.u16 = xsave->DataSelector;
|
||||
dst->fip.u32 = xsave->ErrorOffset;
|
||||
dst->fdp.u32 = xsave->DataOffset;
|
||||
dst->mxcsr.u32 = xsave->MxCsr;
|
||||
dst->mxcsr_mask.u32 = xsave->MxCsr_Mask;
|
||||
|
||||
M128A *float_s = xsave->FloatRegisters;
|
||||
SYMS_Reg80 *float_d = &dst->fpr0;
|
||||
for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){
|
||||
MemoryCopy(float_d, float_s, sizeof(*float_d));
|
||||
}
|
||||
|
||||
if (!avx_available){
|
||||
M128A *xmm_s = xsave->XmmRegisters;
|
||||
SYMS_Reg256 *xmm_d = &dst->ymm0;
|
||||
for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){
|
||||
MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s));
|
||||
}
|
||||
}
|
||||
|
||||
if (avx_available){
|
||||
DWORD part0_length = 0;
|
||||
M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length);
|
||||
DWORD part1_length = 0;
|
||||
M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length);
|
||||
Assert(part0_length == part1_length);
|
||||
|
||||
DWORD count = part0_length/sizeof(part0[0]);
|
||||
count = ClampTop(count, 16);
|
||||
SYMS_Reg256 *ymm_d = &dst->ymm0;
|
||||
for (DWORD i = 0;
|
||||
i < count;
|
||||
i += 1, part0 += 1, part1 += 1, ymm_d += 1){
|
||||
// TODO(allen): Are we writing these out in the right order? Seems weird right?
|
||||
ymm_d->u64[3] = part0->Low;
|
||||
ymm_d->u64[2] = part0->High;
|
||||
ymm_d->u64[1] = part1->Low;
|
||||
ymm_d->u64[0] = part1->High;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// NOTE(allen): Check available features
|
||||
U32 feature_mask = GetEnabledXStateFeatures();
|
||||
B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX);
|
||||
|
||||
// NOTE(allen): Setup the context
|
||||
CONTEXT *ctx = 0;
|
||||
U32 ctx_flags = DEMON_W32_CTX_X64_ALL;
|
||||
if (avx_enabled){
|
||||
ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE;
|
||||
}
|
||||
DWORD size = 0;
|
||||
InitializeContext(0, ctx_flags, 0, &size);
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
|
||||
void *ctx_memory = push_array(scratch.arena, U8, size);
|
||||
if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){
|
||||
ctx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
B32 avx_available = false;
|
||||
|
||||
if (ctx != 0){
|
||||
// NOTE(allen): Finish Context Setup
|
||||
if (avx_enabled){
|
||||
SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX);
|
||||
}
|
||||
|
||||
// NOTE(allen): Determine what features are available on this particular ctx
|
||||
// TODO(allen): Experiment carefully with this nonsense.
|
||||
// Does avx_enabled = avx_available in all circumstances or not?
|
||||
DWORD64 xstate_flags = 0;
|
||||
if (GetXStateFeaturesMask(ctx, &xstate_flags)){
|
||||
if (xstate_flags & XSTATE_MASK_AVX){
|
||||
avx_available = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
B32 result = false;
|
||||
if (ctx != 0){
|
||||
// NOTE(allen): Convert SYMS_RegX64 -> CONTEXT
|
||||
ctx->ContextFlags = ctx_flags;
|
||||
|
||||
ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32;
|
||||
|
||||
ctx->Rax = src->rax.u64;
|
||||
ctx->Rcx = src->rcx.u64;
|
||||
ctx->Rdx = src->rdx.u64;
|
||||
ctx->Rbx = src->rbx.u64;
|
||||
ctx->Rsp = src->rsp.u64;
|
||||
ctx->Rbp = src->rbp.u64;
|
||||
ctx->Rsi = src->rsi.u64;
|
||||
ctx->Rdi = src->rdi.u64;
|
||||
ctx->R8 = src->r8.u64;
|
||||
ctx->R9 = src->r9.u64;
|
||||
ctx->R10 = src->r10.u64;
|
||||
ctx->R11 = src->r11.u64;
|
||||
ctx->R12 = src->r12.u64;
|
||||
ctx->R13 = src->r13.u64;
|
||||
ctx->R14 = src->r14.u64;
|
||||
ctx->R15 = src->r15.u64;
|
||||
ctx->Rip = src->rip.u64;
|
||||
ctx->SegCs = src->cs.u16;
|
||||
ctx->SegDs = src->ds.u16;
|
||||
ctx->SegEs = src->es.u16;
|
||||
ctx->SegFs = src->fs.u16;
|
||||
ctx->SegGs = src->gs.u16;
|
||||
ctx->SegSs = src->ss.u16;
|
||||
ctx->Dr0 = src->dr0.u32;
|
||||
ctx->Dr1 = src->dr1.u32;
|
||||
ctx->Dr2 = src->dr2.u32;
|
||||
ctx->Dr3 = src->dr3.u32;
|
||||
ctx->Dr6 = src->dr6.u32;
|
||||
ctx->Dr7 = src->dr7.u32;
|
||||
|
||||
ctx->EFlags = src->rflags.u64;
|
||||
|
||||
XSAVE_FORMAT *fxsave = &ctx->FltSave;
|
||||
fxsave->ControlWord = src->fcw.u16;
|
||||
fxsave->StatusWord = src->fsw.u16;
|
||||
fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16);
|
||||
fxsave->ErrorOpcode = src->fop.u16;
|
||||
fxsave->ErrorSelector = src->fcs.u16;
|
||||
fxsave->DataSelector = src->fds.u16;
|
||||
fxsave->ErrorOffset = src->fip.u32;
|
||||
fxsave->DataOffset = src->fdp.u32;
|
||||
|
||||
M128A *float_d = fxsave->FloatRegisters;
|
||||
SYMS_Reg80 *float_s = &src->fpr0;
|
||||
for (U32 n = 0;
|
||||
n < 8;
|
||||
n += 1, float_s += 1, float_d += 1){
|
||||
MemoryCopy(float_d, float_s, 10);
|
||||
}
|
||||
|
||||
if (!avx_available){
|
||||
M128A *xmm_d = fxsave->XmmRegisters;
|
||||
SYMS_Reg256 *xmm_s = &src->ymm0;
|
||||
for (U32 n = 0;
|
||||
n < 8;
|
||||
n += 1, xmm_d += 1, xmm_s += 1){
|
||||
MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d));
|
||||
}
|
||||
}
|
||||
|
||||
if (avx_available){
|
||||
DWORD part0_length = 0;
|
||||
M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length);
|
||||
DWORD part1_length = 0;
|
||||
M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length);
|
||||
Assert(part0_length == part1_length);
|
||||
|
||||
DWORD count = part0_length/sizeof(part0[0]);
|
||||
count = ClampTop(count, 16);
|
||||
SYMS_Reg256 *ymm_d = &src->ymm0;
|
||||
for (DWORD i = 0;
|
||||
i < count;
|
||||
i += 1, part0 += 1, part1 += 1, ymm_d += 1){
|
||||
// TODO(allen): Are we writing these out in the right order? Seems weird right?
|
||||
part0->Low = ymm_d->u64[3];
|
||||
part0->High = ymm_d->u64[2];
|
||||
part1->Low = ymm_d->u64[1];
|
||||
part1->High = ymm_d->u64[0];
|
||||
}
|
||||
}
|
||||
|
||||
//- set thread context
|
||||
HANDLE thread_handle = thread;
|
||||
if (SetThreadContext(thread_handle, ctx)){
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size)
|
||||
{
|
||||
B32 result = true;
|
||||
U8 *ptr = (U8*)dst;
|
||||
U8 *opl = ptr + size;
|
||||
U64 cursor = src_address;
|
||||
for (;ptr < opl;){
|
||||
SIZE_T to_read = (SIZE_T)(opl - ptr);
|
||||
SIZE_T actual_read = 0;
|
||||
if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
ptr += actual_read;
|
||||
cursor += actual_read;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size)
|
||||
{
|
||||
B32 result = true;
|
||||
U8 *ptr = (U8*)src;
|
||||
U8 *opl = ptr + size;
|
||||
U64 cursor = dst_address;
|
||||
for (;ptr < opl;){
|
||||
SIZE_T to_write = (SIZE_T)(opl - ptr);
|
||||
SIZE_T actual_write = 0;
|
||||
if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
ptr += actual_write;
|
||||
cursor += actual_write;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_launch_process(OS_LaunchOptions *options)
|
||||
{
|
||||
B32 result = false;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
StringJoin join_params = {0};
|
||||
join_params.pre = str8_lit("\"");
|
||||
join_params.sep = str8_lit("\" \"");
|
||||
join_params.post = str8_lit("\"");
|
||||
String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params);
|
||||
|
||||
StringJoin join_params2 = {0};
|
||||
join_params2.sep = str8_lit("\0");
|
||||
join_params2.post = str8_lit("\0");
|
||||
String8 env = str8_list_join(scratch.arena, &options->env, &join_params2);
|
||||
|
||||
String16 cmd16 = str16_from_8(scratch.arena, cmd);
|
||||
String16 dir16 = str16_from_8(scratch.arena, options->path);
|
||||
String16 env16 = str16_from_8(scratch.arena, env);
|
||||
|
||||
DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE;
|
||||
STARTUPINFOW startup_info = {sizeof(startup_info)};
|
||||
PROCESS_INFORMATION process_info = {0};
|
||||
if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str,
|
||||
&startup_info, &process_info))
|
||||
{
|
||||
CloseHandle(process_info.hProcess);
|
||||
CloseHandle(process_info.hThread);
|
||||
result = true;
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
global HANDLE g_process_1 = 0;
|
||||
global DWORD g_process_id_1 = 0;
|
||||
global U64 g_process_injection_addr_1 = 0;
|
||||
global HANDLE g_process_2 = 0;
|
||||
global DWORD g_process_id_2 = 0;
|
||||
|
||||
internal B32
|
||||
test_w32_inject_thread(HANDLE process, U64 start_address)
|
||||
{
|
||||
B32 result = false;
|
||||
LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)start_address;
|
||||
HANDLE thread = CreateRemoteThread(process, 0, 0, start, 0, 0, 0);
|
||||
if(thread != 0)
|
||||
{
|
||||
CloseHandle(thread);
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
test_halt(void)
|
||||
{
|
||||
test_w32_inject_thread(g_process_1, g_process_injection_addr_1);
|
||||
}
|
||||
|
||||
internal TEST_DebugEvent
|
||||
test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
TEST_DebugEvent result = {0};
|
||||
|
||||
//- rjf: freeze thread
|
||||
if(suspend_thread)
|
||||
{
|
||||
DWORD result = SuspendThread(suspend_thread);
|
||||
DWORD error = GetLastError();
|
||||
int x = 0;
|
||||
}
|
||||
|
||||
//- rjf: write traps
|
||||
U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count);
|
||||
{
|
||||
TEST_Trap *trap = traps;
|
||||
for(U64 i = 0; i < traps_count; i += 1, trap += 1)
|
||||
{
|
||||
if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1))
|
||||
{
|
||||
U8 int3 = 0xCC;
|
||||
test_w32_write_memory(trap->process, trap->address, &int3, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
trap_swap_bytes[i] = 0xCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: set single step bit
|
||||
if(step_thread != 0)
|
||||
{
|
||||
SYMS_RegX64 regs = {0};
|
||||
test_w32_read_x64_regs(step_thread, ®s);
|
||||
regs.rflags.u64 |= 0x100;
|
||||
test_w32_write_x64_regs(step_thread, ®s);
|
||||
}
|
||||
|
||||
//- rjf: continue
|
||||
local_persist B32 need_resume = 0;
|
||||
local_persist DWORD resume_pid = 0;
|
||||
local_persist DWORD resume_tid = 0;
|
||||
|
||||
if(need_resume)
|
||||
{
|
||||
need_resume = 0;
|
||||
ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE);
|
||||
}
|
||||
|
||||
//- rjf: get event
|
||||
DEBUG_EVENT evt = {0};
|
||||
if(WaitForDebugEvent(&evt, INFINITE))
|
||||
{
|
||||
need_resume = 1;
|
||||
resume_pid = evt.dwProcessId;
|
||||
resume_tid = evt.dwThreadId;
|
||||
result.evt = evt;
|
||||
|
||||
switch(evt.dwDebugEventCode)
|
||||
{
|
||||
default:break;
|
||||
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("create process");
|
||||
result.process_id = evt.dwProcessId;
|
||||
result.process = evt.u.CreateProcessInfo.hProcess;
|
||||
result.thread_id = evt.dwThreadId;
|
||||
result.thread = evt.u.CreateProcessInfo.hThread;
|
||||
if(g_process_1 == 0)
|
||||
{
|
||||
g_process_1 = result.process;
|
||||
g_process_id_1 = result.process_id;
|
||||
|
||||
// injection memory
|
||||
{
|
||||
U8 injection_code[64];
|
||||
injection_code[0] = 0xCC;
|
||||
injection_code[1] = 0xC3;
|
||||
for (U64 i = 2; i < 64; i += 1){
|
||||
injection_code[i] = 0xCC;
|
||||
}
|
||||
|
||||
U64 injection_size = 64;
|
||||
U64 injection_address = (U64)VirtualAllocEx(g_process_1, 0, injection_size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE);
|
||||
test_w32_write_memory(g_process_1, injection_address, injection_code, sizeof(injection_code));
|
||||
g_process_injection_addr_1 = injection_address;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
g_process_2 = result.process;
|
||||
g_process_id_2 = result.process_id;
|
||||
}
|
||||
}break;
|
||||
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("exit process");
|
||||
result.process_id = evt.dwProcessId;
|
||||
}break;
|
||||
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("create thread");
|
||||
result.thread_id = evt.dwThreadId;
|
||||
result.thread = evt.u.CreateThread.hThread;
|
||||
}break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("exit thread");
|
||||
result.thread_id = evt.dwThreadId;
|
||||
}break;
|
||||
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("load dll");
|
||||
}break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("unload dll");
|
||||
}break;
|
||||
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("exception");
|
||||
|
||||
EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception;
|
||||
EXCEPTION_RECORD *exception = &edi->ExceptionRecord;
|
||||
|
||||
switch(exception->ExceptionCode)
|
||||
{
|
||||
case DEMON_W32_EXCEPTION_BREAKPOINT:
|
||||
{
|
||||
result.name = str8_lit("breakpoint");
|
||||
result.addr = (U64)exception->ExceptionAddress;
|
||||
}break;
|
||||
|
||||
case DEMON_W32_EXCEPTION_SINGLE_STEP:
|
||||
{
|
||||
result.name = str8_lit("single_step");
|
||||
}break;
|
||||
|
||||
case DEMON_W32_EXCEPTION_THROW:
|
||||
{
|
||||
result.name = str8_lit("exception throw");
|
||||
}break;
|
||||
|
||||
case DEMON_W32_EXCEPTION_ACCESS_VIOLATION:
|
||||
case DEMON_W32_EXCEPTION_IN_PAGE_ERROR:
|
||||
{
|
||||
result.name = str8_lit("exception access violation");
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
}break;
|
||||
}
|
||||
|
||||
}break;
|
||||
|
||||
case OUTPUT_DEBUG_STRING_EVENT:
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
result.name = str8_lit("output debug string");
|
||||
|
||||
U64 string_address = (U64)evt.u.DebugString.lpDebugStringData;
|
||||
U64 string_size = (U64)evt.u.DebugString.nDebugStringLength;
|
||||
|
||||
// TODO(allen): is the string in UTF-8 or UTF-16?
|
||||
|
||||
U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1);
|
||||
test_w32_read_memory(g_process_id_1 == evt.dwProcessId ? g_process_1 : g_process_2, buffer, string_address, string_size);
|
||||
buffer[string_size] = 0;
|
||||
|
||||
printf("%s\n", buffer);
|
||||
scratch_end(scratch);
|
||||
}break;
|
||||
|
||||
case RIP_EVENT:
|
||||
{
|
||||
result.name = str8_lit("rip event");
|
||||
}break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: set single step bit
|
||||
if(step_thread != 0)
|
||||
{
|
||||
SYMS_RegX64 regs = {0};
|
||||
test_w32_read_x64_regs(step_thread, ®s);
|
||||
regs.rflags.u64 &= ~0x100;
|
||||
test_w32_write_x64_regs(step_thread, ®s);
|
||||
}
|
||||
|
||||
//- rjf: unset traps
|
||||
{
|
||||
TEST_Trap *trap = traps;
|
||||
for(U64 i = 0; i < traps_count; i += 1, trap += 1)
|
||||
{
|
||||
U8 og_byte = trap_swap_bytes[i];
|
||||
if(og_byte != 0xCC)
|
||||
{
|
||||
test_w32_write_memory(trap->process, trap->address, &og_byte, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: resume thread
|
||||
if(suspend_thread)
|
||||
{
|
||||
ResumeThread(suspend_thread);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal DWORD
|
||||
test_halter_thread(void *params)
|
||||
{
|
||||
HANDLE original_process_handle = params;
|
||||
Sleep(1500);
|
||||
test_halt();
|
||||
#if 0
|
||||
DWORD process_id = GetProcessId(original_process_handle);
|
||||
HANDLE elevated_process_handle = OpenProcess(PROCESS_SUSPEND_RESUME, 0, process_id);
|
||||
LONG result = NtSuspendProcess(elevated_process_handle);
|
||||
CloseHandle(elevated_process_handle);
|
||||
DebugBreakProcess(process);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argument_count, char **arguments)
|
||||
{
|
||||
os_init(argument_count, arguments);
|
||||
Arena *arena = arena_alloc();
|
||||
|
||||
NtSuspendProcess = (NtSuspendProcessFunction *)GetProcAddress(GetModuleHandle("ntdll"), "NtSuspendProcess");
|
||||
|
||||
// rjf: launch
|
||||
{
|
||||
OS_LaunchOptions opts = {0};
|
||||
opts.path = os_get_path(arena, OS_SystemPath_Current);
|
||||
str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop.exe"));
|
||||
B32 launch_good = test_launch_process(&opts);
|
||||
int x = 0;
|
||||
}
|
||||
|
||||
// rjf: get process/thread handles
|
||||
HANDLE process = 0;
|
||||
HANDLE thread1 = 0;
|
||||
U64 thread1_id = 0;
|
||||
{
|
||||
for(TEST_DebugEvent evt = {0};;)
|
||||
{
|
||||
evt = test_run_process(0, 0, 0, 0);
|
||||
if(evt.process)
|
||||
{
|
||||
process = evt.process;
|
||||
}
|
||||
if(evt.thread)
|
||||
{
|
||||
thread1 = evt.thread;
|
||||
thread1_id = evt.thread_id;
|
||||
}
|
||||
if(process != 0 && thread1 != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: get first breakpoint
|
||||
{
|
||||
for(TEST_DebugEvent evt = {0};;)
|
||||
{
|
||||
evt = test_run_process(0, 0, 0, 0);
|
||||
if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: launch halter thread
|
||||
DWORD halter_id = 0;
|
||||
{
|
||||
CreateThread(0, 0, test_halter_thread, process, 0, &halter_id);
|
||||
}
|
||||
|
||||
// rjf: run + wait for event
|
||||
for(;;)
|
||||
{
|
||||
TEST_DebugEvent evt = test_run_process(0, 0, 0, 0);
|
||||
int x = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//- rjf: run until 2nd thread starts up
|
||||
HANDLE thread2 = 0;
|
||||
U64 thread2_id = 0;
|
||||
{
|
||||
for(TEST_DebugEvent evt = {0};;)
|
||||
{
|
||||
evt = test_run_process(0, 0, 0, 0/*ArrayCount(traps), traps*/);
|
||||
if(evt.thread)
|
||||
{
|
||||
thread2 = evt.thread;
|
||||
thread2_id = evt.thread_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: wait for first output string
|
||||
{
|
||||
for(TEST_DebugEvent evt = {0};;)
|
||||
{
|
||||
evt = test_run_process(0, 0, 0, 0);
|
||||
if(evt.evt.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: wait for bps
|
||||
{
|
||||
// U64 thread1_stop_vaddr = 0x0000000140001119;
|
||||
// U64 thread2_stop_vaddr = 0x00000001400010C8;
|
||||
// TEST_Trap traps[] =
|
||||
{
|
||||
// {process, thread1_stop_vaddr},
|
||||
//{process, thread2_stop_vaddr},
|
||||
};
|
||||
TEST_DebugEvent evt = {0};
|
||||
//for(;;)
|
||||
{
|
||||
evt = test_run_process(0, thread2, 0, 0/*ArrayCount(traps), traps*/);
|
||||
int x = 0;
|
||||
}
|
||||
for(;;) {}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,874 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/base_inc.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "syms_helpers/syms_internal_overrides.h"
|
||||
#include "syms/syms_inc.h"
|
||||
#include "syms_helpers/syms_helpers.h"
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "syms_helpers/syms_internal_overrides.c"
|
||||
#include "syms/syms_inc.c"
|
||||
#include "syms_helpers/syms_helpers.c"
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Win32 Demon Exceptions
|
||||
|
||||
#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Win32 Demon Register API Codes
|
||||
|
||||
#define DEMON_W32_CTX_X86 0x00010000
|
||||
#define DEMON_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DEMON_W32_CTX_INTEL_CONTROL 0x0001
|
||||
#define DEMON_W32_CTX_INTEL_INTEGER 0x0002
|
||||
#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004
|
||||
#define DEMON_W32_CTX_INTEL_FLOATS 0x0008
|
||||
#define DEMON_W32_CTX_INTEL_DEBUG 0x0010
|
||||
#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DEMON_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \
|
||||
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
|
||||
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \
|
||||
DEMON_W32_CTX_INTEL_EXTENDED)
|
||||
#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \
|
||||
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
|
||||
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \
|
||||
DEMON_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
struct TEST_DebugEvent
|
||||
{
|
||||
String8 name;
|
||||
U64 process_id;
|
||||
U64 thread_id;
|
||||
HANDLE process;
|
||||
HANDLE thread;
|
||||
U64 addr;
|
||||
DEBUG_EVENT evt;
|
||||
};
|
||||
|
||||
struct TEST_Trap
|
||||
{
|
||||
HANDLE process;
|
||||
U64 address;
|
||||
};
|
||||
|
||||
internal U16
|
||||
test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave)
|
||||
{
|
||||
U16 result = 0;
|
||||
U32 top = (fxsave->StatusWord >> 11) & 7;
|
||||
for (U32 fpr = 0; fpr < 8; fpr += 1){
|
||||
U32 tag = 3;
|
||||
if (fxsave->TagWord & (1 << fpr)){
|
||||
U32 st = (fpr - top)&7;
|
||||
|
||||
SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16];
|
||||
U16 exponent = fp->sign1_exp15 & bitmask15;
|
||||
U64 integer_part = fp->int1_frac63 >> 63;
|
||||
U64 fraction_part = fp->int1_frac63 & bitmask63;
|
||||
|
||||
// tag: 0 - normal; 1 - zero; 2 - special
|
||||
tag = 2;
|
||||
if (exponent == 0){
|
||||
if (integer_part == 0 && fraction_part == 0){
|
||||
tag = 1;
|
||||
}
|
||||
}
|
||||
else if (exponent != bitmask15 && integer_part != 0){
|
||||
tag = 0;
|
||||
}
|
||||
}
|
||||
result |= tag << (2 * fpr);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal U16
|
||||
test_w32_xsave_tag_word_from_real_tag_word(U16 ftw)
|
||||
{
|
||||
U16 compact = 0;
|
||||
for (U32 fpr = 0; fpr < 8; fpr++){
|
||||
U32 tag = (ftw >> (fpr * 2)) & 3;
|
||||
if (tag != 3){
|
||||
compact |= (1 << fpr);
|
||||
}
|
||||
}
|
||||
return(compact);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// NOTE(allen): Check available features
|
||||
U32 feature_mask = GetEnabledXStateFeatures();
|
||||
B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX);
|
||||
|
||||
// NOTE(allen): Setup the context
|
||||
CONTEXT *ctx = 0;
|
||||
U32 ctx_flags = DEMON_W32_CTX_X64_ALL;
|
||||
if (avx_enabled){
|
||||
ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE;
|
||||
}
|
||||
DWORD size = 0;
|
||||
InitializeContext(0, ctx_flags, 0, &size);
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
|
||||
void *ctx_memory = push_array(scratch.arena, U8, size);
|
||||
if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){
|
||||
ctx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
B32 avx_available = false;
|
||||
|
||||
if (ctx != 0){
|
||||
// NOTE(allen): Finish Context Setup
|
||||
if (avx_enabled){
|
||||
SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX);
|
||||
}
|
||||
|
||||
// NOTE(allen): Determine what features are available on this particular ctx
|
||||
// TODO(allen): Experiment carefully with this nonsense.
|
||||
// Does avx_enabled = avx_available in all circumstances or not?
|
||||
DWORD64 xstate_flags = 0;
|
||||
if (GetXStateFeaturesMask(ctx, &xstate_flags)){
|
||||
if (xstate_flags & XSTATE_MASK_AVX){
|
||||
avx_available = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get thread context
|
||||
HANDLE thread_handle = thread;
|
||||
if (!GetThreadContext(thread_handle, ctx)){
|
||||
ctx = 0;
|
||||
}
|
||||
|
||||
B32 result = false;
|
||||
if (ctx != 0){
|
||||
result = true;
|
||||
|
||||
// NOTE(allen): Convert CONTEXT -> SYMS_RegX64
|
||||
dst->rax.u64 = ctx->Rax;
|
||||
dst->rcx.u64 = ctx->Rcx;
|
||||
dst->rdx.u64 = ctx->Rdx;
|
||||
dst->rbx.u64 = ctx->Rbx;
|
||||
dst->rsp.u64 = ctx->Rsp;
|
||||
dst->rbp.u64 = ctx->Rbp;
|
||||
dst->rsi.u64 = ctx->Rsi;
|
||||
dst->rdi.u64 = ctx->Rdi;
|
||||
dst->r8.u64 = ctx->R8;
|
||||
dst->r9.u64 = ctx->R9;
|
||||
dst->r10.u64 = ctx->R10;
|
||||
dst->r11.u64 = ctx->R11;
|
||||
dst->r12.u64 = ctx->R12;
|
||||
dst->r13.u64 = ctx->R13;
|
||||
dst->r14.u64 = ctx->R14;
|
||||
dst->r15.u64 = ctx->R15;
|
||||
dst->rip.u64 = ctx->Rip;
|
||||
dst->cs.u16 = ctx->SegCs;
|
||||
dst->ds.u16 = ctx->SegDs;
|
||||
dst->es.u16 = ctx->SegEs;
|
||||
dst->fs.u16 = ctx->SegFs;
|
||||
dst->gs.u16 = ctx->SegGs;
|
||||
dst->ss.u16 = ctx->SegSs;
|
||||
dst->dr0.u32 = ctx->Dr0;
|
||||
dst->dr1.u32 = ctx->Dr1;
|
||||
dst->dr2.u32 = ctx->Dr2;
|
||||
dst->dr3.u32 = ctx->Dr3;
|
||||
dst->dr6.u32 = ctx->Dr6;
|
||||
dst->dr7.u32 = ctx->Dr7;
|
||||
|
||||
// NOTE(allen): This bit is "supposed to always be 1" I guess.
|
||||
// TODO(allen): Not sure what this is all about but I haven't investigated it yet.
|
||||
// This might be totally not necessary or something.
|
||||
dst->rflags.u64 = ctx->EFlags | 0x2;
|
||||
|
||||
XSAVE_FORMAT *xsave = &ctx->FltSave;
|
||||
dst->fcw.u16 = xsave->ControlWord;
|
||||
dst->fsw.u16 = xsave->StatusWord;
|
||||
dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave);
|
||||
dst->fop.u16 = xsave->ErrorOpcode;
|
||||
dst->fcs.u16 = xsave->ErrorSelector;
|
||||
dst->fds.u16 = xsave->DataSelector;
|
||||
dst->fip.u32 = xsave->ErrorOffset;
|
||||
dst->fdp.u32 = xsave->DataOffset;
|
||||
dst->mxcsr.u32 = xsave->MxCsr;
|
||||
dst->mxcsr_mask.u32 = xsave->MxCsr_Mask;
|
||||
|
||||
M128A *float_s = xsave->FloatRegisters;
|
||||
SYMS_Reg80 *float_d = &dst->fpr0;
|
||||
for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){
|
||||
MemoryCopy(float_d, float_s, sizeof(*float_d));
|
||||
}
|
||||
|
||||
if (!avx_available){
|
||||
M128A *xmm_s = xsave->XmmRegisters;
|
||||
SYMS_Reg256 *xmm_d = &dst->ymm0;
|
||||
for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){
|
||||
MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s));
|
||||
}
|
||||
}
|
||||
|
||||
if (avx_available){
|
||||
DWORD part0_length = 0;
|
||||
M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length);
|
||||
DWORD part1_length = 0;
|
||||
M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length);
|
||||
Assert(part0_length == part1_length);
|
||||
|
||||
DWORD count = part0_length/sizeof(part0[0]);
|
||||
count = ClampTop(count, 16);
|
||||
SYMS_Reg256 *ymm_d = &dst->ymm0;
|
||||
for (DWORD i = 0;
|
||||
i < count;
|
||||
i += 1, part0 += 1, part1 += 1, ymm_d += 1){
|
||||
// TODO(allen): Are we writing these out in the right order? Seems weird right?
|
||||
ymm_d->u64[3] = part0->Low;
|
||||
ymm_d->u64[2] = part0->High;
|
||||
ymm_d->u64[1] = part1->Low;
|
||||
ymm_d->u64[0] = part1->High;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// NOTE(allen): Check available features
|
||||
U32 feature_mask = GetEnabledXStateFeatures();
|
||||
B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX);
|
||||
|
||||
// NOTE(allen): Setup the context
|
||||
CONTEXT *ctx = 0;
|
||||
U32 ctx_flags = DEMON_W32_CTX_X64_ALL;
|
||||
if (avx_enabled){
|
||||
ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE;
|
||||
}
|
||||
DWORD size = 0;
|
||||
InitializeContext(0, ctx_flags, 0, &size);
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
|
||||
void *ctx_memory = push_array(scratch.arena, U8, size);
|
||||
if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){
|
||||
ctx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
B32 avx_available = false;
|
||||
|
||||
if (ctx != 0){
|
||||
// NOTE(allen): Finish Context Setup
|
||||
if (avx_enabled){
|
||||
SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX);
|
||||
}
|
||||
|
||||
// NOTE(allen): Determine what features are available on this particular ctx
|
||||
// TODO(allen): Experiment carefully with this nonsense.
|
||||
// Does avx_enabled = avx_available in all circumstances or not?
|
||||
DWORD64 xstate_flags = 0;
|
||||
if (GetXStateFeaturesMask(ctx, &xstate_flags)){
|
||||
if (xstate_flags & XSTATE_MASK_AVX){
|
||||
avx_available = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
B32 result = false;
|
||||
if (ctx != 0){
|
||||
// NOTE(allen): Convert SYMS_RegX64 -> CONTEXT
|
||||
ctx->ContextFlags = ctx_flags;
|
||||
|
||||
ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32;
|
||||
|
||||
ctx->Rax = src->rax.u64;
|
||||
ctx->Rcx = src->rcx.u64;
|
||||
ctx->Rdx = src->rdx.u64;
|
||||
ctx->Rbx = src->rbx.u64;
|
||||
ctx->Rsp = src->rsp.u64;
|
||||
ctx->Rbp = src->rbp.u64;
|
||||
ctx->Rsi = src->rsi.u64;
|
||||
ctx->Rdi = src->rdi.u64;
|
||||
ctx->R8 = src->r8.u64;
|
||||
ctx->R9 = src->r9.u64;
|
||||
ctx->R10 = src->r10.u64;
|
||||
ctx->R11 = src->r11.u64;
|
||||
ctx->R12 = src->r12.u64;
|
||||
ctx->R13 = src->r13.u64;
|
||||
ctx->R14 = src->r14.u64;
|
||||
ctx->R15 = src->r15.u64;
|
||||
ctx->Rip = src->rip.u64;
|
||||
ctx->SegCs = src->cs.u16;
|
||||
ctx->SegDs = src->ds.u16;
|
||||
ctx->SegEs = src->es.u16;
|
||||
ctx->SegFs = src->fs.u16;
|
||||
ctx->SegGs = src->gs.u16;
|
||||
ctx->SegSs = src->ss.u16;
|
||||
ctx->Dr0 = src->dr0.u32;
|
||||
ctx->Dr1 = src->dr1.u32;
|
||||
ctx->Dr2 = src->dr2.u32;
|
||||
ctx->Dr3 = src->dr3.u32;
|
||||
ctx->Dr6 = src->dr6.u32;
|
||||
ctx->Dr7 = src->dr7.u32;
|
||||
|
||||
ctx->EFlags = src->rflags.u64;
|
||||
|
||||
XSAVE_FORMAT *fxsave = &ctx->FltSave;
|
||||
fxsave->ControlWord = src->fcw.u16;
|
||||
fxsave->StatusWord = src->fsw.u16;
|
||||
fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16);
|
||||
fxsave->ErrorOpcode = src->fop.u16;
|
||||
fxsave->ErrorSelector = src->fcs.u16;
|
||||
fxsave->DataSelector = src->fds.u16;
|
||||
fxsave->ErrorOffset = src->fip.u32;
|
||||
fxsave->DataOffset = src->fdp.u32;
|
||||
|
||||
M128A *float_d = fxsave->FloatRegisters;
|
||||
SYMS_Reg80 *float_s = &src->fpr0;
|
||||
for (U32 n = 0;
|
||||
n < 8;
|
||||
n += 1, float_s += 1, float_d += 1){
|
||||
MemoryCopy(float_d, float_s, 10);
|
||||
}
|
||||
|
||||
if (!avx_available){
|
||||
M128A *xmm_d = fxsave->XmmRegisters;
|
||||
SYMS_Reg256 *xmm_s = &src->ymm0;
|
||||
for (U32 n = 0;
|
||||
n < 8;
|
||||
n += 1, xmm_d += 1, xmm_s += 1){
|
||||
MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d));
|
||||
}
|
||||
}
|
||||
|
||||
if (avx_available){
|
||||
DWORD part0_length = 0;
|
||||
M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length);
|
||||
DWORD part1_length = 0;
|
||||
M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length);
|
||||
Assert(part0_length == part1_length);
|
||||
|
||||
DWORD count = part0_length/sizeof(part0[0]);
|
||||
count = ClampTop(count, 16);
|
||||
SYMS_Reg256 *ymm_d = &src->ymm0;
|
||||
for (DWORD i = 0;
|
||||
i < count;
|
||||
i += 1, part0 += 1, part1 += 1, ymm_d += 1){
|
||||
// TODO(allen): Are we writing these out in the right order? Seems weird right?
|
||||
part0->Low = ymm_d->u64[3];
|
||||
part0->High = ymm_d->u64[2];
|
||||
part1->Low = ymm_d->u64[1];
|
||||
part1->High = ymm_d->u64[0];
|
||||
}
|
||||
}
|
||||
|
||||
//- set thread context
|
||||
HANDLE thread_handle = thread;
|
||||
if (SetThreadContext(thread_handle, ctx)){
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size)
|
||||
{
|
||||
B32 result = true;
|
||||
U8 *ptr = (U8*)dst;
|
||||
U8 *opl = ptr + size;
|
||||
U64 cursor = src_address;
|
||||
for (;ptr < opl;){
|
||||
SIZE_T to_read = (SIZE_T)(opl - ptr);
|
||||
SIZE_T actual_read = 0;
|
||||
if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
ptr += actual_read;
|
||||
cursor += actual_read;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size)
|
||||
{
|
||||
B32 result = true;
|
||||
U8 *ptr = (U8*)src;
|
||||
U8 *opl = ptr + size;
|
||||
U64 cursor = dst_address;
|
||||
for (;ptr < opl;){
|
||||
SIZE_T to_write = (SIZE_T)(opl - ptr);
|
||||
SIZE_T actual_write = 0;
|
||||
if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
ptr += actual_write;
|
||||
cursor += actual_write;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal B32
|
||||
test_launch_process(OS_LaunchOptions *options)
|
||||
{
|
||||
B32 result = false;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
StringJoin join_params = {0};
|
||||
join_params.pre = str8_lit("\"");
|
||||
join_params.sep = str8_lit("\" \"");
|
||||
join_params.post = str8_lit("\"");
|
||||
String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params);
|
||||
|
||||
StringJoin join_params2 = {0};
|
||||
join_params2.sep = str8_lit("\0");
|
||||
join_params2.post = str8_lit("\0");
|
||||
String8 env = str8_list_join(scratch.arena, &options->env, &join_params2);
|
||||
|
||||
String16 cmd16 = str16_from_8(scratch.arena, cmd);
|
||||
String16 dir16 = str16_from_8(scratch.arena, options->path);
|
||||
String16 env16 = str16_from_8(scratch.arena, env);
|
||||
|
||||
DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE;
|
||||
STARTUPINFOW startup_info = {sizeof(startup_info)};
|
||||
PROCESS_INFORMATION process_info = {0};
|
||||
if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str,
|
||||
&startup_info, &process_info))
|
||||
{
|
||||
CloseHandle(process_info.hProcess);
|
||||
CloseHandle(process_info.hThread);
|
||||
result = true;
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
global HANDLE g_process = 0;
|
||||
global DWORD g_process_id = 0;
|
||||
global HANDLE g_thread1 = 0;
|
||||
global DWORD g_thread1_id = 0;
|
||||
global HANDLE g_thread2 = 0;
|
||||
global DWORD g_thread2_id = 0;
|
||||
|
||||
internal TEST_DebugEvent
|
||||
test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
TEST_DebugEvent result = {0};
|
||||
|
||||
//- rjf: freeze thread
|
||||
if(suspend_thread)
|
||||
{
|
||||
DWORD result = SuspendThread(suspend_thread);
|
||||
DWORD error = GetLastError();
|
||||
int x = 0;
|
||||
}
|
||||
|
||||
//- rjf: write traps
|
||||
U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count);
|
||||
{
|
||||
TEST_Trap *trap = traps;
|
||||
for(U64 i = 0; i < traps_count; i += 1, trap += 1)
|
||||
{
|
||||
if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1))
|
||||
{
|
||||
U8 int3 = 0xCC;
|
||||
test_w32_write_memory(trap->process, trap->address, &int3, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
trap_swap_bytes[i] = 0xCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: set single step bit
|
||||
if(step_thread != 0)
|
||||
{
|
||||
SYMS_RegX64 regs = {0};
|
||||
test_w32_read_x64_regs(step_thread, ®s);
|
||||
regs.rflags.u64 |= 0x100;
|
||||
test_w32_write_x64_regs(step_thread, ®s);
|
||||
}
|
||||
|
||||
//- rjf: continue
|
||||
local_persist B32 need_resume = 0;
|
||||
local_persist DWORD resume_pid = 0;
|
||||
local_persist DWORD resume_tid = 0;
|
||||
|
||||
if(need_resume)
|
||||
{
|
||||
need_resume = 0;
|
||||
ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE);
|
||||
}
|
||||
|
||||
//- rjf: get event
|
||||
DEBUG_EVENT evt = {0};
|
||||
if(WaitForDebugEvent(&evt, INFINITE))
|
||||
{
|
||||
need_resume = 1;
|
||||
resume_pid = evt.dwProcessId;
|
||||
resume_tid = evt.dwThreadId;
|
||||
result.evt = evt;
|
||||
|
||||
switch(evt.dwDebugEventCode)
|
||||
{
|
||||
default:break;
|
||||
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("create process");
|
||||
result.process_id = evt.dwProcessId;
|
||||
result.process = evt.u.CreateProcessInfo.hProcess;
|
||||
result.thread_id = evt.dwThreadId;
|
||||
result.thread = evt.u.CreateProcessInfo.hThread;
|
||||
if(g_process == 0)
|
||||
{
|
||||
g_process = result.process;
|
||||
g_process_id = result.process_id;
|
||||
}
|
||||
if(g_thread1 == 0)
|
||||
{
|
||||
g_thread1 = result.thread;
|
||||
g_thread1_id = result.thread_id;
|
||||
}
|
||||
}break;
|
||||
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("exit process");
|
||||
result.process_id = evt.dwProcessId;
|
||||
}break;
|
||||
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("create thread");
|
||||
result.thread_id = evt.dwThreadId;
|
||||
result.thread = evt.u.CreateThread.hThread;
|
||||
g_thread2 = result.thread;
|
||||
g_thread2_id = result.thread_id;
|
||||
}break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("exit thread");
|
||||
result.thread_id = evt.dwThreadId;
|
||||
}break;
|
||||
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("load dll");
|
||||
}break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("unload dll");
|
||||
}break;
|
||||
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
{
|
||||
result.name = str8_lit("exception");
|
||||
|
||||
EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception;
|
||||
EXCEPTION_RECORD *exception = &edi->ExceptionRecord;
|
||||
|
||||
switch(exception->ExceptionCode)
|
||||
{
|
||||
case DEMON_W32_EXCEPTION_BREAKPOINT:
|
||||
{
|
||||
result.name = str8_lit("breakpoint");
|
||||
result.addr = (U64)exception->ExceptionAddress;
|
||||
|
||||
local_persist B32 did_first_bp = 0;
|
||||
if(did_first_bp != 0)
|
||||
{
|
||||
HANDLE thread = evt.dwThreadId == g_thread1_id ? g_thread1 : g_thread2;
|
||||
SYMS_RegX64 regs = {0};
|
||||
test_w32_read_x64_regs(thread, ®s);
|
||||
regs.rip.u64 = result.addr;
|
||||
test_w32_write_x64_regs(thread, ®s);
|
||||
}
|
||||
did_first_bp = 1;
|
||||
|
||||
}break;
|
||||
|
||||
case DEMON_W32_EXCEPTION_SINGLE_STEP:
|
||||
{
|
||||
result.name = str8_lit("single_step");
|
||||
}break;
|
||||
|
||||
case DEMON_W32_EXCEPTION_THROW:
|
||||
{
|
||||
result.name = str8_lit("exception throw");
|
||||
}break;
|
||||
|
||||
case DEMON_W32_EXCEPTION_ACCESS_VIOLATION:
|
||||
case DEMON_W32_EXCEPTION_IN_PAGE_ERROR:
|
||||
{
|
||||
result.name = str8_lit("exception access violation");
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
}break;
|
||||
}
|
||||
|
||||
}break;
|
||||
|
||||
case OUTPUT_DEBUG_STRING_EVENT:
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
result.name = str8_lit("output debug string");
|
||||
|
||||
U64 string_address = (U64)evt.u.DebugString.lpDebugStringData;
|
||||
U64 string_size = (U64)evt.u.DebugString.nDebugStringLength;
|
||||
|
||||
// TODO(allen): is the string in UTF-8 or UTF-16?
|
||||
|
||||
U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1);
|
||||
test_w32_read_memory(g_process, buffer, string_address, string_size);
|
||||
buffer[string_size] = 0;
|
||||
|
||||
printf("%s\n", buffer);
|
||||
scratch_end(scratch);
|
||||
}break;
|
||||
|
||||
case RIP_EVENT:
|
||||
{
|
||||
result.name = str8_lit("rip event");
|
||||
}break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: set single step bit
|
||||
if(step_thread != 0)
|
||||
{
|
||||
SYMS_RegX64 regs = {0};
|
||||
test_w32_read_x64_regs(step_thread, ®s);
|
||||
regs.rflags.u64 &= ~0x100;
|
||||
test_w32_write_x64_regs(step_thread, ®s);
|
||||
}
|
||||
|
||||
//- rjf: unset traps
|
||||
{
|
||||
TEST_Trap *trap = traps;
|
||||
for(U64 i = 0; i < traps_count; i += 1, trap += 1)
|
||||
{
|
||||
U8 og_byte = trap_swap_bytes[i];
|
||||
if(og_byte != 0xCC)
|
||||
{
|
||||
test_w32_write_memory(trap->process, trap->address, &og_byte, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: check for more events
|
||||
for(int i = 0; i < 100; i += 1)
|
||||
{
|
||||
DEBUG_EVENT evt = {0};
|
||||
if(WaitForDebugEvent(&evt, 0))
|
||||
{
|
||||
int x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: resume thread
|
||||
if(suspend_thread)
|
||||
{
|
||||
ResumeThread(suspend_thread);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argument_count, char **arguments)
|
||||
{
|
||||
os_init(argument_count, arguments);
|
||||
Arena *arena = arena_alloc();
|
||||
|
||||
U64 before_loop_stop_vaddr = 0x0000000140001089;
|
||||
U64 inner_loop_stop_vaddr = 0x0000000140001098;
|
||||
|
||||
// rjf: launch
|
||||
{
|
||||
OS_LaunchOptions opts = {0};
|
||||
opts.path = os_get_path(arena, OS_SystemPath_Current);
|
||||
str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop_threads_win32.exe"));
|
||||
B32 launch_good = test_launch_process(&opts);
|
||||
int x = 0;
|
||||
}
|
||||
|
||||
// rjf: get process/thread handles
|
||||
HANDLE process = 0;
|
||||
HANDLE thread1 = 0;
|
||||
U64 thread1_id = 0;
|
||||
{
|
||||
for(TEST_DebugEvent evt = {0};;)
|
||||
{
|
||||
evt = test_run_process(0, 0, 0, 0);
|
||||
if(evt.process)
|
||||
{
|
||||
process = evt.process;
|
||||
}
|
||||
if(evt.thread)
|
||||
{
|
||||
thread1 = evt.thread;
|
||||
thread1_id = evt.thread_id;
|
||||
}
|
||||
if(process != 0 && thread1 != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: get first breakpoint
|
||||
{
|
||||
for(TEST_DebugEvent evt = {0};;)
|
||||
{
|
||||
evt = test_run_process(0, 0, 0, 0);
|
||||
if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: run until 2nd thread starts up
|
||||
HANDLE thread2 = 0;
|
||||
U64 thread2_id = 0;
|
||||
{
|
||||
TEST_Trap traps[] =
|
||||
{
|
||||
{process, before_loop_stop_vaddr},
|
||||
};
|
||||
int trap_count = 0; //ArrayCount(traps);
|
||||
for(TEST_DebugEvent evt = {0};;)
|
||||
{
|
||||
evt = test_run_process(0, 0, trap_count, traps);
|
||||
if(str8_match(evt.name, str8_lit("breakpoint"), 0))
|
||||
{
|
||||
trap_count = 0;
|
||||
}
|
||||
if(evt.thread)
|
||||
{
|
||||
thread2 = evt.thread;
|
||||
thread2_id = evt.thread_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: wait for bps
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
TEST_Trap traps[] =
|
||||
{
|
||||
{process, 0x0000000140001098},
|
||||
{process, 0x00000001400010fb},
|
||||
{process, 0x00000001400010bc},
|
||||
{process, 0x00000001400010d7},
|
||||
};
|
||||
|
||||
for(int i = 0;; i += 1)
|
||||
{
|
||||
TEST_DebugEvent evt = test_run_process(0, 0, 1, &traps[i % ArrayCount(traps)]);
|
||||
|
||||
// rjf: check regs
|
||||
{
|
||||
U64 rip = 0;
|
||||
SYMS_RegX64 *regs = push_array(scratch.arena, SYMS_RegX64, 1);
|
||||
if(evt.evt.dwThreadId == g_thread1_id && test_w32_read_x64_regs(thread1, regs))
|
||||
{
|
||||
rip = regs->rip.u64;
|
||||
}
|
||||
if(evt.evt.dwThreadId == g_thread2_id && test_w32_read_x64_regs(thread2, regs))
|
||||
{
|
||||
rip = regs->rip.u64;
|
||||
}
|
||||
|
||||
for(int i = 0; i < ArrayCount(traps); i += 1)
|
||||
{
|
||||
if(traps[i].address == rip)
|
||||
{
|
||||
printf("WRONG BP! 0x%I64x\n", rip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(str8_match(evt.name, str8_lit("breakpoint"), 0))
|
||||
{
|
||||
HANDLE step = 0;
|
||||
HANDLE suspend = 0;
|
||||
step = evt.evt.dwThreadId == thread2_id ? thread2 : thread1;
|
||||
suspend = step == thread2 ? thread1 : thread2;
|
||||
evt = test_run_process(step, suspend, 0, 0);
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,286 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_WIN32_H
|
||||
#define DEMON_CORE_WIN32_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Windows Includes
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Exception Codes
|
||||
|
||||
#define DMN_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DMN_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DMN_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DMN_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DMN_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DMN_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DMN_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DMN_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DMN_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DMN_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DMN_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DMN_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DMN_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DMN_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DMN_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DMN_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DMN_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DMN_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DMN_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DMN_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DMN_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DMN_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DMN_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DMN_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DMN_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DMN_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DMN_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DMN_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DMN_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DMN_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DMN_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DMN_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DMN_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DMN_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DMN_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
#define DMN_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u
|
||||
#define DMN_w32_EXCEPTION_CLRDBG_NOTIFICATION 0x04242420u
|
||||
#define DMN_w32_EXCEPTION_CLR 0xE0434352u
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Register Codes
|
||||
|
||||
#define DMN_W32_CTX_X86 0x00010000
|
||||
#define DMN_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags
|
||||
#define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15
|
||||
#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 // segds, seges, segfs, and seggs
|
||||
#define DMN_W32_CTX_INTEL_FLOATS 0x0008 // xmm0-xmm15
|
||||
#define DMN_W32_CTX_INTEL_DEBUG 0x0010 // dr0-dr3 and dr6-dr7
|
||||
#define DMN_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DMN_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DMN_W32_CTX_X86_ALL (DMN_W32_CTX_X86 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_DEBUG | \
|
||||
DMN_W32_CTX_INTEL_EXTENDED)
|
||||
#define DMN_W32_CTX_X64_ALL (DMN_W32_CTX_X64 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_FLOATS | \
|
||||
DMN_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Entity State
|
||||
|
||||
typedef enum DMN_W32_EntityKind
|
||||
{
|
||||
DMN_W32_EntityKind_Null,
|
||||
DMN_W32_EntityKind_Root,
|
||||
DMN_W32_EntityKind_Process,
|
||||
DMN_W32_EntityKind_Thread,
|
||||
DMN_W32_EntityKind_Module,
|
||||
DMN_W32_EntityKind_COUNT
|
||||
}
|
||||
DMN_W32_EntityKind;
|
||||
|
||||
typedef struct DMN_W32_Entity DMN_W32_Entity;
|
||||
struct DMN_W32_Entity
|
||||
{
|
||||
DMN_W32_Entity *first;
|
||||
DMN_W32_Entity *last;
|
||||
DMN_W32_Entity *next;
|
||||
DMN_W32_Entity *prev;
|
||||
DMN_W32_Entity *parent;
|
||||
DMN_W32_EntityKind kind;
|
||||
U32 gen;
|
||||
U64 id;
|
||||
HANDLE handle;
|
||||
Arch arch;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
U64 injection_address;
|
||||
B32 did_first_bp;
|
||||
}
|
||||
proc;
|
||||
struct
|
||||
{
|
||||
U64 thread_local_base;
|
||||
U64 last_name_hash;
|
||||
U64 name_gather_time_us;
|
||||
}
|
||||
thread;
|
||||
struct
|
||||
{
|
||||
Rng1U64 vaddr_range;
|
||||
U64 address_of_name_pointer;
|
||||
B32 is_main;
|
||||
B32 name_is_unicode;
|
||||
}
|
||||
module;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityNode DMN_W32_EntityNode;
|
||||
struct DMN_W32_EntityNode
|
||||
{
|
||||
DMN_W32_EntityNode *next;
|
||||
DMN_W32_Entity *v;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashNode DMN_W32_EntityIDHashNode;
|
||||
struct DMN_W32_EntityIDHashNode
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *next;
|
||||
DMN_W32_EntityIDHashNode *prev;
|
||||
U64 id;
|
||||
DMN_W32_Entity *entity;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashSlot DMN_W32_EntityIDHashSlot;
|
||||
struct DMN_W32_EntityIDHashSlot
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *first;
|
||||
DMN_W32_EntityIDHashNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Injection Types
|
||||
|
||||
typedef struct DMN_W32_InjectedBreak DMN_W32_InjectedBreak;
|
||||
struct DMN_W32_InjectedBreak
|
||||
{
|
||||
U64 code;
|
||||
U64 user_data;
|
||||
};
|
||||
|
||||
#define DMN_W32_INJECTED_CODE_SIZE 32
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Image Info Types
|
||||
|
||||
typedef struct DMN_W32_ImageInfo DMN_W32_ImageInfo;
|
||||
struct DMN_W32_ImageInfo
|
||||
{
|
||||
Arch arch;
|
||||
U32 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Dynamically-Loaded Win32 Function Types
|
||||
|
||||
typedef HRESULT DMN_W32_GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct DMN_W32_Shared DMN_W32_Shared;
|
||||
struct DMN_W32_Shared
|
||||
{
|
||||
// rjf: top-level info
|
||||
Arena *arena;
|
||||
String8List env_strings;
|
||||
|
||||
// rjf: access locking mechanism
|
||||
OS_Handle access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: run/mem/reg gens
|
||||
U64 run_gen;
|
||||
U64 mem_gen;
|
||||
U64 reg_gen;
|
||||
|
||||
// rjf: detaching info
|
||||
Arena *detach_arena;
|
||||
DMN_HandleList detach_processes;
|
||||
|
||||
// rjf: entity state
|
||||
Arena *entities_arena;
|
||||
DMN_W32_Entity *entities_base;
|
||||
DMN_W32_Entity *entities_first_free;
|
||||
U64 entities_count;
|
||||
DMN_W32_EntityIDHashSlot *entities_id_hash_slots;
|
||||
U64 entities_id_hash_slots_count;
|
||||
DMN_W32_EntityIDHashNode *entities_id_hash_node_free;
|
||||
|
||||
// rjf: launch state
|
||||
B32 new_process_pending;
|
||||
|
||||
// rjf: run results
|
||||
B32 resume_needed;
|
||||
U32 resume_pid;
|
||||
U32 resume_tid;
|
||||
B32 exception_not_handled;
|
||||
|
||||
// rjf: halting info
|
||||
DMN_Handle halter_process;
|
||||
U32 halter_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DMN_W32_Shared *dmn_w32_shared = 0;
|
||||
global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil};
|
||||
global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0;
|
||||
thread_static B32 dmn_w32_ctrl_thread = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 dmn_w32_hash_from_string(String8 string);
|
||||
internal U64 dmn_w32_hash_from_id(U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Helpers
|
||||
|
||||
//- rjf: entity <-> handle
|
||||
internal DMN_Handle dmn_w32_handle_from_entity(DMN_W32_Entity *entity);
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_handle(DMN_Handle handle);
|
||||
|
||||
//- rjf: entity allocation/deallocation
|
||||
internal DMN_W32_Entity *dmn_w32_entity_alloc(DMN_W32_Entity *parent, DMN_W32_EntityKind kind, U64 id);
|
||||
internal void dmn_w32_entity_release(DMN_W32_Entity *entity);
|
||||
|
||||
//- rjf: kind*id -> entity
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Module Info Extraction
|
||||
|
||||
internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32-Level Process/Thread Reads/Writes
|
||||
|
||||
//- rjf: processes
|
||||
internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src);
|
||||
internal String8 dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
|
||||
internal String16 dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
|
||||
#define dmn_w32_process_read_struct(process, vaddr, ptr) dmn_w32_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
#define dmn_w32_process_write_struct(process, vaddr, ptr) dmn_w32_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr);
|
||||
|
||||
//- rjf: threads
|
||||
internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave);
|
||||
internal U16 dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw);
|
||||
internal B32 dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block);
|
||||
internal B32 dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block);
|
||||
|
||||
//- rjf: remote thread injection
|
||||
internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address);
|
||||
|
||||
#endif // DEMON_CORE_WIN32_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,385 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_OS_WIN32_H
|
||||
#define DEMON_OS_WIN32_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Win32 Demon Headers Negotation
|
||||
|
||||
// windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Win32 Demon Types
|
||||
|
||||
//- entities
|
||||
|
||||
// Demon Win32 Entity Extensions
|
||||
// Process: ext points to independently allocated DEMON_W32_Ext
|
||||
// Thread : ext points to independently allocated DEMON_W32_Ext
|
||||
// Module : ext set to HANDLE
|
||||
|
||||
typedef union DEMON_W32_Ext DEMON_W32_Ext;
|
||||
union DEMON_W32_Ext
|
||||
{
|
||||
DEMON_W32_Ext *next;
|
||||
struct{
|
||||
HANDLE handle;
|
||||
U64 injection_address;
|
||||
B32 did_first_bp;
|
||||
} proc;
|
||||
struct{
|
||||
HANDLE handle;
|
||||
U64 thread_local_base;
|
||||
U64 last_name_hash;
|
||||
U64 name_gather_time_us;
|
||||
B32 last_run_reported_trap;
|
||||
U64 last_run_reported_trap_pre_rip;
|
||||
U64 last_run_reported_trap_post_rip;
|
||||
} thread;
|
||||
struct{
|
||||
HANDLE handle;
|
||||
U64 address_of_name_pointer;
|
||||
B32 is_main;
|
||||
B32 name_is_unicode;
|
||||
} module;
|
||||
};
|
||||
|
||||
//- helpers
|
||||
|
||||
typedef struct DEMON_W32_InjectedBreak DEMON_W32_InjectedBreak;
|
||||
struct DEMON_W32_InjectedBreak
|
||||
{
|
||||
U64 code;
|
||||
U64 user_data;
|
||||
};
|
||||
#define DEMON_W32_INJECTED_CODE_SIZE 32
|
||||
|
||||
typedef struct DEMON_W32_ImageInfo DEMON_W32_ImageInfo;
|
||||
struct DEMON_W32_ImageInfo
|
||||
{
|
||||
Architecture arch;
|
||||
U32 size;
|
||||
};
|
||||
|
||||
typedef struct DEMON_W32_EntityNode DEMON_W32_EntityNode;
|
||||
struct DEMON_W32_EntityNode
|
||||
{
|
||||
DEMON_W32_EntityNode *next;
|
||||
DEMON_Entity *entity;
|
||||
};
|
||||
|
||||
typedef HRESULT GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription);
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Win32 Demon Exceptions
|
||||
|
||||
#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
#define DEMON_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Win32 Demon Register API Codes
|
||||
|
||||
#define DEMON_W32_CTX_X86 0x00010000
|
||||
#define DEMON_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DEMON_W32_CTX_INTEL_CONTROL 0x0001
|
||||
#define DEMON_W32_CTX_INTEL_INTEGER 0x0002
|
||||
#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004
|
||||
#define DEMON_W32_CTX_INTEL_FLOATS 0x0008
|
||||
#define DEMON_W32_CTX_INTEL_DEBUG 0x0010
|
||||
#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DEMON_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \
|
||||
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
|
||||
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \
|
||||
DEMON_W32_CTX_INTEL_EXTENDED)
|
||||
#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \
|
||||
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
|
||||
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \
|
||||
DEMON_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: DOS Header Types
|
||||
|
||||
// this is the "MZ" as a 16-bit short
|
||||
#define DEMON_DOS_MAGIC 0x5a4d
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct DEMON_DosHeader DEMON_DosHeader;
|
||||
struct DEMON_DosHeader
|
||||
{
|
||||
U16 magic;
|
||||
U16 last_page_size;
|
||||
U16 page_count;
|
||||
U16 reloc_count;
|
||||
U16 paragraph_header_size;
|
||||
U16 min_paragraph;
|
||||
U16 max_paragraph;
|
||||
U16 init_ss;
|
||||
U16 init_sp;
|
||||
U16 checksum;
|
||||
U16 init_ip;
|
||||
U16 init_cs;
|
||||
U16 reloc_table_file_off;
|
||||
U16 overlay_number;
|
||||
U16 reserved[4];
|
||||
U16 oem_id;
|
||||
U16 oem_info;
|
||||
U16 reserved2[10];
|
||||
U32 coff_file_offset;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Coff Header Types
|
||||
|
||||
#define DEMON_PE_MAGIC 0x00004550u
|
||||
|
||||
typedef U16 DEMON_CoffMachineType;
|
||||
enum{
|
||||
DEMON_CoffMachineType_UNKNOWN = 0x0,
|
||||
DEMON_CoffMachineType_X86 = 0x14c,
|
||||
DEMON_CoffMachineType_X64 = 0x8664,
|
||||
DEMON_CoffMachineType_ARM33 = 0x1d3,
|
||||
DEMON_CoffMachineType_ARM = 0x1c0,
|
||||
DEMON_CoffMachineType_ARM64 = 0xaa64,
|
||||
DEMON_CoffMachineType_ARMNT = 0x1c4,
|
||||
DEMON_CoffMachineType_EBC = 0xebc,
|
||||
DEMON_CoffMachineType_IA64 = 0x200,
|
||||
DEMON_CoffMachineType_M32R = 0x9041,
|
||||
DEMON_CoffMachineType_MIPS16 = 0x266,
|
||||
DEMON_CoffMachineType_MIPSFPU = 0x366,
|
||||
DEMON_CoffMachineType_MIPSFPU16 = 0x466,
|
||||
DEMON_CoffMachineType_POWERPC = 0x1f0,
|
||||
DEMON_CoffMachineType_POWERPCFP = 0x1f1,
|
||||
DEMON_CoffMachineType_R4000 = 0x166,
|
||||
DEMON_CoffMachineType_RISCV32 = 0x5032,
|
||||
DEMON_CoffMachineType_RISCV64 = 0x5064,
|
||||
DEMON_CoffMachineType_RISCV128 = 0x5128,
|
||||
DEMON_CoffMachineType_SH3 = 0x1a2,
|
||||
DEMON_CoffMachineType_SH3DSP = 0x1a3,
|
||||
DEMON_CoffMachineType_SH4 = 0x1a6,
|
||||
DEMON_CoffMachineType_SH5 = 0x1a8,
|
||||
DEMON_CoffMachineType_THUMB = 0x1c2,
|
||||
DEMON_CoffMachineType_WCEMIPSV2 = 0x169,
|
||||
DEMON_CoffMachineType_COUNT = 25
|
||||
};
|
||||
|
||||
typedef U16 DEMON_CoffFlags;
|
||||
enum{
|
||||
DEMON_CoffFlag_RELOC_STRIPPED = (1 << 0),
|
||||
DEMON_CoffFlag_EXECUTABLE_IMAGE = (1 << 1),
|
||||
DEMON_CoffFlag_LINE_NUMS_STRIPPED = (1 << 2),
|
||||
DEMON_CoffFlag_SYM_STRIPPED = (1 << 3),
|
||||
DEMON_CoffFlag_RESERVED_0 = (1 << 4),
|
||||
DEMON_CoffFlag_LARGE_ADDRESS_AWARE = (1 << 5),
|
||||
DEMON_CoffFlag_RESERVED_1 = (1 << 6),
|
||||
DEMON_CoffFlag_RESERVED_2 = (1 << 7),
|
||||
DEMON_CoffFlag_32BIT_MACHINE = (1 << 8),
|
||||
DEMON_CoffFlag_DEBUG_STRIPPED = (1 << 9),
|
||||
DEMON_CoffFlag_REMOVABLE_RUN_FROM_SWAP = (1 << 10),
|
||||
DEMON_CoffFlag_NET_RUN_FROM_SWAP = (1 << 11),
|
||||
DEMON_CoffFlag_SYSTEM = (1 << 12),
|
||||
DEMON_CoffFlag_DLL = (1 << 13),
|
||||
DEMON_CoffFlag_UP_SYSTEM_ONLY = (1 << 14),
|
||||
DEMON_CoffFlag_BYTES_RESERVED_HI = (1 << 15),
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct DEMON_CoffHeader DEMON_CoffHeader;
|
||||
struct DEMON_CoffHeader
|
||||
{
|
||||
DEMON_CoffMachineType machine;
|
||||
U16 section_count;
|
||||
U32 time_date_stamp;
|
||||
// TODO: rename to "unix_timestamp"
|
||||
U32 pointer_to_symbol_table;
|
||||
U32 number_of_symbols;
|
||||
// TODO: rename to "symbol_count"
|
||||
U16 size_of_optional_header;
|
||||
// TODO: rename to "optional_header_size"
|
||||
DEMON_CoffFlags flags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: PE Header Types
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef U16 DEMON_PeWindowsSubsystem;
|
||||
enum{
|
||||
DEMON_PeWindowsSubsystem_UNKNOWN = 0,
|
||||
DEMON_PeWindowsSubsystem_NATIVE = 1,
|
||||
DEMON_PeWindowsSubsystem_WINDOWS_GUI = 2,
|
||||
DEMON_PeWindowsSubsystem_WINDOWS_CUI = 3,
|
||||
DEMON_PeWindowsSubsystem_OS2_CUI = 5,
|
||||
DEMON_PeWindowsSubsystem_POSIX_CUI = 7,
|
||||
DEMON_PeWindowsSubsystem_NATIVE_WINDOWS = 8,
|
||||
DEMON_PeWindowsSubsystem_WINDOWS_CE_GUI = 9,
|
||||
DEMON_PeWindowsSubsystem_EFI_APPLICATION = 10,
|
||||
DEMON_PeWindowsSubsystem_EFI_BOOT_SERVICE_DRIVER = 11,
|
||||
DEMON_PeWindowsSubsystem_EFI_RUNTIME_DRIVER = 12,
|
||||
DEMON_PeWindowsSubsystem_EFI_ROM = 13,
|
||||
DEMON_PeWindowsSubsystem_XBOX = 14,
|
||||
DEMON_PeWindowsSubsystem_WINDOWS_BOOT_APPLICATION = 16,
|
||||
DEMON_PeWindowsSubsystem_COUNT = 14
|
||||
};
|
||||
|
||||
typedef U16 DEMON_DllCharacteristics;
|
||||
enum{
|
||||
DEMON_DllCharacteristic_HIGH_ENTROPY_VA = (1 << 5),
|
||||
DEMON_DllCharacteristic_DYNAMIC_BASE = (1 << 6),
|
||||
DEMON_DllCharacteristic_FORCE_INTEGRITY = (1 << 7),
|
||||
DEMON_DllCharacteristic_NX_COMPAT = (1 << 8),
|
||||
DEMON_DllCharacteristic_NO_ISOLATION = (1 << 9),
|
||||
DEMON_DllCharacteristic_NO_SEH = (1 << 10),
|
||||
DEMON_DllCharacteristic_NO_BIND = (1 << 11),
|
||||
DEMON_DllCharacteristic_APPCONTAINER = (1 << 12),
|
||||
DEMON_DllCharacteristic_WDM_DRIVER = (1 << 13),
|
||||
DEMON_DllCharacteristic_GUARD_CF = (1 << 14),
|
||||
DEMON_DllCharacteristic_TERMINAL_SERVER_AWARE = (1 << 15),
|
||||
};
|
||||
|
||||
typedef struct DEMON_PeOptionalHeader32 DEMON_PeOptionalHeader32;
|
||||
struct DEMON_PeOptionalHeader32
|
||||
{
|
||||
U16 magic;
|
||||
U8 major_linker_version;
|
||||
U8 minor_linker_version;
|
||||
U32 sizeof_code;
|
||||
U32 sizeof_inited_data;
|
||||
U32 sizeof_uninited_data;
|
||||
U32 entry_point_va;
|
||||
U32 code_base;
|
||||
U32 data_base;
|
||||
U32 image_base;
|
||||
U32 section_alignment;
|
||||
U32 file_alignment;
|
||||
U16 major_os_ver;
|
||||
U16 minor_os_ver;
|
||||
U16 major_img_ver;
|
||||
U16 minor_img_ver;
|
||||
U16 major_subsystem_ver;
|
||||
U16 minor_subsystem_ver;
|
||||
U32 win32_version_value;
|
||||
U32 sizeof_image;
|
||||
U32 sizeof_headers;
|
||||
U32 check_sum;
|
||||
DEMON_PeWindowsSubsystem subsystem;
|
||||
DEMON_DllCharacteristics dll_characteristics;
|
||||
U32 sizeof_stack_reserve;
|
||||
U32 sizeof_stack_commit;
|
||||
U32 sizeof_heap_reserve;
|
||||
U32 sizeof_heap_commit;
|
||||
U32 loader_flags;
|
||||
U32 data_dir_count;
|
||||
};
|
||||
|
||||
typedef struct DEMON_PeOptionalHeader32Plus DEMON_PeOptionalHeader32Plus;
|
||||
struct DEMON_PeOptionalHeader32Plus
|
||||
{
|
||||
U16 magic;
|
||||
U8 major_linker_version;
|
||||
U8 minor_linker_version;
|
||||
U32 sizeof_code;
|
||||
U32 sizeof_inited_data;
|
||||
U32 sizeof_uninited_data;
|
||||
U32 entry_point_va;
|
||||
U32 code_base;
|
||||
U64 image_base;
|
||||
U32 section_alignment;
|
||||
U32 file_alignment;
|
||||
U16 major_os_ver;
|
||||
U16 minor_os_ver;
|
||||
U16 major_img_ver;
|
||||
U16 minor_img_ver;
|
||||
U16 major_subsystem_ver;
|
||||
U16 minor_subsystem_ver;
|
||||
U32 win32_version_value;
|
||||
U32 sizeof_image;
|
||||
U32 sizeof_headers;
|
||||
U32 check_sum;
|
||||
DEMON_PeWindowsSubsystem subsystem;
|
||||
DEMON_DllCharacteristics dll_characteristics;
|
||||
U64 sizeof_stack_reserve;
|
||||
U64 sizeof_stack_commit;
|
||||
U64 sizeof_heap_reserve;
|
||||
U64 sizeof_heap_commit;
|
||||
U32 loader_flags;
|
||||
U32 data_dir_count;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64 demon_w32_hash_from_string(String8 string);
|
||||
internal DEMON_W32_Ext* demon_w32_ext_alloc(void);
|
||||
internal DEMON_W32_Ext* demon_w32_ext(DEMON_Entity *entity);
|
||||
|
||||
internal U64 demon_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size);
|
||||
internal B32 demon_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size);
|
||||
internal String8 demon_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
|
||||
internal String16 demon_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
|
||||
|
||||
#define demon_w32_read_struct(h,dst,src) demon_w32_read_memory((h), (dst), (src), sizeof(*(dst)))
|
||||
|
||||
internal DEMON_W32_ImageInfo demon_w32_image_info_from_base(HANDLE process_handle, U64 base);
|
||||
internal DWORD demon_w32_inject_thread(DEMON_Entity *process, U64 start_address);
|
||||
|
||||
internal U16 demon_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave);
|
||||
internal U16 demon_w32_xsave_tag_word_from_real_tag_word(U16 ftw);
|
||||
|
||||
internal DWORD demon_w32_win32_from_memory_protect_flags(DEMON_MemoryProtectFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Experiments
|
||||
|
||||
internal void demon_w32_peak_at_tls(DEMON_Handle handle);
|
||||
|
||||
#endif //DEMON_OS_WIN32_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,235 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[] =
|
||||
{
|
||||
{ str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("exit"), str8_lit_comp("Exits the debugger."), str8_lit_comp("quit,close,abort"), str8_lit_comp("Exit"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_X},
|
||||
{ str8_lit_comp("run_command"), str8_lit_comp("Runs a command from the command palette."), str8_lit_comp("help,cmd"), str8_lit_comp("Run Command"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_CmdSpec, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("error"), str8_lit_comp("Notifies of an error."), str8_lit_comp(""), str8_lit_comp("Error"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp("Launch and Run"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_EntityList, DF_EntityKind_Target, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Play},
|
||||
{ str8_lit_comp("launch_and_init"), str8_lit_comp("Starts debugging a new instance of a target, then stops at the program's entry point."), str8_lit_comp("launch,start,entry,point"), str8_lit_comp("Launch and Initialize"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_EntityList, DF_EntityKind_Target, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_PlayStepForward},
|
||||
{ str8_lit_comp("kill"), str8_lit_comp("Kills the specified existing debugged process(es)."), str8_lit_comp("stop,kill"), str8_lit_comp("Kill"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_EntityList, DF_EntityKind_Process, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Stop},
|
||||
{ str8_lit_comp("kill_all"), str8_lit_comp("Kills all debugged child processes."), str8_lit_comp("stop,kill,all"), str8_lit_comp("Kill All"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Stop},
|
||||
{ str8_lit_comp("detach"), str8_lit_comp("Detaches the specified debugged process."), str8_lit_comp("detach"), str8_lit_comp("Detach"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_EntityList, DF_EntityKind_Process, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("continue"), str8_lit_comp("Continues all halted threads."), str8_lit_comp(""), str8_lit_comp("Continue"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Play},
|
||||
{ str8_lit_comp("step_into_inst"), str8_lit_comp("Performs a step that goes into calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp("Step Into (Assembly)"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_StepInto},
|
||||
{ str8_lit_comp("step_over_inst"), str8_lit_comp("Performs a step that skips calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp("Step Over (Assembly)"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_StepOver},
|
||||
{ str8_lit_comp("step_into_line"), str8_lit_comp("Performs a step that goes into calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp("Step Into (Line)"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_StepInto},
|
||||
{ str8_lit_comp("step_over_line"), str8_lit_comp("Performs a step that skips calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp("Step Over (Line)"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_StepOver},
|
||||
{ str8_lit_comp("step_out"), str8_lit_comp("Runs to the end of the current function and exits it."), str8_lit_comp(""), str8_lit_comp("Step Out"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_StepOut},
|
||||
{ str8_lit_comp("halt"), str8_lit_comp("Halts all running processes."), str8_lit_comp("pause"), str8_lit_comp("Halt"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Pause},
|
||||
{ str8_lit_comp("soft_halt_refresh"), str8_lit_comp("Interrupts all running processes to collect data, and then resumes them."), str8_lit_comp(""), str8_lit_comp("Soft Halt Refresh"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Refresh},
|
||||
{ str8_lit_comp("set_thread_ip"), str8_lit_comp("Sets the passed thread's instruction pointer at the passed address."), str8_lit_comp(""), str8_lit_comp("Set Thread IP"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_VirtualAddr, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("run_to_line"), str8_lit_comp("Runs until a particular source line is hit."), str8_lit_comp(""), str8_lit_comp("Run To Line"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Play},
|
||||
{ str8_lit_comp("run_to_address"), str8_lit_comp("Runs until a particular address is hit."), str8_lit_comp(""), str8_lit_comp("Run To Address"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_VirtualAddr, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_PlayStepForward},
|
||||
{ str8_lit_comp("run"), str8_lit_comp("Runs all targets after starting them if they have not been started yet."), str8_lit_comp("play"), str8_lit_comp("Run"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Play},
|
||||
{ str8_lit_comp("restart"), str8_lit_comp("Kills all running processes, then restarts the targets which were used to launch all current processes (if any)."), str8_lit_comp("restart,retry"), str8_lit_comp("Restart"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Redo},
|
||||
{ str8_lit_comp("step_into"), str8_lit_comp("Steps once, possibly into function calls, for either line or instructions."), str8_lit_comp(""), str8_lit_comp("Step Into"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_StepInto},
|
||||
{ str8_lit_comp("step_over"), str8_lit_comp("Steps once, always over function calls, for either line or instructions."), str8_lit_comp(""), str8_lit_comp("Step Over"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_StepOver},
|
||||
{ str8_lit_comp("run_to_cursor"), str8_lit_comp("Runs the selected thread to the current cursor."), str8_lit_comp(""), str8_lit_comp("Run To Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Play},
|
||||
{ str8_lit_comp("set_next_statement"), str8_lit_comp("Sets the selected thread's instruction pointer to the cursor's position."), str8_lit_comp(""), str8_lit_comp("Set Next Statement"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_RightArrow},
|
||||
{ str8_lit_comp("enable_solo_stepping_mode"), str8_lit_comp("Enables 'solo stepping mode', which suspends all non-selected threads before stepping."), str8_lit_comp("solo,stepping,mode,suspend"), str8_lit_comp("Enable Solo Stepping Mode"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Thread},
|
||||
{ str8_lit_comp("disable_solo_stepping_mode"), str8_lit_comp("Disables 'solo stepping mode', which suspends all non-selected threads before stepping."), str8_lit_comp("solo,stepping,mode,suspend"), str8_lit_comp("Disable Solo Stepping Mode"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Thread},
|
||||
{ str8_lit_comp("select_thread"), str8_lit_comp("Selects a thread."), str8_lit_comp(""), str8_lit_comp("Select Thread"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Thread, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("select_thread_window"), str8_lit_comp("Selects a thread for the active window, overriding the global selected thread."), str8_lit_comp(""), str8_lit_comp("Select Thread On Window"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Thread, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("select_thread_view"), str8_lit_comp("Selects a thread for the active view, overriding the global and per-window selected threads."), str8_lit_comp(""), str8_lit_comp("Select Thread On View"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Thread, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("select_unwind"), str8_lit_comp("Selects an unwind frame number for the selected thread."), str8_lit_comp(""), str8_lit_comp("Select Unwind"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("up_one_frame"), str8_lit_comp("Selects the callstack frame above the currently selected."), str8_lit_comp(""), str8_lit_comp("Up One Frame"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_UpArrow},
|
||||
{ str8_lit_comp("down_one_frame"), str8_lit_comp("Selects the callstack frame below the currently selected."), str8_lit_comp(""), str8_lit_comp("Down One Frame"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_DownArrow},
|
||||
{ str8_lit_comp("freeze_thread"), str8_lit_comp("Freezes the passed thread."), str8_lit_comp(""), str8_lit_comp("Freeze Thread"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Thread, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Locked},
|
||||
{ str8_lit_comp("thaw_thread"), str8_lit_comp("Thaws the passed thread."), str8_lit_comp(""), str8_lit_comp("Thaw Thread"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Thread, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Unlocked},
|
||||
{ str8_lit_comp("freeze_process"), str8_lit_comp("Freezes the passed process."), str8_lit_comp(""), str8_lit_comp("Freeze Process"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Process, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Locked},
|
||||
{ str8_lit_comp("thaw_process"), str8_lit_comp("Thaws the passed process."), str8_lit_comp(""), str8_lit_comp("Thaw Process"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Process, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Unlocked},
|
||||
{ str8_lit_comp("freeze_machine"), str8_lit_comp("Freezes the passed machine."), str8_lit_comp(""), str8_lit_comp("Freeze Machine"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Entity, DF_EntityKind_Machine, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Locked},
|
||||
{ str8_lit_comp("thaw_machine"), str8_lit_comp("Thaws the passed machine."), str8_lit_comp(""), str8_lit_comp("Thaw Machine"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Entity, DF_EntityKind_Machine, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Unlocked},
|
||||
{ str8_lit_comp("freeze_local_machine"), str8_lit_comp("Freezes the local machine."), str8_lit_comp(""), str8_lit_comp("Freeze Local Machine"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Machine},
|
||||
{ str8_lit_comp("thaw_local_machine"), str8_lit_comp("Thaws the local machine."), str8_lit_comp(""), str8_lit_comp("Thaw Local Machine"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Machine},
|
||||
{ str8_lit_comp("inc_ui_font_scale"), str8_lit_comp("Increases the font size used for UI."), str8_lit_comp(""), str8_lit_comp("Increase UI Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("dec_ui_font_scale"), str8_lit_comp("Decreases the font size used for UI."), str8_lit_comp(""), str8_lit_comp("Decrease UI Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("inc_code_font_scale"), str8_lit_comp("Increases the font size used for code."), str8_lit_comp(""), str8_lit_comp("Increase Code Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("dec_code_font_scale"), str8_lit_comp("Decreases the font size used for code."), str8_lit_comp(""), str8_lit_comp("Decrease Code Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("open_window"), str8_lit_comp("Opens a new window."), str8_lit_comp(""), str8_lit_comp("Open New Window"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Window},
|
||||
{ str8_lit_comp("close_window"), str8_lit_comp("Closes an opened window."), str8_lit_comp(""), str8_lit_comp("Close Window"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Window},
|
||||
{ str8_lit_comp("toggle_fullscreen"), str8_lit_comp("Toggles fullscreen view on the active window."), str8_lit_comp(""), str8_lit_comp("Toggle Fullscreen"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Window},
|
||||
{ str8_lit_comp("confirm_accept"), str8_lit_comp("Accepts the active confirmation prompt."), str8_lit_comp(""), str8_lit_comp("Confirm Accept"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("confirm_cancel"), str8_lit_comp("Cancels the active confirmation prompt."), str8_lit_comp(""), str8_lit_comp("Confirm Cancel"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("reset_to_default_panels"), str8_lit_comp("Resets the window to the default panel layout."), str8_lit_comp("panel"), str8_lit_comp("Reset To Default Panel Layout"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Window},
|
||||
{ str8_lit_comp("new_panel_right"), str8_lit_comp("Creates a new panel to the right of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Vertically"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_XSplit},
|
||||
{ str8_lit_comp("new_panel_down"), str8_lit_comp("Creates a new panel at the bottom of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Horizontally"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_YSplit},
|
||||
{ str8_lit_comp("rotate_panel_columns"), str8_lit_comp("Rotates all panels at the closest column level of the panel hierarchy."), str8_lit_comp(""), str8_lit_comp("Rotate Panel Columns"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("next_panel"), str8_lit_comp("Cycles the active panel forward."), str8_lit_comp(""), str8_lit_comp("Focus Next Panel"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_RightArrow},
|
||||
{ str8_lit_comp("prev_panel"), str8_lit_comp("Cycles the active panel backwards."), str8_lit_comp(""), str8_lit_comp("Focus Previous Panel"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_LeftArrow},
|
||||
{ str8_lit_comp("focus_panel"), str8_lit_comp("Focuses a new panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("focus_panel_right"), str8_lit_comp("Focuses a panel rightward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Right"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_RightArrow},
|
||||
{ str8_lit_comp("focus_panel_left"), str8_lit_comp("Focuses a panel leftward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Left"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_LeftArrow},
|
||||
{ str8_lit_comp("focus_panel_up"), str8_lit_comp("Focuses a panel upward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Up"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_UpArrow},
|
||||
{ str8_lit_comp("focus_panel_down"), str8_lit_comp("Focuses a panel downward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Down"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_DownArrow},
|
||||
{ str8_lit_comp("undo"), str8_lit_comp("Undoes the previous action."), str8_lit_comp(""), str8_lit_comp("Undo"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Undo},
|
||||
{ str8_lit_comp("redo"), str8_lit_comp("Redoes the first previously undone action."), str8_lit_comp(""), str8_lit_comp("Redo"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Redo},
|
||||
{ str8_lit_comp("go_back"), str8_lit_comp("Returns to the previously selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp("Go Back"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_LeftArrow},
|
||||
{ str8_lit_comp("go_forward"), str8_lit_comp("Returns to the next selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp("Go Forward"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_RightArrow},
|
||||
{ str8_lit_comp("close_panel"), str8_lit_comp("Closes the currently active panel."), str8_lit_comp(""), str8_lit_comp("Close Panel"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_ClosePanel},
|
||||
{ str8_lit_comp("next_tab"), str8_lit_comp("Focuses the next tab on the active panel."), str8_lit_comp(""), str8_lit_comp("Focus Next Tab"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_RightArrow},
|
||||
{ str8_lit_comp("prev_tab"), str8_lit_comp("Focuses the previous tab on the active panel."), str8_lit_comp(""), str8_lit_comp("Focus Previous Tab"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_LeftArrow},
|
||||
{ str8_lit_comp("move_tab_right"), str8_lit_comp("Moves the selected tab right one slot."), str8_lit_comp(""), str8_lit_comp("Move Tab Right"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_RightArrow},
|
||||
{ str8_lit_comp("move_tab_left"), str8_lit_comp("Moves the selected tab left one slot."), str8_lit_comp(""), str8_lit_comp("Move Tab Left"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_LeftArrow},
|
||||
{ str8_lit_comp("open_tab"), str8_lit_comp("Opens a new tab with the parameterized view specification."), str8_lit_comp(""), str8_lit_comp("Open Tab"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("close_tab"), str8_lit_comp("Closes the currently opened tab."), str8_lit_comp(""), str8_lit_comp("Close Tab"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_X},
|
||||
{ str8_lit_comp("move_tab"), str8_lit_comp("Moves a tab to a new panel."), str8_lit_comp(""), str8_lit_comp("Move Tab"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("tab_bar_top"), str8_lit_comp("Anchors a panel's tab bar to the top of the panel."), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Top"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_UpArrow},
|
||||
{ str8_lit_comp("tab_bar_bottom"), str8_lit_comp("Anchors a panel's tab bar to the bottom of the panel."), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Bottom"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_DownArrow},
|
||||
{ str8_lit_comp("set_current_path"), str8_lit_comp("Sets the debugger's current path, which is used as a starting point when browsing for files."), str8_lit_comp(""), str8_lit_comp("Set Current Path"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("open"), str8_lit_comp("Opens a file."), str8_lit_comp("code,source,file"), str8_lit_comp("Open"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*1)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("reload"), str8_lit_comp("Reloads a loaded file."), str8_lit_comp("code,source,file,reload"), str8_lit_comp("Reload"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_File, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("reload_active"), str8_lit_comp("Reloads the active file."), str8_lit_comp("code,source,file,reload"), str8_lit_comp("Reload Active File"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("switch"), str8_lit_comp("Switches to a loaded file."), str8_lit_comp("code,source,file"), str8_lit_comp("Switch"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_File, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("switch_to_partner_file"), str8_lit_comp("Switches to the focused file's partner; or from header to implementation or vice versa."), str8_lit_comp("code,source,file"), str8_lit_comp("Switch To Partner File"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("set_file_override_link_src"), str8_lit_comp("Sets the source path for an override file link."), str8_lit_comp(""), str8_lit_comp("Set File Override Link Source"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("set_file_override_link_dst"), str8_lit_comp("Sets the destination path for an override file link."), str8_lit_comp(""), str8_lit_comp("Set File Override Link Destination"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("set_file_replacement_path"), str8_lit_comp("Sets the path which should be used as the replacement for the passed file."), str8_lit_comp(""), str8_lit_comp("Set File Replacement Path"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("open_user"), str8_lit_comp("Opens a user file path, immediately loading it, and begins autosaving to it."), str8_lit_comp("load,user,profile,layout"), str8_lit_comp("Open User"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*1)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Person},
|
||||
{ str8_lit_comp("open_profile"), str8_lit_comp("Opens a profile file path, immediately loading it, and begins autosaving to it."), str8_lit_comp("profile,project,session"), str8_lit_comp("Open Profile"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*1)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Briefcase},
|
||||
{ str8_lit_comp("apply_user_data"), str8_lit_comp("Applies user data from the active user file."), str8_lit_comp(""), str8_lit_comp("Apply User Data"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("apply_profile_data"), str8_lit_comp("Applies profile data from the active profile file."), str8_lit_comp(""), str8_lit_comp("Apply Profile Data"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("write_user_data"), str8_lit_comp("Writes user data to the active user file."), str8_lit_comp(""), str8_lit_comp("Write User Data"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("write_profile_data"), str8_lit_comp("Writes profile data to the active profile file."), str8_lit_comp(""), str8_lit_comp("Write Profile Data"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_left"), str8_lit_comp("Moves the cursor or selection left."), str8_lit_comp(""), str8_lit_comp("Move Left"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_right"), str8_lit_comp("Moves the cursor or selection right."), str8_lit_comp(""), str8_lit_comp("Move Right"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up"), str8_lit_comp("Moves the cursor or selection up."), str8_lit_comp(""), str8_lit_comp("Move Up"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down"), str8_lit_comp("Moves the cursor or selection down."), str8_lit_comp(""), str8_lit_comp("Move Down"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_left_select"), str8_lit_comp("Moves the cursor or selection left, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Left Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_right_select"), str8_lit_comp("Moves the cursor or selection right, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Right Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up_select"), str8_lit_comp("Moves the cursor or selection up, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down_select"), str8_lit_comp("Moves the cursor or selection down, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_left_chunk"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp("Move Left Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_right_chunk"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp("Move Right Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up_chunk"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp("Move Up Chunk"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down_chunk"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp("Move Down Chunk"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up_page"), str8_lit_comp("Moves the cursor or selection up one page."), str8_lit_comp(""), str8_lit_comp("Move Up Page"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down_page"), str8_lit_comp("Moves the cursor or selection down one page."), str8_lit_comp(""), str8_lit_comp("Move Down Page"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up_whole"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content."), str8_lit_comp(""), str8_lit_comp("Move Up Whole"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down_whole"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content."), str8_lit_comp(""), str8_lit_comp("Move Down Whole"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_left_chunk_select"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp("Move Left Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_right_chunk_select"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp("Move Right Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up_chunk_select"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp("Move Up Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down_chunk_select"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp("Move Down Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up_page_select"), str8_lit_comp("Moves the cursor or selection up one page, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Page Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down_page_select"), str8_lit_comp("Moves the cursor or selection down one page, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Page Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_up_whole_select"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Whole Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_down_whole_select"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Whole Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_home"), str8_lit_comp("Moves the cursor to the beginning of the line."), str8_lit_comp(""), str8_lit_comp("Move Home"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_end"), str8_lit_comp("Moves the cursor to the end of the line."), str8_lit_comp(""), str8_lit_comp("Move End"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_home_select"), str8_lit_comp("Moves the cursor to the beginning of the line, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Home Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("move_end_select"), str8_lit_comp("Moves the cursor to the end of the line, while selecting."), str8_lit_comp(""), str8_lit_comp("Move End Select"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("select_all"), str8_lit_comp("Selects everything possible."), str8_lit_comp(""), str8_lit_comp("Select All"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("delete_single"), str8_lit_comp("Deletes a single element to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Delete Single"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("delete_chunk"), str8_lit_comp("Deletes a chunk to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Delete Chunk"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("backspace_single"), str8_lit_comp("Deletes a single element to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Backspace Single"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("backspace_chunk"), str8_lit_comp("Deletes a chunk to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Backspace Chunk"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("copy"), str8_lit_comp("Copies the active selection to the clipboard."), str8_lit_comp(""), str8_lit_comp("Copy"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Clipboard},
|
||||
{ str8_lit_comp("cut"), str8_lit_comp("Copies the active selection to the clipboard, then deletes it."), str8_lit_comp(""), str8_lit_comp("Cut"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Clipboard},
|
||||
{ str8_lit_comp("paste"), str8_lit_comp("Pastes the current contents of the clipboard."), str8_lit_comp(""), str8_lit_comp("Paste"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Clipboard},
|
||||
{ str8_lit_comp("insert_text"), str8_lit_comp("Inserts the text that was used to cause this command."), str8_lit_comp(""), str8_lit_comp("Insert Text"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("goto_line"), str8_lit_comp("Jumps to a line number in the current code file."), str8_lit_comp(""), str8_lit_comp("Go To Line"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_TextPoint, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("goto_address"), str8_lit_comp("Jumps to an address in the current memory or disassembly view."), str8_lit_comp(""), str8_lit_comp("Go To Address"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_VirtualAddr, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("center_cursor"), str8_lit_comp("Snaps the current code view to center the cursor."), str8_lit_comp(""), str8_lit_comp("Center Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("contain_cursor"), str8_lit_comp("Snaps the current code view to contain the cursor."), str8_lit_comp(""), str8_lit_comp("Contain Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("find_text_forward"), str8_lit_comp("Searches the current code file forward (from the cursor) for a string."), str8_lit_comp(""), str8_lit_comp("Find Text (Forward)"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_String, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*1)|(DF_CmdQueryFlag_SelectOldInput*1)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("find_text_backward"), str8_lit_comp("Searches the current code file backwards (from the cursor) for a string."), str8_lit_comp(""), str8_lit_comp("Find Text (Backwards)"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_String, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*1)|(DF_CmdQueryFlag_SelectOldInput*1)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("find_next"), str8_lit_comp("Searches the current code file forward (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp("Find Next"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*1)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("find_prev"), str8_lit_comp("Searches the current code file backwards (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp("Find Previous"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*1)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("find_thread"), str8_lit_comp("Jumps to the passed thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp("Find Thread"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Thread, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("find_selected_thread"), str8_lit_comp("Jumps to the selected thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp("Find Selected Thread"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("goto_name"), str8_lit_comp("Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp("Go To Name"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_String, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("goto_name_at_cursor"), str8_lit_comp("Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp("Go To Name At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("toggle_watch_expr"), str8_lit_comp("Adds or removes an expression to an opened watch view."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("toggle_watch_expr_at_cursor"), str8_lit_comp("Adds or removes the expression that the cursor or selection is currently over to an opened watch view."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("set_columns"), str8_lit_comp("Sets the number of columns for a memory view."), str8_lit_comp(""), str8_lit_comp("Set Columns"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Index, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Thumbnails},
|
||||
{ str8_lit_comp("toggle_address_visibility"), str8_lit_comp("Toggles the visibility of addresses in a disassembly view."), str8_lit_comp(""), str8_lit_comp("Toggle Address Visibility"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Thumbnails},
|
||||
{ str8_lit_comp("toggle_code_bytes_visibility"), str8_lit_comp("Toggles the visibility of machine code bytes in a disassembly view."), str8_lit_comp(""), str8_lit_comp("Toggle Code Bytes Visibility"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Thumbnails},
|
||||
{ str8_lit_comp("enable_entity"), str8_lit_comp("Enables an entity."), str8_lit_comp(""), str8_lit_comp("Enable Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("disable_entity"), str8_lit_comp("Disables an entity."), str8_lit_comp(""), str8_lit_comp("Disable Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("freeze_entity"), str8_lit_comp("Freezes an entity."), str8_lit_comp(""), str8_lit_comp("Freeze Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("thaw_entity"), str8_lit_comp("Thaws an entity."), str8_lit_comp(""), str8_lit_comp("Thaw Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("remove_entity"), str8_lit_comp("Removes an entity."), str8_lit_comp(""), str8_lit_comp("Remove Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("name_entity"), str8_lit_comp("Equips an entity with a name."), str8_lit_comp(""), str8_lit_comp("Name Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("edit_entity"), str8_lit_comp("Opens the editor for an entity."), str8_lit_comp(""), str8_lit_comp("Edit Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("duplicate_entity"), str8_lit_comp("Duplicates an entity."), str8_lit_comp(""), str8_lit_comp("Duplicate Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("text_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified line of source code."), str8_lit_comp(""), str8_lit_comp("Text Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled},
|
||||
{ str8_lit_comp("address_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("Address Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_VirtualAddr, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CircleFilled},
|
||||
{ str8_lit_comp("function_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("Function Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_String, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CircleFilled},
|
||||
{ str8_lit_comp("toggle_breakpoint_cursor"), str8_lit_comp("Places or removes a breakpoint on the line on which the active cursor sits."), str8_lit_comp(""), str8_lit_comp("Toggle Breakpoint At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled},
|
||||
{ str8_lit_comp("remove_breakpoint"), str8_lit_comp("Removes an existing breakpoint."), str8_lit_comp(""), str8_lit_comp("Remove Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Breakpoint, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Trash},
|
||||
{ str8_lit_comp("enable_breakpoint"), str8_lit_comp("Enables a breakpoint."), str8_lit_comp(""), str8_lit_comp("Enable Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Breakpoint, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CheckFilled},
|
||||
{ str8_lit_comp("disable_breakpoint"), str8_lit_comp("Disables a breakpoint."), str8_lit_comp(""), str8_lit_comp("Disable Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Breakpoint, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CheckHollow},
|
||||
{ str8_lit_comp("toggle_watch_pin"), str8_lit_comp("Places or removes a watch pin on a textual location on a particular entity."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Pin"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("toggle_watch_pin_at_cursor"), str8_lit_comp("Places or removes a watch pin at the cursor on the currently active file."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Pin At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_String, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("add_target"), str8_lit_comp("Adds a new target."), str8_lit_comp("application,executable,debug"), str8_lit_comp("Add Target"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*1)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Target},
|
||||
{ str8_lit_comp("remove_target"), str8_lit_comp("Removes an existing target."), str8_lit_comp("delete,remove,target"), str8_lit_comp("Remove Target"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Target, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Trash},
|
||||
{ str8_lit_comp("edit_target"), str8_lit_comp("Edits an existing target."), str8_lit_comp(""), str8_lit_comp("Edit Target"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Target, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Pencil},
|
||||
{ str8_lit_comp("select_target"), str8_lit_comp("Selects a target."), str8_lit_comp(""), str8_lit_comp("Select Target"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Target, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Target},
|
||||
{ str8_lit_comp("enable_target"), str8_lit_comp("Enables a target, in addition to all targets currently enabled."), str8_lit_comp(""), str8_lit_comp("Enable Target"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Target, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CheckFilled},
|
||||
{ str8_lit_comp("disable_target"), str8_lit_comp("Disables a target."), str8_lit_comp(""), str8_lit_comp("Disable Target"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Entity, DF_EntityKind_Target, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CheckHollow},
|
||||
{ str8_lit_comp("retry_ended_process"), str8_lit_comp("Launches a new process with the same options as the passed ended process."), str8_lit_comp(""), str8_lit_comp("Retry Ended Process"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Entity, DF_EntityKind_Process, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("attach"), str8_lit_comp("Attaches to a process that is already running on the local machine."), str8_lit_comp(""), str8_lit_comp("Attach"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_ID, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("register_as_jit_debugger"), str8_lit_comp("Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system."), str8_lit_comp(""), str8_lit_comp("Register As Just-In-Time (JIT) Debugger"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("entity_ref_fast_path"), str8_lit_comp("Activates the default behavior when clicking an entity reference."), str8_lit_comp(""), str8_lit_comp("Entity Reference Fast Path"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("spawn_entity_view"), str8_lit_comp("Spawns a new view, given an entity and other parameterizations."), str8_lit_comp(""), str8_lit_comp("Spawn Entity View"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("find_code_location"), str8_lit_comp("Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary."), str8_lit_comp(""), str8_lit_comp("Find Code Location"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("filter"), str8_lit_comp("Begins filtering the active view."), str8_lit_comp("sort,search,filter,find"), str8_lit_comp("Filter"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("apply_filter"), str8_lit_comp("Applies the typed filter to the active view."), str8_lit_comp("sort,search,filter,find,apply"), str8_lit_comp("Apply Filter"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("clear_filter"), str8_lit_comp("Clears the filter applied to the active view."), str8_lit_comp("sort,search,filter,find,clear"), str8_lit_comp("Clear Filter"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Find},
|
||||
{ str8_lit_comp("commands"), str8_lit_comp("Opens the list of all commands."), str8_lit_comp(""), str8_lit_comp("Commands"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_List},
|
||||
{ str8_lit_comp("target"), str8_lit_comp("Opens the editor for a target."), str8_lit_comp(""), str8_lit_comp("Target"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Target},
|
||||
{ str8_lit_comp("targets"), str8_lit_comp("Opens the list of all targets."), str8_lit_comp(""), str8_lit_comp("Targets"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Target},
|
||||
{ str8_lit_comp("file_path_map"), str8_lit_comp("Opens the file path mapping editor."), str8_lit_comp(""), str8_lit_comp("File Path Map"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("scheduler"), str8_lit_comp("Opens the scheduler view, for process and thread controls."), str8_lit_comp("threads,processes,targets"), str8_lit_comp("Scheduler"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Scheduler},
|
||||
{ str8_lit_comp("call_stack"), str8_lit_comp("Opens the call stack view."), str8_lit_comp("callstack,thread"), str8_lit_comp("Call Stack"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Thread},
|
||||
{ str8_lit_comp("modules"), str8_lit_comp("Opens the modules view."), str8_lit_comp(""), str8_lit_comp("Modules"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Module},
|
||||
{ str8_lit_comp("pending_entity"), str8_lit_comp("Opens a view which waits for the passed entity to be completely loaded, then replaces itself with a new view."), str8_lit_comp(""), str8_lit_comp("Pending Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("code"), str8_lit_comp("Opens the code view for an already-loaded file."), str8_lit_comp(""), str8_lit_comp("Code"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("watch"), str8_lit_comp("Opens a watch view."), str8_lit_comp(""), str8_lit_comp("Watch"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("locals"), str8_lit_comp("Opens a locals view."), str8_lit_comp(""), str8_lit_comp("Locals"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("registers"), str8_lit_comp("Opens a registers view."), str8_lit_comp(""), str8_lit_comp("Registers"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("globals"), str8_lit_comp("Opens a globals view."), str8_lit_comp(""), str8_lit_comp("Globals"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("thread_locals"), str8_lit_comp("Opens a thread locals view."), str8_lit_comp(""), str8_lit_comp("Thread Locals"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("types"), str8_lit_comp("Opens a types view."), str8_lit_comp(""), str8_lit_comp("Types"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("procedures"), str8_lit_comp("Opens a procedures view."), str8_lit_comp(""), str8_lit_comp("Procedures"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Binoculars},
|
||||
{ str8_lit_comp("output"), str8_lit_comp("Opens an output view."), str8_lit_comp(""), str8_lit_comp("Output"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_List},
|
||||
{ str8_lit_comp("memory"), str8_lit_comp("Opens a memory view."), str8_lit_comp(""), str8_lit_comp("Memory"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Grid},
|
||||
{ str8_lit_comp("disassembly"), str8_lit_comp("Opens the disassembly view."), str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Glasses},
|
||||
{ str8_lit_comp("breakpoints"), str8_lit_comp("Opens the breakpoints view."), str8_lit_comp(""), str8_lit_comp("Breakpoints"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled},
|
||||
{ str8_lit_comp("watch_pins"), str8_lit_comp("Opens the watch pins view."), str8_lit_comp(""), str8_lit_comp("Watch Pins"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Pin},
|
||||
{ str8_lit_comp("exception_filters"), str8_lit_comp("Opens the exception filters view."), str8_lit_comp("exceptions,filters"), str8_lit_comp("Exception Filters"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Gear},
|
||||
{ str8_lit_comp("theme"), str8_lit_comp("Opens the theme view."), str8_lit_comp("theme,color,scheme,palette"), str8_lit_comp("Theme"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Palette},
|
||||
{ str8_lit_comp("pick_file"), str8_lit_comp("Opens the file browser to pick a file."), str8_lit_comp(""), str8_lit_comp("Pick File"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*1)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("pick_folder"), str8_lit_comp("Opens the file browser to pick a folder."), str8_lit_comp(""), str8_lit_comp("Pick Folder"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*1)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_FolderOpenFilled},
|
||||
{ str8_lit_comp("pick_file_or_folder"), str8_lit_comp("Opens the file browser to pick a file or folder."), str8_lit_comp(""), str8_lit_comp("Pick File/Folder"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*1)|(DF_CmdQueryFlag_AllowFolders*1)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_FileOutline},
|
||||
{ str8_lit_comp("complete_query"), str8_lit_comp("Completes a query."), str8_lit_comp(""), str8_lit_comp("Complete Query"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("cancel_query"), str8_lit_comp("Cancels a query."), str8_lit_comp(""), str8_lit_comp("Cancel Query"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
{ str8_lit_comp("toggle_dev_menu"), str8_lit_comp("Opens and closes the developer menu."), str8_lit_comp(""), str8_lit_comp("Toggle Developer Menu"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null},
|
||||
};
|
||||
|
||||
DF_CoreViewRuleSpecInfo df_g_core_view_rule_spec_info_table[] =
|
||||
{
|
||||
{str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, },
|
||||
{str8_lit_comp("array"), str8_lit_comp("Array"), str8_lit_comp("Specifies that a pointer points to N elements, rather than only 1."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(array) , 0, },
|
||||
{str8_lit_comp("list"), str8_lit_comp("List"), str8_lit_comp("Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(list) , },
|
||||
{str8_lit_comp("bswap"), str8_lit_comp("Byte Swap"), str8_lit_comp("Specifies that all integer primitives should be byte-swapped, such that their endianness is reversed."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(bswap) , 0, },
|
||||
{str8_lit_comp("dec"), str8_lit_comp("Decimal Base (Base 10)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-10 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, },
|
||||
{str8_lit_comp("bin"), str8_lit_comp("Binary Base (Base 2)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-2 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, },
|
||||
{str8_lit_comp("oct"), str8_lit_comp("Octal Base (Base 8)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-8 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, },
|
||||
{str8_lit_comp("hex"), str8_lit_comp("Hexadecimal Base (Base 16)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-16 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, },
|
||||
{str8_lit_comp("only"), str8_lit_comp("Only Specified Members"), str8_lit_comp("Specifies that only the specified members should appear in struct, union, or class evaluations."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(only) , },
|
||||
{str8_lit_comp("omit"), str8_lit_comp("Omit Specified Members"), str8_lit_comp("Omits a list of member names from appearing in struct, union, or class evaluations."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(omit) , },
|
||||
{str8_lit_comp("no_addr"), str8_lit_comp("Disable Address Values"), str8_lit_comp("Displays only what pointers point to, if possible, without the pointer's address value."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, },
|
||||
{str8_lit_comp("rgba"), str8_lit_comp("Color (RGBA)"), str8_lit_comp("Displays as a color, interpreting the data as encoding R, G, B, and A values."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(rgba) , },
|
||||
{str8_lit_comp("text"), str8_lit_comp("Text"), str8_lit_comp("Displays as text."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(text) , },
|
||||
{str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), str8_lit_comp("Displays as disassembled instructions, interpreting the data as raw machine code."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(disasm) , },
|
||||
{str8_lit_comp("bitmap"), str8_lit_comp("Bitmap"), str8_lit_comp("Displays as a bitmap, interpreting the data as raw pixel data."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(bitmap) , },
|
||||
{str8_lit_comp("geo"), str8_lit_comp("Geometry"), str8_lit_comp("Displays as geometry, interpreting the data as vertex data."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(geo) , },
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "df/core/df_core.c"
|
||||
#include "df/gfx/df_gfx.c"
|
||||
#include "df/gfx/df_views.c"
|
||||
#include "df/gfx/df_view_rule_hooks.c"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user