mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-09-23 01:30:04 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76ce8a79c2 | ||
|
|
932db741fa | ||
|
|
0add3ef72c | ||
|
|
e417a96ce4 | ||
|
|
b2262532a7 | ||
|
|
b24326f502 | ||
|
|
66c1fa337c |
@@ -21,12 +21,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
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 msvc debug || exit /b 1
|
||||||
call build rdi_from_pdb msvc debug || exit /b 1
|
call build raddbg_from_pdb msvc debug || exit /b 1
|
||||||
call build rdi_from_dwarf msvc debug || exit /b 1
|
call build raddbg_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 raddbg clang debug || exit /b 1
|
||||||
call build rdi_from_pdb clang debug || exit /b 1
|
call build raddbg_from_pdb clang debug || exit /b 1
|
||||||
call build rdi_from_dwarf clang debug || exit /b 1
|
call build raddbg_from_dwarf clang debug || exit /b 1
|
||||||
call build rdi_dump clang debug || exit /b 1
|
|
||||||
call build radlink msvc debug || exit /b 1
|
|
||||||
call build radlink clang debug || exit /b 1
|
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
# The RAD Debugger Project
|
# 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
|
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
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
|
plans to expand and port in the future. In the future we'll expand to also
|
||||||
@@ -17,23 +11,26 @@ with any information you can gather, like dump files (along with the build you
|
|||||||
used), instructions to reproduce, test executables, and so on.
|
used), instructions to reproduce, test executables, and so on.
|
||||||
|
|
||||||
You can download pre-built binaries for the debugger
|
You can download pre-built binaries for the debugger
|
||||||
[here](https://github.com/EpicGamesExt/raddebugger/releases).
|
[here](https://github.com/EpicGames/raddebugger/releases).
|
||||||
|
|
||||||
The RAD Debugger project aims to simplify the debugger by simplifying and
|
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
|
unifying the underlying debug info format. In that pursuit we've built
|
||||||
Debug Info (RDI) format, which is what the debugger parses and uses. To work
|
the RADDBG debug info format, which is what the debugger parses and uses. To
|
||||||
with existing toolchains, we convert PDB (and eventually PE/ELF files with
|
work with existing toolchains, we convert PDB (and eventually PE/ELF files
|
||||||
embedded DWARF) into the RDI format on-demand.
|
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 RDI format is currently specified in code, in the files within the
|
The RADDBG format is currently specified in code, in the files within the
|
||||||
`src/lib_rdi_format` folder. The other relevant folders for working with the
|
`src/raddbg_format` folder. The other relevant folders for working with the
|
||||||
format are:
|
format are:
|
||||||
|
|
||||||
- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info.
|
- `raddbg_cons`: The RADDBG construction layer, for constructing RADDBG files.
|
||||||
- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase
|
- `raddbg_convert`: Our implementation of PDB-to-RADDBG (and an in-progress
|
||||||
layer, or built as an executable with a command line interface frontend.
|
implementation of a DWARF-to-RADDBG) conversion.
|
||||||
- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter.
|
- `raddbg_dump`: Code for textually dumping information from RADDBG files.
|
||||||
- `rdi_dump`: Our RDI textual dumping utility.
|
|
||||||
|
|
||||||
## Development Setup Instructions
|
## Development Setup Instructions
|
||||||
|
|
||||||
@@ -90,12 +87,13 @@ You should see the following output:
|
|||||||
```
|
```
|
||||||
[debug mode]
|
[debug mode]
|
||||||
[msvc compile]
|
[msvc compile]
|
||||||
|
[default mode, assuming `raddbg` build]
|
||||||
metagen_main.c
|
metagen_main.c
|
||||||
searching C:\devel\raddebugger/src... 309 files found
|
searching C:\devel\raddebugger/src... 299 files found
|
||||||
parsing metadesk... 15 metadesk files parsed
|
parsing metadesk... 12 metadesk files parsed
|
||||||
gathering tables... 96 tables found
|
gathering tables... 37 tables found
|
||||||
generating layer code...
|
generating layer code...
|
||||||
raddbg_main.c
|
raddbg.cpp
|
||||||
```
|
```
|
||||||
|
|
||||||
If everything worked correctly, there will be a `build` folder in the root
|
If everything worked correctly, there will be a `build` folder in the root
|
||||||
@@ -119,6 +117,18 @@ 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,
|
still issues. So, we feel that the top priority is eliminating these issues,
|
||||||
such that the debugging experience is rock solid.
|
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
|
### Local x64 Linux Debugging Phase
|
||||||
|
|
||||||
The next priority for the project is to take the rock solid x64 Windows
|
The next priority for the project is to take the rock solid x64 Windows
|
||||||
@@ -133,10 +143,11 @@ The major parts of this phase are:
|
|||||||
|
|
||||||
- Porting the `src/demon` layer to implement the Demon local process control
|
- Porting the `src/demon` layer to implement the Demon local process control
|
||||||
abstraction API.
|
abstraction API.
|
||||||
- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer.
|
- Porting the `src/unwind` layer to support x64 ELF unwinding (currently, there
|
||||||
- Creating a DWARF-to-RDI converter (in the same way that we've built a
|
is only an x64 PE unwinding implementation).
|
||||||
PDB-to-RDI converter). A partial implementation of this is in
|
- Creating a DWARF-to-RADDBG converter (in the same way that we've built a PDB-
|
||||||
`src/rdi_from_dwarf`.
|
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
|
- 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).
|
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
|
- Porting the `src/font_provider` layer to a Linux-compatible font
|
||||||
@@ -158,45 +169,6 @@ like remote debugging, porting to different architectures, further improving
|
|||||||
the debugger's features (like improving the visualization engine), and so on.
|
the debugger's features (like improving the visualization engine), and so on.
|
||||||
But for now, we're mostly focused on those first two phases.
|
But for now, we're mostly focused on those first two phases.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# The RAD Linker
|
|
||||||
|
|
||||||
The RAD Linker is a new performance linker for generating x64 PE/COFF binaries. It is designed to be very fast when creating gigantic executables. It generates standard PDB files for debugging, but it can also optionally create RAD Debugger debug info too (useful for huge executables that otherwise create broken PDBs that overflow internal 32-bit tables).
|
|
||||||
|
|
||||||
The RAD Linker is primarily optimized to handle huge linking projects - in our test cases (where debug info is multiple gigabytes), we see 50% faster link times.
|
|
||||||
|
|
||||||
The command line syntax is fully compatible with MSVC and you can get a full list of implemented switches from `/help`.
|
|
||||||
|
|
||||||
Our current designed-for use case for the linker is to help with the compile-debug cycle of huge projects. We don't yet have support for dead-code-elimination or link-time-optimizations, but these features are on the road map.
|
|
||||||
|
|
||||||
By default, the RAD linker spawns as many threads as there are cores, so if you plan to run multiple linkers in parallel, you can limit the number of thread workers via `/rad_workers`.
|
|
||||||
|
|
||||||
We also have support for large memory pages, which, when enabled, reduce link time by
|
|
||||||
another 25%. To link with large pages, you need to explicitly request them via `/rad_large_pages`. Large pages are off by default, since Windows support for large pages is a bit buggy - we recommend they only be used in Docker or VM images where the environment is reset after each link. In a standard Windows environment, using large pages otherwise will fragment memory quickly forcing a reboot. We are working on a Linux port of the linker that will be able to build with large pages robustly.
|
|
||||||
|
|
||||||
## Short Term Roadmap
|
|
||||||
- Porting linker to Linux (for Windows executables, just running on Linux).
|
|
||||||
- Debug info features
|
|
||||||
- Get DWARF debug info converter up-and-running.
|
|
||||||
- Smooth out rough edges in RADDBGI builder.
|
|
||||||
- Improve build speed further (especially for tiny and mid sizes projects).
|
|
||||||
- Other features to come
|
|
||||||
- Dead-code-elimination via `/opt:ref`.
|
|
||||||
- Link Time Optimizations with the help of clang (we won't support LTCG from MSVC compiler since it is undocumented).
|
|
||||||
|
|
||||||
## To build the RAD Linker
|
|
||||||
- Setup development environment, [see](#Development-Setup-Instructions)
|
|
||||||
- Run `build radlink release` or if you have clang installed `build radlink release clang`. We favor latter option for better code generation.
|
|
||||||
|
|
||||||
If build was successful linker executable is placed in `build` folder under `radlink.exe`.
|
|
||||||
|
|
||||||
## Benchmarks
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Top-Level Directory Descriptions
|
## Top-Level Directory Descriptions
|
||||||
|
|
||||||
- `data`: Small binary files which are used when building, either to embed
|
- `data`: Small binary files which are used when building, either to embed
|
||||||
@@ -207,8 +179,7 @@ After setting up the codebase and building, the following directories will
|
|||||||
also exist:
|
also exist:
|
||||||
|
|
||||||
- `build`: All build artifacts. Not checked in to version control.
|
- `build`: All build artifacts. Not checked in to version control.
|
||||||
- `local`: Local files, used for local build configuration input files. Not
|
- `local`: Local files, used for local build configuration input files.
|
||||||
checked in to version control.
|
|
||||||
|
|
||||||
## Codebase Introduction
|
## Codebase Introduction
|
||||||
|
|
||||||
@@ -235,16 +206,10 @@ Layers depend on other layers, but circular dependencies would break the
|
|||||||
separability and isolation utility of layers (in effect, forming one big layer),
|
separability and isolation utility of layers (in effect, forming one big layer),
|
||||||
so in other words, layers are arranged into a directed acyclic graph.
|
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:
|
A list of the layers in the codebase and their associated namespaces is below:
|
||||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||||
memory allocators, helper macros, command-line parsing, and so on. Depends
|
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||||
on no other codebase layers.
|
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
|
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||||
Format) file format.
|
Format) file format.
|
||||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||||
@@ -252,70 +217,45 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||||
processes are halted. When attached processes are running, it is halted.
|
processes are halted. When attached processes are running, it is halted.
|
||||||
Driven by a debugger frontend on another thread.
|
Driven by a debugger frontend on another thread.
|
||||||
- `dasm_cache` (`DASM_`): An asynchronous disassembly decoder and cache. Users
|
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
|
||||||
ask for disassembly for some data, with a particular architecture, and other
|
disassembly for a particular virtual address range in a process, and threads
|
||||||
various parameters, and threads implemented in this layer decode and cache the
|
implemented in this layer decode and cache the disassembly for that range.
|
||||||
disassembly for that data with those parameters.
|
- `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug
|
||||||
- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info
|
info stored in the RADDBG format. Users ask for debug info for a particular
|
||||||
stored in the RDI format. Users ask for debug info for a particular path, and
|
executable, and on separate threads, this layer loads the associated debug
|
||||||
on separate threads, this layer loads the associated debug info file. If
|
info file. If necessary, it will launch a separate conversion process to
|
||||||
necessary, it will launch a separate conversion process to convert original
|
convert original debug info into the RADDBG format.
|
||||||
debug info into the RDI format.
|
- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process
|
||||||
- `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. The abstraction is used to provide a common interface for process
|
||||||
control on target platforms. Used to implement part of `ctrl`.
|
control on target platforms. Used to implement part of `ctrl`.
|
||||||
- `draw` (`DR_`): Implements a high-level graphics drawing API for the
|
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
|
||||||
debugger's purposes, using the underlying `render` abstraction layer. Provides
|
debugger "entity cache" (where "entities" include processes, threads, modules,
|
||||||
high-level APIs for various draw commands, but takes care of batching them,
|
breakpoints, source files, targets, and so on). Implements a command loop
|
||||||
and so on.
|
for driving process control, which is used to implement stepping commands and
|
||||||
- `eval` (`E_`): Implements a compiler for an expression language built for
|
user breakpoints. Implements extractors and caches for various entity-related
|
||||||
evaluation of variables, registers, types, and more, from debugger-attached
|
data, like full thread unwinds and local variable maps. Also implements core
|
||||||
processes, debug info, debugger state, and files. Broken into several phases
|
building blocks for evaluation and evaluation visualization.
|
||||||
mostly corresponding to traditional compiler phases - lexer, parser,
|
- `df/gfx` (`DF_`): The debugger's graphical frontend. Builds on top of
|
||||||
type-checker, IR generation, and IR evaluation.
|
`df/core` to provide all graphical features, including windows, panels, all
|
||||||
- `eval_visualization` (`EV_`): Implements the core non-graphical evaluation
|
of the various debugger interfaces, and evaluation visualization.
|
||||||
visualization engine, which can be used to visualize evaluations (provided by
|
- `draw` (`D_`): Implements a high-level graphics drawing API for the debugger's
|
||||||
the `eval` layer) in a number of ways. Implements core data structures and
|
purposes, using the underlying `render` abstraction layer. Provides high-level
|
||||||
transforms for the `Watch` view.
|
APIs for various draw commands, but takes care of batching them, and so on.
|
||||||
- `file_stream` (`FS_`): Provides asynchronous file loading, storing the
|
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
|
||||||
artifacts inside of the cache implemented by the `hash_store` layer, and
|
evaluation of variables, registers, and so on from debugger-attached processes
|
||||||
hot-reloading the contents of files when they change. Allows callers to map
|
and/or debug info. Broken into several phases mostly corresponding to
|
||||||
file paths to data hashes, which can then be used to obtain the file's data.
|
traditional compiler phases - lexer, parser, type-checker, IR generation, and
|
||||||
- `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in
|
IR evaluation.
|
||||||
CPU-side data for text shaping, and in GPU texture atlases for rasterized
|
- `font_cache` (`F_`): Implements a cache of rasterized font data, both in CPU-
|
||||||
glyphs. All cache information is sourced from the `font_provider` abstraction
|
side data for text shaping, and in GPU texture atlases for rasterized glyphs.
|
||||||
layer.
|
All cache information is sourced from the `font_provider` abstraction layer.
|
||||||
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
||||||
and font rasterization backends.
|
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
|
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||||
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
for asynchronously preparing data for visualization.
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a
|
- `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
|
128-bit hash of the data. Used as a general data store by other layers.
|
||||||
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
|
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
||||||
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, 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
|
generates C code which is then included by hand-written C code. Currently, it
|
||||||
@@ -330,12 +270,8 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
duplicate version of `base` and `os` are included in this layer. They are
|
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
|
updated manually, as needed. This is to ensure the stability of the
|
||||||
metaprogram.
|
metaprogram.
|
||||||
- `msf` (`MSF_`): Code for parsing and/or writing the MSF file format.
|
|
||||||
- `mule` (no namespace): Test executables for battle testing debugger
|
- `mule` (no namespace): Test executables for battle testing debugger
|
||||||
functionality.
|
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
|
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
||||||
types in other debuggers.
|
types in other debuggers.
|
||||||
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
||||||
@@ -344,28 +280,23 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
graphical operating system features under an abstract API, which is
|
graphical operating system features under an abstract API, which is
|
||||||
implemented per-target-operating-system.
|
implemented per-target-operating-system.
|
||||||
- `path` (`PATH_`): Small helpers for manipulating file path strings.
|
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
- `pdb` (`PDB_`): Code for parsing and/or writing the PDB file format.
|
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)
|
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
|
||||||
file format.
|
file format.
|
||||||
- `raddbg` (`RD_`): The layer which ties everything together for the main
|
- `raddbg` (no namespace): The layer which ties everything together for the main
|
||||||
graphical debugger. Implements the debugger's graphical frontend, all of the
|
graphical debugger. Not much "meat", just drives `df`, implements command line
|
||||||
debugger-specific UI, the debugger executable's command line interface, and
|
options, and so on.
|
||||||
all of the built-in visualizers.
|
- `raddbg_cons` (`CONS_`): Implements an API for constructing files of the
|
||||||
- `rdi_breakpad_from_pdb` (`P2B_`): Our implementation, using the codebase's RDI
|
RADDBG debug info file format.
|
||||||
technology, for extracting information from PDBs and generating Breakpad text
|
- `raddbg_dump` (`DUMP_`): A dumper utility program for dumping textualizations
|
||||||
dumps.
|
of RADDBG debug info files.
|
||||||
- `rdi_dump` (no namespace): A dumper utility program for dumping
|
- `raddbg_format` (`RADDBG_`): Standalone types and helper functions for the
|
||||||
textualizations of RDI debug info files.
|
RADDBG debug info file format. Does not depend on `base`.
|
||||||
- `rdi_format` (no namespace): A layer which includes the `lib_rdi_format` layer
|
- `raddbg_markup` (`RADDBG_`): Standalone header file for marking up user
|
||||||
and bundles it with codebase-specific helpers, to easily include the library
|
programs to work with various features in the `raddbg` debugger. Does not
|
||||||
in codebase programs, and have it be integrated with codebase constructs.
|
depend on `base`.
|
||||||
- `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
|
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
||||||
supported architectures. Used in reading/writing registers in `demon`, or in
|
supported architectures. Used in reading/writing registers in `demon`, or in
|
||||||
looking up register metadata.
|
looking up register metadata.
|
||||||
@@ -374,19 +305,21 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
level drawing API - this layer is strictly for minimally abstracting on an
|
level drawing API - this layer is strictly for minimally abstracting on an
|
||||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||||
layer.
|
layer.
|
||||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
- `scratch` (no namespace): Scratch space for small and transient test or sample
|
||||||
- `task_system` (`TS_`): Implements a system for kicking off asynchronous tasks
|
programs.
|
||||||
and obtaining artifacts from those tasks once they've completed.
|
|
||||||
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||||
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
for asynchronously preparing data for visualization.
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
- `text_cache` (`TXT_`): Implements an asynchronously-filled cache for textual
|
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
|
||||||
analysis data (tokens, line ranges, and so on), filled by data sourced in the
|
reloaded, asynchronously parsed, and asynchronously mutated source code files.
|
||||||
`hash_store` layer's cache. Used for asynchronously preparing data for
|
Used by the debugger to visualize source code files. Users ask for text lines,
|
||||||
visualization (like for the source code viewer).
|
tokens, and metadata, and it is prepared on background threads.
|
||||||
- `third_party` (no namespace): External code from other projects, which some
|
- `type_graph` (`TG_`): Code for analyzing and navigating type structures from
|
||||||
layers in the codebase depend on. All external code is included and built
|
RADDBG debug info files, with the additional capability of constructing
|
||||||
directly within the codebase.
|
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
|
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
||||||
core immediate mode hierarchical user interface data structure building
|
core immediate mode hierarchical user interface data structure building
|
||||||
API, and has helper layers for building some higher-level widgets.
|
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.
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ cd /D "%~dp0"
|
|||||||
|
|
||||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||||
::
|
::
|
||||||
:: This is a central build script for the RAD Debugger project, for use in
|
:: This is a central build script for the RAD Debugger project. It takes a list
|
||||||
:: Windows development environments. It takes a list of simple alphanumeric-
|
:: of simple alphanumeric-only arguments which control (a) what is built, (b)
|
||||||
:: only arguments which control (a) what is built, (b) which compiler & linker
|
:: which compiler & linker are used, and (c) extra high-level build options. By
|
||||||
:: are used, and (c) extra high-level build options. By default, if no options
|
:: default, if no options are passed, then the main "raddbg" graphical debugger
|
||||||
:: are passed, then the main "raddbg" graphical debugger is built.
|
:: is built.
|
||||||
::
|
::
|
||||||
:: Below is a non-exhaustive list of possible ways to use the script:
|
:: Below is a non-exhaustive list of possible ways to use the script:
|
||||||
:: `build raddbg`
|
:: `build raddbg`
|
||||||
:: `build raddbg clang`
|
:: `build raddbg clang`
|
||||||
:: `build raddbg release`
|
:: `build raddbg release`
|
||||||
:: `build raddbg asan telemetry`
|
:: `build raddbg asan telemetry`
|
||||||
:: `build rdi_from_pdb`
|
:: `build raddbg_from_pdb`
|
||||||
::
|
::
|
||||||
:: For a full list of possible build targets and their build command lines,
|
:: For a full list of possible build targets and their build command lines,
|
||||||
:: search for @build_targets in this file.
|
:: search for @build_targets in this file.
|
||||||
@@ -34,7 +34,6 @@ if "%release%"=="1" set debug=0 && echo [release mode]
|
|||||||
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
||||||
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
||||||
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
|
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 ------------------------------------
|
:: --- Unpack Command Line Build Arguments ------------------------------------
|
||||||
set auto_compile_flags=
|
set auto_compile_flags=
|
||||||
@@ -43,27 +42,26 @@ if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=add
|
|||||||
|
|
||||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
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 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 /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
set cl_debug= call cl /Od %cl_common% %auto_compile_flags%
|
||||||
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
set cl_release= call cl /O2 /DNDEBUG %cl_common% %auto_compile_flags%
|
||||||
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
|
set clang_debug= call clang -g -O0 %clang_common% %auto_compile_flags%
|
||||||
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %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" /pdbaltpath:%%%%_PDB%%%%
|
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" -Xlinker /pdbaltpath:%%%%_PDB%%%%
|
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res
|
||||||
set cl_out= /out:
|
set cl_out= /out:
|
||||||
set clang_out= -o
|
set clang_out= -o
|
||||||
|
|
||||||
:: --- Per-Build Settings -----------------------------------------------------
|
:: --- Per-Build Settings -----------------------------------------------------
|
||||||
|
set gfx=-DOS_FEATURE_GRAPHICAL=1
|
||||||
|
set net=-DOS_FEATURE_SOCKET=1
|
||||||
set link_dll=-DLL
|
set link_dll=-DLL
|
||||||
set link_icon=logo.res
|
|
||||||
if "%msvc%"=="1" set only_compile=/c
|
if "%msvc%"=="1" set only_compile=/c
|
||||||
if "%clang%"=="1" set only_compile=-c
|
if "%clang%"=="1" set only_compile=-c
|
||||||
if "%msvc%"=="1" set EHsc=/EHsc
|
if "%msvc%"=="1" set EHsc=/EHsc
|
||||||
if "%clang%"=="1" set EHsc=
|
if "%clang%"=="1" set EHsc=
|
||||||
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
|
if "%msvc%"=="1" set rc=rc.exe
|
||||||
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
|
if "%clang%"=="1" set rc=llvm-rc.exe
|
||||||
if "%msvc%"=="1" set rc=call rc
|
|
||||||
if "%clang%"=="1" set rc=call llvm-rc
|
|
||||||
|
|
||||||
:: --- Choose Compile/Link Lines ----------------------------------------------
|
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||||
@@ -87,7 +85,7 @@ pushd build
|
|||||||
popd
|
popd
|
||||||
|
|
||||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
:: --- Get Current Git Commit Id ----------------------------------------------
|
||||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DRADDBG_GIT=\"%%i\"
|
||||||
|
|
||||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||||
if "%no_meta%"=="1" echo [skipping metagen]
|
if "%no_meta%"=="1" echo [skipping metagen]
|
||||||
@@ -100,26 +98,16 @@ if not "%no_meta%"=="1" (
|
|||||||
|
|
||||||
:: --- Build Everything (@build_targets) --------------------------------------
|
:: --- Build Everything (@build_targets) --------------------------------------
|
||||||
pushd build
|
pushd build
|
||||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
|
if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1
|
||||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %out%radlink.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 "%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 "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.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 "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.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 "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.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 "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1
|
||||||
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
|
if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.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" 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 "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
|
if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || 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_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
|
||||||
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
|
popd
|
||||||
|
|
||||||
:: --- Unset ------------------------------------------------------------------
|
:: --- Unset ------------------------------------------------------------------
|
||||||
@@ -130,10 +118,3 @@ set compile_link=
|
|||||||
set out=
|
set out=
|
||||||
set msvc=
|
set msvc=
|
||||||
set debug=
|
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
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
+86
-37
@@ -45,52 +45,101 @@ load_paths =
|
|||||||
|
|
||||||
commands =
|
commands =
|
||||||
{
|
{
|
||||||
//- rjf: fkey command slots (change locally but do not commit)
|
.rjf_f1 =
|
||||||
.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, },
|
.win = "build raddbg telemetry",
|
||||||
.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, },
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
//- rjf: local target builds
|
.footer_panel = true,
|
||||||
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_rdi_from_pdb = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.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, },
|
.rjf_f2 =
|
||||||
.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, },
|
.win = "build raddbg_from_pdb",
|
||||||
.build_mule_main = { .win = "build mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.build_mule_module = { .win = "build mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
.build_mule_hotload = { .win = "build mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_mule_peb_trample = { .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.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, },
|
.rjf_f3 =
|
||||||
.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, },
|
.win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --profile:local_dev.raddbg_profile && popd",
|
||||||
.build_rdi_dump_wsl = { .win = "wsl ./build.sh rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.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, },
|
.out = "*compilation*",
|
||||||
.build_ryan_scratch_wsl = { .win = "wsl ./build.sh ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_mule_main_wsl = { .win = "wsl ./build.sh mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_mule_module_wsl = { .win = "wsl ./build.sh mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.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, },
|
.build_raddbg =
|
||||||
|
{
|
||||||
//- rjf: local target runs
|
.win = "build raddbg",
|
||||||
.run_raddbg = { .win = "pushd build && raddbg.exe && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.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 =
|
fkey_command =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.F1 = "build_raddbg",
|
||||||
.F2 = "f2",
|
.F3 = "run_raddbg",
|
||||||
.F3 = "f3",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fkey_command_override =
|
fkey_command_override =
|
||||||
{
|
{
|
||||||
.rjf =
|
.rjf =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.F1 = "rjf_f1",
|
||||||
.F2 = "f2",
|
.F2 = "rjf_f2",
|
||||||
.F3 = "f3",
|
.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
|
||||||
+223
-155
@@ -2,175 +2,175 @@
|
|||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Functions
|
// Implementation
|
||||||
|
|
||||||
//- rjf: arena creation/destruction
|
|
||||||
|
|
||||||
internal Arena *
|
internal Arena *
|
||||||
arena_alloc_(ArenaParams *params)
|
arena_alloc__sized(U64 init_res, U64 init_cmt)
|
||||||
{
|
{
|
||||||
// rjf: round up reserve/commit sizes
|
ProfBeginFunction();
|
||||||
U64 reserve_size = params->reserve_size;
|
Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res);
|
||||||
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 *memory = 0;
|
||||||
void *base = params->optional_backing_buffer;
|
U64 res = 0;
|
||||||
if(base == 0)
|
U64 cmt = 0;
|
||||||
|
B32 large_pages = os_large_pages_enabled();
|
||||||
|
if(large_pages)
|
||||||
{
|
{
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
U64 page_size = os_large_page_size();
|
||||||
{
|
res = AlignPow2(init_res, page_size);
|
||||||
base = os_reserve_large(reserve_size);
|
#if OS_WINDOWS
|
||||||
os_commit_large(base, commit_size);
|
cmt = res;
|
||||||
}
|
#else
|
||||||
else
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
{
|
|
||||||
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
|
#endif
|
||||||
|
memory = os_reserve_large(res);
|
||||||
|
if(!os_commit_large(memory, cmt))
|
||||||
|
{
|
||||||
|
memory = 0;
|
||||||
|
os_release(memory, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
U64 page_size = os_page_size();
|
||||||
|
res = AlignPow2(init_res, page_size);
|
||||||
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
|
memory = os_reserve(res);
|
||||||
|
if(!os_commit(memory, cmt))
|
||||||
|
{
|
||||||
|
memory = 0;
|
||||||
|
os_release(memory, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// rjf: extract arena header & fill
|
Arena *arena = (Arena*)memory;
|
||||||
Arena *arena = (Arena *)base;
|
if(arena)
|
||||||
|
{
|
||||||
|
AsanPoisonMemoryRegion(memory, cmt);
|
||||||
|
AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE);
|
||||||
|
arena->prev = 0;
|
||||||
arena->current = arena;
|
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->base_pos = 0;
|
||||||
arena->pos = ARENA_HEADER_SIZE;
|
arena->pos = ARENA_HEADER_SIZE;
|
||||||
arena->cmt = commit_size;
|
arena->cmt = cmt;
|
||||||
arena->res = reserve_size;
|
arena->res = res;
|
||||||
#if ARENA_FREE_LIST
|
arena->align = 8;
|
||||||
arena->free_size = 0;
|
#if ENABLE_DEV
|
||||||
arena->free_last = 0;
|
arena->dev = 0;
|
||||||
#endif
|
#endif
|
||||||
AsanPoisonMemoryRegion(base, commit_size);
|
arena->grow = 1;
|
||||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
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;
|
return arena;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_release(Arena *arena)
|
arena_release(Arena *arena)
|
||||||
{
|
{
|
||||||
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) {
|
||||||
{
|
prev = node->prev;
|
||||||
prev = n->prev;
|
os_release(node, node->res);
|
||||||
os_release(n, n->res);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: arena push/pop core functions
|
internal U64
|
||||||
|
arena_huge_push_threshold(void)
|
||||||
|
{
|
||||||
|
U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE;
|
||||||
|
U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1;
|
||||||
|
return threshold;
|
||||||
|
}
|
||||||
|
|
||||||
internal void *
|
internal void *
|
||||||
arena_push(Arena *arena, U64 size, U64 align)
|
arena_push__impl(Arena *arena, U64 size)
|
||||||
{
|
{
|
||||||
Arena *current = arena->current;
|
Arena *current = arena->current;
|
||||||
U64 pos_pre = AlignPow2(current->pos, align);
|
U64 pos_mem = AlignPow2(current->pos, arena->align);
|
||||||
U64 pos_pst = pos_pre + size;
|
U64 pos_new = pos_mem + size;
|
||||||
|
|
||||||
// rjf: chain, if needed
|
if (current->res < pos_new && arena->grow) {
|
||||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
Arena *new_block;
|
||||||
{
|
|
||||||
Arena *new_block = 0;
|
|
||||||
|
|
||||||
#if ARENA_FREE_LIST
|
// normal growth path
|
||||||
Arena *prev_block;
|
if (size < arena_huge_push_threshold()) {
|
||||||
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
|
new_block = arena_alloc();
|
||||||
{
|
|
||||||
if(new_block->res >= AlignPow2(size, align))
|
|
||||||
{
|
|
||||||
if(prev_block)
|
|
||||||
{
|
|
||||||
prev_block->prev = new_block->prev;
|
|
||||||
}
|
}
|
||||||
else
|
// huge growth path
|
||||||
{
|
else {
|
||||||
arena->free_last = new_block->prev;
|
U64 new_block_size = size + ARENA_HEADER_SIZE;
|
||||||
|
new_block = arena_alloc__sized(new_block_size, new_block_size);
|
||||||
}
|
}
|
||||||
arena->free_size -= new_block->res_size;
|
|
||||||
AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(new_block == 0)
|
if (new_block) {
|
||||||
{
|
|
||||||
U64 res_size = current->res_size;
|
|
||||||
U64 cmt_size = current->cmt_size;
|
|
||||||
if(size + ARENA_HEADER_SIZE > res_size)
|
|
||||||
{
|
|
||||||
res_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
|
||||||
cmt_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
|
||||||
}
|
|
||||||
new_block = arena_alloc(.reserve_size = res_size,
|
|
||||||
.commit_size = cmt_size,
|
|
||||||
.flags = current->flags);
|
|
||||||
new_block->base_pos = current->base_pos + current->res;
|
new_block->base_pos = current->base_pos + current->res;
|
||||||
SLLStackPush_N(arena->current, new_block, prev);
|
SLLStackPush_N(arena->current, new_block, prev);
|
||||||
}
|
|
||||||
|
|
||||||
current = new_block;
|
current = new_block;
|
||||||
pos_pre = AlignPow2(current->pos, align);
|
pos_mem = AlignPow2(current->pos, current->align);
|
||||||
pos_pst = pos_pre + size;
|
pos_new = pos_mem + size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: commit new pages, if needed
|
if (current->cmt < pos_new) {
|
||||||
if(current->cmt < pos_pst)
|
U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size;
|
||||||
{
|
B32 is_cmt_ok;
|
||||||
U64 cmt_pst_aligned = pos_pst + current->cmt_size-1;
|
|
||||||
cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size;
|
if (current->large_pages) {
|
||||||
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES);
|
||||||
U64 cmt_size = cmt_pst_clamped - current->cmt;
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
U8 *cmt_ptr = (U8 *)current + current->cmt;
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
if(current->flags & ArenaFlag_LargePages)
|
is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size);
|
||||||
{
|
} else {
|
||||||
os_commit_large(cmt_ptr, cmt_size);
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE);
|
||||||
}
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
else
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
{
|
is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size);
|
||||||
os_commit(cmt_ptr, cmt_size);
|
|
||||||
}
|
|
||||||
current->cmt = cmt_pst_clamped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: push onto current block
|
if (is_cmt_ok) {
|
||||||
void *result = 0;
|
current->cmt = cmt_new_clamped;
|
||||||
if(current->cmt >= pos_pst)
|
}
|
||||||
{
|
}
|
||||||
result = (U8 *)current+pos_pre;
|
|
||||||
current->pos = pos_pst;
|
void *memory = 0;
|
||||||
AsanUnpoisonMemoryRegion(result, size);
|
|
||||||
|
if (current->cmt >= pos_new) {
|
||||||
|
memory = (U8*)current + pos_mem;
|
||||||
|
current->pos = pos_new;
|
||||||
|
AsanUnpoisonMemoryRegion(memory, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: panic on failure
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
#if OS_FEATURE_GRAPHICAL
|
||||||
if(Unlikely(result == 0))
|
if(Unlikely(memory == 0))
|
||||||
{
|
{
|
||||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||||
os_abort(1);
|
os_exit_process(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
@@ -182,35 +182,95 @@ arena_pos(Arena *arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_pop_to(Arena *arena, U64 pos)
|
arena_pop_to(Arena *arena, U64 big_pos_unclamped)
|
||||||
{
|
{
|
||||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped);
|
||||||
Arena *current = arena->current;
|
|
||||||
|
|
||||||
#if ARENA_FREE_LIST
|
// unroll the chain
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
Arena *current = arena->current;
|
||||||
{
|
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) {
|
||||||
prev = current->prev;
|
|
||||||
current->pos = ARENA_HEADER_SIZE;
|
|
||||||
arena->free_size += current->res_size;
|
|
||||||
SLLStackPush_N(arena->free_last, current, prev);
|
|
||||||
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res_size - ARENA_HEADER_SIZE);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
|
||||||
{
|
|
||||||
prev = current->prev;
|
prev = current->prev;
|
||||||
os_release(current, current->res);
|
os_release(current, current->res);
|
||||||
}
|
}
|
||||||
#endif
|
AssertAlways(current);
|
||||||
arena->current = current;
|
arena->current = current;
|
||||||
|
|
||||||
|
// compute arena-relative position
|
||||||
U64 new_pos = big_pos - current->base_pos;
|
U64 new_pos = big_pos - current->base_pos;
|
||||||
AssertAlways(new_pos <= current->pos);
|
AssertAlways(new_pos <= current->pos);
|
||||||
|
|
||||||
|
// poison popped memory block
|
||||||
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
||||||
|
|
||||||
|
// update position
|
||||||
current->pos = new_pos;
|
current->pos = new_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: arena push/pop helpers
|
internal void
|
||||||
|
arena_absorb(Arena *arena, Arena *sub)
|
||||||
|
{
|
||||||
|
#if ENABLE_DEV
|
||||||
|
arena_annotate_absorb__dev(arena, sub);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// base adjustment
|
||||||
|
Arena *current = arena->current;
|
||||||
|
U64 base_adjust = current->base_pos + current->res;
|
||||||
|
for (Arena *node = sub->current; node != 0; node = node->prev) {
|
||||||
|
node->base_pos += base_adjust;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach sub to arena
|
||||||
|
sub->prev = arena->current;
|
||||||
|
arena->current = sub->current;
|
||||||
|
sub->current = sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Wrappers
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
arena_push(Arena *arena, U64 size)
|
||||||
|
{
|
||||||
|
void *memory = arena_push__impl(arena, size);
|
||||||
|
#if ENABLE_DEV
|
||||||
|
arena_annotate_push__dev(arena, size, memory);
|
||||||
|
#endif
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
arena_push_contiguous(Arena *arena, U64 size)
|
||||||
|
{
|
||||||
|
B32 restore = arena->grow;
|
||||||
|
arena->grow = 0;
|
||||||
|
void *memory = arena_push(arena, size);
|
||||||
|
arena->grow = restore;
|
||||||
|
#if ENABLE_DEV
|
||||||
|
arena_annotate_push__dev(arena, size, memory);
|
||||||
|
#endif
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_push_align(Arena *arena, U64 align)
|
||||||
|
{
|
||||||
|
Assert(IsPow2(align));
|
||||||
|
U64 amt = AlignPadPow2(arena->pos, align);
|
||||||
|
void *ptr = arena_push(arena, amt);
|
||||||
|
MemoryZero(ptr, amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_put_back(Arena *arena, U64 amt)
|
||||||
|
{
|
||||||
|
U64 pos_old = arena_pos(arena);
|
||||||
|
U64 pos_new = pos_old;
|
||||||
|
if (amt < pos_old) {
|
||||||
|
pos_new = pos_old - amt;
|
||||||
|
}
|
||||||
|
arena_pop_to(arena, pos_new);
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_clear(Arena *arena)
|
arena_clear(Arena *arena)
|
||||||
@@ -218,20 +278,6 @@ arena_clear(Arena *arena)
|
|||||||
arena_pop_to(arena, 0);
|
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
|
internal Temp
|
||||||
temp_begin(Arena *arena)
|
temp_begin(Arena *arena)
|
||||||
{
|
{
|
||||||
@@ -245,3 +291,25 @@ temp_end(Temp temp)
|
|||||||
{
|
{
|
||||||
arena_pop_to(temp.arena, temp.pos);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+49
-50
@@ -7,49 +7,39 @@
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Constants
|
//~ rjf: Constants
|
||||||
|
|
||||||
#if ARENA_FREE_LIST
|
|
||||||
#define ARENA_HEADER_SIZE 128
|
#define ARENA_HEADER_SIZE 128
|
||||||
#else
|
|
||||||
# define ARENA_HEADER_SIZE 64
|
#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
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Types
|
//~ rjf: Arena 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;
|
typedef struct Arena Arena;
|
||||||
struct Arena
|
struct Arena
|
||||||
{
|
{
|
||||||
Arena *prev; // previous arena in chain
|
struct Arena *prev;
|
||||||
Arena *current; // current arena in chain
|
struct Arena *current;
|
||||||
ArenaFlags flags;
|
|
||||||
U32 cmt_size;
|
|
||||||
U64 res_size;
|
|
||||||
U64 base_pos;
|
U64 base_pos;
|
||||||
U64 pos;
|
U64 pos;
|
||||||
U64 cmt;
|
U64 cmt;
|
||||||
U64 res;
|
U64 res;
|
||||||
#if ARENA_FREE_LIST
|
U64 align;
|
||||||
U64 free_size;
|
struct ArenaDev *dev;
|
||||||
Arena *free_last;
|
B8 grow;
|
||||||
#endif
|
B8 large_pages;
|
||||||
};
|
};
|
||||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
|
||||||
|
|
||||||
typedef struct Temp Temp;
|
typedef struct Temp Temp;
|
||||||
struct Temp
|
struct Temp
|
||||||
@@ -59,37 +49,46 @@ struct Temp
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Global Defaults
|
// Implementation
|
||||||
|
|
||||||
global U64 arena_default_reserve_size = MB(64);
|
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt);
|
||||||
global U64 arena_default_commit_size = KB(64);
|
|
||||||
global ArenaFlags arena_default_flags = 0;
|
|
||||||
|
|
||||||
////////////////////////////////
|
internal Arena* arena_alloc(void);
|
||||||
//~ 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);
|
internal void arena_release(Arena *arena);
|
||||||
|
|
||||||
//- rjf: arena push/pop/pos core functions
|
internal void* arena_push__impl(Arena *arena, U64 size);
|
||||||
internal void *arena_push(Arena *arena, U64 size, U64 align);
|
|
||||||
internal U64 arena_pos(Arena *arena);
|
internal U64 arena_pos(Arena *arena);
|
||||||
internal void arena_pop_to(Arena *arena, U64 pos);
|
internal void arena_pop_to(Arena *arena, U64 pos);
|
||||||
|
|
||||||
//- rjf: arena push/pop helpers
|
internal void arena_absorb(Arena *arena, Arena *sub);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Wrappers
|
||||||
|
|
||||||
|
internal void* arena_push(Arena *arena, U64 size);
|
||||||
|
internal void* arena_push_contiguous(Arena *arena, U64 size);
|
||||||
internal void arena_clear(Arena *arena);
|
internal void arena_clear(Arena *arena);
|
||||||
internal void arena_pop(Arena *arena, U64 amt);
|
internal void arena_push_align(Arena *arena, U64 align);
|
||||||
|
internal void arena_put_back(Arena *arena, U64 amt);
|
||||||
|
|
||||||
//- rjf: temporary arena scopes
|
|
||||||
internal Temp temp_begin(Arena *arena);
|
internal Temp temp_begin(Arena *arena);
|
||||||
internal void temp_end(Temp temp);
|
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))
|
//~ NOTE(allen): "Mini-Arena" Helper
|
||||||
#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)))
|
internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size);
|
||||||
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ 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
|
#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
|
||||||
@@ -82,7 +82,6 @@ internal CmdLine
|
|||||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||||
{
|
{
|
||||||
CmdLine parsed = {0};
|
CmdLine parsed = {0};
|
||||||
parsed.exe_name = command_line.first->string;
|
|
||||||
|
|
||||||
// NOTE(rjf): Set up config option table.
|
// NOTE(rjf): Set up config option table.
|
||||||
{
|
{
|
||||||
@@ -92,7 +91,6 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
|||||||
|
|
||||||
// NOTE(rjf): Parse command line.
|
// NOTE(rjf): Parse command line.
|
||||||
B32 after_passthrough_option = 0;
|
B32 after_passthrough_option = 0;
|
||||||
B32 first_passthrough = 1;
|
|
||||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||||
{
|
{
|
||||||
next = node->next;
|
next = node->next;
|
||||||
@@ -176,11 +174,10 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
|||||||
|
|
||||||
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||||
// handled by tool-specific code.
|
// handled by tool-specific code.
|
||||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
else if(!str8_match(node->string, str8_lit("--"), 0))
|
||||||
{
|
{
|
||||||
str8_list_push(arena, &parsed.inputs, node->string);
|
str8_list_push(arena, &parsed.inputs, node->string);
|
||||||
after_passthrough_option = 1;
|
after_passthrough_option = 1;
|
||||||
first_passthrough = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ struct CmdLineOptList
|
|||||||
typedef struct CmdLine CmdLine;
|
typedef struct CmdLine CmdLine;
|
||||||
struct CmdLine
|
struct CmdLine
|
||||||
{
|
{
|
||||||
String8 exe_name;
|
|
||||||
CmdLineOptList options;
|
CmdLineOptList options;
|
||||||
String8List inputs;
|
String8List inputs;
|
||||||
U64 option_table_size;
|
U64 option_table_size;
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
#ifndef BASE_CONTEXT_CRACKING_H
|
#ifndef BASE_CONTEXT_CRACKING_H
|
||||||
#define BASE_CONTEXT_CRACKING_H
|
#define BASE_CONTEXT_CRACKING_H
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Clang OS/Arch Cracking
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
|
|
||||||
# define COMPILER_CLANG 1
|
# define COMPILER_CLANG 1
|
||||||
@@ -18,7 +15,7 @@
|
|||||||
# elif defined(__APPLE__) && defined(__MACH__)
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
# define OS_MAC 1
|
# define OS_MAC 1
|
||||||
# else
|
# else
|
||||||
# error This compiler/OS combo is not supported.
|
# error This compiler/platform combo is not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||||
@@ -30,40 +27,17 @@
|
|||||||
# elif defined(__arm__)
|
# elif defined(__arm__)
|
||||||
# define ARCH_ARM32 1
|
# define ARCH_ARM32 1
|
||||||
# else
|
# else
|
||||||
# error Architecture not supported.
|
# error architecture not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MSVC OS/Arch Cracking
|
|
||||||
|
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
# define COMPILER_MSVC 1
|
# define COMPILER_CL 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)
|
# if defined(_WIN32)
|
||||||
# define OS_WINDOWS 1
|
# define OS_WINDOWS 1
|
||||||
# else
|
# else
|
||||||
# error This compiler/OS combo is not supported.
|
# error This compiler/platform combo is not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(_M_AMD64)
|
# if defined(_M_AMD64)
|
||||||
@@ -75,12 +49,9 @@
|
|||||||
# elif defined(_M_ARM)
|
# elif defined(_M_ARM)
|
||||||
# define ARCH_ARM32 1
|
# define ARCH_ARM32 1
|
||||||
# else
|
# else
|
||||||
# error Architecture not supported.
|
# error architecture not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: GCC OS/Arch Cracking
|
|
||||||
|
|
||||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
|
||||||
# define COMPILER_GCC 1
|
# define COMPILER_GCC 1
|
||||||
@@ -88,7 +59,7 @@
|
|||||||
# if defined(__gnu_linux__) || defined(__linux__)
|
# if defined(__gnu_linux__) || defined(__linux__)
|
||||||
# define OS_LINUX 1
|
# define OS_LINUX 1
|
||||||
# else
|
# else
|
||||||
# error This compiler/OS combo is not supported.
|
# error This compiler/platform combo is not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||||
@@ -100,96 +71,26 @@
|
|||||||
# elif defined(__arm__)
|
# elif defined(__arm__)
|
||||||
# define ARCH_ARM32 1
|
# define ARCH_ARM32 1
|
||||||
# else
|
# else
|
||||||
# error Architecture not supported.
|
# error architecture not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# error Compiler not supported.
|
# error This compiler is not supported yet
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Arch Cracking
|
|
||||||
|
|
||||||
#if defined(ARCH_X64)
|
#if defined(ARCH_X64)
|
||||||
# define ARCH_64BIT 1
|
# define ARCH_64BIT 1
|
||||||
#elif defined(ARCH_X86)
|
#elif defined(ARCH_X86)
|
||||||
# define ARCH_32BIT 1
|
# define ARCH_32BIT 1
|
||||||
#endif
|
#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)
|
#if defined(__cplusplus)
|
||||||
# define LANG_CPP 1
|
# define LANG_CPP 1
|
||||||
#else
|
#else
|
||||||
# define LANG_C 1
|
# define LANG_C 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
// zeroify
|
||||||
//~ 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)
|
#if !defined(ARCH_32BIT)
|
||||||
# define ARCH_32BIT 0
|
# define ARCH_32BIT 0
|
||||||
@@ -209,8 +110,8 @@
|
|||||||
#if !defined(ARCH_ARM32)
|
#if !defined(ARCH_ARM32)
|
||||||
# define ARCH_ARM32 0
|
# define ARCH_ARM32 0
|
||||||
#endif
|
#endif
|
||||||
#if !defined(COMPILER_MSVC)
|
#if !defined(COMPILER_CL)
|
||||||
# define COMPILER_MSVC 0
|
# define COMPILER_CL 0
|
||||||
#endif
|
#endif
|
||||||
#if !defined(COMPILER_GCC)
|
#if !defined(COMPILER_GCC)
|
||||||
# define COMPILER_GCC 0
|
# define COMPILER_GCC 0
|
||||||
@@ -234,14 +135,10 @@
|
|||||||
# define LANG_C 0
|
# define LANG_C 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
||||||
//~ rjf: Unsupported Errors
|
# define ARCH_LITTLE_ENDIAN 1
|
||||||
|
#else
|
||||||
#if ARCH_X86
|
# error Endianness of this architecture not understood by context cracker
|
||||||
# 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
|
||||||
|
|
||||||
#endif // BASE_CONTEXT_CRACKING_H
|
#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
|
|
||||||
+7
-9
@@ -4,17 +4,15 @@
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Base Includes
|
//~ rjf: Base Includes
|
||||||
|
|
||||||
#undef MARKUP_LAYER_COLOR
|
#undef RADDBG_LAYER_COLOR
|
||||||
#define MARKUP_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||||
|
|
||||||
#include "base_core.c"
|
#include "base_types.c"
|
||||||
#include "base_profile.c"
|
#include "base_markup.c"
|
||||||
#include "base_arena.c"
|
#include "base_arena.c"
|
||||||
#include "base_math.c"
|
#include "base_math.c"
|
||||||
#include "base_strings.c"
|
#include "base_string.c"
|
||||||
#include "base_thread_context.c"
|
#include "base_thread_context.c"
|
||||||
#include "base_command_line.c"
|
#include "base_command_line.c"
|
||||||
#include "base_markup.c"
|
#include "base_arena_dev.c"
|
||||||
#include "base_meta.c"
|
#include "base_bits.c"
|
||||||
#include "base_log.c"
|
|
||||||
#include "base_entry_point.c"
|
|
||||||
|
|||||||
+7
-8
@@ -8,17 +8,16 @@
|
|||||||
//~ rjf: Base Includes
|
//~ rjf: Base Includes
|
||||||
|
|
||||||
#include "base_context_cracking.h"
|
#include "base_context_cracking.h"
|
||||||
|
#include "base_types.h"
|
||||||
#include "base_core.h"
|
#include "base_markup.h"
|
||||||
#include "base_profile.h"
|
#include "base_ins.h"
|
||||||
|
#include "base_linked_lists.h"
|
||||||
#include "base_arena.h"
|
#include "base_arena.h"
|
||||||
#include "base_math.h"
|
#include "base_math.h"
|
||||||
#include "base_strings.h"
|
#include "base_string.h"
|
||||||
#include "base_thread_context.h"
|
#include "base_thread_context.h"
|
||||||
#include "base_command_line.h"
|
#include "base_command_line.h"
|
||||||
#include "base_markup.h"
|
#include "base_arena_dev.h"
|
||||||
#include "base_meta.h"
|
#include "base_bits.h"
|
||||||
#include "base_log.h"
|
|
||||||
#include "base_entry_point.h"
|
|
||||||
|
|
||||||
#endif // BASE_INC_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
|
|
||||||
@@ -1,21 +1,2 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|||||||
+71
-4
@@ -4,9 +4,76 @@
|
|||||||
#ifndef BASE_MARKUP_H
|
#ifndef BASE_MARKUP_H
|
||||||
#define BASE_MARKUP_H
|
#define BASE_MARKUP_H
|
||||||
|
|
||||||
internal void set_thread_name(String8 string);
|
////////////////////////////////
|
||||||
internal void set_thread_namef(char *fmt, ...);
|
//~ rjf: Zero Settings
|
||||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__))
|
|
||||||
#define ThreadName(str) (set_thread_name(str))
|
#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
|
#endif // BASE_MARKUP_H
|
||||||
|
|||||||
@@ -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,2 +0,0 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
@@ -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
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Third Party Includes
|
//~ rjf: Third Party Includes
|
||||||
|
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
#if !SUPPLEMENT_UNIT
|
||||||
# define STB_SPRINTF_IMPLEMENTATION
|
# define STB_SPRINTF_IMPLEMENTATION
|
||||||
# define STB_SPRINTF_STATIC
|
# define STB_SPRINTF_STATIC
|
||||||
# include "third_party/stb/stb_sprintf.h"
|
# include "third_party/stb/stb_sprintf.h"
|
||||||
@@ -946,11 +946,11 @@ str8_array_from_list(Arena *arena, String8List *list)
|
|||||||
{
|
{
|
||||||
String8Array array;
|
String8Array array;
|
||||||
array.count = list->node_count;
|
array.count = list->node_count;
|
||||||
array.v = push_array_no_zero(arena, String8, array.count);
|
array.strings = push_array_no_zero(arena, String8, array.count);
|
||||||
U64 idx = 0;
|
U64 idx = 0;
|
||||||
for(String8Node *n = list->first; n != 0; n = n->next, idx += 1)
|
for(String8Node *n = list->first; n != 0; n = n->next, idx += 1)
|
||||||
{
|
{
|
||||||
array.v[idx] = n->string;
|
array.strings[idx] = n->string;
|
||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
@@ -960,7 +960,7 @@ str8_array_reserve(Arena *arena, U64 count)
|
|||||||
{
|
{
|
||||||
String8Array arr;
|
String8Array arr;
|
||||||
arr.count = 0;
|
arr.count = 0;
|
||||||
arr.v = push_array(arena, String8, count);
|
arr.strings = push_array(arena, String8, count);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1281,7 +1281,7 @@ utf16_decode(U16 *str, U64 max){
|
|||||||
result.codepoint = str[0];
|
result.codepoint = str[0];
|
||||||
result.inc = 1;
|
result.inc = 1;
|
||||||
if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000){
|
if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000){
|
||||||
result.codepoint = ((str[0] - 0xD800) << 10) | ((str[1] - 0xDC00) + 0x10000);
|
result.codepoint = ((str[0] - 0xD800) << 10) | (str[1] - 0xDC00) + 0x10000;
|
||||||
result.inc = 2;
|
result.inc = 2;
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
@@ -1306,7 +1306,7 @@ utf8_encode(U8 *str, U32 codepoint){
|
|||||||
inc = 3;
|
inc = 3;
|
||||||
}
|
}
|
||||||
else if (codepoint <= 0x10FFFF){
|
else if (codepoint <= 0x10FFFF){
|
||||||
str[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3);
|
str[0] = (bitmask4 << 3) | ((codepoint >> 18) & bitmask3);
|
||||||
str[1] = bit8 | ((codepoint >> 12) & bitmask6);
|
str[1] = bit8 | ((codepoint >> 12) & bitmask6);
|
||||||
str[2] = bit8 | ((codepoint >> 6) & bitmask6);
|
str[2] = bit8 | ((codepoint >> 6) & bitmask6);
|
||||||
str[3] = bit8 | ( codepoint & bitmask6);
|
str[3] = bit8 | ( codepoint & bitmask6);
|
||||||
@@ -1358,7 +1358,7 @@ str8_from_16(Arena *arena, String16 in){
|
|||||||
size += utf8_encode(str + size, consume.codepoint);
|
size += utf8_encode(str + size, consume.codepoint);
|
||||||
}
|
}
|
||||||
str[size] = 0;
|
str[size] = 0;
|
||||||
arena_pop(arena, (cap - size));
|
arena_put_back(arena, (cap - size));
|
||||||
return(str8(str, size));
|
return(str8(str, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1375,7 +1375,7 @@ str16_from_8(Arena *arena, String8 in){
|
|||||||
size += utf16_encode(str + size, consume.codepoint);
|
size += utf16_encode(str + size, consume.codepoint);
|
||||||
}
|
}
|
||||||
str[size] = 0;
|
str[size] = 0;
|
||||||
arena_pop(arena, (cap - size)*2);
|
arena_put_back(arena, (cap - size)*2);
|
||||||
return(str16(str, size));
|
return(str16(str, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1390,7 +1390,7 @@ str8_from_32(Arena *arena, String32 in){
|
|||||||
size += utf8_encode(str + size, *ptr);
|
size += utf8_encode(str + size, *ptr);
|
||||||
}
|
}
|
||||||
str[size] = 0;
|
str[size] = 0;
|
||||||
arena_pop(arena, (cap - size));
|
arena_put_back(arena, (cap - size));
|
||||||
return(str8(str, size));
|
return(str8(str, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1408,7 +1408,7 @@ str32_from_8(Arena *arena, String8 in){
|
|||||||
size += 1;
|
size += 1;
|
||||||
}
|
}
|
||||||
str[size] = 0;
|
str[size] = 0;
|
||||||
arena_pop(arena, (cap - size)*4);
|
arena_put_back(arena, (cap - size)*4);
|
||||||
return(str32(str, size));
|
return(str32(str, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1565,102 +1565,6 @@ string_from_elapsed_time(Arena *arena, DateTime dt){
|
|||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Text Indentation
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
indented_from_string(Arena *arena, String8 string)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
read_only local_persist U8 indentation_bytes[] = " ";
|
|
||||||
String8List indented_strings = {0};
|
|
||||||
S64 depth = 0;
|
|
||||||
S64 next_depth = 0;
|
|
||||||
U64 line_begin_off = 0;
|
|
||||||
for(U64 off = 0; off <= string.size; off += 1)
|
|
||||||
{
|
|
||||||
U8 byte = off<string.size ? string.str[off] : 0;
|
|
||||||
switch(byte)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case '{':case '[':case '(':{next_depth += 1; next_depth = Max(0, next_depth);}break;
|
|
||||||
case '}':case ']':case ')':{next_depth -= 1; next_depth = Max(0, next_depth); depth = next_depth;}break;
|
|
||||||
case '\n':
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
String8 line = str8_skip_chop_whitespace(str8_substr(string, r1u64(line_begin_off, off)));
|
|
||||||
if(line.size != 0)
|
|
||||||
{
|
|
||||||
str8_list_pushf(scratch.arena, &indented_strings, "%.*s%S\n", (int)depth*2, indentation_bytes, line);
|
|
||||||
}
|
|
||||||
line_begin_off = off+1;
|
|
||||||
depth = next_depth;
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String8 result = str8_list_join(arena, &indented_strings, 0);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Text Wrapping
|
|
||||||
|
|
||||||
internal String8List
|
|
||||||
wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent)
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
Rng1U64 line_range = r1u64(0, 0);
|
|
||||||
U64 wrapped_indent_level = 0;
|
|
||||||
static char *spaces = " ";
|
|
||||||
for (U64 idx = 0; idx <= string.size; idx += 1){
|
|
||||||
U8 chr = idx < string.size ? string.str[idx] : 0;
|
|
||||||
if (chr == '\n'){
|
|
||||||
Rng1U64 candidate_line_range = line_range;
|
|
||||||
candidate_line_range.max = idx;
|
|
||||||
// NOTE(nick): when wrapping is interrupted with \n we emit a string without including \n
|
|
||||||
// because later tool_fprint_list inserts separator after each node
|
|
||||||
// except for last node, so don't strip last \n.
|
|
||||||
if (idx + 1 == string.size){
|
|
||||||
candidate_line_range.max += 1;
|
|
||||||
}
|
|
||||||
String8 substr = str8_substr(string, candidate_line_range);
|
|
||||||
str8_list_push(arena, &list, substr);
|
|
||||||
line_range = r1u64(idx+1,idx+1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (char_is_space(chr) || chr == 0){
|
|
||||||
Rng1U64 candidate_line_range = line_range;
|
|
||||||
candidate_line_range.max = idx;
|
|
||||||
String8 substr = str8_substr(string, candidate_line_range);
|
|
||||||
U64 width_this_line = max_width-wrapped_indent_level;
|
|
||||||
if (list.node_count == 0){
|
|
||||||
width_this_line = first_line_max_width;
|
|
||||||
}
|
|
||||||
if (substr.size > width_this_line){
|
|
||||||
String8 line = str8_substr(string, line_range);
|
|
||||||
if (wrapped_indent_level > 0){
|
|
||||||
line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line);
|
|
||||||
}
|
|
||||||
str8_list_push(arena, &list, line);
|
|
||||||
line_range = r1u64(line_range.max+1, candidate_line_range.max);
|
|
||||||
wrapped_indent_level = ClampTop(64, wrap_indent);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
line_range = candidate_line_range;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (line_range.min < string.size && line_range.max > line_range.min){
|
|
||||||
String8 line = str8_substr(string, line_range);
|
|
||||||
if (wrapped_indent_level > 0){
|
|
||||||
line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line);
|
|
||||||
}
|
|
||||||
str8_list_push(arena, &list, line);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String <-> Color
|
//~ rjf: String <-> Color
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_STRINGS_H
|
#ifndef BASE_STRING_H
|
||||||
#define BASE_STRINGS_H
|
#define BASE_STRING_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Third Party Includes
|
//~ rjf: Third Party Includes
|
||||||
@@ -63,7 +63,7 @@ struct String8List
|
|||||||
typedef struct String8Array String8Array;
|
typedef struct String8Array String8Array;
|
||||||
struct String8Array
|
struct String8Array
|
||||||
{
|
{
|
||||||
String8 *v;
|
String8 *strings;
|
||||||
U64 count;
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -326,16 +326,6 @@ internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
|||||||
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
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
|
//~ rjf: String <-> Color
|
||||||
|
|
||||||
@@ -378,4 +368,4 @@ internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, Stri
|
|||||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
#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)))
|
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
|
||||||
|
|
||||||
#endif // BASE_STRINGS_H
|
#endif // BASE_STRING_H
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
// NOTE(allen): Thread Context Functions
|
// NOTE(allen): Thread Context Functions
|
||||||
|
|
||||||
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
#if !SUPPLEMENT_UNIT
|
||||||
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -19,15 +19,6 @@ tctx_init_and_equip(TCTX *tctx){
|
|||||||
tctx_thread_local = tctx;
|
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*
|
internal TCTX*
|
||||||
tctx_get_equipped(void){
|
tctx_get_equipped(void){
|
||||||
return(tctx_thread_local);
|
return(tctx_thread_local);
|
||||||
|
|||||||
@@ -23,10 +23,9 @@ struct TCTX
|
|||||||
// NOTE(allen): Thread Context Functions
|
// NOTE(allen): Thread Context Functions
|
||||||
|
|
||||||
internal void tctx_init_and_equip(TCTX *tctx);
|
internal void tctx_init_and_equip(TCTX *tctx);
|
||||||
internal void tctx_release(void);
|
|
||||||
internal TCTX* tctx_get_equipped(void);
|
internal TCTX* tctx_get_equipped(void);
|
||||||
|
|
||||||
internal Arena* tctx_get_scratch(Arena **conflicts, U64 countt);
|
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
|
||||||
|
|
||||||
internal void tctx_set_thread_name(String8 name);
|
internal void tctx_set_thread_name(String8 name);
|
||||||
internal String8 tctx_get_thread_name(void);
|
internal String8 tctx_get_thread_name(void);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Safe Casts
|
//~ Safe Casts
|
||||||
|
|
||||||
internal U16
|
internal U16
|
||||||
safe_cast_u16(U32 x)
|
safe_cast_u16(U32 x)
|
||||||
@@ -141,106 +141,6 @@ bswap_u64(U64 x)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if COMPILER_MSVC || (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 "Bit intrinsic functions not defined for this compiler."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Enum -> Sign
|
//~ rjf: Enum -> Sign
|
||||||
|
|
||||||
@@ -387,14 +287,6 @@ txt_rng_union(TxtRng a, TxtRng b)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
|
||||||
txt_rng_contains(TxtRng r, TxtPt pt)
|
|
||||||
{
|
|
||||||
B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) &&
|
|
||||||
txt_pt_less_than(pt, r.max));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Toolchain/Environment Enum Functions
|
//~ rjf: Toolchain/Environment Enum Functions
|
||||||
|
|
||||||
@@ -452,8 +344,8 @@ architecture_from_context(void){
|
|||||||
internal Compiler
|
internal Compiler
|
||||||
compiler_from_context(void){
|
compiler_from_context(void){
|
||||||
Compiler compiler = Compiler_Null;
|
Compiler compiler = Compiler_Null;
|
||||||
#if COMPILER_MSVC
|
#if COMPILER_CL
|
||||||
compiler = Compiler_msvc;
|
compiler = Compiler_cl;
|
||||||
#elif COMPILER_GCC
|
#elif COMPILER_GCC
|
||||||
compiler = Compiler_gcc;
|
compiler = Compiler_gcc;
|
||||||
#elif COMPILER_CLANG
|
#elif COMPILER_CLANG
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_CORE_H
|
#ifndef BASE_TYPES_H
|
||||||
#define BASE_CORE_H
|
#define BASE_TYPES_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Foreign Includes
|
//~ rjf: Foreign Includes
|
||||||
@@ -13,6 +13,17 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Build Configuration
|
||||||
|
|
||||||
|
#if !defined(ENABLE_DEV)
|
||||||
|
# define ENABLE_DEV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SUPPLEMENT_UNIT)
|
||||||
|
# define SUPPLEMENT_UNIT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Codebase Keywords
|
//~ rjf: Codebase Keywords
|
||||||
|
|
||||||
@@ -20,7 +31,7 @@
|
|||||||
#define global static
|
#define global static
|
||||||
#define local_persist static
|
#define local_persist static
|
||||||
|
|
||||||
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
|
||||||
# pragma section(".rdata$", read)
|
# pragma section(".rdata$", read)
|
||||||
# define read_only __declspec(allocate(".rdata$"))
|
# define read_only __declspec(allocate(".rdata$"))
|
||||||
#elif (COMPILER_CLANG && OS_LINUX)
|
#elif (COMPILER_CLANG && OS_LINUX)
|
||||||
@@ -34,93 +45,6 @@
|
|||||||
# define read_only
|
# define read_only
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define thread_static __declspec(thread)
|
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
|
||||||
# define thread_static __thread
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Linkage Keyword Macros
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
# define shared_function C_LINKAGE __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
# define shared_function C_LINKAGE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LANG_CPP
|
|
||||||
# define C_LINKAGE_BEGIN extern "C"{
|
|
||||||
# define C_LINKAGE_END }
|
|
||||||
# define C_LINKAGE extern "C"
|
|
||||||
#else
|
|
||||||
# define C_LINKAGE_BEGIN
|
|
||||||
# define C_LINKAGE_END
|
|
||||||
# define C_LINKAGE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Units
|
|
||||||
|
|
||||||
#define KB(n) (((U64)(n)) << 10)
|
|
||||||
#define MB(n) (((U64)(n)) << 20)
|
|
||||||
#define GB(n) (((U64)(n)) << 30)
|
|
||||||
#define TB(n) (((U64)(n)) << 40)
|
|
||||||
#define Thousand(n) ((n)*1000)
|
|
||||||
#define Million(n) ((n)*1000000)
|
|
||||||
#define Billion(n) ((n)*1000000000)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Branch Predictor Hints
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
# define Expect(expr, val) __builtin_expect((expr), (val))
|
|
||||||
#else
|
|
||||||
# define Expect(expr, val) (expr)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define Likely(expr) Expect(expr,1)
|
|
||||||
#define Unlikely(expr) Expect(expr,0)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Clamps, Mins, Maxes
|
|
||||||
|
|
||||||
#define Min(A,B) (((A)<(B))?(A):(B))
|
|
||||||
#define Max(A,B) (((A)>(B))?(A):(B))
|
|
||||||
#define ClampTop(A,X) Min(A,X)
|
|
||||||
#define ClampBot(X,B) Max(X,B)
|
|
||||||
#define Clamp(A,X,B) (((X)<(A))?(A):((X)>(B))?(B):(X))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type -> Alignment
|
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define AlignOf(T) __alignof(T)
|
|
||||||
#elif COMPILER_CLANG
|
|
||||||
# define AlignOf(T) __alignof(T)
|
|
||||||
#elif COMPILER_GCC
|
|
||||||
# define AlignOf(T) __alignof__(T)
|
|
||||||
#else
|
|
||||||
# error AlignOf not defined for this compiler.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Member Offsets
|
|
||||||
|
|
||||||
#define Member(T,m) (((T*)0)->m)
|
|
||||||
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
|
|
||||||
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
|
|
||||||
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: For-Loop Construct Macros
|
|
||||||
|
|
||||||
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
|
|
||||||
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
|
|
||||||
|
|
||||||
#define EachEnumVal(type, it) type it = (type)0; it < type##_COUNT; it = (type)(it+1)
|
|
||||||
#define EachNonZeroEnumVal(type, it) type it = (type)1; it < type##_COUNT; it = (type)(it+1)
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Memory Operation Macros
|
//~ rjf: Memory Operation Macros
|
||||||
|
|
||||||
@@ -143,127 +67,147 @@
|
|||||||
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
|
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
|
||||||
|
|
||||||
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
|
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
|
||||||
#define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
|
#define MemoryConsume(T,p,e) \
|
||||||
|
( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Units
|
||||||
|
|
||||||
|
#define KB(n) (((U64)(n)) << 10)
|
||||||
|
#define MB(n) (((U64)(n)) << 20)
|
||||||
|
#define GB(n) (((U64)(n)) << 30)
|
||||||
|
#define TB(n) (((U64)(n)) << 40)
|
||||||
|
#define Thousand(n) ((n)*1000)
|
||||||
|
#define Million(n) ((n)*1000000)
|
||||||
|
#define Billion(n) ((n)*1000000000)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Asserts
|
//~ rjf: Asserts
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
#if COMPILER_CL
|
||||||
# define Trap() __debugbreak()
|
# define Trap() __debugbreak()
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
# define Trap() __builtin_trap()
|
# define Trap() __builtin_trap()
|
||||||
# else
|
# else
|
||||||
# error Unknown trap intrinsic for this compiler.
|
# error "undefined trap"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0)
|
#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0)
|
||||||
#if BUILD_DEBUG
|
#if !defined(NDEBUG)
|
||||||
# define Assert(x) AssertAlways(x)
|
# define Assert(x) AssertAlways(x)
|
||||||
#else
|
#else
|
||||||
# define Assert(x) (void)(x)
|
# define Assert(x) (void)(x)
|
||||||
#endif
|
#endif
|
||||||
|
#define AssertImplies(a,b) Assert(!(a) || b)
|
||||||
|
#define AssertIff(a,b) Assert(!!(a) == !!(b))
|
||||||
#define InvalidPath Assert(!"Invalid Path!")
|
#define InvalidPath Assert(!"Invalid Path!")
|
||||||
#define NotImplemented Assert(!"Not Implemented!")
|
#define NotImplemented Assert(!"Not Implemented!")
|
||||||
#define NoOp ((void)0)
|
|
||||||
#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1]
|
#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1]
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Atomic Operations
|
//~ rjf: Branch Predictor Hints
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define Expect(expr, val) __builtin_expect((expr), (val))
|
||||||
|
#else
|
||||||
|
# define Expect(expr, val) (expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Likely(expr) Expect(expr,1)
|
||||||
|
#define Unlikely(expr) Expect(expr,0)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Misc. Helper Macros
|
||||||
|
|
||||||
|
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
#define Stmnt(S) do{ S }while(0)
|
||||||
|
|
||||||
|
#define Stringify_(S) #S
|
||||||
|
#define Stringify(S) Stringify_(S)
|
||||||
|
|
||||||
|
#define Glue_(A,B) A##B
|
||||||
|
#define Glue(A,B) Glue_(A,B)
|
||||||
|
|
||||||
|
#define Min(A,B) ( ((A)<(B))?(A):(B) )
|
||||||
|
#define Max(A,B) ( ((A)>(B))?(A):(B) )
|
||||||
|
|
||||||
|
#define ClampTop(A,X) Min(A,X)
|
||||||
|
#define ClampBot(X,B) Max(X,B)
|
||||||
|
#define Clamp(A,X,B) ( ((X)<(A))?(A):((X)>(B))?(B):(X) )
|
||||||
|
|
||||||
|
#define PtrClampTop(A,X) ClampTop(A,X)
|
||||||
|
#define PtrClampBot(X,B) ClampBot(X,B)
|
||||||
|
#define PtrClamp(A,X,B) Clamp(A,X,B)
|
||||||
|
|
||||||
|
#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b))
|
||||||
|
|
||||||
|
#define Swap(T,a,b) Stmnt( T t__ = a; a = b; b = t__; )
|
||||||
|
|
||||||
|
#if ARCH_64BIT
|
||||||
|
# define IntFromPtr(ptr) ((U64)(ptr))
|
||||||
|
#elif ARCH_32BIT
|
||||||
|
# define IntFromPtr(ptr) ((U32)(ptr))
|
||||||
|
#else
|
||||||
|
# error missing ptr cast for this architecture
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PtrFromInt(i) (void*)((U8*)0 + (i))
|
||||||
|
|
||||||
|
#define Member(T,m) (((T*)0)->m)
|
||||||
|
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
|
||||||
|
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
|
||||||
|
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
|
||||||
|
|
||||||
|
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
|
||||||
|
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
|
||||||
|
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
|
||||||
|
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
|
||||||
|
#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0)
|
||||||
|
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
|
||||||
|
|
||||||
|
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
|
||||||
|
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
|
||||||
|
|
||||||
|
#if LANG_CPP
|
||||||
|
# define zero_struct {}
|
||||||
|
#else
|
||||||
|
# define zero_struct {0}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
|
||||||
|
# define this_function_name "unknown"
|
||||||
|
#else
|
||||||
|
# define this_function_name __func__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LANG_CPP
|
||||||
|
# define C_LINKAGE_BEGIN extern "C"{
|
||||||
|
# define C_LINKAGE_END }
|
||||||
|
# define C_LINKAGE extern "C"
|
||||||
|
#else
|
||||||
|
# define C_LINKAGE_BEGIN
|
||||||
|
# define C_LINKAGE_END
|
||||||
|
# define C_LINKAGE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if COMPILER_CL
|
||||||
|
# define thread_static __declspec(thread)
|
||||||
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
|
# define thread_static __thread
|
||||||
|
#endif
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
# include <windows.h>
|
# define shared_function C_LINKAGE __declspec(dllexport)
|
||||||
# include <tmmintrin.h>
|
|
||||||
# include <wmmintrin.h>
|
|
||||||
# include <intrin.h>
|
|
||||||
# if ARCH_X64
|
|
||||||
# define ins_atomic_u64_eval(x) InterlockedAdd64((volatile __int64 *)(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) InterlockedAdd64((volatile __int64 *)(x), c)
|
|
||||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c))
|
|
||||||
# define ins_atomic_u32_eval(x,c) InterlockedAdd((volatile LONG *)(x), 0)
|
|
||||||
# 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))
|
|
||||||
#else
|
#else
|
||||||
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
# define shared_function C_LINKAGE
|
||||||
# endif
|
|
||||||
#elif OS_LINUX
|
|
||||||
# if ARCH_X64
|
|
||||||
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
|
|
||||||
# else
|
|
||||||
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# error Atomic intrinsics not defined for this operating system.
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Linked List Building Macros
|
//~ ASAN
|
||||||
|
|
||||||
//- rjf: linked list macro helpers
|
#if COMPILER_CL
|
||||||
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
|
|
||||||
#define SetNil(nil,p) ((p) = nil)
|
|
||||||
|
|
||||||
//- rjf: doubly-linked-lists
|
|
||||||
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
|
|
||||||
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
|
|
||||||
CheckNil(nil,p) ? \
|
|
||||||
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
|
|
||||||
((p)==(l)) ? \
|
|
||||||
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
|
|
||||||
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
|
|
||||||
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
|
|
||||||
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
|
|
||||||
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
|
|
||||||
((n) == (l) ? (l) = (l)->prev : (0)),\
|
|
||||||
(CheckNil(nil,(n)->prev) ? (0) :\
|
|
||||||
((n)->prev->next = (n)->next)),\
|
|
||||||
(CheckNil(nil,(n)->next) ? (0) :\
|
|
||||||
((n)->next->prev = (n)->prev)))
|
|
||||||
|
|
||||||
//- rjf: singly-linked, doubly-headed lists (queues)
|
|
||||||
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
|
||||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
|
||||||
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
|
|
||||||
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
|
||||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
|
||||||
((n)->next=(f),(f)=(n)))
|
|
||||||
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
|
|
||||||
(SetNil(nil,f),SetNil(nil,l)):\
|
|
||||||
((f)=(f)->next))
|
|
||||||
|
|
||||||
//- rjf: singly-linked, singly-headed lists (stacks)
|
|
||||||
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
|
|
||||||
#define SLLStackPop_N(f,next) ((f)=(f)->next)
|
|
||||||
|
|
||||||
//- rjf: doubly-linked-list helpers
|
|
||||||
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
|
||||||
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
|
||||||
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
|
||||||
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
|
|
||||||
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
|
||||||
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
|
||||||
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
|
||||||
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
|
|
||||||
|
|
||||||
//- rjf: singly-linked, doubly-headed list helpers
|
|
||||||
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
|
|
||||||
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
|
|
||||||
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
|
|
||||||
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
|
|
||||||
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
|
|
||||||
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
|
|
||||||
|
|
||||||
//- rjf: singly-linked, singly-headed list helpers
|
|
||||||
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
|
|
||||||
#define SLLStackPop(f) SLLStackPop_N(f,next)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Address Sanitizer Markup
|
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# if defined(__SANITIZE_ADDRESS__)
|
# if defined(__SANITIZE_ADDRESS__)
|
||||||
# define ASAN_ENABLED 1
|
# define ASAN_ENABLED 1
|
||||||
# define NO_ASAN __declspec(no_sanitize_address)
|
# define NO_ASAN __declspec(no_sanitize_address)
|
||||||
@@ -278,63 +222,24 @@ CheckNil(nil,p) ? \
|
|||||||
# endif
|
# endif
|
||||||
# define NO_ASAN __attribute__((no_sanitize("address")))
|
# define NO_ASAN __attribute__((no_sanitize("address")))
|
||||||
#else
|
#else
|
||||||
# define NO_ASAN
|
# error "NO_ASAN is not defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ASAN_ENABLED
|
#if ASAN_ENABLED
|
||||||
|
|
||||||
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
|
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
|
||||||
C_LINKAGE void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
|
||||||
C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
C_LINKAGE_BEGIN
|
||||||
|
void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
||||||
|
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
||||||
|
C_LINKAGE_END
|
||||||
|
|
||||||
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
|
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
|
||||||
# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size))
|
# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||||
#else
|
#else
|
||||||
# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
||||||
# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Misc. Helper Macros
|
|
||||||
|
|
||||||
#define Stringify_(S) #S
|
|
||||||
#define Stringify(S) Stringify_(S)
|
|
||||||
|
|
||||||
#define Glue_(A,B) A##B
|
|
||||||
#define Glue(A,B) Glue_(A,B)
|
|
||||||
|
|
||||||
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
|
|
||||||
|
|
||||||
#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b))
|
|
||||||
|
|
||||||
#define Swap(T,a,b) do{T t__ = a; a = b; b = t__;}while(0)
|
|
||||||
|
|
||||||
#if ARCH_64BIT
|
|
||||||
# define IntFromPtr(ptr) ((U64)(ptr))
|
|
||||||
#elif ARCH_32BIT
|
|
||||||
# define IntFromPtr(ptr) ((U32)(ptr))
|
|
||||||
#else
|
|
||||||
# error Missing pointer-to-integer cast for this architecture.
|
|
||||||
#endif
|
|
||||||
#define PtrFromInt(i) (void*)((U8*)0 + (i))
|
|
||||||
|
|
||||||
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
|
|
||||||
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
|
|
||||||
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
|
|
||||||
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
|
|
||||||
#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0)
|
|
||||||
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
|
|
||||||
|
|
||||||
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
|
|
||||||
|
|
||||||
#if LANG_CPP
|
|
||||||
# define zero_struct {}
|
|
||||||
#else
|
|
||||||
# define zero_struct {0}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
|
|
||||||
# define this_function_name "unknown"
|
|
||||||
#else
|
|
||||||
# define this_function_name __func__
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -354,7 +259,10 @@ typedef S32 B32;
|
|||||||
typedef S64 B64;
|
typedef S64 B64;
|
||||||
typedef float F32;
|
typedef float F32;
|
||||||
typedef double F64;
|
typedef double F64;
|
||||||
typedef void VoidProc(void);
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Large Base Types
|
||||||
|
|
||||||
typedef struct U128 U128;
|
typedef struct U128 U128;
|
||||||
struct U128
|
struct U128
|
||||||
{
|
{
|
||||||
@@ -364,6 +272,8 @@ struct U128
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Basic Types & Spaces
|
//~ rjf: Basic Types & Spaces
|
||||||
|
|
||||||
|
typedef void VoidProc(void);
|
||||||
|
|
||||||
typedef enum Dimension
|
typedef enum Dimension
|
||||||
{
|
{
|
||||||
Dimension_X,
|
Dimension_X,
|
||||||
@@ -404,19 +314,6 @@ typedef enum Corner
|
|||||||
}
|
}
|
||||||
Corner;
|
Corner;
|
||||||
|
|
||||||
typedef enum Dir2
|
|
||||||
{
|
|
||||||
Dir2_Invalid = -1,
|
|
||||||
Dir2_Left,
|
|
||||||
Dir2_Up,
|
|
||||||
Dir2_Right,
|
|
||||||
Dir2_Down,
|
|
||||||
Dir2_COUNT
|
|
||||||
}
|
|
||||||
Dir2;
|
|
||||||
#define axis2_from_dir2(d) (((d) & 1) ? Axis2_Y : Axis2_X)
|
|
||||||
#define side_from_dir2(d) (((d) < Dir2_Right) ? Side_Min : Side_Max)
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Toolchain/Environment Enums
|
//~ rjf: Toolchain/Environment Enums
|
||||||
|
|
||||||
@@ -444,7 +341,7 @@ Architecture;
|
|||||||
typedef enum Compiler
|
typedef enum Compiler
|
||||||
{
|
{
|
||||||
Compiler_Null,
|
Compiler_Null,
|
||||||
Compiler_msvc,
|
Compiler_cl,
|
||||||
Compiler_gcc,
|
Compiler_gcc,
|
||||||
Compiler_clang,
|
Compiler_clang,
|
||||||
Compiler_COUNT,
|
Compiler_COUNT,
|
||||||
@@ -672,13 +569,11 @@ struct DateTime
|
|||||||
U16 min; // [0,59]
|
U16 min; // [0,59]
|
||||||
U16 hour; // [0,24]
|
U16 hour; // [0,24]
|
||||||
U16 day; // [0,30]
|
U16 day; // [0,30]
|
||||||
union
|
union{
|
||||||
{
|
|
||||||
WeekDay week_day;
|
WeekDay week_day;
|
||||||
U32 wday;
|
U32 wday;
|
||||||
};
|
};
|
||||||
union
|
union{
|
||||||
{
|
|
||||||
Month month;
|
Month month;
|
||||||
U32 mon;
|
U32 mon;
|
||||||
};
|
};
|
||||||
@@ -706,7 +601,7 @@ struct FileProperties
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Safe Casts
|
//~ Safe Casts
|
||||||
|
|
||||||
internal U16 safe_cast_u16(U32 x);
|
internal U16 safe_cast_u16(U32 x);
|
||||||
internal U32 safe_cast_u32(U64 x);
|
internal U32 safe_cast_u32(U64 x);
|
||||||
@@ -734,15 +629,6 @@ internal U16 bswap_u16(U16 x);
|
|||||||
internal U32 bswap_u32(U32 x);
|
internal U32 bswap_u32(U32 x);
|
||||||
internal U64 bswap_u64(U64 x);
|
internal U64 bswap_u64(U64 x);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Enum -> Sign
|
//~ rjf: Enum -> Sign
|
||||||
|
|
||||||
@@ -765,7 +651,6 @@ internal TxtPt txt_pt_max(TxtPt a, TxtPt b);
|
|||||||
internal TxtRng txt_rng(TxtPt min, TxtPt max);
|
internal TxtRng txt_rng(TxtPt min, TxtPt max);
|
||||||
internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b);
|
internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b);
|
||||||
internal TxtRng txt_rng_union(TxtRng a, TxtRng b);
|
internal TxtRng txt_rng_union(TxtRng a, TxtRng b);
|
||||||
internal B32 txt_rng_contains(TxtRng r, TxtPt pt);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Toolchain/Environment Enum Functions
|
//~ rjf: Toolchain/Environment Enum Functions
|
||||||
@@ -792,9 +677,4 @@ internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_dat
|
|||||||
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||||
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||||
|
|
||||||
////////////////////////////////
|
#endif // BASE_TYPES_H
|
||||||
//~ rjf: Sorts
|
|
||||||
|
|
||||||
#define quick_sort(ptr, count, element_size, cmp_function) qsort((ptr), (count), (element_size), (int (*)(const void *, const void *))(cmp_function))
|
|
||||||
|
|
||||||
#endif // BASE_CORE_H
|
|
||||||
@@ -1,647 +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 U64
|
|
||||||
cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out)
|
|
||||||
{
|
|
||||||
*out = cv_numeric_from_data_range(data.str + offset, data.str + data.size);
|
|
||||||
return out->encoded_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
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+1 <= 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, String8 strtbl, COFF_SectionHeaderArray 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.v[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 = str8_cstring_capped((char*)(strtbl.str + name_off),
|
|
||||||
(char*)(strtbl.str + strtbl.size));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = str8_cstring_capped((char*)(strtbl.str + name_off),
|
|
||||||
(char*)(strtbl.str + strtbl.size));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.file_off = hdr->file_off;
|
|
||||||
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,630 +0,0 @@
|
|||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Numerics
|
|
||||||
|
|
||||||
@table(name val)
|
|
||||||
CV_NumericKindTable:
|
|
||||||
{
|
|
||||||
{CHAR 0x8000}
|
|
||||||
{SHORT 0x8001}
|
|
||||||
{USHORT 0x8002}
|
|
||||||
{LONG 0x8003}
|
|
||||||
{ULONG 0x8004}
|
|
||||||
{FLOAT32 0x8005}
|
|
||||||
{FLOAT64 0x8006}
|
|
||||||
{FLOAT80 0x8007}
|
|
||||||
{FLOAT128 0x8008}
|
|
||||||
{QUADWORD 0x8009}
|
|
||||||
{UQUADWORD 0x800a}
|
|
||||||
{FLOAT48 0x800b}
|
|
||||||
{COMPLEX32 0x800c}
|
|
||||||
{COMPLEX64 0x800d}
|
|
||||||
{COMPLEX80 0x800e}
|
|
||||||
{COMPLEX128 0x800f}
|
|
||||||
{VARSTRING 0x8010}
|
|
||||||
{OCTWORD 0x8017}
|
|
||||||
{UOCTWORD 0x8018}
|
|
||||||
{DECIMAL 0x8019}
|
|
||||||
{DATE 0x801a}
|
|
||||||
{UTF8STRING 0x801b}
|
|
||||||
{FLOAT16 0x801c}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_NumericKind:
|
|
||||||
{
|
|
||||||
@expand(CV_NumericKindTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_NumericKind)
|
|
||||||
cv_string_from_numeric_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_NumericKindTable a) `case CV_NumericKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Architectures
|
|
||||||
|
|
||||||
@table(name val)
|
|
||||||
CV_ArchTable:
|
|
||||||
{
|
|
||||||
{8080 0x00}
|
|
||||||
{8086 0x01}
|
|
||||||
{80286 0x02}
|
|
||||||
{80386 0x03}
|
|
||||||
{80486 0x04}
|
|
||||||
{PENTIUM 0x05}
|
|
||||||
{PENTIUMII 0x06}
|
|
||||||
{PENTIUMIII 0x07}
|
|
||||||
{MIPS 0x10}
|
|
||||||
{MIPS16 0x11}
|
|
||||||
{MIPS32 0x12}
|
|
||||||
{MIPS64 0x13}
|
|
||||||
{MIPSI 0x14}
|
|
||||||
{MIPSII 0x15}
|
|
||||||
{MIPSIII 0x16}
|
|
||||||
{MIPSIV 0x17}
|
|
||||||
{MIPSV 0x18}
|
|
||||||
{M68000 0x20}
|
|
||||||
{M68010 0x21}
|
|
||||||
{M68020 0x22}
|
|
||||||
{M68030 0x23}
|
|
||||||
{M68040 0x24}
|
|
||||||
{ALPHA 0x30}
|
|
||||||
{ALPHA_21164 0x31}
|
|
||||||
{ALPHA_21164A 0x32}
|
|
||||||
{ALPHA_21264 0x33}
|
|
||||||
{ALPHA_21364 0x34}
|
|
||||||
{PPC601 0x40}
|
|
||||||
{PPC603 0x41}
|
|
||||||
{PPC604 0x42}
|
|
||||||
{PPC620 0x43}
|
|
||||||
{PPCFP 0x44}
|
|
||||||
{PPCBE 0x45}
|
|
||||||
{SH3 0x50}
|
|
||||||
{SH3E 0x51}
|
|
||||||
{SH3DSP 0x52}
|
|
||||||
{SH4 0x53}
|
|
||||||
{SHMEDIA 0x54}
|
|
||||||
{ARM3 0x60}
|
|
||||||
{ARM4 0x61}
|
|
||||||
{ARM4T 0x62}
|
|
||||||
{ARM5 0x63}
|
|
||||||
{ARM5T 0x64}
|
|
||||||
{ARM6 0x65}
|
|
||||||
{ARM_XMAC 0x66}
|
|
||||||
{ARM_WMMX 0x67}
|
|
||||||
{ARM7 0x68}
|
|
||||||
{OMNI 0x70}
|
|
||||||
{IA64_1 0x80}
|
|
||||||
{IA64_2 0x81}
|
|
||||||
{CEE 0x90}
|
|
||||||
{AM33 0xA0}
|
|
||||||
{M32R 0xB0}
|
|
||||||
{TRICORE 0xC0}
|
|
||||||
{X64 0xD0}
|
|
||||||
{EBC 0xE0}
|
|
||||||
{THUMB 0xF0}
|
|
||||||
{ARMNT 0xF4}
|
|
||||||
{ARM64 0xF6}
|
|
||||||
{D3D11_SHADER 0x100}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_Arch:
|
|
||||||
{
|
|
||||||
@expand(CV_ArchTable a) `$(a.name) = $(a.val)`,
|
|
||||||
`IA64 = CV_Arch_IA64_1`,
|
|
||||||
`PENTIUMPRO = CV_Arch_PENTIUMII`,
|
|
||||||
`MIPSR4000 = CV_Arch_MIPS`,
|
|
||||||
`ALPHA_21064 = CV_Arch_ALPHA`,
|
|
||||||
`AMD64 = CV_Arch_X64`,
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_Arch)
|
|
||||||
cv_string_from_arch:
|
|
||||||
{
|
|
||||||
@expand(CV_ArchTable a) `case CV_Arch_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Registers
|
|
||||||
|
|
||||||
@table(name val) CV_AllRegTable:
|
|
||||||
{
|
|
||||||
{ERR 30000}
|
|
||||||
{TEB 30001}
|
|
||||||
{TIMER 30002}
|
|
||||||
{EFAD1 30003}
|
|
||||||
{EFAD2 30004}
|
|
||||||
{EFAD3 30005}
|
|
||||||
{VFRAME 30006}
|
|
||||||
{HANDLE 30007}
|
|
||||||
{PARAMS 30008}
|
|
||||||
{LOCALS 30009}
|
|
||||||
{TID 30010}
|
|
||||||
{ENV 30011}
|
|
||||||
{CMDLN 30012}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_AllReg:
|
|
||||||
{
|
|
||||||
@expand(CV_AllRegTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Sym Kinds
|
|
||||||
|
|
||||||
@table(name header_type_name val) CV_SymKindTable:
|
|
||||||
{
|
|
||||||
{COMPILE Compile 0x0001}
|
|
||||||
{REGISTER_16t - 0x0002}
|
|
||||||
{CONSTANT_16t - 0x0003}
|
|
||||||
{UDT_16t - 0x0004}
|
|
||||||
{SSEARCH StartSearch 0x0005}
|
|
||||||
{END - 0x0006}
|
|
||||||
{SKIP - 0x0007}
|
|
||||||
{CVRESERVE - 0x0008}
|
|
||||||
{OBJNAME_ST - 0x0009}
|
|
||||||
{ENDARG - 0x000a}
|
|
||||||
{COBOLUDT_16t - 0x000b}
|
|
||||||
{MANYREG_16t - 0x000c}
|
|
||||||
{RETURN Return 0x000d}
|
|
||||||
{ENTRYTHIS - 0x000e}
|
|
||||||
{BPREL16 - 0x0100}
|
|
||||||
{LDATA16 - 0x0101}
|
|
||||||
{GDATA16 - 0x0102}
|
|
||||||
{PUB16 - 0x0103}
|
|
||||||
{LPROC16 - 0x0104}
|
|
||||||
{GPROC16 - 0x0105}
|
|
||||||
{THUNK16 - 0x0106}
|
|
||||||
{BLOCK16 - 0x0107}
|
|
||||||
{WITH16 - 0x0108}
|
|
||||||
{LABEL16 - 0x0109}
|
|
||||||
{CEXMODEL16 - 0x010a}
|
|
||||||
{VFTABLE16 - 0x010b}
|
|
||||||
{REGREL16 - 0x010c}
|
|
||||||
{BPREL32_16t - 0x0200}
|
|
||||||
{LDATA32_16t - 0x0201}
|
|
||||||
{GDATA32_16t - 0x0202}
|
|
||||||
{PUB32_16t - 0x0203}
|
|
||||||
{LPROC32_16t - 0x0204}
|
|
||||||
{GPROC32_16t - 0x0205}
|
|
||||||
{THUNK32_ST - 0x0206}
|
|
||||||
{BLOCK32_ST - 0x0207}
|
|
||||||
{WITH32_ST - 0x0208}
|
|
||||||
{LABEL32_ST - 0x0209}
|
|
||||||
{CEXMODEL32 - 0x020a}
|
|
||||||
{VFTABLE32_16t - 0x020b}
|
|
||||||
{REGREL32_16t - 0x020c}
|
|
||||||
{LTHREAD32_16t - 0x020d}
|
|
||||||
{GTHREAD32_16t - 0x020e}
|
|
||||||
{SLINK32 SLink32 0x020f}
|
|
||||||
{LPROCMIPS_16t - 0x0300}
|
|
||||||
{GPROCMIPS_16t - 0x0301}
|
|
||||||
{PROCREF_ST - 0x0400}
|
|
||||||
{DATAREF_ST - 0x0401}
|
|
||||||
{ALIGN - 0x0402}
|
|
||||||
{LPROCREF_ST - 0x0403}
|
|
||||||
{OEM OEM 0x0404}
|
|
||||||
{TI16_MAX - 0x1000}
|
|
||||||
{CONSTANT_ST - 0x1002}
|
|
||||||
{UDT_ST - 0x1003}
|
|
||||||
{COBOLUDT_ST - 0x1004}
|
|
||||||
{MANYREG_ST - 0x1005}
|
|
||||||
{BPREL32_ST - 0x1006}
|
|
||||||
{LDATA32_ST - 0x1007}
|
|
||||||
{GDATA32_ST - 0x1008}
|
|
||||||
{PUB32_ST - 0x1009}
|
|
||||||
{LPROC32_ST - 0x100a}
|
|
||||||
{GPROC32_ST - 0x100b}
|
|
||||||
{VFTABLE32 VPath32 0x100c}
|
|
||||||
{REGREL32_ST - 0x100d}
|
|
||||||
{LTHREAD32_ST - 0x100e}
|
|
||||||
{GTHREAD32_ST - 0x100f}
|
|
||||||
{LPROCMIPS_ST - 0x1010}
|
|
||||||
{GPROCMIPS_ST - 0x1011}
|
|
||||||
{FRAMEPROC Frameproc 0x1012}
|
|
||||||
{COMPILE2_ST - 0x1013}
|
|
||||||
{MANYREG2_ST - 0x1014}
|
|
||||||
{LPROCIA64_ST - 0x1015}
|
|
||||||
{GPROCIA64_ST - 0x1016}
|
|
||||||
{LOCALSLOT_ST - 0x1017}
|
|
||||||
{PARAMSLOT_ST - 0x1018}
|
|
||||||
{ANNOTATION Annotation 0x1019}
|
|
||||||
{GMANPROC_ST - 0x101a}
|
|
||||||
{LMANPROC_ST - 0x101b}
|
|
||||||
{RESERVED1 - 0x101c}
|
|
||||||
{RESERVED2 - 0x101d}
|
|
||||||
{RESERVED3 - 0x101e}
|
|
||||||
{RESERVED4 - 0x101f}
|
|
||||||
{LMANDATA_ST - 0x1020}
|
|
||||||
{GMANDATA_ST - 0x1021}
|
|
||||||
{MANFRAMEREL_ST - 0x1022}
|
|
||||||
{MANREGISTER_ST - 0x1023}
|
|
||||||
{MANSLOT_ST - 0x1024}
|
|
||||||
{MANMANYREG_ST - 0x1025}
|
|
||||||
{MANREGREL_ST - 0x1026}
|
|
||||||
{MANMANYREG2_ST - 0x1027}
|
|
||||||
{MANTYPREF - 0x1028}
|
|
||||||
{UNAMESPACE_ST - 0x1029}
|
|
||||||
{ST_MAX - 0x1100}
|
|
||||||
{OBJNAME ObjName 0x1101}
|
|
||||||
{THUNK32 Thunk32 0x1102}
|
|
||||||
{BLOCK32 Block32 0x1103}
|
|
||||||
{WITH32 - 0x1104}
|
|
||||||
{LABEL32 Label32 0x1105}
|
|
||||||
{REGISTER Register 0x1106}
|
|
||||||
{CONSTANT Constant 0x1107}
|
|
||||||
{UDT UDT 0x1108}
|
|
||||||
{COBOLUDT - 0x1109}
|
|
||||||
{MANYREG Manyreg 0x110a}
|
|
||||||
{BPREL32 BPRel32 0x110b}
|
|
||||||
{LDATA32 Data32 0x110c}
|
|
||||||
{GDATA32 Data32 0x110d}
|
|
||||||
{PUB32 Pub32 0x110e}
|
|
||||||
{LPROC32 Proc32 0x110f}
|
|
||||||
{GPROC32 Proc32 0x1110}
|
|
||||||
{REGREL32 Regrel32 0x1111}
|
|
||||||
{LTHREAD32 Thread32 0x1112}
|
|
||||||
{GTHREAD32 Thread32 0x1113}
|
|
||||||
{LPROCMIPS - 0x1114}
|
|
||||||
{GPROCMIPS - 0x1115}
|
|
||||||
{COMPILE2 Compile2 0x1116}
|
|
||||||
{MANYREG2 Manyreg2 0x1117}
|
|
||||||
{LPROCIA64 - 0x1118}
|
|
||||||
{GPROCIA64 - 0x1119}
|
|
||||||
{LOCALSLOT Slot 0x111a}
|
|
||||||
{PARAMSLOT - 0x111b}
|
|
||||||
{LMANDATA - 0x111c}
|
|
||||||
{GMANDATA - 0x111d}
|
|
||||||
{MANFRAMEREL AttrFrameRel 0x111e}
|
|
||||||
{MANREGISTER AttrReg 0x111f}
|
|
||||||
{MANSLOT - 0x1120}
|
|
||||||
{MANMANYREG AttrManyReg 0x1121}
|
|
||||||
{MANREGREL AttrRegRel 0x1122}
|
|
||||||
{MANMANYREG2 - 0x1123}
|
|
||||||
{UNAMESPACE UNamespace 0x1124}
|
|
||||||
{PROCREF Ref2 0x1125}
|
|
||||||
{DATAREF Ref2 0x1126}
|
|
||||||
{LPROCREF Ref2 0x1127}
|
|
||||||
{ANNOTATIONREF - 0x1128}
|
|
||||||
{TOKENREF - 0x1129}
|
|
||||||
{GMANPROC - 0x112a}
|
|
||||||
{LMANPROC - 0x112b}
|
|
||||||
{TRAMPOLINE Trampoline 0x112c}
|
|
||||||
{MANCONSTANT - 0x112d}
|
|
||||||
{ATTR_FRAMEREL AttrFrameRel 0x112e}
|
|
||||||
{ATTR_REGISTER AttrReg 0x112f}
|
|
||||||
{ATTR_REGREL AttrRegRel 0x1130}
|
|
||||||
{ATTR_MANYREG AttrManyReg 0x1131}
|
|
||||||
{SEPCODE Sepcode 0x1132}
|
|
||||||
{DEFRANGE_2005 - 0x1134}
|
|
||||||
{DEFRANGE2_2005 - 0x1135}
|
|
||||||
{SECTION Section 0x1136}
|
|
||||||
{COFFGROUP CoffGroup 0x1137}
|
|
||||||
{EXPORT Export 0x1138}
|
|
||||||
{CALLSITEINFO CallSiteInfo 0x1139}
|
|
||||||
{FRAMECOOKIE FrameCookie 0x113a}
|
|
||||||
{DISCARDED Discarded 0x113b}
|
|
||||||
{COMPILE3 Compile3 0x113c}
|
|
||||||
{ENVBLOCK EnvBlock 0x113d}
|
|
||||||
{LOCAL Local 0x113e}
|
|
||||||
{DEFRANGE - 0x113f}
|
|
||||||
{DEFRANGE_SUBFIELD DefrangeSubfield 0x1140}
|
|
||||||
{DEFRANGE_REGISTER DefrangeRegister 0x1141}
|
|
||||||
{DEFRANGE_FRAMEPOINTER_REL DefrangeFramepointerRel 0x1142}
|
|
||||||
{DEFRANGE_SUBFIELD_REGISTER DefrangeSubfieldRegister 0x1143}
|
|
||||||
{DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE DefrangeFramepointerRelFullScope 0x1144}
|
|
||||||
{DEFRANGE_REGISTER_REL DefrangeRegisterRel 0x1145}
|
|
||||||
{LPROC32_ID - 0x1146}
|
|
||||||
{GPROC32_ID - 0x1147}
|
|
||||||
{LPROCMIPS_ID - 0x1148}
|
|
||||||
{GPROCMIPS_ID - 0x1149}
|
|
||||||
{LPROCIA64_ID - 0x114a}
|
|
||||||
{GPROCIA64_ID - 0x114b}
|
|
||||||
{BUILDINFO BuildInfo 0x114c}
|
|
||||||
{INLINESITE InlineSite 0x114d}
|
|
||||||
{INLINESITE_END - 0x114e}
|
|
||||||
{PROC_ID_END - 0x114f}
|
|
||||||
{DEFRANGE_HLSL - 0x1150}
|
|
||||||
{GDATA_HLSL - 0x1151}
|
|
||||||
{LDATA_HLSL - 0x1152}
|
|
||||||
{FILESTATIC FileStatic 0x1153}
|
|
||||||
{LPROC32_DPC - 0x1155}
|
|
||||||
{LPROC32_DPC_ID - 0x1156}
|
|
||||||
{DEFRANGE_DPC_PTR_TAG - 0x1157}
|
|
||||||
{DPC_SYM_TAG_MAP - 0x1158}
|
|
||||||
{ARMSWITCHTABLE - 0x1159}
|
|
||||||
{CALLEES FunctionList 0x115a}
|
|
||||||
{CALLERS FunctionList 0x115b}
|
|
||||||
{POGODATA PogoInfo 0x115c}
|
|
||||||
{INLINESITE2 InlineSite2 0x115d}
|
|
||||||
{HEAPALLOCSITE HeapAllocSite 0x115e}
|
|
||||||
{MOD_TYPEREF ModTypeRef 0x115f}
|
|
||||||
{REF_MINIPDB RefMiniPdb 0x1160}
|
|
||||||
{PDBMAP - 0x1161}
|
|
||||||
{GDATA_HLSL32 - 0x1162}
|
|
||||||
{LDATA_HLSL32 - 0x1163}
|
|
||||||
{GDATA_HLSL32_EX - 0x1164}
|
|
||||||
{LDATA_HLSL32_EX - 0x1165}
|
|
||||||
{FASTLINK FastLink 0x1167}
|
|
||||||
{INLINEES Inlinees 0x1168}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_SymKind:
|
|
||||||
{
|
|
||||||
@expand(CV_SymKindTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_SymKind)
|
|
||||||
cv_string_from_sym_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_SymKindTable a) `case CV_SymKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions)
|
|
||||||
{
|
|
||||||
`internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions) @c_file
|
|
||||||
{
|
|
||||||
`internal U64`;
|
|
||||||
`cv_header_struct_size_from_sym_kind(CV_SymKind v)`;
|
|
||||||
`{`;
|
|
||||||
`U64 result = 0;`;
|
|
||||||
`switch(v)`;
|
|
||||||
`{`;
|
|
||||||
`default:{}break;`;
|
|
||||||
@expand(CV_SymKindTable a) `$(a.header_type_name != "-" -> "case CV_SymKind_"..a.name..":{result = sizeof(CV_Sym"..a.header_type_name..");}break;")`;
|
|
||||||
`}`;
|
|
||||||
`return result;`;
|
|
||||||
`}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Basic Types
|
|
||||||
|
|
||||||
@table(name val type_name)
|
|
||||||
CV_BasicTypeTable:
|
|
||||||
{
|
|
||||||
{NOTYPE 0x00 "" }
|
|
||||||
{ABS 0x01 "" }
|
|
||||||
{SEGMENT 0x02 "" }
|
|
||||||
{VOID 0x03 "void" }
|
|
||||||
{CURRENCY 0x04 "" }
|
|
||||||
{NBASICSTR 0x05 "" }
|
|
||||||
{FBASICSTR 0x06 "" }
|
|
||||||
{NOTTRANS 0x07 "" }
|
|
||||||
{HRESULT 0x08 "HRESULT" }
|
|
||||||
{CHAR 0x10 "char" }
|
|
||||||
{SHORT 0x11 "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:
|
|
||||||
{
|
|
||||||
{NOTYPE - 0x0000}
|
|
||||||
{MODIFIER_16t - 0x0001}
|
|
||||||
{POINTER_16t - 0x0002}
|
|
||||||
{ARRAY_16t - 0x0003}
|
|
||||||
{CLASS_16t - 0x0004}
|
|
||||||
{STRUCTURE_16t - 0x0005}
|
|
||||||
{UNION_16t - 0x0006}
|
|
||||||
{ENUM_16t - 0x0007}
|
|
||||||
{PROCEDURE_16t - 0x0008}
|
|
||||||
{MFUNCTION_16t - 0x0009}
|
|
||||||
{VTSHAPE VTShape 0x000a}
|
|
||||||
{COBOL0_16t - 0x000b}
|
|
||||||
{COBOL1 - 0x000c}
|
|
||||||
{BARRAY_16t - 0x000d}
|
|
||||||
{LABEL Label 0x000e}
|
|
||||||
{NULL - 0x000f}
|
|
||||||
{NOTTRAN - 0x0010}
|
|
||||||
{DIMARRAY_16t - 0x0011}
|
|
||||||
{VFTPATH_16t - 0x0012}
|
|
||||||
{PRECOMP_16t - 0x0013}
|
|
||||||
{ENDPRECOMP - 0x0014}
|
|
||||||
{OEM_16t - 0x0015}
|
|
||||||
{TYPESERVER_ST - 0x0016}
|
|
||||||
{SKIP_16t - 0x0200}
|
|
||||||
{ARGLIST_16t - 0x0201}
|
|
||||||
{DEFARG_16t - 0x0202}
|
|
||||||
{LIST - 0x0203}
|
|
||||||
{FIELDLIST_16t - 0x0204}
|
|
||||||
{DERIVED_16t - 0x0205}
|
|
||||||
{BITFIELD_16t - 0x0206}
|
|
||||||
{METHODLIST_16t - 0x0207}
|
|
||||||
{DIMCONU_16t - 0x0208}
|
|
||||||
{DIMCONLU_16t - 0x0209}
|
|
||||||
{DIMVARU_16t - 0x020a}
|
|
||||||
{DIMVARLU_16t - 0x020b}
|
|
||||||
{REFSYM - 0x020c}
|
|
||||||
{BCLASS_16t - 0x0400}
|
|
||||||
{VBCLASS_16t - 0x0401}
|
|
||||||
{IVBCLASS_16t - 0x0402}
|
|
||||||
{ENUMERATE_ST - 0x0403}
|
|
||||||
{FRIENDFCN_16t - 0x0404}
|
|
||||||
{INDEX_16t - 0x0405}
|
|
||||||
{MEMBER_16t - 0x0406}
|
|
||||||
{STMEMBER_16t - 0x0407}
|
|
||||||
{METHOD_16t - 0x0408}
|
|
||||||
{NESTTYPE_16t - 0x0409}
|
|
||||||
{VFUNCTAB_16t - 0x040a}
|
|
||||||
{FRIENDCLS_16t - 0x040b}
|
|
||||||
{ONEMETHOD_16t - 0x040c}
|
|
||||||
{VFUNCOFF_16t - 0x040d}
|
|
||||||
{TI16_MAX - 0x1000}
|
|
||||||
{MODIFIER Modifier 0x1001}
|
|
||||||
{POINTER Pointer 0x1002}
|
|
||||||
{ARRAY_ST - 0x1003}
|
|
||||||
{CLASS_ST - 0x1004}
|
|
||||||
{STRUCTURE_ST - 0x1005}
|
|
||||||
{UNION_ST - 0x1006}
|
|
||||||
{ENUM_ST - 0x1007}
|
|
||||||
{PROCEDURE Procedure 0x1008}
|
|
||||||
{MFUNCTION MFunction 0x1009}
|
|
||||||
{COBOL0 - 0x100a}
|
|
||||||
{BARRAY - 0x100b}
|
|
||||||
{DIMARRAY_ST - 0x100c}
|
|
||||||
{VFTPATH VFPath 0x100d}
|
|
||||||
{PRECOMP_ST - 0x100e}
|
|
||||||
{OEM - 0x100f}
|
|
||||||
{ALIAS_ST - 0x1010}
|
|
||||||
{OEM2 - 0x1011}
|
|
||||||
{SKIP Skip 0x1200}
|
|
||||||
{ARGLIST ArgList 0x1201}
|
|
||||||
{DEFARG_ST - 0x1202}
|
|
||||||
{FIELDLIST - 0x1203}
|
|
||||||
{DERIVED - 0x1204}
|
|
||||||
{BITFIELD BitField 0x1205}
|
|
||||||
{METHODLIST MethodListMember 0x1206}
|
|
||||||
{DIMCONU - 0x1207}
|
|
||||||
{DIMCONLU - 0x1208}
|
|
||||||
{DIMVARU - 0x1209}
|
|
||||||
{DIMVARLU - 0x120a}
|
|
||||||
{BCLASS BClass 0x1400}
|
|
||||||
{VBCLASS VBClass 0x1401}
|
|
||||||
{IVBCLASS - 0x1402}
|
|
||||||
{FRIENDFCN_ST - 0x1403}
|
|
||||||
{INDEX Index 0x1404}
|
|
||||||
{MEMBER_ST - 0x1405}
|
|
||||||
{STMEMBER_ST - 0x1406}
|
|
||||||
{METHOD_ST - 0x1407}
|
|
||||||
{NESTTYPE_ST - 0x1408}
|
|
||||||
{VFUNCTAB VFuncTab 0x1409}
|
|
||||||
{FRIENDCLS - 0x140a}
|
|
||||||
{ONEMETHOD_ST - 0x140b}
|
|
||||||
{VFUNCOFF VFuncOff 0x140c}
|
|
||||||
{NESTTYPEEX_ST - 0x140d}
|
|
||||||
{MEMBERMODIFY_ST - 0x140e}
|
|
||||||
{MANAGED_ST - 0x140f}
|
|
||||||
{ST_MAX - 0x1500}
|
|
||||||
{TYPESERVER TypeServer 0x1501}
|
|
||||||
{ENUMERATE Enumerate 0x1502}
|
|
||||||
{ARRAY Array 0x1503}
|
|
||||||
{CLASS Struct 0x1504}
|
|
||||||
{STRUCTURE Struct 0x1505}
|
|
||||||
{UNION Union 0x1506}
|
|
||||||
{ENUM Enum 0x1507}
|
|
||||||
{DIMARRAY - 0x1508}
|
|
||||||
{PRECOMP PreComp 0x1509}
|
|
||||||
{ALIAS Alias 0x150a}
|
|
||||||
{DEFARG - 0x150b}
|
|
||||||
{FRIENDFCN - 0x150c}
|
|
||||||
{MEMBER Member 0x150d}
|
|
||||||
{STMEMBER StMember 0x150e}
|
|
||||||
{METHOD Method 0x150f}
|
|
||||||
{NESTTYPE NestType 0x1510}
|
|
||||||
{ONEMETHOD OneMethod 0x1511}
|
|
||||||
{NESTTYPEEX NestTypeEx 0x1512}
|
|
||||||
{MEMBERMODIFY - 0x1513}
|
|
||||||
{MANAGED - 0x1514}
|
|
||||||
{TYPESERVER2 TypeServer2 0x1515}
|
|
||||||
{STRIDED_ARRAY - 0x1516}
|
|
||||||
{HLSL - 0x1517}
|
|
||||||
{MODIFIER_EX - 0x1518}
|
|
||||||
{INTERFACE Struct 0x1519}
|
|
||||||
{BINTERFACE - 0x151a}
|
|
||||||
{VECTOR - 0x151b}
|
|
||||||
{MATRIX - 0x151c}
|
|
||||||
{VFTABLE - 0x151d}
|
|
||||||
{FUNC_ID FuncId 0x1601}
|
|
||||||
{MFUNC_ID MFuncId 0x1602}
|
|
||||||
{BUILDINFO BuildInfo 0x1603}
|
|
||||||
{SUBSTR_LIST SubstrList 0x1604}
|
|
||||||
{STRING_ID StringId 0x1605}
|
|
||||||
{UDT_SRC_LINE UDTSrcLine 0x1606}
|
|
||||||
{UDT_MOD_SRC_LINE UDTModSrcLine 0x1607}
|
|
||||||
{CLASS2 Struct2 0x1608}
|
|
||||||
{STRUCT2 Struct2 0x1609}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_LeafKind:
|
|
||||||
{
|
|
||||||
@expand(CV_LeafKindTable a) `$(a.name) = $(a.val)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_LeafKind)
|
|
||||||
cv_string_from_leaf_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_LeafKindTable a) `case CV_LeafKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions)
|
|
||||||
{
|
|
||||||
`internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions) @c_file
|
|
||||||
{
|
|
||||||
`internal U64`;
|
|
||||||
`cv_header_struct_size_from_leaf_kind(CV_LeafKind v)`;
|
|
||||||
`{`;
|
|
||||||
`U64 result = 0;`;
|
|
||||||
`switch(v)`;
|
|
||||||
`{`;
|
|
||||||
`default:{}break;`;
|
|
||||||
@expand(CV_LeafKindTable a) `$(a.header_type_name != "-" -> "case CV_LeafKind_"..a.name..":{result = sizeof(CV_Leaf"..a.header_type_name..");}break;")`;
|
|
||||||
`}`;
|
|
||||||
`return result;`;
|
|
||||||
`}`;
|
|
||||||
}
|
|
||||||
@@ -1,84 +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);
|
|
||||||
|
|
||||||
internal String8 cv_string_from_inline_range_kind(CV_InlineRangeKind kind);
|
|
||||||
|
|
||||||
#endif // CODEVIEW_STRINGIZE_H
|
|
||||||
@@ -1,718 +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_NOTYPE:{result = str8_lit("NOTYPE");}break;
|
|
||||||
case CV_LeafKind_MODIFIER_16t:{result = str8_lit("MODIFIER_16t");}break;
|
|
||||||
case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break;
|
|
||||||
case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break;
|
|
||||||
case CV_LeafKind_CLASS_16t:{result = str8_lit("CLASS_16t");}break;
|
|
||||||
case CV_LeafKind_STRUCTURE_16t:{result = str8_lit("STRUCTURE_16t");}break;
|
|
||||||
case CV_LeafKind_UNION_16t:{result = str8_lit("UNION_16t");}break;
|
|
||||||
case CV_LeafKind_ENUM_16t:{result = str8_lit("ENUM_16t");}break;
|
|
||||||
case CV_LeafKind_PROCEDURE_16t:{result = str8_lit("PROCEDURE_16t");}break;
|
|
||||||
case CV_LeafKind_MFUNCTION_16t:{result = str8_lit("MFUNCTION_16t");}break;
|
|
||||||
case CV_LeafKind_VTSHAPE:{result = str8_lit("VTSHAPE");}break;
|
|
||||||
case CV_LeafKind_COBOL0_16t:{result = str8_lit("COBOL0_16t");}break;
|
|
||||||
case CV_LeafKind_COBOL1:{result = str8_lit("COBOL1");}break;
|
|
||||||
case CV_LeafKind_BARRAY_16t:{result = str8_lit("BARRAY_16t");}break;
|
|
||||||
case CV_LeafKind_LABEL:{result = str8_lit("LABEL");}break;
|
|
||||||
case CV_LeafKind_NULL:{result = str8_lit("NULL");}break;
|
|
||||||
case CV_LeafKind_NOTTRAN:{result = str8_lit("NOTTRAN");}break;
|
|
||||||
case CV_LeafKind_DIMARRAY_16t:{result = str8_lit("DIMARRAY_16t");}break;
|
|
||||||
case CV_LeafKind_VFTPATH_16t:{result = str8_lit("VFTPATH_16t");}break;
|
|
||||||
case CV_LeafKind_PRECOMP_16t:{result = str8_lit("PRECOMP_16t");}break;
|
|
||||||
case CV_LeafKind_ENDPRECOMP:{result = str8_lit("ENDPRECOMP");}break;
|
|
||||||
case CV_LeafKind_OEM_16t:{result = str8_lit("OEM_16t");}break;
|
|
||||||
case CV_LeafKind_TYPESERVER_ST:{result = str8_lit("TYPESERVER_ST");}break;
|
|
||||||
case CV_LeafKind_SKIP_16t:{result = str8_lit("SKIP_16t");}break;
|
|
||||||
case CV_LeafKind_ARGLIST_16t:{result = str8_lit("ARGLIST_16t");}break;
|
|
||||||
case CV_LeafKind_DEFARG_16t:{result = str8_lit("DEFARG_16t");}break;
|
|
||||||
case CV_LeafKind_LIST:{result = str8_lit("LIST");}break;
|
|
||||||
case CV_LeafKind_FIELDLIST_16t:{result = str8_lit("FIELDLIST_16t");}break;
|
|
||||||
case CV_LeafKind_DERIVED_16t:{result = str8_lit("DERIVED_16t");}break;
|
|
||||||
case CV_LeafKind_BITFIELD_16t:{result = str8_lit("BITFIELD_16t");}break;
|
|
||||||
case CV_LeafKind_METHODLIST_16t:{result = str8_lit("METHODLIST_16t");}break;
|
|
||||||
case CV_LeafKind_DIMCONU_16t:{result = str8_lit("DIMCONU_16t");}break;
|
|
||||||
case CV_LeafKind_DIMCONLU_16t:{result = str8_lit("DIMCONLU_16t");}break;
|
|
||||||
case CV_LeafKind_DIMVARU_16t:{result = str8_lit("DIMVARU_16t");}break;
|
|
||||||
case CV_LeafKind_DIMVARLU_16t:{result = str8_lit("DIMVARLU_16t");}break;
|
|
||||||
case CV_LeafKind_REFSYM:{result = str8_lit("REFSYM");}break;
|
|
||||||
case CV_LeafKind_BCLASS_16t:{result = str8_lit("BCLASS_16t");}break;
|
|
||||||
case CV_LeafKind_VBCLASS_16t:{result = str8_lit("VBCLASS_16t");}break;
|
|
||||||
case CV_LeafKind_IVBCLASS_16t:{result = str8_lit("IVBCLASS_16t");}break;
|
|
||||||
case CV_LeafKind_ENUMERATE_ST:{result = str8_lit("ENUMERATE_ST");}break;
|
|
||||||
case CV_LeafKind_FRIENDFCN_16t:{result = str8_lit("FRIENDFCN_16t");}break;
|
|
||||||
case CV_LeafKind_INDEX_16t:{result = str8_lit("INDEX_16t");}break;
|
|
||||||
case CV_LeafKind_MEMBER_16t:{result = str8_lit("MEMBER_16t");}break;
|
|
||||||
case CV_LeafKind_STMEMBER_16t:{result = str8_lit("STMEMBER_16t");}break;
|
|
||||||
case CV_LeafKind_METHOD_16t:{result = str8_lit("METHOD_16t");}break;
|
|
||||||
case CV_LeafKind_NESTTYPE_16t:{result = str8_lit("NESTTYPE_16t");}break;
|
|
||||||
case CV_LeafKind_VFUNCTAB_16t:{result = str8_lit("VFUNCTAB_16t");}break;
|
|
||||||
case CV_LeafKind_FRIENDCLS_16t:{result = str8_lit("FRIENDCLS_16t");}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD_16t:{result = str8_lit("ONEMETHOD_16t");}break;
|
|
||||||
case CV_LeafKind_VFUNCOFF_16t:{result = str8_lit("VFUNCOFF_16t");}break;
|
|
||||||
case CV_LeafKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break;
|
|
||||||
case CV_LeafKind_MODIFIER:{result = str8_lit("MODIFIER");}break;
|
|
||||||
case CV_LeafKind_POINTER:{result = str8_lit("POINTER");}break;
|
|
||||||
case CV_LeafKind_ARRAY_ST:{result = str8_lit("ARRAY_ST");}break;
|
|
||||||
case CV_LeafKind_CLASS_ST:{result = str8_lit("CLASS_ST");}break;
|
|
||||||
case CV_LeafKind_STRUCTURE_ST:{result = str8_lit("STRUCTURE_ST");}break;
|
|
||||||
case CV_LeafKind_UNION_ST:{result = str8_lit("UNION_ST");}break;
|
|
||||||
case CV_LeafKind_ENUM_ST:{result = str8_lit("ENUM_ST");}break;
|
|
||||||
case CV_LeafKind_PROCEDURE:{result = str8_lit("PROCEDURE");}break;
|
|
||||||
case CV_LeafKind_MFUNCTION:{result = str8_lit("MFUNCTION");}break;
|
|
||||||
case CV_LeafKind_COBOL0:{result = str8_lit("COBOL0");}break;
|
|
||||||
case CV_LeafKind_BARRAY:{result = str8_lit("BARRAY");}break;
|
|
||||||
case CV_LeafKind_DIMARRAY_ST:{result = str8_lit("DIMARRAY_ST");}break;
|
|
||||||
case CV_LeafKind_VFTPATH:{result = str8_lit("VFTPATH");}break;
|
|
||||||
case CV_LeafKind_PRECOMP_ST:{result = str8_lit("PRECOMP_ST");}break;
|
|
||||||
case CV_LeafKind_OEM:{result = str8_lit("OEM");}break;
|
|
||||||
case CV_LeafKind_ALIAS_ST:{result = str8_lit("ALIAS_ST");}break;
|
|
||||||
case CV_LeafKind_OEM2:{result = str8_lit("OEM2");}break;
|
|
||||||
case CV_LeafKind_SKIP:{result = str8_lit("SKIP");}break;
|
|
||||||
case CV_LeafKind_ARGLIST:{result = str8_lit("ARGLIST");}break;
|
|
||||||
case CV_LeafKind_DEFARG_ST:{result = str8_lit("DEFARG_ST");}break;
|
|
||||||
case CV_LeafKind_FIELDLIST:{result = str8_lit("FIELDLIST");}break;
|
|
||||||
case CV_LeafKind_DERIVED:{result = str8_lit("DERIVED");}break;
|
|
||||||
case CV_LeafKind_BITFIELD:{result = str8_lit("BITFIELD");}break;
|
|
||||||
case CV_LeafKind_METHODLIST:{result = str8_lit("METHODLIST");}break;
|
|
||||||
case CV_LeafKind_DIMCONU:{result = str8_lit("DIMCONU");}break;
|
|
||||||
case CV_LeafKind_DIMCONLU:{result = str8_lit("DIMCONLU");}break;
|
|
||||||
case CV_LeafKind_DIMVARU:{result = str8_lit("DIMVARU");}break;
|
|
||||||
case CV_LeafKind_DIMVARLU:{result = str8_lit("DIMVARLU");}break;
|
|
||||||
case CV_LeafKind_BCLASS:{result = str8_lit("BCLASS");}break;
|
|
||||||
case CV_LeafKind_VBCLASS:{result = str8_lit("VBCLASS");}break;
|
|
||||||
case CV_LeafKind_IVBCLASS:{result = str8_lit("IVBCLASS");}break;
|
|
||||||
case CV_LeafKind_FRIENDFCN_ST:{result = str8_lit("FRIENDFCN_ST");}break;
|
|
||||||
case CV_LeafKind_INDEX:{result = str8_lit("INDEX");}break;
|
|
||||||
case CV_LeafKind_MEMBER_ST:{result = str8_lit("MEMBER_ST");}break;
|
|
||||||
case CV_LeafKind_STMEMBER_ST:{result = str8_lit("STMEMBER_ST");}break;
|
|
||||||
case CV_LeafKind_METHOD_ST:{result = str8_lit("METHOD_ST");}break;
|
|
||||||
case CV_LeafKind_NESTTYPE_ST:{result = str8_lit("NESTTYPE_ST");}break;
|
|
||||||
case CV_LeafKind_VFUNCTAB:{result = str8_lit("VFUNCTAB");}break;
|
|
||||||
case CV_LeafKind_FRIENDCLS:{result = str8_lit("FRIENDCLS");}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD_ST:{result = str8_lit("ONEMETHOD_ST");}break;
|
|
||||||
case CV_LeafKind_VFUNCOFF:{result = str8_lit("VFUNCOFF");}break;
|
|
||||||
case CV_LeafKind_NESTTYPEEX_ST:{result = str8_lit("NESTTYPEEX_ST");}break;
|
|
||||||
case CV_LeafKind_MEMBERMODIFY_ST:{result = str8_lit("MEMBERMODIFY_ST");}break;
|
|
||||||
case CV_LeafKind_MANAGED_ST:{result = str8_lit("MANAGED_ST");}break;
|
|
||||||
case CV_LeafKind_ST_MAX:{result = str8_lit("ST_MAX");}break;
|
|
||||||
case CV_LeafKind_TYPESERVER:{result = str8_lit("TYPESERVER");}break;
|
|
||||||
case CV_LeafKind_ENUMERATE:{result = str8_lit("ENUMERATE");}break;
|
|
||||||
case CV_LeafKind_ARRAY:{result = str8_lit("ARRAY");}break;
|
|
||||||
case CV_LeafKind_CLASS:{result = str8_lit("CLASS");}break;
|
|
||||||
case CV_LeafKind_STRUCTURE:{result = str8_lit("STRUCTURE");}break;
|
|
||||||
case CV_LeafKind_UNION:{result = str8_lit("UNION");}break;
|
|
||||||
case CV_LeafKind_ENUM:{result = str8_lit("ENUM");}break;
|
|
||||||
case CV_LeafKind_DIMARRAY:{result = str8_lit("DIMARRAY");}break;
|
|
||||||
case CV_LeafKind_PRECOMP:{result = str8_lit("PRECOMP");}break;
|
|
||||||
case CV_LeafKind_ALIAS:{result = str8_lit("ALIAS");}break;
|
|
||||||
case CV_LeafKind_DEFARG:{result = str8_lit("DEFARG");}break;
|
|
||||||
case CV_LeafKind_FRIENDFCN:{result = str8_lit("FRIENDFCN");}break;
|
|
||||||
case CV_LeafKind_MEMBER:{result = str8_lit("MEMBER");}break;
|
|
||||||
case CV_LeafKind_STMEMBER:{result = str8_lit("STMEMBER");}break;
|
|
||||||
case CV_LeafKind_METHOD:{result = str8_lit("METHOD");}break;
|
|
||||||
case CV_LeafKind_NESTTYPE:{result = str8_lit("NESTTYPE");}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD:{result = str8_lit("ONEMETHOD");}break;
|
|
||||||
case CV_LeafKind_NESTTYPEEX:{result = str8_lit("NESTTYPEEX");}break;
|
|
||||||
case CV_LeafKind_MEMBERMODIFY:{result = str8_lit("MEMBERMODIFY");}break;
|
|
||||||
case CV_LeafKind_MANAGED:{result = str8_lit("MANAGED");}break;
|
|
||||||
case CV_LeafKind_TYPESERVER2:{result = str8_lit("TYPESERVER2");}break;
|
|
||||||
case CV_LeafKind_STRIDED_ARRAY:{result = str8_lit("STRIDED_ARRAY");}break;
|
|
||||||
case CV_LeafKind_HLSL:{result = str8_lit("HLSL");}break;
|
|
||||||
case CV_LeafKind_MODIFIER_EX:{result = str8_lit("MODIFIER_EX");}break;
|
|
||||||
case CV_LeafKind_INTERFACE:{result = str8_lit("INTERFACE");}break;
|
|
||||||
case CV_LeafKind_BINTERFACE:{result = str8_lit("BINTERFACE");}break;
|
|
||||||
case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break;
|
|
||||||
case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break;
|
|
||||||
case CV_LeafKind_VFTABLE:{result = str8_lit("VFTABLE");}break;
|
|
||||||
case CV_LeafKind_FUNC_ID:{result = str8_lit("FUNC_ID");}break;
|
|
||||||
case CV_LeafKind_MFUNC_ID:{result = str8_lit("MFUNC_ID");}break;
|
|
||||||
case CV_LeafKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
|
|
||||||
case CV_LeafKind_SUBSTR_LIST:{result = str8_lit("SUBSTR_LIST");}break;
|
|
||||||
case CV_LeafKind_STRING_ID:{result = str8_lit("STRING_ID");}break;
|
|
||||||
case CV_LeafKind_UDT_SRC_LINE:{result = str8_lit("UDT_SRC_LINE");}break;
|
|
||||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = str8_lit("UDT_MOD_SRC_LINE");}break;
|
|
||||||
case CV_LeafKind_CLASS2:{result = str8_lit("CLASS2");}break;
|
|
||||||
case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
cv_header_struct_size_from_sym_kind(CV_SymKind v)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_SymKind_COMPILE:{result = sizeof(CV_SymCompile);}break;
|
|
||||||
case CV_SymKind_SSEARCH:{result = sizeof(CV_SymStartSearch);}break;
|
|
||||||
case CV_SymKind_RETURN:{result = sizeof(CV_SymReturn);}break;
|
|
||||||
case CV_SymKind_SLINK32:{result = sizeof(CV_SymSLink32);}break;
|
|
||||||
case CV_SymKind_OEM:{result = sizeof(CV_SymOEM);}break;
|
|
||||||
case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break;
|
|
||||||
case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break;
|
|
||||||
case CV_SymKind_ANNOTATION:{result = sizeof(CV_SymAnnotation);}break;
|
|
||||||
case CV_SymKind_OBJNAME:{result = sizeof(CV_SymObjName);}break;
|
|
||||||
case CV_SymKind_THUNK32:{result = sizeof(CV_SymThunk32);}break;
|
|
||||||
case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break;
|
|
||||||
case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break;
|
|
||||||
case CV_SymKind_REGISTER:{result = sizeof(CV_SymRegister);}break;
|
|
||||||
case CV_SymKind_CONSTANT:{result = sizeof(CV_SymConstant);}break;
|
|
||||||
case CV_SymKind_UDT:{result = sizeof(CV_SymUDT);}break;
|
|
||||||
case CV_SymKind_MANYREG:{result = sizeof(CV_SymManyreg);}break;
|
|
||||||
case CV_SymKind_BPREL32:{result = sizeof(CV_SymBPRel32);}break;
|
|
||||||
case CV_SymKind_LDATA32:{result = sizeof(CV_SymData32);}break;
|
|
||||||
case CV_SymKind_GDATA32:{result = sizeof(CV_SymData32);}break;
|
|
||||||
case CV_SymKind_PUB32:{result = sizeof(CV_SymPub32);}break;
|
|
||||||
case CV_SymKind_LPROC32:{result = sizeof(CV_SymProc32);}break;
|
|
||||||
case CV_SymKind_GPROC32:{result = sizeof(CV_SymProc32);}break;
|
|
||||||
case CV_SymKind_REGREL32:{result = sizeof(CV_SymRegrel32);}break;
|
|
||||||
case CV_SymKind_LTHREAD32:{result = sizeof(CV_SymThread32);}break;
|
|
||||||
case CV_SymKind_GTHREAD32:{result = sizeof(CV_SymThread32);}break;
|
|
||||||
case CV_SymKind_COMPILE2:{result = sizeof(CV_SymCompile2);}break;
|
|
||||||
case CV_SymKind_MANYREG2:{result = sizeof(CV_SymManyreg2);}break;
|
|
||||||
case CV_SymKind_LOCALSLOT:{result = sizeof(CV_SymSlot);}break;
|
|
||||||
case CV_SymKind_MANFRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
|
|
||||||
case CV_SymKind_MANREGISTER:{result = sizeof(CV_SymAttrReg);}break;
|
|
||||||
case CV_SymKind_MANMANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
|
|
||||||
case CV_SymKind_MANREGREL:{result = sizeof(CV_SymAttrRegRel);}break;
|
|
||||||
case CV_SymKind_UNAMESPACE:{result = sizeof(CV_SymUNamespace);}break;
|
|
||||||
case CV_SymKind_PROCREF:{result = sizeof(CV_SymRef2);}break;
|
|
||||||
case CV_SymKind_DATAREF:{result = sizeof(CV_SymRef2);}break;
|
|
||||||
case CV_SymKind_LPROCREF:{result = sizeof(CV_SymRef2);}break;
|
|
||||||
case CV_SymKind_TRAMPOLINE:{result = sizeof(CV_SymTrampoline);}break;
|
|
||||||
case CV_SymKind_ATTR_FRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break;
|
|
||||||
case CV_SymKind_ATTR_REGISTER:{result = sizeof(CV_SymAttrReg);}break;
|
|
||||||
case CV_SymKind_ATTR_REGREL:{result = sizeof(CV_SymAttrRegRel);}break;
|
|
||||||
case CV_SymKind_ATTR_MANYREG:{result = sizeof(CV_SymAttrManyReg);}break;
|
|
||||||
case CV_SymKind_SEPCODE:{result = sizeof(CV_SymSepcode);}break;
|
|
||||||
case CV_SymKind_SECTION:{result = sizeof(CV_SymSection);}break;
|
|
||||||
case CV_SymKind_COFFGROUP:{result = sizeof(CV_SymCoffGroup);}break;
|
|
||||||
case CV_SymKind_EXPORT:{result = sizeof(CV_SymExport);}break;
|
|
||||||
case CV_SymKind_CALLSITEINFO:{result = sizeof(CV_SymCallSiteInfo);}break;
|
|
||||||
case CV_SymKind_FRAMECOOKIE:{result = sizeof(CV_SymFrameCookie);}break;
|
|
||||||
case CV_SymKind_DISCARDED:{result = sizeof(CV_SymDiscarded);}break;
|
|
||||||
case CV_SymKind_COMPILE3:{result = sizeof(CV_SymCompile3);}break;
|
|
||||||
case CV_SymKind_ENVBLOCK:{result = sizeof(CV_SymEnvBlock);}break;
|
|
||||||
case CV_SymKind_LOCAL:{result = sizeof(CV_SymLocal);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_SUBFIELD:{result = sizeof(CV_SymDefrangeSubfield);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_REGISTER:{result = sizeof(CV_SymDefrangeRegister);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = sizeof(CV_SymDefrangeFramepointerRel);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = sizeof(CV_SymDefrangeSubfieldRegister);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = sizeof(CV_SymDefrangeFramepointerRelFullScope);}break;
|
|
||||||
case CV_SymKind_DEFRANGE_REGISTER_REL:{result = sizeof(CV_SymDefrangeRegisterRel);}break;
|
|
||||||
case CV_SymKind_BUILDINFO:{result = sizeof(CV_SymBuildInfo);}break;
|
|
||||||
case CV_SymKind_INLINESITE:{result = sizeof(CV_SymInlineSite);}break;
|
|
||||||
case CV_SymKind_FILESTATIC:{result = sizeof(CV_SymFileStatic);}break;
|
|
||||||
case CV_SymKind_CALLEES:{result = sizeof(CV_SymFunctionList);}break;
|
|
||||||
case CV_SymKind_CALLERS:{result = sizeof(CV_SymFunctionList);}break;
|
|
||||||
case CV_SymKind_POGODATA:{result = sizeof(CV_SymPogoInfo);}break;
|
|
||||||
case CV_SymKind_INLINESITE2:{result = sizeof(CV_SymInlineSite2);}break;
|
|
||||||
case CV_SymKind_HEAPALLOCSITE:{result = sizeof(CV_SymHeapAllocSite);}break;
|
|
||||||
case CV_SymKind_MOD_TYPEREF:{result = sizeof(CV_SymModTypeRef);}break;
|
|
||||||
case CV_SymKind_REF_MINIPDB:{result = sizeof(CV_SymRefMiniPdb);}break;
|
|
||||||
case CV_SymKind_FASTLINK:{result = sizeof(CV_SymFastLink);}break;
|
|
||||||
case CV_SymKind_INLINEES:{result = sizeof(CV_SymInlinees);}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
internal U64
|
|
||||||
cv_header_struct_size_from_leaf_kind(CV_LeafKind v)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
switch(v)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case CV_LeafKind_VTSHAPE:{result = sizeof(CV_LeafVTShape);}break;
|
|
||||||
case CV_LeafKind_LABEL:{result = sizeof(CV_LeafLabel);}break;
|
|
||||||
case CV_LeafKind_MODIFIER:{result = sizeof(CV_LeafModifier);}break;
|
|
||||||
case CV_LeafKind_POINTER:{result = sizeof(CV_LeafPointer);}break;
|
|
||||||
case CV_LeafKind_PROCEDURE:{result = sizeof(CV_LeafProcedure);}break;
|
|
||||||
case CV_LeafKind_MFUNCTION:{result = sizeof(CV_LeafMFunction);}break;
|
|
||||||
case CV_LeafKind_VFTPATH:{result = sizeof(CV_LeafVFPath);}break;
|
|
||||||
case CV_LeafKind_SKIP:{result = sizeof(CV_LeafSkip);}break;
|
|
||||||
case CV_LeafKind_ARGLIST:{result = sizeof(CV_LeafArgList);}break;
|
|
||||||
case CV_LeafKind_BITFIELD:{result = sizeof(CV_LeafBitField);}break;
|
|
||||||
case CV_LeafKind_METHODLIST:{result = sizeof(CV_LeafMethodListMember);}break;
|
|
||||||
case CV_LeafKind_BCLASS:{result = sizeof(CV_LeafBClass);}break;
|
|
||||||
case CV_LeafKind_VBCLASS:{result = sizeof(CV_LeafVBClass);}break;
|
|
||||||
case CV_LeafKind_INDEX:{result = sizeof(CV_LeafIndex);}break;
|
|
||||||
case CV_LeafKind_VFUNCTAB:{result = sizeof(CV_LeafVFuncTab);}break;
|
|
||||||
case CV_LeafKind_VFUNCOFF:{result = sizeof(CV_LeafVFuncOff);}break;
|
|
||||||
case CV_LeafKind_TYPESERVER:{result = sizeof(CV_LeafTypeServer);}break;
|
|
||||||
case CV_LeafKind_ENUMERATE:{result = sizeof(CV_LeafEnumerate);}break;
|
|
||||||
case CV_LeafKind_ARRAY:{result = sizeof(CV_LeafArray);}break;
|
|
||||||
case CV_LeafKind_CLASS:{result = sizeof(CV_LeafStruct);}break;
|
|
||||||
case CV_LeafKind_STRUCTURE:{result = sizeof(CV_LeafStruct);}break;
|
|
||||||
case CV_LeafKind_UNION:{result = sizeof(CV_LeafUnion);}break;
|
|
||||||
case CV_LeafKind_ENUM:{result = sizeof(CV_LeafEnum);}break;
|
|
||||||
case CV_LeafKind_PRECOMP:{result = sizeof(CV_LeafPreComp);}break;
|
|
||||||
case CV_LeafKind_ALIAS:{result = sizeof(CV_LeafAlias);}break;
|
|
||||||
case CV_LeafKind_MEMBER:{result = sizeof(CV_LeafMember);}break;
|
|
||||||
case CV_LeafKind_STMEMBER:{result = sizeof(CV_LeafStMember);}break;
|
|
||||||
case CV_LeafKind_METHOD:{result = sizeof(CV_LeafMethod);}break;
|
|
||||||
case CV_LeafKind_NESTTYPE:{result = sizeof(CV_LeafNestType);}break;
|
|
||||||
case CV_LeafKind_ONEMETHOD:{result = sizeof(CV_LeafOneMethod);}break;
|
|
||||||
case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break;
|
|
||||||
case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break;
|
|
||||||
case CV_LeafKind_INTERFACE:{result = sizeof(CV_LeafStruct);}break;
|
|
||||||
case CV_LeafKind_FUNC_ID:{result = sizeof(CV_LeafFuncId);}break;
|
|
||||||
case CV_LeafKind_MFUNC_ID:{result = sizeof(CV_LeafMFuncId);}break;
|
|
||||||
case CV_LeafKind_BUILDINFO:{result = sizeof(CV_LeafBuildInfo);}break;
|
|
||||||
case CV_LeafKind_SUBSTR_LIST:{result = sizeof(CV_LeafSubstrList);}break;
|
|
||||||
case CV_LeafKind_STRING_ID:{result = sizeof(CV_LeafStringId);}break;
|
|
||||||
case CV_LeafKind_UDT_SRC_LINE:{result = sizeof(CV_LeafUDTSrcLine);}break;
|
|
||||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = sizeof(CV_LeafUDTModSrcLine);}break;
|
|
||||||
case CV_LeafKind_CLASS2:{result = sizeof(CV_LeafStruct2);}break;
|
|
||||||
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,528 +0,0 @@
|
|||||||
// Copyright (c) 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_NOTYPE = 0x0000,
|
|
||||||
CV_LeafKind_MODIFIER_16t = 0x0001,
|
|
||||||
CV_LeafKind_POINTER_16t = 0x0002,
|
|
||||||
CV_LeafKind_ARRAY_16t = 0x0003,
|
|
||||||
CV_LeafKind_CLASS_16t = 0x0004,
|
|
||||||
CV_LeafKind_STRUCTURE_16t = 0x0005,
|
|
||||||
CV_LeafKind_UNION_16t = 0x0006,
|
|
||||||
CV_LeafKind_ENUM_16t = 0x0007,
|
|
||||||
CV_LeafKind_PROCEDURE_16t = 0x0008,
|
|
||||||
CV_LeafKind_MFUNCTION_16t = 0x0009,
|
|
||||||
CV_LeafKind_VTSHAPE = 0x000a,
|
|
||||||
CV_LeafKind_COBOL0_16t = 0x000b,
|
|
||||||
CV_LeafKind_COBOL1 = 0x000c,
|
|
||||||
CV_LeafKind_BARRAY_16t = 0x000d,
|
|
||||||
CV_LeafKind_LABEL = 0x000e,
|
|
||||||
CV_LeafKind_NULL = 0x000f,
|
|
||||||
CV_LeafKind_NOTTRAN = 0x0010,
|
|
||||||
CV_LeafKind_DIMARRAY_16t = 0x0011,
|
|
||||||
CV_LeafKind_VFTPATH_16t = 0x0012,
|
|
||||||
CV_LeafKind_PRECOMP_16t = 0x0013,
|
|
||||||
CV_LeafKind_ENDPRECOMP = 0x0014,
|
|
||||||
CV_LeafKind_OEM_16t = 0x0015,
|
|
||||||
CV_LeafKind_TYPESERVER_ST = 0x0016,
|
|
||||||
CV_LeafKind_SKIP_16t = 0x0200,
|
|
||||||
CV_LeafKind_ARGLIST_16t = 0x0201,
|
|
||||||
CV_LeafKind_DEFARG_16t = 0x0202,
|
|
||||||
CV_LeafKind_LIST = 0x0203,
|
|
||||||
CV_LeafKind_FIELDLIST_16t = 0x0204,
|
|
||||||
CV_LeafKind_DERIVED_16t = 0x0205,
|
|
||||||
CV_LeafKind_BITFIELD_16t = 0x0206,
|
|
||||||
CV_LeafKind_METHODLIST_16t = 0x0207,
|
|
||||||
CV_LeafKind_DIMCONU_16t = 0x0208,
|
|
||||||
CV_LeafKind_DIMCONLU_16t = 0x0209,
|
|
||||||
CV_LeafKind_DIMVARU_16t = 0x020a,
|
|
||||||
CV_LeafKind_DIMVARLU_16t = 0x020b,
|
|
||||||
CV_LeafKind_REFSYM = 0x020c,
|
|
||||||
CV_LeafKind_BCLASS_16t = 0x0400,
|
|
||||||
CV_LeafKind_VBCLASS_16t = 0x0401,
|
|
||||||
CV_LeafKind_IVBCLASS_16t = 0x0402,
|
|
||||||
CV_LeafKind_ENUMERATE_ST = 0x0403,
|
|
||||||
CV_LeafKind_FRIENDFCN_16t = 0x0404,
|
|
||||||
CV_LeafKind_INDEX_16t = 0x0405,
|
|
||||||
CV_LeafKind_MEMBER_16t = 0x0406,
|
|
||||||
CV_LeafKind_STMEMBER_16t = 0x0407,
|
|
||||||
CV_LeafKind_METHOD_16t = 0x0408,
|
|
||||||
CV_LeafKind_NESTTYPE_16t = 0x0409,
|
|
||||||
CV_LeafKind_VFUNCTAB_16t = 0x040a,
|
|
||||||
CV_LeafKind_FRIENDCLS_16t = 0x040b,
|
|
||||||
CV_LeafKind_ONEMETHOD_16t = 0x040c,
|
|
||||||
CV_LeafKind_VFUNCOFF_16t = 0x040d,
|
|
||||||
CV_LeafKind_TI16_MAX = 0x1000,
|
|
||||||
CV_LeafKind_MODIFIER = 0x1001,
|
|
||||||
CV_LeafKind_POINTER = 0x1002,
|
|
||||||
CV_LeafKind_ARRAY_ST = 0x1003,
|
|
||||||
CV_LeafKind_CLASS_ST = 0x1004,
|
|
||||||
CV_LeafKind_STRUCTURE_ST = 0x1005,
|
|
||||||
CV_LeafKind_UNION_ST = 0x1006,
|
|
||||||
CV_LeafKind_ENUM_ST = 0x1007,
|
|
||||||
CV_LeafKind_PROCEDURE = 0x1008,
|
|
||||||
CV_LeafKind_MFUNCTION = 0x1009,
|
|
||||||
CV_LeafKind_COBOL0 = 0x100a,
|
|
||||||
CV_LeafKind_BARRAY = 0x100b,
|
|
||||||
CV_LeafKind_DIMARRAY_ST = 0x100c,
|
|
||||||
CV_LeafKind_VFTPATH = 0x100d,
|
|
||||||
CV_LeafKind_PRECOMP_ST = 0x100e,
|
|
||||||
CV_LeafKind_OEM = 0x100f,
|
|
||||||
CV_LeafKind_ALIAS_ST = 0x1010,
|
|
||||||
CV_LeafKind_OEM2 = 0x1011,
|
|
||||||
CV_LeafKind_SKIP = 0x1200,
|
|
||||||
CV_LeafKind_ARGLIST = 0x1201,
|
|
||||||
CV_LeafKind_DEFARG_ST = 0x1202,
|
|
||||||
CV_LeafKind_FIELDLIST = 0x1203,
|
|
||||||
CV_LeafKind_DERIVED = 0x1204,
|
|
||||||
CV_LeafKind_BITFIELD = 0x1205,
|
|
||||||
CV_LeafKind_METHODLIST = 0x1206,
|
|
||||||
CV_LeafKind_DIMCONU = 0x1207,
|
|
||||||
CV_LeafKind_DIMCONLU = 0x1208,
|
|
||||||
CV_LeafKind_DIMVARU = 0x1209,
|
|
||||||
CV_LeafKind_DIMVARLU = 0x120a,
|
|
||||||
CV_LeafKind_BCLASS = 0x1400,
|
|
||||||
CV_LeafKind_VBCLASS = 0x1401,
|
|
||||||
CV_LeafKind_IVBCLASS = 0x1402,
|
|
||||||
CV_LeafKind_FRIENDFCN_ST = 0x1403,
|
|
||||||
CV_LeafKind_INDEX = 0x1404,
|
|
||||||
CV_LeafKind_MEMBER_ST = 0x1405,
|
|
||||||
CV_LeafKind_STMEMBER_ST = 0x1406,
|
|
||||||
CV_LeafKind_METHOD_ST = 0x1407,
|
|
||||||
CV_LeafKind_NESTTYPE_ST = 0x1408,
|
|
||||||
CV_LeafKind_VFUNCTAB = 0x1409,
|
|
||||||
CV_LeafKind_FRIENDCLS = 0x140a,
|
|
||||||
CV_LeafKind_ONEMETHOD_ST = 0x140b,
|
|
||||||
CV_LeafKind_VFUNCOFF = 0x140c,
|
|
||||||
CV_LeafKind_NESTTYPEEX_ST = 0x140d,
|
|
||||||
CV_LeafKind_MEMBERMODIFY_ST = 0x140e,
|
|
||||||
CV_LeafKind_MANAGED_ST = 0x140f,
|
|
||||||
CV_LeafKind_ST_MAX = 0x1500,
|
|
||||||
CV_LeafKind_TYPESERVER = 0x1501,
|
|
||||||
CV_LeafKind_ENUMERATE = 0x1502,
|
|
||||||
CV_LeafKind_ARRAY = 0x1503,
|
|
||||||
CV_LeafKind_CLASS = 0x1504,
|
|
||||||
CV_LeafKind_STRUCTURE = 0x1505,
|
|
||||||
CV_LeafKind_UNION = 0x1506,
|
|
||||||
CV_LeafKind_ENUM = 0x1507,
|
|
||||||
CV_LeafKind_DIMARRAY = 0x1508,
|
|
||||||
CV_LeafKind_PRECOMP = 0x1509,
|
|
||||||
CV_LeafKind_ALIAS = 0x150a,
|
|
||||||
CV_LeafKind_DEFARG = 0x150b,
|
|
||||||
CV_LeafKind_FRIENDFCN = 0x150c,
|
|
||||||
CV_LeafKind_MEMBER = 0x150d,
|
|
||||||
CV_LeafKind_STMEMBER = 0x150e,
|
|
||||||
CV_LeafKind_METHOD = 0x150f,
|
|
||||||
CV_LeafKind_NESTTYPE = 0x1510,
|
|
||||||
CV_LeafKind_ONEMETHOD = 0x1511,
|
|
||||||
CV_LeafKind_NESTTYPEEX = 0x1512,
|
|
||||||
CV_LeafKind_MEMBERMODIFY = 0x1513,
|
|
||||||
CV_LeafKind_MANAGED = 0x1514,
|
|
||||||
CV_LeafKind_TYPESERVER2 = 0x1515,
|
|
||||||
CV_LeafKind_STRIDED_ARRAY = 0x1516,
|
|
||||||
CV_LeafKind_HLSL = 0x1517,
|
|
||||||
CV_LeafKind_MODIFIER_EX = 0x1518,
|
|
||||||
CV_LeafKind_INTERFACE = 0x1519,
|
|
||||||
CV_LeafKind_BINTERFACE = 0x151a,
|
|
||||||
CV_LeafKind_VECTOR = 0x151b,
|
|
||||||
CV_LeafKind_MATRIX = 0x151c,
|
|
||||||
CV_LeafKind_VFTABLE = 0x151d,
|
|
||||||
CV_LeafKind_FUNC_ID = 0x1601,
|
|
||||||
CV_LeafKind_MFUNC_ID = 0x1602,
|
|
||||||
CV_LeafKind_BUILDINFO = 0x1603,
|
|
||||||
CV_LeafKind_SUBSTR_LIST = 0x1604,
|
|
||||||
CV_LeafKind_STRING_ID = 0x1605,
|
|
||||||
CV_LeafKind_UDT_SRC_LINE = 0x1606,
|
|
||||||
CV_LeafKind_UDT_MOD_SRC_LINE = 0x1607,
|
|
||||||
CV_LeafKind_CLASS2 = 0x1608,
|
|
||||||
CV_LeafKind_STRUCT2 = 0x1609,
|
|
||||||
} CV_LeafKindEnum;
|
|
||||||
|
|
||||||
internal String8 cv_string_from_numeric_kind(CV_NumericKind v);
|
|
||||||
internal String8 cv_string_from_arch(CV_Arch v);
|
|
||||||
internal String8 cv_string_from_sym_kind(CV_SymKind v);
|
|
||||||
internal String8 cv_string_from_basic_type(CV_BasicType v);
|
|
||||||
internal String8 cv_type_name_from_basic_type(CV_BasicType v);
|
|
||||||
internal String8 cv_string_from_leaf_kind(CV_LeafKind v);
|
|
||||||
internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);
|
|
||||||
internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);
|
|
||||||
#endif // CODEVIEW_META_H
|
|
||||||
+47
-305
@@ -28,7 +28,7 @@ coff_is_obj(String8 data)
|
|||||||
switch (header->machine) {
|
switch (header->machine) {
|
||||||
case COFF_MachineType_UNKNOWN:
|
case COFF_MachineType_UNKNOWN:
|
||||||
case COFF_MachineType_X86: case COFF_MachineType_X64:
|
case COFF_MachineType_X86: case COFF_MachineType_X64:
|
||||||
case COFF_MachineType_AM33: case COFF_MachineType_ARM:
|
case COFF_MachineType_ARM33: case COFF_MachineType_ARM:
|
||||||
case COFF_MachineType_ARM64: case COFF_MachineType_ARMNT:
|
case COFF_MachineType_ARM64: case COFF_MachineType_ARMNT:
|
||||||
case COFF_MachineType_EBC: case COFF_MachineType_IA64:
|
case COFF_MachineType_EBC: case COFF_MachineType_IA64:
|
||||||
case COFF_MachineType_M32R: case COFF_MachineType_MIPS16:
|
case COFF_MachineType_M32R: case COFF_MachineType_MIPS16:
|
||||||
@@ -304,7 +304,7 @@ coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off,
|
|||||||
{
|
{
|
||||||
COFF_Symbol32Array result;
|
COFF_Symbol32Array result;
|
||||||
result.count = symbol_count;
|
result.count = symbol_count;
|
||||||
result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8);
|
result.v = push_array_no_zero(arena, COFF_Symbol32, result.count);
|
||||||
|
|
||||||
COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)(data.str + symbol_array_off);
|
COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)(data.str + symbol_array_off);
|
||||||
for (U64 isymbol = 0; isymbol < symbol_count; isymbol += 1) {
|
for (U64 isymbol = 0; isymbol < symbol_count; isymbol += 1) {
|
||||||
@@ -393,28 +393,6 @@ coff_word_size_from_machine(COFF_MachineType machine)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_default_exe_base_from_machine(COFF_MachineType machine)
|
|
||||||
{
|
|
||||||
U64 exe_base = 0;
|
|
||||||
switch (coff_word_size_from_machine(machine)) {
|
|
||||||
case 4: exe_base = 0x400000; break;
|
|
||||||
case 8: exe_base = 0x140000000; break;
|
|
||||||
}
|
|
||||||
return exe_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_default_dll_base_from_machine(COFF_MachineType machine)
|
|
||||||
{
|
|
||||||
U64 dll_base = 0;
|
|
||||||
switch (coff_word_size_from_machine(machine)) {
|
|
||||||
case 4: dll_base = 0x10000000; break;
|
|
||||||
case 8: dll_base = 0x180000000; break;
|
|
||||||
}
|
|
||||||
return dll_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
coff_make_import_lookup(Arena *arena, U16 hint, String8 name)
|
coff_make_import_lookup(Arena *arena, U16 hint, String8 name)
|
||||||
{
|
{
|
||||||
@@ -443,114 +421,6 @@ coff_make_ordinal_64(U16 hint)
|
|||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_make_import_header_by_name(Arena *arena,
|
|
||||||
String8 dll_name,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
COFF_TimeStamp time_stamp,
|
|
||||||
String8 name,
|
|
||||||
U16 hint,
|
|
||||||
COFF_ImportHeaderType type)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
U16 sig1;
|
|
||||||
U16 sig2;
|
|
||||||
U16 version;
|
|
||||||
COFF_MachineType machine;
|
|
||||||
COFF_TimeStamp time_stamp;
|
|
||||||
U32 sizeof_data;
|
|
||||||
U16 hint_ordinal;
|
|
||||||
U16 flags;
|
|
||||||
} import_header = {
|
|
||||||
COFF_MachineType_UNKNOWN, // sig1
|
|
||||||
max_U16, // sig2
|
|
||||||
0, // version
|
|
||||||
machine,
|
|
||||||
time_stamp,
|
|
||||||
safe_cast_u32(name.size + dll_name.size + 2), // sizeof_data
|
|
||||||
0, // hint_ordinal
|
|
||||||
0, // flags
|
|
||||||
};
|
|
||||||
|
|
||||||
import_header.flags |= (U16)(type & COFF_IMPORT_HEADER_TYPE_MASK) << COFF_IMPORT_HEADER_TYPE_SHIFT;
|
|
||||||
import_header.flags |= COFF_ImportHeaderNameType_NAME << COFF_IMPORT_HEADER_NAME_TYPE_SHIFT;
|
|
||||||
import_header.hint_ordinal = hint;
|
|
||||||
|
|
||||||
// alloc memory
|
|
||||||
U64 buffer_size = sizeof(import_header) + import_header.sizeof_data;
|
|
||||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
|
||||||
|
|
||||||
// copy header
|
|
||||||
MemoryCopy(buffer, &import_header, sizeof(import_header));
|
|
||||||
|
|
||||||
// copy function name
|
|
||||||
U8 *func_name = buffer + sizeof(import_header);
|
|
||||||
MemoryCopy(func_name, name.str, name.size);
|
|
||||||
func_name[name.size] = 0;
|
|
||||||
|
|
||||||
// copy dll name
|
|
||||||
U8 *dll_name_buffer = buffer + sizeof(import_header) + name.size + 1;
|
|
||||||
MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size);
|
|
||||||
dll_name_buffer[dll_name.size] = 0;
|
|
||||||
|
|
||||||
String8 import_data = str8(buffer, buffer_size);
|
|
||||||
return import_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_make_import_header_by_ordinal(Arena *arena,
|
|
||||||
String8 dll_name,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
COFF_TimeStamp time_stamp,
|
|
||||||
U16 ordinal,
|
|
||||||
COFF_ImportHeaderType type)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
U16 sig1;
|
|
||||||
U16 sig2;
|
|
||||||
U16 version;
|
|
||||||
COFF_MachineType machine;
|
|
||||||
COFF_TimeStamp time_stamp;
|
|
||||||
U32 sizeof_data;
|
|
||||||
U16 hint_ordinal;
|
|
||||||
U16 flags;
|
|
||||||
} import_header = {
|
|
||||||
COFF_MachineType_UNKNOWN, // sig1
|
|
||||||
max_U16, // sig2
|
|
||||||
0, // version
|
|
||||||
machine,
|
|
||||||
time_stamp,
|
|
||||||
safe_cast_u32(/* name.size + */ dll_name.size + 2), // sizeof_data
|
|
||||||
0, // hint_ordinal
|
|
||||||
0, // flags
|
|
||||||
};
|
|
||||||
|
|
||||||
import_header.flags |= (U16)(type & COFF_IMPORT_HEADER_TYPE_MASK) << COFF_IMPORT_HEADER_TYPE_SHIFT;
|
|
||||||
import_header.flags |= COFF_ImportHeaderNameType_ORDINAL << COFF_IMPORT_HEADER_NAME_TYPE_SHIFT;
|
|
||||||
import_header.hint_ordinal = ordinal;
|
|
||||||
|
|
||||||
// alloc memory
|
|
||||||
U64 buffer_size = sizeof(import_header) + import_header.sizeof_data;
|
|
||||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
|
||||||
|
|
||||||
// copy header
|
|
||||||
MemoryCopyStruct(buffer, &import_header);
|
|
||||||
|
|
||||||
// no function name write zero
|
|
||||||
U8 *func_name = buffer + sizeof(import_header);
|
|
||||||
func_name[0] = 0;
|
|
||||||
|
|
||||||
// copy dll name
|
|
||||||
U8 *dll_name_buffer = buffer + sizeof(import_header) + /* name.size */ + 1;
|
|
||||||
MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size);
|
|
||||||
dll_name_buffer[dll_name.size] = 0;
|
|
||||||
|
|
||||||
String8 import_data = str8(buffer, buffer_size);
|
|
||||||
return import_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b)
|
coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b)
|
||||||
{
|
{
|
||||||
@@ -585,25 +455,6 @@ coff_resource_id_copy(Arena *arena, COFF_ResourceID id)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
|
||||||
coff_sizeof_resource_id(COFF_ResourceID id)
|
|
||||||
{
|
|
||||||
U64 size = 0;
|
|
||||||
switch (id.type) {
|
|
||||||
case COFF_ResourceIDType_NULL: break;
|
|
||||||
case COFF_ResourceIDType_NUMBER: {
|
|
||||||
size += sizeof(U16);
|
|
||||||
size += sizeof(U16);
|
|
||||||
} break;
|
|
||||||
case COFF_ResourceIDType_STRING: {
|
|
||||||
size += sizeof(U16);
|
|
||||||
size += (id.u.string.size + /* null: */1) * sizeof(U16);
|
|
||||||
} break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
return AlignPow2(size, COFF_RES_ALIGN);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ResourceID
|
internal COFF_ResourceID
|
||||||
coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
|
coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
|
||||||
{
|
{
|
||||||
@@ -707,67 +558,6 @@ coff_resource_list_from_data(Arena *arena, String8 data)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_write_resource_id(Arena *arena, String8List *srl, COFF_ResourceID id)
|
|
||||||
{
|
|
||||||
switch (id.type) {
|
|
||||||
case COFF_ResourceIDType_NULL: break;
|
|
||||||
case COFF_ResourceIDType_NUMBER: {
|
|
||||||
str8_serial_push_u16(arena, srl, max_U16);
|
|
||||||
str8_serial_push_u16(arena, srl, id.u.number);
|
|
||||||
} break;
|
|
||||||
case COFF_ResourceIDType_STRING: {
|
|
||||||
String16 str16 = str16_from_8(arena, id.u.string);
|
|
||||||
Assert(str16.size <= max_U16);
|
|
||||||
str8_serial_push_u16(arena, srl, str16.size);
|
|
||||||
str8_serial_push_data(arena, srl, str16.str, str16.size);
|
|
||||||
} break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
str8_serial_push_align(arena, srl, COFF_RES_ALIGN);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8List
|
|
||||||
coff_write_resource(Arena *arena,
|
|
||||||
COFF_ResourceID type,
|
|
||||||
COFF_ResourceID name,
|
|
||||||
U32 data_version,
|
|
||||||
COFF_ResourceMemoryFlags memory_flags,
|
|
||||||
U16 language_id,
|
|
||||||
U32 version,
|
|
||||||
U32 characteristics,
|
|
||||||
String8 data)
|
|
||||||
{
|
|
||||||
U64 header_size = sizeof(COFF_ResourceHeaderPrefix) +
|
|
||||||
coff_sizeof_resource_id(type) +
|
|
||||||
coff_sizeof_resource_id(name) +
|
|
||||||
sizeof(data_version) +
|
|
||||||
sizeof(memory_flags) +
|
|
||||||
sizeof(language_id) +
|
|
||||||
sizeof(version) +
|
|
||||||
sizeof(characteristics);
|
|
||||||
|
|
||||||
COFF_ResourceHeaderPrefix *header = push_array(arena, COFF_ResourceHeaderPrefix, 1);
|
|
||||||
header->data_size = safe_cast_u32(data.size);
|
|
||||||
header->header_size = safe_cast_u32(header_size);
|
|
||||||
|
|
||||||
String8List srl = {0};
|
|
||||||
str8_serial_begin(arena, &srl);
|
|
||||||
str8_serial_push_data(arena, &srl, &g_coff_res_magic[0], sizeof(g_coff_res_magic));
|
|
||||||
str8_serial_push_data(arena, &srl, header, sizeof(*header));
|
|
||||||
coff_write_resource_id(arena, &srl, type);
|
|
||||||
coff_write_resource_id(arena, &srl, name);
|
|
||||||
str8_serial_push_u32(arena, &srl, data_version);
|
|
||||||
str8_serial_push_u16(arena, &srl, memory_flags);
|
|
||||||
str8_serial_push_u16(arena, &srl, language_id);
|
|
||||||
str8_serial_push_u32(arena, &srl, version);
|
|
||||||
str8_serial_push_u32(arena, &srl, characteristics);
|
|
||||||
str8_serial_push_string(arena, &srl, data);
|
|
||||||
str8_serial_push_align(arena, &srl, COFF_RES_ALIGN);
|
|
||||||
|
|
||||||
return srl;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal COFF_DataType
|
internal COFF_DataType
|
||||||
@@ -801,22 +591,18 @@ coff_is_import(String8 data)
|
|||||||
internal B32
|
internal B32
|
||||||
coff_is_archive(String8 data)
|
coff_is_archive(String8 data)
|
||||||
{
|
{
|
||||||
B32 is_archive = 0;
|
U64 sig = 0;
|
||||||
U8 sig[sizeof(g_coff_archive_sig)];
|
str8_deserial_read_struct(data, 0, &sig);
|
||||||
if (str8_deserial_read_struct(data, 0, &sig) == sizeof(sig)) {
|
B32 is_archive = sig == COFF_ARCHIVE_SIG;
|
||||||
is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0;
|
|
||||||
}
|
|
||||||
return is_archive;
|
return is_archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
coff_is_thin_archive(String8 data)
|
coff_is_thin_archive(String8 data)
|
||||||
{
|
{
|
||||||
B32 is_archive = 0;
|
U64 sig = 0;
|
||||||
U8 sig[sizeof(g_coff_thin_archive_sig)];
|
str8_deserial_read_struct(data, 0, &sig);
|
||||||
if (str8_deserial_read_struct(data, 0, &sig) == sizeof(sig)) {
|
B32 is_archive = sig == COFF_THIN_ARCHIVE_SIG;
|
||||||
is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0;
|
|
||||||
}
|
|
||||||
return is_archive;
|
return is_archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,9 +751,11 @@ coff_read_archive_long_name(String8 long_names, String8 name)
|
|||||||
internal U64
|
internal U64
|
||||||
coff_archive_member_iter_init(String8 data)
|
coff_archive_member_iter_init(String8 data)
|
||||||
{
|
{
|
||||||
U64 cursor = data.size;
|
U64 cursor = 0;
|
||||||
if (coff_is_archive(data)) {
|
U64 sig = 0;
|
||||||
cursor = sizeof(g_coff_archive_sig);
|
cursor += str8_deserial_read_struct(data, cursor, &sig);
|
||||||
|
if (sig != COFF_ARCHIVE_SIG) {
|
||||||
|
cursor = data.size;
|
||||||
}
|
}
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
@@ -1127,9 +915,11 @@ coff_archive_from_data(Arena *arena, String8 data)
|
|||||||
internal U64
|
internal U64
|
||||||
coff_thin_archive_member_iter_init(String8 data)
|
coff_thin_archive_member_iter_init(String8 data)
|
||||||
{
|
{
|
||||||
U64 cursor = data.size;
|
U64 cursor = 0;
|
||||||
if (coff_is_thin_archive(data)) {
|
U64 sig = 0;
|
||||||
cursor = sizeof(g_coff_thin_archive_sig);
|
cursor += str8_deserial_read_struct(data, cursor, &sig);
|
||||||
|
if (sig != COFF_THIN_ARCHIVE_SIG) {
|
||||||
|
cursor = data.size;
|
||||||
}
|
}
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
@@ -1200,46 +990,6 @@ coff_archive_parse_from_data(Arena *arena, String8 data)
|
|||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
read_only struct
|
|
||||||
{
|
|
||||||
String8 string;
|
|
||||||
COFF_MachineType machine;
|
|
||||||
} g_coff_machine_map[] = {
|
|
||||||
{ str8_lit_comp(""), COFF_MachineType_UNKNOWN },
|
|
||||||
{ str8_lit_comp("X86"), COFF_MachineType_X86 },
|
|
||||||
{ str8_lit_comp("X64"), COFF_MachineType_X64 },
|
|
||||||
{ str8_lit_comp("AM33"), COFF_MachineType_AM33 },
|
|
||||||
{ str8_lit_comp("ARM"), COFF_MachineType_ARM },
|
|
||||||
{ str8_lit_comp("ARM64"), COFF_MachineType_ARM64 },
|
|
||||||
{ str8_lit_comp("ARMNT"), COFF_MachineType_ARMNT },
|
|
||||||
{ str8_lit_comp("EBC"), COFF_MachineType_EBC },
|
|
||||||
{ str8_lit_comp("IA64"), COFF_MachineType_IA64 },
|
|
||||||
{ str8_lit_comp("M32R"), COFF_MachineType_M32R },
|
|
||||||
{ str8_lit_comp("MIPS16"), COFF_MachineType_MIPS16 },
|
|
||||||
{ str8_lit_comp("MIPSFPU"), COFF_MachineType_MIPSFPU },
|
|
||||||
{ str8_lit_comp("MIPSFPU16"), COFF_MachineType_MIPSFPU16 },
|
|
||||||
{ str8_lit_comp("POWERPC"), COFF_MachineType_POWERPC },
|
|
||||||
{ str8_lit_comp("POWERPCFP"), COFF_MachineType_POWERPCFP },
|
|
||||||
{ str8_lit_comp("R4000"), COFF_MachineType_R4000 },
|
|
||||||
{ str8_lit_comp("RISCV32"), COFF_MachineType_RISCV32 },
|
|
||||||
{ str8_lit_comp("RISCV64"), COFF_MachineType_RISCV64 },
|
|
||||||
{ str8_lit_comp("SH3"), COFF_MachineType_SH3 },
|
|
||||||
{ str8_lit_comp("SH3DSP"), COFF_MachineType_SH3DSP },
|
|
||||||
{ str8_lit_comp("SH4"), COFF_MachineType_SH4 },
|
|
||||||
{ str8_lit_comp("SH5"), COFF_MachineType_SH5 },
|
|
||||||
{ str8_lit_comp("THUMB"), COFF_MachineType_THUMB },
|
|
||||||
{ str8_lit_comp("WCEMIPSV2"), COFF_MachineType_WCEMIPSV2 },
|
|
||||||
};
|
|
||||||
|
|
||||||
read_only static struct {
|
|
||||||
char * name;
|
|
||||||
COFF_ImportHeaderType type;
|
|
||||||
} g_coff_import_header_type_map[] = {
|
|
||||||
{ "CODE", COFF_ImportHeaderType_CODE },
|
|
||||||
{ "DATA", COFF_ImportHeaderType_DATA },
|
|
||||||
{ "CONST", COFF_ImportHeaderType_CONST },
|
|
||||||
};
|
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
coff_string_from_comdat_select_type(COFF_ComdatSelectType select)
|
coff_string_from_comdat_select_type(COFF_ComdatSelectType select)
|
||||||
{
|
{
|
||||||
@@ -1259,10 +1009,35 @@ coff_string_from_comdat_select_type(COFF_ComdatSelectType select)
|
|||||||
internal String8
|
internal String8
|
||||||
coff_string_from_machine_type(COFF_MachineType machine)
|
coff_string_from_machine_type(COFF_MachineType machine)
|
||||||
{
|
{
|
||||||
Assert(machine < ArrayCount(g_coff_machine_map));
|
String8 result = str8(0,0);
|
||||||
Assert(machine == g_coff_machine_map[machine].machine);
|
switch (machine) {
|
||||||
String8 string = g_coff_machine_map[machine].string;
|
case COFF_MachineType_UNKNOWN: result = str8_lit("UNKNOWN"); break;
|
||||||
return string;
|
case COFF_MachineType_X86: result = str8_lit("X86"); break;
|
||||||
|
case COFF_MachineType_X64: result = str8_lit("X64"); break;
|
||||||
|
case COFF_MachineType_ARM33: result = str8_lit("ARM33"); break;
|
||||||
|
case COFF_MachineType_ARM: result = str8_lit("ARM"); break;
|
||||||
|
case COFF_MachineType_ARM64: result = str8_lit("ARM64"); break;
|
||||||
|
case COFF_MachineType_ARMNT: result = str8_lit("ARMNT"); break;
|
||||||
|
case COFF_MachineType_EBC: result = str8_lit("EBC"); break;
|
||||||
|
case COFF_MachineType_IA64: result = str8_lit("IA64"); break;
|
||||||
|
case COFF_MachineType_M32R: result = str8_lit("M32R"); break;
|
||||||
|
case COFF_MachineType_MIPS16: result = str8_lit("MIPS16"); break;
|
||||||
|
case COFF_MachineType_MIPSFPU: result = str8_lit("MIPSFPU"); break;
|
||||||
|
case COFF_MachineType_MIPSFPU16: result = str8_lit("MIPSFPU16"); break;
|
||||||
|
case COFF_MachineType_POWERPC: result = str8_lit("POWERPC"); break;
|
||||||
|
case COFF_MachineType_POWERPCFP: result = str8_lit("POWERPCFP"); break;
|
||||||
|
case COFF_MachineType_R4000: result = str8_lit("R4000"); break;
|
||||||
|
case COFF_MachineType_RISCV32: result = str8_lit("RISCV32"); break;
|
||||||
|
case COFF_MachineType_RISCV64: result = str8_lit("RISCV64"); break;
|
||||||
|
case COFF_MachineType_RISCV128: result = str8_lit("RISCV128"); break;
|
||||||
|
case COFF_MachineType_SH3: result = str8_lit("SH3"); break;
|
||||||
|
case COFF_MachineType_SH3DSP: result = str8_lit("SH3DSP"); break;
|
||||||
|
case COFF_MachineType_SH4: result = str8_lit("SH4"); break;
|
||||||
|
case COFF_MachineType_SH5: result = str8_lit("SH5"); break;
|
||||||
|
case COFF_MachineType_THUMB: result = str8_lit("THUMB"); break;
|
||||||
|
case COFF_MachineType_WCEMIPSV2: result = str8_lit("WCEMIPSV2"); break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
@@ -1342,36 +1117,3 @@ coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
|
||||||
coff_string_from_import_header_type(COFF_ImportHeaderType type)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
|
||||||
if (g_coff_import_header_type_map[i].type == type) {
|
|
||||||
return str8_cstring(g_coff_import_header_type_map[i].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str8(0,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_MachineType
|
|
||||||
coff_machine_from_string(String8 string)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
|
|
||||||
if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
|
|
||||||
return g_coff_machine_map[i].machine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return COFF_MachineType_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal COFF_ImportHeaderType
|
|
||||||
coff_import_header_type_from_string(String8 name)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
|
||||||
if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) {
|
|
||||||
return g_coff_import_header_type_map[i].type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return COFF_ImportHeaderType_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+7
-65
@@ -11,16 +11,6 @@ typedef U32 COFF_TimeStamp;
|
|||||||
|
|
||||||
#pragma pack(push,1)
|
#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;
|
typedef U16 COFF_Flags;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -48,7 +38,7 @@ enum
|
|||||||
COFF_MachineType_UNKNOWN = 0x0,
|
COFF_MachineType_UNKNOWN = 0x0,
|
||||||
COFF_MachineType_X86 = 0x14c,
|
COFF_MachineType_X86 = 0x14c,
|
||||||
COFF_MachineType_X64 = 0x8664,
|
COFF_MachineType_X64 = 0x8664,
|
||||||
COFF_MachineType_AM33 = 0x1d3,
|
COFF_MachineType_ARM33 = 0x1d3,
|
||||||
COFF_MachineType_ARM = 0x1c0,
|
COFF_MachineType_ARM = 0x1c0,
|
||||||
COFF_MachineType_ARM64 = 0xaa64,
|
COFF_MachineType_ARM64 = 0xaa64,
|
||||||
COFF_MachineType_ARMNT = 0x1c4,
|
COFF_MachineType_ARMNT = 0x1c4,
|
||||||
@@ -556,11 +546,6 @@ typedef U32 COFF_FeatFlags;
|
|||||||
|
|
||||||
#define COFF_RES_ALIGN 4u
|
#define COFF_RES_ALIGN 4u
|
||||||
|
|
||||||
read_only U8 g_coff_res_magic[] = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct COFF_ResourceHeaderPrefix
|
typedef struct COFF_ResourceHeaderPrefix
|
||||||
{
|
{
|
||||||
U32 data_size;
|
U32 data_size;
|
||||||
@@ -648,12 +633,14 @@ typedef struct COFF_ResourceDirEntry
|
|||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
read_only global U8 g_coff_archive_sig[8] = "!<arch>\n";
|
// !<arch>\n
|
||||||
read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
|
#define COFF_ARCHIVE_SIG 0x0A3E686372613C21ULL
|
||||||
|
// !<thin>\n
|
||||||
|
#define COFF_THIN_ARCHIVE_SIG 0xA3E6E6968743C21ULL
|
||||||
|
|
||||||
|
#define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15
|
||||||
|
|
||||||
#define COFF_ARCHIVE_ALIGN 2
|
#define COFF_ARCHIVE_ALIGN 2
|
||||||
#define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15
|
|
||||||
#define COFF_ARCHIVE_MEMBER_HEADER_SIZE 60
|
|
||||||
|
|
||||||
typedef struct COFF_ArchiveMemberHeader
|
typedef struct COFF_ArchiveMemberHeader
|
||||||
{
|
{
|
||||||
@@ -820,14 +807,6 @@ typedef struct COFF_ArchiveParse
|
|||||||
String8 long_names;
|
String8 long_names;
|
||||||
} COFF_ArchiveParse;
|
} COFF_ArchiveParse;
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct COFF_SectionHeaderArray
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
COFF_SectionHeader *v;
|
|
||||||
} COFF_SectionHeaderArray;
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Globals
|
//~ rjf: Globals
|
||||||
|
|
||||||
@@ -856,47 +835,17 @@ internal COFF_Symbol16Node * coff_symbol16_list_push(Arena *arena, COFF_Symbol16
|
|||||||
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
|
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
|
||||||
|
|
||||||
internal U64 coff_word_size_from_machine(COFF_MachineType machine);
|
internal U64 coff_word_size_from_machine(COFF_MachineType machine);
|
||||||
internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine);
|
|
||||||
internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
|
|
||||||
|
|
||||||
internal String8 coff_make_import_lookup(Arena *arena, U16 hint, String8 name);
|
internal String8 coff_make_import_lookup(Arena *arena, U16 hint, String8 name);
|
||||||
internal U32 coff_make_ordinal_32(U16 hint);
|
internal U32 coff_make_ordinal_32(U16 hint);
|
||||||
internal U64 coff_make_ordinal_64(U16 hint);
|
internal U64 coff_make_ordinal_64(U16 hint);
|
||||||
|
|
||||||
internal String8 coff_make_import_header_by_name(Arena *arena,
|
|
||||||
String8 dll_name,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
COFF_TimeStamp time_stamp,
|
|
||||||
String8 name,
|
|
||||||
U16 hint,
|
|
||||||
COFF_ImportHeaderType type);
|
|
||||||
internal String8 coff_make_import_header_by_ordinal(Arena *arena,
|
|
||||||
String8 dll_name,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
COFF_TimeStamp time_stamp,
|
|
||||||
U16 ordinal,
|
|
||||||
COFF_ImportHeaderType type);
|
|
||||||
|
|
||||||
|
|
||||||
internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b);
|
internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b);
|
||||||
internal COFF_ResourceID coff_resource_id_copy(Arena *arena, COFF_ResourceID id);
|
internal COFF_ResourceID coff_resource_id_copy(Arena *arena, COFF_ResourceID id);
|
||||||
internal U64 coff_sizeof_resource_id(COFF_ResourceID id);
|
|
||||||
internal COFF_ResourceID coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16);
|
internal COFF_ResourceID coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16);
|
||||||
internal U64 coff_read_resource_id(String8 res, U64 off, COFF_ResourceID_16 *id_out);
|
internal U64 coff_read_resource_id(String8 res, U64 off, COFF_ResourceID_16 *id_out);
|
||||||
internal U64 coff_read_resource(String8 data, U64 off, Arena *arena, COFF_Resource *res_out);
|
internal U64 coff_read_resource(String8 data, U64 off, Arena *arena, COFF_Resource *res_out);
|
||||||
internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data);
|
internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data);
|
||||||
|
|
||||||
internal void coff_write_resource_id(Arena *arena, String8List *srl, COFF_ResourceID id);
|
|
||||||
internal String8List coff_write_resource(Arena *arena,
|
|
||||||
COFF_ResourceID type,
|
|
||||||
COFF_ResourceID name,
|
|
||||||
U32 data_version,
|
|
||||||
COFF_ResourceMemoryFlags memory_flags,
|
|
||||||
U16 language_id,
|
|
||||||
U32 version,
|
|
||||||
U32 characteristics,
|
|
||||||
String8 data);
|
|
||||||
|
|
||||||
internal COFF_DataType coff_data_type_from_data(String8 data);
|
internal COFF_DataType coff_data_type_from_data(String8 data);
|
||||||
internal B32 coff_is_import(String8 data);
|
internal B32 coff_is_import(String8 data);
|
||||||
internal B32 coff_is_archive(String8 data);
|
internal B32 coff_is_archive(String8 data);
|
||||||
@@ -916,15 +865,8 @@ internal COFF_ArchiveParse coff_thin_archive_from_data(Arena *arena, String8 da
|
|||||||
internal COFF_ArchiveType coff_archive_type_from_data(String8 data);
|
internal COFF_ArchiveType coff_archive_type_from_data(String8 data);
|
||||||
internal COFF_ArchiveParse coff_archive_parse_from_data(Arena *arena, String8 data);
|
internal COFF_ArchiveParse coff_archive_parse_from_data(Arena *arena, String8 data);
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// String <-> Enum
|
|
||||||
|
|
||||||
internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select);
|
internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select);
|
||||||
internal String8 coff_string_from_machine_type(COFF_MachineType machine);
|
internal String8 coff_string_from_machine_type(COFF_MachineType machine);
|
||||||
internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags);
|
internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags);
|
||||||
internal String8 coff_string_from_import_header_type(COFF_ImportHeaderType type);
|
|
||||||
|
|
||||||
internal COFF_MachineType coff_machine_from_string(String8 string);
|
|
||||||
internal COFF_ImportHeaderType coff_import_header_type_from_string(String8 name);
|
|
||||||
|
|
||||||
#endif //COFF_H
|
#endif //COFF_H
|
||||||
|
|||||||
+24
-45
@@ -2,35 +2,7 @@
|
|||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Entity Kinds
|
//~ rjf: Tables
|
||||||
|
|
||||||
@table(name 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)
|
@table(name lower_name code default display_string)
|
||||||
CTRL_ExceptionCodeKindTable:
|
CTRL_ExceptionCodeKindTable:
|
||||||
@@ -74,33 +46,40 @@ CTRL_ExceptionCodeKindTable:
|
|||||||
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@enum CTRL_ExceptionCodeKind:
|
////////////////////////////////
|
||||||
|
//~ rjf: Generators
|
||||||
|
|
||||||
|
@table_gen_enum CTRL_ExceptionCodeKind:
|
||||||
{
|
{
|
||||||
Null,
|
`CTRL_ExceptionCodeKind_Null,`;
|
||||||
@expand(CTRL_ExceptionCodeKindTable a) `$(a.name)`,
|
@expand(CTRL_ExceptionCodeKindTable a) `CTRL_ExceptionCodeKind_$(a.name),`;
|
||||||
COUNT,
|
`CTRL_ExceptionCodeKind_COUNT`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@data(U32) ctrl_exception_code_kind_code_table:
|
@table_gen_data(type:U32, fallback:0)
|
||||||
|
ctrl_exception_code_kind_code_table:
|
||||||
{
|
{
|
||||||
`0`;
|
`0,`;
|
||||||
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code)`;
|
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code),`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@data(String8) ctrl_exception_code_kind_display_string_table:
|
@table_gen_data(type:String8, fallback:`{0}`)
|
||||||
|
ctrl_exception_code_kind_display_string_table:
|
||||||
{
|
{
|
||||||
`{0}`;
|
`{0},`;
|
||||||
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`;
|
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)"),`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@data(String8) ctrl_exception_code_kind_lowercase_code_string_table:
|
@table_gen_data(type:String8, fallback:`{0}`)
|
||||||
|
ctrl_exception_code_kind_lowercase_code_string_table:
|
||||||
{
|
{
|
||||||
`{0}`;
|
`{0},`;
|
||||||
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`;
|
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)"),`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@data(B8) ctrl_exception_code_kind_default_enable_table:
|
@table_gen_data(type:B8, fallback:0)
|
||||||
|
ctrl_exception_code_kind_default_enable_table:
|
||||||
{
|
{
|
||||||
`0`;
|
`0,`;
|
||||||
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default)`;
|
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default),`;
|
||||||
}
|
}
|
||||||
|
|||||||
+1532
-3992
File diff suppressed because it is too large
Load Diff
+138
-693
File diff suppressed because it is too large
Load Diff
@@ -3,186 +3,3 @@
|
|||||||
|
|
||||||
//- GENERATED CODE
|
//- 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
|
|
||||||
|
|
||||||
|
|||||||
+168
-21
@@ -6,19 +6,6 @@
|
|||||||
#ifndef CTRL_META_H
|
#ifndef CTRL_META_H
|
||||||
#define 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
|
typedef enum CTRL_ExceptionCodeKind
|
||||||
{
|
{
|
||||||
CTRL_ExceptionCodeKind_Null,
|
CTRL_ExceptionCodeKind_Null,
|
||||||
@@ -59,16 +46,176 @@ CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
|
|||||||
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
|
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
|
||||||
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
|
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
|
||||||
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
|
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
|
||||||
CTRL_ExceptionCodeKind_COUNT,
|
CTRL_ExceptionCodeKind_COUNT
|
||||||
} CTRL_ExceptionCodeKind;
|
} CTRL_ExceptionCodeKind;
|
||||||
|
|
||||||
C_LINKAGE_BEGIN
|
U32 ctrl_exception_code_kind_code_table[] =
|
||||||
extern String8 ctrl_entity_kind_display_string_table[8];
|
{
|
||||||
extern U32 ctrl_exception_code_kind_code_table[38];
|
0,
|
||||||
extern String8 ctrl_exception_code_kind_display_string_table[38];
|
0x40010005,
|
||||||
extern String8 ctrl_exception_code_kind_lowercase_code_string_table[38];
|
0x40010008,
|
||||||
extern B8 ctrl_exception_code_kind_default_enable_table[38];
|
0x40080201,
|
||||||
|
0x40080202,
|
||||||
|
0x0000071a,
|
||||||
|
0x80000002,
|
||||||
|
0xc0000005,
|
||||||
|
0xc0000006,
|
||||||
|
0xc0000008,
|
||||||
|
0xc0000017,
|
||||||
|
0xc000001d,
|
||||||
|
0xc0000025,
|
||||||
|
0xc0000026,
|
||||||
|
0xc000008c,
|
||||||
|
0xc000008d,
|
||||||
|
0xc000008e,
|
||||||
|
0xc000008f,
|
||||||
|
0xc0000090,
|
||||||
|
0xc0000091,
|
||||||
|
0xc0000092,
|
||||||
|
0xc0000093,
|
||||||
|
0xc0000094,
|
||||||
|
0xc0000095,
|
||||||
|
0xc0000096,
|
||||||
|
0xc00000fd,
|
||||||
|
0xc0000135,
|
||||||
|
0xc0000138,
|
||||||
|
0xc0000139,
|
||||||
|
0xc0000142,
|
||||||
|
0xc00002b4,
|
||||||
|
0xc00002b5,
|
||||||
|
0xc0000420,
|
||||||
|
0xc06d007e,
|
||||||
|
0xc06d007f,
|
||||||
|
0xe073616e,
|
||||||
|
0xe0736171,
|
||||||
|
0x0000087a,
|
||||||
|
};
|
||||||
|
|
||||||
|
String8 ctrl_exception_code_kind_display_string_table[] =
|
||||||
|
{
|
||||||
|
{0},
|
||||||
|
str8_lit_comp("(Win32) Control-C"),
|
||||||
|
str8_lit_comp("(Win32) Control-Break"),
|
||||||
|
str8_lit_comp("(Win32) WinRT Originate Error"),
|
||||||
|
str8_lit_comp("(Win32) WinRT Transform Error"),
|
||||||
|
str8_lit_comp("(Win32) RPC Call Cancelled"),
|
||||||
|
str8_lit_comp("(Win32) Data Type Misalignment"),
|
||||||
|
str8_lit_comp("(Win32) Access Violation"),
|
||||||
|
str8_lit_comp("(Win32) In Page Error"),
|
||||||
|
str8_lit_comp("(Win32) Invalid Handle Specified"),
|
||||||
|
str8_lit_comp("(Win32) Not Enough Quota"),
|
||||||
|
str8_lit_comp("(Win32) Illegal Instruction"),
|
||||||
|
str8_lit_comp("(Win32) Cannot Continue From Exception"),
|
||||||
|
str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"),
|
||||||
|
str8_lit_comp("(Win32) Array Bounds Exceeded"),
|
||||||
|
str8_lit_comp("(Win32) Floating-Point Denormal Operand"),
|
||||||
|
str8_lit_comp("(Win32) Floating-Point Division By Zero"),
|
||||||
|
str8_lit_comp("(Win32) Floating-Point Inexact Result"),
|
||||||
|
str8_lit_comp("(Win32) Floating-Point Invalid Operation"),
|
||||||
|
str8_lit_comp("(Win32) Floating-Point Overflow"),
|
||||||
|
str8_lit_comp("(Win32) Floating-Point Stack Check"),
|
||||||
|
str8_lit_comp("(Win32) Floating-Point Underflow"),
|
||||||
|
str8_lit_comp("(Win32) Integer Division By Zero"),
|
||||||
|
str8_lit_comp("(Win32) Integer Overflow"),
|
||||||
|
str8_lit_comp("(Win32) Privileged Instruction"),
|
||||||
|
str8_lit_comp("(Win32) Stack Overflow"),
|
||||||
|
str8_lit_comp("(Win32) Unable To Locate DLL"),
|
||||||
|
str8_lit_comp("(Win32) Ordinal Not Found"),
|
||||||
|
str8_lit_comp("(Win32) Entry Point Not Found"),
|
||||||
|
str8_lit_comp("(Win32) DLL Initialization Failed"),
|
||||||
|
str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"),
|
||||||
|
str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"),
|
||||||
|
str8_lit_comp("(Win32) Assertion Failed"),
|
||||||
|
str8_lit_comp("(Win32) Module Not Found"),
|
||||||
|
str8_lit_comp("(Win32) Procedure Not Found"),
|
||||||
|
str8_lit_comp("(Win32) Sanitizer Error Detected"),
|
||||||
|
str8_lit_comp("(Win32) Sanitizer Raw Access Violation"),
|
||||||
|
str8_lit_comp("(Win32) DirectX Debug Layer"),
|
||||||
|
};
|
||||||
|
|
||||||
|
String8 ctrl_exception_code_kind_lowercase_code_string_table[] =
|
||||||
|
{
|
||||||
|
{0},
|
||||||
|
str8_lit_comp("win32_ctrl_c"),
|
||||||
|
str8_lit_comp("win32_ctrl_break"),
|
||||||
|
str8_lit_comp("win32_win_rt_originate_error"),
|
||||||
|
str8_lit_comp("win32_win_rt_transform_error"),
|
||||||
|
str8_lit_comp("win32_rpc_call_cancelled"),
|
||||||
|
str8_lit_comp("win32_datatype_misalignment"),
|
||||||
|
str8_lit_comp("win32_access_violation"),
|
||||||
|
str8_lit_comp("win32_in_page_error"),
|
||||||
|
str8_lit_comp("win32_invalid_handle"),
|
||||||
|
str8_lit_comp("win32_not_enough_quota"),
|
||||||
|
str8_lit_comp("win32_illegal_instruction"),
|
||||||
|
str8_lit_comp("win32_cannot_continue_exception"),
|
||||||
|
str8_lit_comp("win32_invalid_exception_disposition"),
|
||||||
|
str8_lit_comp("win32_array_bounds_exceeded"),
|
||||||
|
str8_lit_comp("win32_floating_point_denormal_operand"),
|
||||||
|
str8_lit_comp("win32_floating_point_division_by_zero"),
|
||||||
|
str8_lit_comp("win32_floating_point_inexact_result"),
|
||||||
|
str8_lit_comp("win32_floating_point_invalid_operation"),
|
||||||
|
str8_lit_comp("win32_floating_point_overflow"),
|
||||||
|
str8_lit_comp("win32_floating_point_stack_check"),
|
||||||
|
str8_lit_comp("win32_floating_point_underflow"),
|
||||||
|
str8_lit_comp("win32_integer_division_by_zero"),
|
||||||
|
str8_lit_comp("win32_integer_overflow"),
|
||||||
|
str8_lit_comp("win32_privileged_instruction"),
|
||||||
|
str8_lit_comp("win32_stack_overflow"),
|
||||||
|
str8_lit_comp("win32_unable_to_locate_dll"),
|
||||||
|
str8_lit_comp("win32_ordinal_not_found"),
|
||||||
|
str8_lit_comp("win32_entry_point_not_found"),
|
||||||
|
str8_lit_comp("win32_dll_initialization_failed"),
|
||||||
|
str8_lit_comp("win32_floating_point_sse_multiple_faults"),
|
||||||
|
str8_lit_comp("win32_floating_point_sse_multiple_traps"),
|
||||||
|
str8_lit_comp("win32_assertion_failed"),
|
||||||
|
str8_lit_comp("win32_module_not_found"),
|
||||||
|
str8_lit_comp("win32_procedure_not_found"),
|
||||||
|
str8_lit_comp("win32_sanitizer_error_detected"),
|
||||||
|
str8_lit_comp("win32_sanitizer_raw_access_violation"),
|
||||||
|
str8_lit_comp("win32_directx_debug_layer"),
|
||||||
|
};
|
||||||
|
|
||||||
|
B8 ctrl_exception_code_kind_default_enable_table[] =
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
C_LINKAGE_END
|
|
||||||
|
|
||||||
#endif // CTRL_META_H
|
#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 launches all active targets." "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,495 +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;
|
|
||||||
String8 stdout_path;
|
|
||||||
String8 stderr_path;
|
|
||||||
String8 stdin_path;
|
|
||||||
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,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
|
|
||||||
+1119
-669
File diff suppressed because it is too large
Load Diff
+342
-166
@@ -5,166 +5,290 @@
|
|||||||
#define DBGI_H
|
#define DBGI_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Cache Key Type
|
//~ rjf: Info Bundle Types
|
||||||
|
|
||||||
typedef struct DI_Key DI_Key;
|
typedef struct DBGI_Parse DBGI_Parse;
|
||||||
struct DI_Key
|
struct DBGI_Parse
|
||||||
{
|
{
|
||||||
String8 path;
|
U64 gen;
|
||||||
U64 min_timestamp;
|
Arena *arena;
|
||||||
};
|
void *exe_base;
|
||||||
|
FileProperties exe_props;
|
||||||
typedef struct DI_KeyNode DI_KeyNode;
|
String8 dbg_path;
|
||||||
struct DI_KeyNode
|
void *dbg_base;
|
||||||
{
|
FileProperties dbg_props;
|
||||||
DI_KeyNode *next;
|
PE_BinInfo pe;
|
||||||
DI_Key v;
|
RADDBG_Parsed rdbg;
|
||||||
};
|
|
||||||
|
|
||||||
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
|
//~ rjf: Exe -> Debug Forced Override Cache Types
|
||||||
|
|
||||||
typedef enum DI_EventKind
|
typedef struct DBGI_ForceNode DBGI_ForceNode;
|
||||||
|
struct DBGI_ForceNode
|
||||||
{
|
{
|
||||||
DI_EventKind_Null,
|
DBGI_ForceNode *next;
|
||||||
DI_EventKind_ConversionStarted,
|
String8 exe_path;
|
||||||
DI_EventKind_ConversionEnded,
|
U64 dbg_path_cap;
|
||||||
DI_EventKind_ConversionFailureUnsupportedFormat,
|
U64 dbg_path_size;
|
||||||
DI_EventKind_COUNT
|
U8 *dbg_path_base;
|
||||||
}
|
|
||||||
DI_EventKind;
|
|
||||||
|
|
||||||
typedef struct DI_Event DI_Event;
|
|
||||||
struct DI_Event
|
|
||||||
{
|
|
||||||
DI_EventKind kind;
|
|
||||||
String8 string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DI_EventNode DI_EventNode;
|
typedef struct DBGI_ForceSlot DBGI_ForceSlot;
|
||||||
struct DI_EventNode
|
struct DBGI_ForceSlot
|
||||||
{
|
{
|
||||||
DI_EventNode *next;
|
DBGI_ForceNode *first;
|
||||||
DI_Event v;
|
DBGI_ForceNode *last;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DI_EventList DI_EventList;
|
typedef struct DBGI_ForceStripe DBGI_ForceStripe;
|
||||||
struct DI_EventList
|
struct DBGI_ForceStripe
|
||||||
{
|
|
||||||
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;
|
Arena *arena;
|
||||||
DI_Node *free_node;
|
|
||||||
DI_StringChunkNode *free_string_chunks[8];
|
|
||||||
OS_Handle rw_mutex;
|
OS_Handle rw_mutex;
|
||||||
OS_Handle cv;
|
OS_Handle cv;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Scoped Access Types
|
//~ rjf: Binary Cache State Types
|
||||||
|
|
||||||
typedef struct DI_Touch DI_Touch;
|
typedef U32 DBGI_BinaryFlags;
|
||||||
struct DI_Touch
|
enum
|
||||||
{
|
{
|
||||||
DI_Touch *next;
|
DBGI_BinaryFlag_ParseInFlight = (1<<0),
|
||||||
DI_Node *node;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DI_Scope DI_Scope;
|
typedef struct DBGI_Binary DBGI_Binary;
|
||||||
struct DI_Scope
|
struct DBGI_Binary
|
||||||
{
|
{
|
||||||
DI_Scope *next;
|
// rjf: links & metadata
|
||||||
DI_Touch *first_touch;
|
DBGI_Binary *next;
|
||||||
DI_Touch *last_touch;
|
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 DI_TCTX DI_TCTX;
|
typedef struct DBGI_BinarySlot DBGI_BinarySlot;
|
||||||
struct DI_TCTX
|
struct DBGI_BinarySlot
|
||||||
|
{
|
||||||
|
DBGI_Binary *first;
|
||||||
|
DBGI_Binary *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DBGI_BinaryStripe DBGI_BinaryStripe;
|
||||||
|
struct DBGI_BinaryStripe
|
||||||
{
|
{
|
||||||
Arena *arena;
|
Arena *arena;
|
||||||
DI_Scope *free_scope;
|
OS_Handle rw_mutex;
|
||||||
DI_Touch *free_touch;
|
OS_Handle cv;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Shared State Types
|
//~ rjf: Fuzzy Search Cache Types
|
||||||
|
|
||||||
typedef struct DI_Shared DI_Shared;
|
typedef enum DBGI_FuzzySearchTarget
|
||||||
struct DI_Shared
|
{
|
||||||
|
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;
|
Arena *arena;
|
||||||
|
String8 exe_path;
|
||||||
|
String8 query;
|
||||||
|
DBGI_FuzzySearchTarget target;
|
||||||
|
};
|
||||||
|
|
||||||
// rjf: node cache
|
typedef struct DBGI_FuzzySearchNode DBGI_FuzzySearchNode;
|
||||||
U64 slots_count;
|
struct DBGI_FuzzySearchNode
|
||||||
DI_Slot *slots;
|
{
|
||||||
U64 stripes_count;
|
DBGI_FuzzySearchNode *next;
|
||||||
DI_Stripe *stripes;
|
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
|
// rjf: user -> parse ring
|
||||||
OS_Handle u2p_ring_mutex;
|
OS_Handle u2p_ring_mutex;
|
||||||
@@ -185,71 +309,123 @@ struct DI_Shared
|
|||||||
// rjf: threads
|
// rjf: threads
|
||||||
U64 parse_thread_count;
|
U64 parse_thread_count;
|
||||||
OS_Handle *parse_threads;
|
OS_Handle *parse_threads;
|
||||||
|
U64 fuzzy_thread_count;
|
||||||
|
DBGI_FuzzySearchThread *fuzzy_threads;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Globals
|
//~ rjf: Globals
|
||||||
|
|
||||||
global DI_Shared *di_shared = 0;
|
global DBGI_Shared *dbgi_shared = 0;
|
||||||
thread_static DI_TCTX *di_tctx = 0;
|
thread_static DBGI_ThreadCtx *dbgi_tctx = 0;
|
||||||
global RDI_Parsed di_rdi_parsed_nil = {0};
|
global DBGI_Parse dbgi_parse_nil =
|
||||||
|
{
|
||||||
////////////////////////////////
|
0,
|
||||||
//~ rjf: Basic Helpers
|
0,
|
||||||
|
0,
|
||||||
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
|
{0},
|
||||||
internal U64 di_hash_from_key(DI_Key *k);
|
{0},
|
||||||
internal DI_Key di_key_zero(void);
|
0,
|
||||||
internal B32 di_key_match(DI_Key *a, DI_Key *b);
|
{0},
|
||||||
internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
|
{0},
|
||||||
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);
|
0,
|
||||||
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
|
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
|
//~ rjf: Main Layer Initialization
|
||||||
|
|
||||||
internal void di_init(void);
|
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
|
//~ rjf: Scope Functions
|
||||||
|
|
||||||
internal DI_Scope *di_scope_open(void);
|
internal DBGI_Scope *dbgi_scope_open(void);
|
||||||
internal void di_scope_close(DI_Scope *scope);
|
internal void dbgi_scope_close(DBGI_Scope *scope);
|
||||||
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node);
|
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: Per-Slot Functions
|
//~ rjf: Binary Cache Functions
|
||||||
|
|
||||||
internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key);
|
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: Per-Stripe Functions
|
//~ rjf: Fuzzy Search Cache Functions
|
||||||
|
|
||||||
internal U64 di_string_bucket_idx_from_string_size(U64 size);
|
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);
|
||||||
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
|
//~ rjf: Parse Threads
|
||||||
|
|
||||||
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
|
internal B32 dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us);
|
||||||
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
internal String8 dbgi_u2p_dequeue_exe_path(Arena *arena);
|
||||||
|
|
||||||
internal void di_p2u_push_event(DI_Event *event);
|
internal void dbgi_p2u_push_event(DBGI_Event *event);
|
||||||
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
|
internal DBGI_EventList dbgi_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||||
|
|
||||||
internal void di_parse_thread__entry_point(void *p);
|
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
|
#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
|
||||||
+780
-97
@@ -2,39 +2,148 @@
|
|||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Generated Code
|
//~ rjf: Main Layer Initialization
|
||||||
|
|
||||||
#include "generated/demon.meta.c"
|
internal void
|
||||||
|
demon_init(void){
|
||||||
////////////////////////////////
|
demon_common_init();
|
||||||
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
|
demon_os_init();
|
||||||
|
|
||||||
//- rjf: handles
|
|
||||||
|
|
||||||
internal DMN_Handle
|
|
||||||
dmn_handle_zero(void)
|
|
||||||
{
|
|
||||||
DMN_Handle h = {0};
|
|
||||||
return h;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
////////////////////////////////
|
||||||
dmn_handle_match(DMN_Handle a, DMN_Handle b)
|
//~ rjf: Basic Type Functions
|
||||||
|
|
||||||
|
//- rjf: stringizing
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
demon_string_from_event_kind(DEMON_EventKind kind){
|
||||||
|
String8 result = str8_lit("unknown");
|
||||||
|
switch (kind){
|
||||||
|
default: break;
|
||||||
|
case DEMON_EventKind_Error: result = str8_lit("Error"); break;
|
||||||
|
case DEMON_EventKind_HandshakeComplete: result = str8_lit("HandshakeComplete"); break;
|
||||||
|
case DEMON_EventKind_CreateProcess: result = str8_lit("CreateProcess"); break;
|
||||||
|
case DEMON_EventKind_ExitProcess: result = str8_lit("ExitProcess"); break;
|
||||||
|
case DEMON_EventKind_CreateThread: result = str8_lit("CreateThread"); break;
|
||||||
|
case DEMON_EventKind_ExitThread: result = str8_lit("ExitThread"); break;
|
||||||
|
case DEMON_EventKind_LoadModule: result = str8_lit("LoadModule"); break;
|
||||||
|
case DEMON_EventKind_UnloadModule: result = str8_lit("UnloadModule"); break;
|
||||||
|
case DEMON_EventKind_Breakpoint: result = str8_lit("Breakpoint"); break;
|
||||||
|
case DEMON_EventKind_Trap: result = str8_lit("Trap"); break;
|
||||||
|
case DEMON_EventKind_SingleStep: result = str8_lit("SingleStep"); break;
|
||||||
|
case DEMON_EventKind_Exception: result = str8_lit("Exception"); break;
|
||||||
|
case DEMON_EventKind_Halt: result = str8_lit("Halt"); break;
|
||||||
|
case DEMON_EventKind_Memory: result = str8_lit("Memory"); break;
|
||||||
|
case DEMON_EventKind_DebugString: result = str8_lit("DebugString"); break;
|
||||||
|
case DEMON_EventKind_SetThreadName: result = str8_lit("SetThreadName"); break;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind){
|
||||||
|
String8 result = str8_lit("unknown");
|
||||||
|
switch (kind){
|
||||||
|
default: break;
|
||||||
|
case DEMON_MemoryEventKind_Commit: result = str8_lit("Commit"); break;
|
||||||
|
case DEMON_MemoryEventKind_Reserve: result = str8_lit("Reserve"); break;
|
||||||
|
case DEMON_MemoryEventKind_Decommit: result = str8_lit("Decommit"); break;
|
||||||
|
case DEMON_MemoryEventKind_Release: result = str8_lit("Release"); break;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
demon_string_from_exception_kind(DEMON_ExceptionKind kind){
|
||||||
|
String8 result = str8_lit("unknown");
|
||||||
|
switch (kind){
|
||||||
|
default: break;
|
||||||
|
case DEMON_ExceptionKind_MemoryRead: result = str8_lit("MemoryRead"); break;
|
||||||
|
case DEMON_ExceptionKind_MemoryWrite: result = str8_lit("MemoryWrite"); break;
|
||||||
|
case DEMON_ExceptionKind_MemoryExecute: result = str8_lit("MemoryExecute"); break;
|
||||||
|
case DEMON_ExceptionKind_CppThrow: result = str8_lit("CppThrow"); break;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event){
|
||||||
|
B32 need_exception_info = (event->kind == DEMON_EventKind_Exception ||
|
||||||
|
event->kind == DEMON_EventKind_Breakpoint ||
|
||||||
|
event->kind == DEMON_EventKind_Halt ||
|
||||||
|
event->kind == DEMON_EventKind_SingleStep);
|
||||||
|
|
||||||
|
// allen: kind
|
||||||
|
String8 kind_string = demon_string_from_event_kind(event->kind);
|
||||||
|
str8_list_pushf(arena, out, "%S: { (%i)", kind_string, event->kind);
|
||||||
|
|
||||||
|
// rjf: basics
|
||||||
{
|
{
|
||||||
return a.u32[0] == b.u32[0] && a.u32[1] == b.u32[1];
|
str8_list_pushf(arena, out, " process: (%I64x)", event->process);
|
||||||
|
str8_list_pushf(arena, out, " thread: (%I64x)", event->thread);
|
||||||
|
str8_list_pushf(arena, out, " module: (%I64x)", event->module);
|
||||||
|
str8_list_pushf(arena, out, " address: (%I64x)", event->address, event->address);
|
||||||
|
str8_list_pushf(arena, out, " size: (0x%I64x, %I64u)", event->size, event->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: string
|
||||||
|
if (event->string.size != 0){
|
||||||
|
str8_list_pushf(arena, out, " string: \"%S\"", event->string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: exception info
|
||||||
|
if (need_exception_info){
|
||||||
|
str8_list_pushf(arena, out, " code: (0x%x, %i)", event->code, event->code);
|
||||||
|
str8_list_pushf(arena, out, " flags: (0x%x, %i)", event->flags, event->flags);
|
||||||
|
str8_list_pushf(arena, out, " signo: (0x%x, %i)", event->signo, event->signo);
|
||||||
|
str8_list_pushf(arena, out, " sigcode: (0x%x, %i)", event->sigcode, event->sigcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: need error info
|
||||||
|
if (event->kind == DEMON_EventKind_Error){
|
||||||
|
str8_list_pushf(arena, out, " error_kind: (0x%x, %i)", event->error_kind, event->error_kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: memory event kind info
|
||||||
|
if (event->memory_kind != DEMON_MemoryEventKind_Null){
|
||||||
|
String8 memory_kind_string = demon_string_from_memory_event_kind(event->memory_kind);
|
||||||
|
str8_list_pushf(arena, out, " memory_kind: (%S, %i)",
|
||||||
|
memory_kind_string, event->memory_kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: exception kind
|
||||||
|
if (need_exception_info){
|
||||||
|
String8 exception_kind_string = demon_string_from_exception_kind(event->exception_kind);
|
||||||
|
str8_list_pushf(arena, out, " exception_kind: (%S, %i)",
|
||||||
|
exception_kind_string, event->exception_kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: instruction ptr
|
||||||
|
if (event->instruction_pointer != 0){
|
||||||
|
str8_list_pushf(arena, out, " instruction_pointer: (%I64x)", event->instruction_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: stack ptr
|
||||||
|
if (event->stack_pointer != 0){
|
||||||
|
str8_list_pushf(arena, out, " stack_pointer: (%I64x)", event->stack_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
str8_list_pushf(arena, out, " user_data: (0x%I64x, %I64u)",
|
||||||
|
event->user_data, event->user_data);
|
||||||
|
str8_list_pushf(arena, out, "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: trap chunk lists
|
//- rjf: trap chunk lists
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap)
|
demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap)
|
||||||
{
|
{
|
||||||
DMN_TrapChunkNode *node = list->last;
|
DEMON_TrapChunkNode *node = list->last;
|
||||||
if(node == 0 || node->count >= node->cap)
|
if(node == 0 || node->count >= node->cap)
|
||||||
{
|
{
|
||||||
node = push_array(arena, DMN_TrapChunkNode, 1);
|
node = push_array(arena, DEMON_TrapChunkNode, 1);
|
||||||
node->cap = cap;
|
node->cap = cap;
|
||||||
node->v = push_array_no_zero(arena, DMN_Trap, node->cap);
|
node->v = push_array_no_zero(arena, DEMON_Trap, node->cap);
|
||||||
SLLQueuePush(list->first, list->last, node);
|
SLLQueuePush(list->first, list->last, node);
|
||||||
list->node_count += 1;
|
list->node_count += 1;
|
||||||
}
|
}
|
||||||
@@ -44,7 +153,7 @@ dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Tra
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push)
|
||||||
{
|
{
|
||||||
if(dst->last == 0)
|
if(dst->last == 0)
|
||||||
{
|
{
|
||||||
@@ -61,11 +170,11 @@ dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push)
|
||||||
{
|
{
|
||||||
for(DMN_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
|
for(DEMON_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
|
||||||
{
|
{
|
||||||
DMN_TrapChunkNode *dst_n = push_array(arena, DMN_TrapChunkNode, 1);
|
DEMON_TrapChunkNode *dst_n = push_array(arena, DEMON_TrapChunkNode, 1);
|
||||||
dst_n->v = src_n->v;
|
dst_n->v = src_n->v;
|
||||||
dst_n->cap = src_n->cap;
|
dst_n->cap = src_n->cap;
|
||||||
dst_n->count = src_n->count;
|
dst_n->count = src_n->count;
|
||||||
@@ -78,111 +187,685 @@ dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DM
|
|||||||
//- rjf: handle lists
|
//- rjf: handle lists
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle)
|
demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle)
|
||||||
{
|
{
|
||||||
DMN_HandleNode *node = push_array(arena, DMN_HandleNode, 1);
|
DEMON_HandleNode *node = push_array(arena, DEMON_HandleNode, 1);
|
||||||
SLLQueuePush(list->first, list->last, node);
|
SLLQueuePush(list->first, list->last, node);
|
||||||
node->v = handle;
|
node->v = handle;
|
||||||
list->count += 1;
|
list->count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DMN_HandleArray
|
internal DEMON_HandleArray
|
||||||
dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list)
|
demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list)
|
||||||
{
|
{
|
||||||
DMN_HandleArray array = {0};
|
DEMON_HandleArray array = {0};
|
||||||
array.count = list->count;
|
array.count = list->count;
|
||||||
array.handles = push_array_no_zero(arena, DMN_Handle, array.count);
|
array.handles = push_array_no_zero(arena, DEMON_Handle, array.count);
|
||||||
U64 idx = 0;
|
U64 idx = 0;
|
||||||
for(DMN_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
|
for(DEMON_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
|
||||||
{
|
{
|
||||||
array.handles[idx] = n->v;
|
array.handles[idx] = n->v;
|
||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DMN_HandleArray
|
internal DEMON_HandleArray
|
||||||
dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src)
|
demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src)
|
||||||
{
|
{
|
||||||
DMN_HandleArray dst = {0};
|
DEMON_HandleArray dst = {0};
|
||||||
dst.count = src->count;
|
dst.count = src->count;
|
||||||
dst.handles = push_array_no_zero(arena, DMN_Handle, dst.count);
|
dst.handles = push_array_no_zero(arena, DEMON_Handle, dst.count);
|
||||||
MemoryCopy(dst.handles, src->handles, sizeof(DMN_Handle)*dst.count);
|
MemoryCopy(dst.handles, src->handles, sizeof(DEMON_Handle)*dst.count);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: event list building
|
////////////////////////////////
|
||||||
|
//~ rjf: Primary Thread & Exclusive Mode Controls
|
||||||
|
|
||||||
internal DMN_Event *
|
internal void
|
||||||
dmn_event_list_push(Arena *arena, DMN_EventList *list)
|
demon_primary_thread_begin(void){
|
||||||
{
|
demon_primary_thread = 1;
|
||||||
DMN_EventNode *n = push_array(arena, DMN_EventNode, 1);
|
}
|
||||||
SLLQueuePush(list->first, list->last, n);
|
|
||||||
list->count += 1;
|
internal void
|
||||||
DMN_Event *result = &n->v;
|
demon_exclusive_mode_begin(void){
|
||||||
return result;
|
Assert(demon_primary_thread);
|
||||||
|
os_mutex_take(demon_state_mutex);
|
||||||
|
demon_run_state = 1;
|
||||||
|
os_mutex_drop(demon_state_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
demon_exclusive_mode_end(void){
|
||||||
|
Assert(demon_primary_thread);
|
||||||
|
os_mutex_take(demon_state_mutex);
|
||||||
|
demon_run_state = 0;
|
||||||
|
os_mutex_drop(demon_state_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
|
//~ rjf: Running/Halting
|
||||||
|
|
||||||
internal U64
|
internal DEMON_EventList
|
||||||
dmn_rip_from_thread(DMN_Handle thread)
|
demon_run(Arena *arena, DEMON_RunCtrls *ctrls)
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
{
|
|
||||||
Arch arch = dmn_arch_from_thread(thread);
|
|
||||||
U64 reg_block_size = regs_block_size_from_arch(arch);
|
|
||||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
|
||||||
dmn_thread_read_reg_block(thread, reg_block);
|
|
||||||
result = regs_rip_from_arch_block(arch, reg_block);
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
dmn_rsp_from_thread(DMN_Handle thread)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
{
|
|
||||||
Arch arch = dmn_arch_from_thread(thread);
|
|
||||||
U64 reg_block_size = regs_block_size_from_arch(arch);
|
|
||||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
|
||||||
dmn_thread_read_reg_block(thread, reg_block);
|
|
||||||
result = regs_rsp_from_arch_block(arch, reg_block);
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Memory Helpers
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
dmn_process_read_cstring(Arena *arena, DMN_Handle process, U64 addr)
|
|
||||||
{
|
{
|
||||||
|
Assert(demon_primary_thread);
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
|
|
||||||
String8List block_list = {0};
|
// convert controls to os controls
|
||||||
|
B32 full_conversion = 1;
|
||||||
for(U64 cursor = addr, stride = 256; ; cursor += stride)
|
DEMON_OS_RunCtrls os_ctrls = {0};
|
||||||
{
|
{
|
||||||
U8 *raw_block = push_array_no_zero(scratch.arena, U8, stride);
|
// convert single_step_thread
|
||||||
U64 read_size = dmn_process_read(process, r1u64(cursor, cursor + stride), raw_block);
|
if (ctrls->single_step_thread != 0){
|
||||||
String8 block = str8_cstring_capped(raw_block, raw_block + read_size);
|
DEMON_Entity *sst_entity = demon_ent_ptr_from_handle(ctrls->single_step_thread);
|
||||||
|
if (sst_entity != 0 &&
|
||||||
str8_list_push(scratch.arena, &block_list, block);
|
sst_entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
os_ctrls.single_step_thread = sst_entity;
|
||||||
if(read_size != stride || (block.size+1 <= read_size && block.str[block.size] == 0))
|
}
|
||||||
{
|
else{
|
||||||
break;
|
full_conversion = 0;
|
||||||
|
goto finish_conversion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String8 result = str8_list_join(arena, &block_list, 0);
|
// convert exception handling flag
|
||||||
|
os_ctrls.ignore_previous_exception = ctrls->ignore_previous_exception;
|
||||||
|
|
||||||
|
// convert fronzen threads
|
||||||
|
os_ctrls.run_entities_are_unfrozen = ctrls->run_entities_are_unfrozen;
|
||||||
|
os_ctrls.run_entities_are_processes = ctrls->run_entities_are_processes;
|
||||||
|
os_ctrls.run_entity_count = ctrls->run_entity_count;
|
||||||
|
os_ctrls.run_entities = push_array_no_zero(scratch.arena, DEMON_Entity*, ctrls->run_entity_count);
|
||||||
|
{
|
||||||
|
DEMON_EntityKind expected_entity_kind = DEMON_EntityKind_Thread;
|
||||||
|
if (os_ctrls.run_entities_are_processes){
|
||||||
|
expected_entity_kind = DEMON_EntityKind_Process;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEMON_Handle *src = ctrls->run_entities;
|
||||||
|
DEMON_Entity **dst = os_ctrls.run_entities;
|
||||||
|
for (U64 i = 0; i < ctrls->run_entity_count; i += 1, src += 1, dst += 1){
|
||||||
|
DEMON_Entity *frozen_thread = demon_ent_ptr_from_handle(*src);
|
||||||
|
if (frozen_thread != 0 &&
|
||||||
|
frozen_thread->kind == expected_entity_kind){
|
||||||
|
*dst = frozen_thread;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
full_conversion = 0;
|
||||||
|
goto finish_conversion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert traps
|
||||||
|
os_ctrls.traps = push_array_no_zero(scratch.arena, DEMON_OS_Trap, ctrls->traps.trap_count);
|
||||||
|
{
|
||||||
|
DEMON_OS_Trap *dst = os_ctrls.traps;
|
||||||
|
|
||||||
|
for (DEMON_TrapChunkNode *node = ctrls->traps.first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
DEMON_Trap *src = node->v;
|
||||||
|
U64 node_trap_count = node->count;
|
||||||
|
for (U64 i = 0; i < node_trap_count; i += 1, src += 1){
|
||||||
|
if (src->process != 0){
|
||||||
|
DEMON_Entity *trap_process = demon_ent_ptr_from_handle(src->process);
|
||||||
|
if (trap_process != 0 &&
|
||||||
|
trap_process->kind == DEMON_EntityKind_Process){
|
||||||
|
dst->process = trap_process;
|
||||||
|
dst->address = src->address;
|
||||||
|
dst += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
full_conversion = 0;
|
||||||
|
goto finish_conversion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os_ctrls.trap_count = (U64)(dst - os_ctrls.traps);
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_conversion:;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the OS implementation of run
|
||||||
|
DEMON_EventList result = {0};
|
||||||
|
if (full_conversion){
|
||||||
|
result = demon_os_run(arena, &os_ctrls);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error);
|
||||||
|
event->error_kind = DEMON_ErrorKind_InvalidHandle;
|
||||||
|
}
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
return result;
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
demon_halt(U64 code, U64 user_data){
|
||||||
|
demon_os_halt(code, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_get_time_counter(void){
|
||||||
|
return(demon_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting
|
||||||
|
|
||||||
|
internal U32
|
||||||
|
demon_launch_process(OS_LaunchOptions *options){
|
||||||
|
Assert(demon_primary_thread);
|
||||||
|
U32 result = demon_os_launch_process(options);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_attach_process(U32 pid){
|
||||||
|
Assert(demon_primary_thread);
|
||||||
|
B32 result = demon_os_attach_process(pid);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_kill_process(DEMON_Handle process, U32 exit_code){
|
||||||
|
Assert(demon_primary_thread);
|
||||||
|
B32 result = 0;
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Process){
|
||||||
|
result = demon_os_kill_process(entity, exit_code);
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_detach_process(DEMON_Handle process){
|
||||||
|
Assert(demon_primary_thread);
|
||||||
|
B32 result = 0;
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Process){
|
||||||
|
result = demon_os_detach_process(entity);
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Entity Functions
|
||||||
|
|
||||||
|
//- rjf: basics
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_object_exists(DEMON_Handle object){
|
||||||
|
B32 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(object);
|
||||||
|
result = (entity != 0);
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: introspection
|
||||||
|
|
||||||
|
internal Architecture
|
||||||
|
demon_arch_from_object(DEMON_Handle object){
|
||||||
|
Architecture result = Architecture_Null;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(object);
|
||||||
|
if (entity != 0){
|
||||||
|
result = (Architecture)entity->arch;
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_base_vaddr_from_module(DEMON_Handle module){
|
||||||
|
U64 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(module);
|
||||||
|
if (entity != 0 && entity->kind == DEMON_EntityKind_Module){
|
||||||
|
result = entity->id;
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Rng1U64
|
||||||
|
demon_vaddr_range_from_module(DEMON_Handle module)
|
||||||
|
{
|
||||||
|
Rng1U64 result = {0};
|
||||||
|
if(demon_access_begin())
|
||||||
|
{
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(module);
|
||||||
|
if(entity != 0 && entity->kind == DEMON_EntityKind_Module)
|
||||||
|
{
|
||||||
|
result = r1u64(entity->id, entity->id+entity->addr_range_dim);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
demon_full_path_from_module(Arena *arena, DEMON_Handle module){
|
||||||
|
String8 result = {0};
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(module);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Module){
|
||||||
|
result = demon_accel_full_path_from_module(arena, entity);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_stack_base_vaddr_from_thread(DEMON_Handle thread){
|
||||||
|
U64 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
|
||||||
|
if (entity != 0 && entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
result = demon_accel_stack_base_vaddr_from_thread(entity);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_tls_root_vaddr_from_thread(DEMON_Handle handle){
|
||||||
|
U64 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(handle);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
result = demon_accel_tls_root_vaddr_from_thread(entity);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DEMON_HandleArray
|
||||||
|
demon_all_processes(Arena *arena){
|
||||||
|
DEMON_HandleArray result = {0};
|
||||||
|
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_proc_count);
|
||||||
|
DEMON_Handle *handle_opl = handles + demon_proc_count;
|
||||||
|
DEMON_Handle *handle_ptr = handles;
|
||||||
|
|
||||||
|
for (DEMON_Entity *process = demon_ent_root->first;
|
||||||
|
process != 0 && handle_ptr < handle_opl;
|
||||||
|
process = process->next){
|
||||||
|
if (process->kind == DEMON_EntityKind_Process){
|
||||||
|
*handle_ptr = demon_ent_handle_from_ptr(process);
|
||||||
|
handle_ptr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.handles = handles;
|
||||||
|
result.count = (U64)(handle_ptr - handles);
|
||||||
|
|
||||||
|
U64 unused_count = demon_proc_count - result.count;
|
||||||
|
arena_put_back(arena, sizeof(DEMON_Handle)*unused_count);
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DEMON_HandleArray
|
||||||
|
demon_threads_from_process(Arena *arena, DEMON_Handle process){
|
||||||
|
DEMON_HandleArray result = {0};
|
||||||
|
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_thread_count);
|
||||||
|
DEMON_Handle *handle_opl = handles + demon_thread_count;
|
||||||
|
DEMON_Handle *handle_ptr = handles;
|
||||||
|
|
||||||
|
DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process);
|
||||||
|
|
||||||
|
if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){
|
||||||
|
for (DEMON_Entity *thread = process_ptr->first;
|
||||||
|
thread != 0 && handle_ptr < handle_opl;
|
||||||
|
thread = thread->next){
|
||||||
|
if (thread->kind == DEMON_EntityKind_Thread){
|
||||||
|
*handle_ptr = demon_ent_handle_from_ptr(thread);
|
||||||
|
handle_ptr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.handles = handles;
|
||||||
|
result.count = (U64)(handle_ptr - handles);
|
||||||
|
|
||||||
|
U64 unused_count = demon_thread_count - result.count;
|
||||||
|
arena_put_back(arena, sizeof(DEMON_Handle)*unused_count);
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DEMON_HandleArray
|
||||||
|
demon_modules_from_process(Arena *arena, DEMON_Handle process){
|
||||||
|
DEMON_HandleArray result = {0};
|
||||||
|
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_module_count);
|
||||||
|
DEMON_Handle *handle_opl = handles + demon_module_count;
|
||||||
|
DEMON_Handle *handle_ptr = handles;
|
||||||
|
|
||||||
|
DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process);
|
||||||
|
|
||||||
|
if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){
|
||||||
|
for (DEMON_Entity *module = process_ptr->first;
|
||||||
|
module != 0 && handle_ptr < handle_opl;
|
||||||
|
module = module->next){
|
||||||
|
if (module->kind == DEMON_EntityKind_Module){
|
||||||
|
*handle_ptr = demon_ent_handle_from_ptr(module);
|
||||||
|
handle_ptr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.handles = handles;
|
||||||
|
result.count = (U64)(handle_ptr - handles);
|
||||||
|
|
||||||
|
U64 unused_count = demon_module_count - result.count;
|
||||||
|
arena_put_back(arena, sizeof(DEMON_Handle)*unused_count);
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: target process memory allocation/protection
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_reserve_memory(DEMON_Handle process, U64 size){
|
||||||
|
U64 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Process){
|
||||||
|
result = demon_os_reserve_memory(entity, size);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags){
|
||||||
|
B32 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Process){
|
||||||
|
demon_os_set_memory_protect_flags(entity, page_vaddr, size, flags);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size){
|
||||||
|
B32 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Process){
|
||||||
|
demon_os_release_memory(entity, vaddr, size);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: target process memory reading/writing
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size){
|
||||||
|
U64 bytes_read = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Process){
|
||||||
|
bytes_read = demon_os_read_memory(entity, dst, src_address, size);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size){
|
||||||
|
B32 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Process){
|
||||||
|
result = demon_os_write_memory(entity, dst_address, src, size);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ_BLOCK_SIZE 4096
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size){
|
||||||
|
// Algorithm:
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// ^ ^ ^
|
||||||
|
// MIN MAX SMAX
|
||||||
|
// [MIN,MAX) - range attempting to read
|
||||||
|
// [MAX,SMAX) - range not yet proven to be impossible to read
|
||||||
|
|
||||||
|
Assert(src_address%READ_BLOCK_SIZE == 0);
|
||||||
|
Assert(size%READ_BLOCK_SIZE == 0);
|
||||||
|
|
||||||
|
U64 read_size = 0;
|
||||||
|
U64 min = 0;
|
||||||
|
U64 max = size;
|
||||||
|
U64 smax = max;
|
||||||
|
|
||||||
|
for (;;){
|
||||||
|
if (max <= min){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt to read range
|
||||||
|
U64 attempt_size = max - min;
|
||||||
|
B32 success = demon_read_memory(process, (U8*)dst + min, src_address + min, attempt_size);
|
||||||
|
|
||||||
|
if (success){
|
||||||
|
// increase successful read size
|
||||||
|
read_size += attempt_size;
|
||||||
|
// adjust range up
|
||||||
|
min = max;
|
||||||
|
max = smax;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// mark this point as too far
|
||||||
|
smax = max - READ_BLOCK_SIZE;
|
||||||
|
// bisect the range for the next read attempt
|
||||||
|
U64 mid = (min + max)/2;
|
||||||
|
U64 aligned_mid = AlignDownPow2(mid, READ_BLOCK_SIZE);
|
||||||
|
max = aligned_mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 result = read_size;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size){
|
||||||
|
U64 read_size = 0;
|
||||||
|
|
||||||
|
if (demon_access_begin()){
|
||||||
|
B32 done = 0;
|
||||||
|
U64 read_opl = src_address + size;
|
||||||
|
|
||||||
|
// pre-aligned part -- [SRC,PRE_OPL)
|
||||||
|
U64 src_block_opl = AlignPow2(src_address, READ_BLOCK_SIZE);
|
||||||
|
U64 pre_opl = Min(src_block_opl, read_opl);
|
||||||
|
if(src_address < pre_opl)
|
||||||
|
{
|
||||||
|
U64 attempt_size = pre_opl - src_address;
|
||||||
|
if(!demon_read_memory(process, dst, src_address, attempt_size))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
read_size += attempt_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// aligned part -- [PRE_OPL,POST_FIRST)
|
||||||
|
U64 read_opl_block_base = AlignDownPow2(read_opl, READ_BLOCK_SIZE);
|
||||||
|
U64 post_first = Max(read_opl_block_base, pre_opl);
|
||||||
|
if (!done && pre_opl < post_first){
|
||||||
|
U64 off = pre_opl - src_address;
|
||||||
|
U64 attempt_size = post_first - pre_opl;
|
||||||
|
U64 actual_size = demon_read_memory_amap_aligned(process, (U8*)dst + off,
|
||||||
|
pre_opl, attempt_size);
|
||||||
|
read_size += actual_size;
|
||||||
|
if (actual_size < attempt_size){
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// post-aligned part -- [POST_FIRST,READ_OPL)
|
||||||
|
if (!done && post_first < read_opl){
|
||||||
|
U64 off = post_first - src_address;
|
||||||
|
U64 attempt_size = read_opl - post_first;
|
||||||
|
if (!demon_read_memory(process, (U8*)dst + off, post_first, attempt_size)){
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
read_size += attempt_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 result = read_size;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef READ_BLOCK_SIZE
|
||||||
|
|
||||||
|
//- rjf: thread registers reading/writing
|
||||||
|
|
||||||
|
internal void*
|
||||||
|
demon_read_regs(DEMON_Handle thread){
|
||||||
|
void *result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
result = demon_accel_read_regs(entity);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_write_regs(DEMON_Handle thread, void *data){
|
||||||
|
B32 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
demon_accel_write_regs(entity, data);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_read_ip(DEMON_Handle thread){
|
||||||
|
U64 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
void *regs = demon_accel_read_regs(entity);
|
||||||
|
result = regs_rip_from_arch_block((Architecture)entity->arch, regs);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
demon_read_sp(DEMON_Handle thread){
|
||||||
|
U64 result = 0;
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
void *regs = demon_accel_read_regs(entity);
|
||||||
|
result = regs_rsp_from_arch_block((Architecture)entity->arch, regs);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
demon_write_ip(DEMON_Handle thread, U64 ip){
|
||||||
|
if (demon_access_begin()){
|
||||||
|
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
|
||||||
|
if (entity != 0 &&
|
||||||
|
entity->kind == DEMON_EntityKind_Thread){
|
||||||
|
void *regs = demon_accel_read_regs(entity);
|
||||||
|
regs_arch_block_write_rip((Architecture)entity->arch, regs, ip);
|
||||||
|
demon_accel_write_regs(entity, regs);
|
||||||
|
}
|
||||||
|
demon_access_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Process Listing
|
||||||
|
|
||||||
|
internal void
|
||||||
|
demon_proc_iter_begin(DEMON_ProcessIter *iter){
|
||||||
|
demon_os_proc_iter_begin(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out){
|
||||||
|
return(demon_os_proc_iter_next(arena, iter, info_out));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
demon_proc_iter_end(DEMON_ProcessIter *iter){
|
||||||
|
demon_os_proc_iter_end(iter);
|
||||||
}
|
}
|
||||||
|
|||||||
+191
-141
@@ -5,70 +5,111 @@
|
|||||||
#define DEMON_CORE_H
|
#define DEMON_CORE_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Control-Thread-Only Context
|
//~ allen: Demon Low Level Entities
|
||||||
//
|
|
||||||
// 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;
|
typedef U64 DEMON_Handle;
|
||||||
struct DMN_CtrlCtx
|
|
||||||
|
typedef struct DEMON_HandleNode DEMON_HandleNode;
|
||||||
|
struct DEMON_HandleNode
|
||||||
{
|
{
|
||||||
U64 u64[1];
|
DEMON_HandleNode *next;
|
||||||
|
DEMON_Handle v;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
typedef struct DEMON_HandleList DEMON_HandleList;
|
||||||
//~ rjf: Handle Types
|
struct DEMON_HandleList
|
||||||
|
|
||||||
typedef union DMN_Handle DMN_Handle;
|
|
||||||
union DMN_Handle
|
|
||||||
{
|
{
|
||||||
U32 u32[2];
|
DEMON_HandleNode *first;
|
||||||
U64 u64[1];
|
DEMON_HandleNode *last;
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_HandleArray DMN_HandleArray;
|
typedef struct DEMON_HandleArray DEMON_HandleArray;
|
||||||
struct DMN_HandleArray
|
struct DEMON_HandleArray
|
||||||
{
|
{
|
||||||
DMN_Handle *handles;
|
DEMON_Handle *handles;
|
||||||
U64 count;
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Generated Code
|
//~ rjf: Memory Protection Flags
|
||||||
|
|
||||||
#include "generated/demon.meta.h"
|
typedef U32 DEMON_MemoryProtectFlags;
|
||||||
|
enum{
|
||||||
|
DEMON_MemoryProtectFlag_Read = (1<<0),
|
||||||
|
DEMON_MemoryProtectFlag_Write = (1<<1),
|
||||||
|
DEMON_MemoryProtectFlag_Execute = (1<<2),
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Event Types
|
//~ allen: Demon Event Types
|
||||||
|
|
||||||
typedef struct DMN_Event DMN_Event;
|
typedef enum DEMON_EventKind
|
||||||
struct DMN_Event
|
|
||||||
{
|
{
|
||||||
DMN_EventKind kind;
|
DEMON_EventKind_Null,
|
||||||
DMN_ErrorKind error_kind;
|
DEMON_EventKind_Error,
|
||||||
DMN_MemoryEventKind memory_kind;
|
DEMON_EventKind_HandshakeComplete,
|
||||||
DMN_ExceptionKind exception_kind;
|
DEMON_EventKind_CreateProcess,
|
||||||
DMN_Handle process;
|
DEMON_EventKind_ExitProcess,
|
||||||
DMN_Handle thread;
|
DEMON_EventKind_CreateThread,
|
||||||
DMN_Handle module;
|
DEMON_EventKind_ExitThread,
|
||||||
Arch arch;
|
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 address;
|
||||||
U64 size;
|
U64 size;
|
||||||
String8 string;
|
String8 string;
|
||||||
@@ -82,162 +123,171 @@ struct DMN_Event
|
|||||||
B32 exception_repeated;
|
B32 exception_repeated;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_EventNode DMN_EventNode;
|
typedef struct DEMON_EventNode DEMON_EventNode;
|
||||||
struct DMN_EventNode
|
struct DEMON_EventNode
|
||||||
{
|
{
|
||||||
DMN_EventNode *next;
|
DEMON_EventNode *next;
|
||||||
DMN_Event v;
|
DEMON_Event v;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_EventList DMN_EventList;
|
typedef struct DEMON_EventList DEMON_EventList;
|
||||||
struct DMN_EventList
|
struct DEMON_EventList
|
||||||
{
|
{
|
||||||
DMN_EventNode *first;
|
DEMON_EventNode *first;
|
||||||
DMN_EventNode *last;
|
DEMON_EventNode *last;
|
||||||
U64 count;
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Run Control Types
|
//~ allen: Demon Run Control Types
|
||||||
|
|
||||||
typedef struct DMN_Trap DMN_Trap;
|
typedef struct DEMON_Trap DEMON_Trap;
|
||||||
struct DMN_Trap
|
struct DEMON_Trap
|
||||||
{
|
{
|
||||||
DMN_Handle process;
|
DEMON_Handle process;
|
||||||
U64 vaddr;
|
U64 address;
|
||||||
U64 id;
|
U64 id;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_TrapChunkNode DMN_TrapChunkNode;
|
typedef struct DEMON_TrapChunkNode DEMON_TrapChunkNode;
|
||||||
struct DMN_TrapChunkNode
|
struct DEMON_TrapChunkNode
|
||||||
{
|
{
|
||||||
DMN_TrapChunkNode *next;
|
DEMON_TrapChunkNode *next;
|
||||||
DMN_Trap *v;
|
DEMON_Trap *v;
|
||||||
U64 cap;
|
U64 cap;
|
||||||
U64 count;
|
U64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_TrapChunkList DMN_TrapChunkList;
|
typedef struct DEMON_TrapChunkList DEMON_TrapChunkList;
|
||||||
struct DMN_TrapChunkList
|
struct DEMON_TrapChunkList
|
||||||
{
|
{
|
||||||
DMN_TrapChunkNode *first;
|
DEMON_TrapChunkNode *first;
|
||||||
DMN_TrapChunkNode *last;
|
DEMON_TrapChunkNode *last;
|
||||||
U64 node_count;
|
U64 node_count;
|
||||||
U64 trap_count;
|
U64 trap_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_RunCtrls DMN_RunCtrls;
|
typedef struct DEMON_RunCtrls DEMON_RunCtrls;
|
||||||
struct DMN_RunCtrls
|
struct DEMON_RunCtrls
|
||||||
{
|
{
|
||||||
DMN_Handle single_step_thread;
|
DEMON_Handle single_step_thread;
|
||||||
B8 ignore_previous_exception;
|
B8 ignore_previous_exception;
|
||||||
B8 run_entities_are_unfrozen;
|
B8 run_entities_are_unfrozen;
|
||||||
B8 run_entities_are_processes;
|
B8 run_entities_are_processes;
|
||||||
DMN_Handle *run_entities;
|
DEMON_Handle *run_entities;
|
||||||
U64 run_entity_count;
|
U64 run_entity_count;
|
||||||
DMN_TrapChunkList traps;
|
DEMON_TrapChunkList traps;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: System Process Listing Types
|
//~ allen: Demon Process Listing
|
||||||
|
|
||||||
typedef struct DMN_ProcessIter DMN_ProcessIter;
|
typedef struct DEMON_ProcessIter DEMON_ProcessIter;
|
||||||
struct DMN_ProcessIter
|
struct DEMON_ProcessIter
|
||||||
{
|
{
|
||||||
U64 v[2];
|
U64 v[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_ProcessInfo DMN_ProcessInfo;
|
typedef struct DEMON_ProcessInfo DEMON_ProcessInfo;
|
||||||
struct DMN_ProcessInfo
|
struct DEMON_ProcessInfo
|
||||||
{
|
{
|
||||||
String8 name;
|
String8 name;
|
||||||
U32 pid;
|
U32 pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
|
//~ rjf: Main Layer Initialization
|
||||||
|
|
||||||
//- rjf: handles
|
internal void demon_init(void);
|
||||||
internal DMN_Handle dmn_handle_zero(void);
|
|
||||||
internal B32 dmn_handle_match(DMN_Handle a, DMN_Handle b);
|
////////////////////////////////
|
||||||
|
//~ 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
|
//- rjf: trap chunk lists
|
||||||
internal void dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap);
|
internal void demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap);
|
||||||
internal void dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
|
internal void demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push);
|
||||||
internal void dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
|
internal void demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push);
|
||||||
|
|
||||||
//- rjf: handle lists
|
//- rjf: handle lists
|
||||||
internal void dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle);
|
internal void demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle);
|
||||||
internal DMN_HandleArray dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list);
|
internal DEMON_HandleArray demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list);
|
||||||
internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src);
|
internal DEMON_HandleArray demon_handle_array_copy(Arena *arena, DEMON_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)
|
//~ rjf: Primary Thread & Exclusive Mode Controls
|
||||||
|
|
||||||
internal U64 dmn_rip_from_thread(DMN_Handle thread);
|
internal void demon_primary_thread_begin(void);
|
||||||
internal U64 dmn_rsp_from_thread(DMN_Handle thread);
|
internal void demon_exclusive_mode_begin(void);
|
||||||
|
internal void demon_exclusive_mode_end(void);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
|
//~ rjf: Running/Halting
|
||||||
|
|
||||||
internal void dmn_init(void);
|
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: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS)
|
//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting
|
||||||
|
|
||||||
internal DMN_CtrlCtx *dmn_ctrl_begin(void);
|
internal U32 demon_launch_process(OS_LaunchOptions *options);
|
||||||
internal void dmn_ctrl_exclusive_access_begin(void);
|
internal B32 demon_attach_process(U32 pid);
|
||||||
internal void dmn_ctrl_exclusive_access_end(void);
|
internal B32 demon_kill_process(DEMON_Handle process, U32 exit_code);
|
||||||
#define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end())
|
internal B32 demon_detach_process(DEMON_Handle process);
|
||||||
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)
|
//~ rjf: Entity Functions
|
||||||
|
|
||||||
internal void dmn_halt(U64 code, U64 user_data);
|
//- 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: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
|
//~ rjf: Process Listing
|
||||||
|
|
||||||
//- rjf: run/memory/register counters
|
internal void demon_proc_iter_begin(DEMON_ProcessIter *iter);
|
||||||
internal U64 dmn_run_gen(void);
|
internal B32 demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out);
|
||||||
internal U64 dmn_mem_gen(void);
|
internal void demon_proc_iter_end(DEMON_ProcessIter *iter);
|
||||||
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)
|
|
||||||
internal String8 dmn_process_read_cstring(Arena *arena, DMN_Handle process, U64 addr);
|
|
||||||
|
|
||||||
//- 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
|
#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)")`
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#include "demon/demon_core.c"
|
#include "demon_core.c"
|
||||||
|
#include "demon_common.c"
|
||||||
|
#include "demon_accel.c"
|
||||||
|
#include "demon_os.c"
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
# include "demon/win32/demon_core_win32.c"
|
# include "win32/demon_os_win32.c"
|
||||||
#elif OS_LINUX
|
#elif OS_LINUX
|
||||||
# include "demon/linux/demon_core_linux.c"
|
# include "linux/demon_os_linux.c"
|
||||||
#else
|
#else
|
||||||
# error Demon layer backend not defined for this operating system.
|
# error No Demon Implementation for This OS
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,14 +4,17 @@
|
|||||||
#ifndef DEMON_INC_H
|
#ifndef DEMON_INC_H
|
||||||
#define DEMON_INC_H
|
#define DEMON_INC_H
|
||||||
|
|
||||||
#include "demon/demon_core.h"
|
#include "demon_core.h"
|
||||||
|
#include "demon_common.h"
|
||||||
|
#include "demon_accel.h"
|
||||||
|
#include "demon_os.h"
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
# include "demon/win32/demon_core_win32.h"
|
# include "win32/demon_os_win32.h"
|
||||||
#elif OS_LINUX
|
#elif OS_LINUX
|
||||||
# include "demon/linux/demon_core_linux.h"
|
# include "linux/demon_os_linux.h"
|
||||||
#else
|
#else
|
||||||
# error Demon layer backend not defined for this operating system.
|
# error No Demon Implementation for This OS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif //DEMON_INC_H
|
#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
|
|
||||||
@@ -98,7 +98,7 @@ demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid){
|
|||||||
temp_end(restore_point);
|
temp_end(restore_point);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
arena_pop(arena, (cap - size - 1));
|
arena_put_back(arena, (cap - size - 1));
|
||||||
result = str8(buffer, size + 1);
|
result = str8(buffer, size + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,10 +115,10 @@ demon_lnx_open_memory_fd_for_pid(pid_t pid){
|
|||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Arch
|
internal Architecture
|
||||||
demon_lnx_arch_from_pid(pid_t pid){
|
demon_lnx_arch_from_pid(pid_t pid){
|
||||||
Temp scratch = scratch_begin(0, 0);
|
Temp scratch = scratch_begin(0, 0);
|
||||||
Arch result = Arch_Null;
|
Architecture result = Architecture_Null;
|
||||||
|
|
||||||
// exe path
|
// exe path
|
||||||
String8 exe_path = demon_lnx_executable_path_from_pid(scratch.arena, pid);
|
String8 exe_path = demon_lnx_executable_path_from_pid(scratch.arena, pid);
|
||||||
@@ -168,22 +168,22 @@ demon_lnx_arch_from_pid(pid_t pid){
|
|||||||
switch (ehdr.e_machine){
|
switch (ehdr.e_machine){
|
||||||
case SYMS_ElfMachineKind_386:
|
case SYMS_ElfMachineKind_386:
|
||||||
{
|
{
|
||||||
result = Arch_x86;
|
result = Architecture_x86;
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case SYMS_ElfMachineKind_ARM:
|
case SYMS_ElfMachineKind_ARM:
|
||||||
{
|
{
|
||||||
result = Arch_arm32;
|
result = Architecture_arm32;
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case SYMS_ElfMachineKind_X86_64:
|
case SYMS_ElfMachineKind_X86_64:
|
||||||
{
|
{
|
||||||
result = Arch_x64;
|
result = Architecture_x64;
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case SYMS_ElfMachineKind_AARCH64:
|
case SYMS_ElfMachineKind_AARCH64:
|
||||||
{
|
{
|
||||||
result = Arch_arm64;
|
result = Architecture_arm64;
|
||||||
}break;
|
}break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,9 +192,9 @@ demon_lnx_arch_from_pid(pid_t pid){
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal DEMON_LNX_ProcessAux
|
internal DEMON_LNX_ProcessAux
|
||||||
demon_lnx_aux_from_pid(pid_t pid, Arch arch){
|
demon_lnx_aux_from_pid(pid_t pid, Architecture arch){
|
||||||
DEMON_LNX_ProcessAux result = {0};
|
DEMON_LNX_ProcessAux result = {0};
|
||||||
B32 addr_32bit = (arch == Arch_x86 || arch == Arch_arm32);
|
B32 addr_32bit = (arch == Architecture_x86 || arch == Architecture_arm32);
|
||||||
|
|
||||||
// open aux data
|
// open aux data
|
||||||
Temp scratch = scratch_begin(0, 0);
|
Temp scratch = scratch_begin(0, 0);
|
||||||
@@ -300,8 +300,8 @@ demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit, U64 phvaddr, U64 ph
|
|||||||
|
|
||||||
internal DEMON_LNX_ModuleNode*
|
internal DEMON_LNX_ModuleNode*
|
||||||
demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process){
|
demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process){
|
||||||
Arch arch = (Arch)process->arch;
|
Architecture arch = (Architecture)process->arch;
|
||||||
B32 is_32bit = (arch == Arch_x86 || arch == Arch_arm32);
|
B32 is_32bit = (arch == Architecture_x86 || arch == Architecture_arm32);
|
||||||
int memory_fd = (int)process->ext_u64;
|
int memory_fd = (int)process->ext_u64;
|
||||||
|
|
||||||
// aux from pid
|
// aux from pid
|
||||||
@@ -839,11 +839,11 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
U8 *trap_swap_bytes = 0;
|
U8 *trap_swap_bytes = 0;
|
||||||
|
|
||||||
if (result.first == 0){
|
if (result.first == 0){
|
||||||
// TODO(allen): per-Arch implementation of single steps
|
// TODO(allen): per-Architecture implementation of single steps
|
||||||
// set single step bit
|
// set single step bit
|
||||||
if (single_step_thread != 0){
|
if (single_step_thread != 0){
|
||||||
switch (single_step_thread->arch){
|
switch (single_step_thread->arch){
|
||||||
case Arch_x86:
|
case Architecture_x86:
|
||||||
{
|
{
|
||||||
// TODO(allen): possibly buggy
|
// TODO(allen): possibly buggy
|
||||||
SYMS_RegX86 regs = {0};
|
SYMS_RegX86 regs = {0};
|
||||||
@@ -852,7 +852,7 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
demon_os_write_regs_x86(single_step_thread, ®s);
|
demon_os_write_regs_x86(single_step_thread, ®s);
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case Arch_x64:
|
case Architecture_x64:
|
||||||
{
|
{
|
||||||
// TODO(allen): possibly buggy
|
// TODO(allen): possibly buggy
|
||||||
SYMS_RegX64 regs = {0};
|
SYMS_RegX64 regs = {0};
|
||||||
@@ -863,7 +863,7 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(allen): per-Arch implementation of traps
|
// TODO(allen): per-Architecture implementation of traps
|
||||||
trap_swap_bytes = push_array_no_zero(scratch.arena, U8, controls->trap_count);
|
trap_swap_bytes = push_array_no_zero(scratch.arena, U8, controls->trap_count);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -980,13 +980,13 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
union{ SYMS_RegX86 x86; SYMS_RegX64 x64; } regs = {0};
|
union{ SYMS_RegX86 x86; SYMS_RegX64 x64; } regs = {0};
|
||||||
|
|
||||||
switch (thread->arch){
|
switch (thread->arch){
|
||||||
case Arch_x86:
|
case Architecture_x86:
|
||||||
{
|
{
|
||||||
demon_os_read_regs_x86(thread, ®s.x86);
|
demon_os_read_regs_x86(thread, ®s.x86);
|
||||||
instruction_pointer = regs.x86.eip.u32;
|
instruction_pointer = regs.x86.eip.u32;
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case Arch_x64:
|
case Architecture_x64:
|
||||||
{
|
{
|
||||||
demon_os_read_regs_x64(thread, ®s.x64);
|
demon_os_read_regs_x64(thread, ®s.x64);
|
||||||
instruction_pointer = regs.x64.rip.u64;
|
instruction_pointer = regs.x64.rip.u64;
|
||||||
@@ -1052,7 +1052,7 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
// this stuff in the log to make sense of it still.
|
// this stuff in the log to make sense of it still.
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
Arch arch = demon_lnx_arch_from_pid(new_pid);
|
Architecture arch = demon_lnx_arch_from_pid(new_pid);
|
||||||
|
|
||||||
// process entity
|
// process entity
|
||||||
DEMON_Entity *new_process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, new_pid);
|
DEMON_Entity *new_process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, new_pid);
|
||||||
@@ -1105,14 +1105,14 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
if (e_kind == DEMON_EventKind_Breakpoint){
|
if (e_kind == DEMON_EventKind_Breakpoint){
|
||||||
// TODO(allen): possibly buggy
|
// TODO(allen): possibly buggy
|
||||||
switch (thread->arch){
|
switch (thread->arch){
|
||||||
case Arch_x86:
|
case Architecture_x86:
|
||||||
{
|
{
|
||||||
instruction_pointer -= 1;
|
instruction_pointer -= 1;
|
||||||
regs.x86.eip.u32 = instruction_pointer;
|
regs.x86.eip.u32 = instruction_pointer;
|
||||||
demon_os_write_regs_x86(thread, ®s.x86);
|
demon_os_write_regs_x86(thread, ®s.x86);
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case Arch_x64:
|
case Architecture_x64:
|
||||||
{
|
{
|
||||||
instruction_pointer -= 1;
|
instruction_pointer -= 1;
|
||||||
regs.x64.rip.u64 = instruction_pointer;
|
regs.x64.rip.u64 = instruction_pointer;
|
||||||
@@ -1336,7 +1336,7 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
if (did_run){
|
if (did_run){
|
||||||
// TODO(allen): per-Arch
|
// TODO(allen): per-Architecture
|
||||||
// unset traps
|
// unset traps
|
||||||
{
|
{
|
||||||
DEMON_OS_Trap *trap = controls->traps;
|
DEMON_OS_Trap *trap = controls->traps;
|
||||||
@@ -1348,7 +1348,7 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(allen): per-Arch
|
// TODO(allen): per-Architecture
|
||||||
// unset single step bit
|
// unset single step bit
|
||||||
// the single step bit is automatically unset whenever we single step
|
// the single step bit is automatically unset whenever we single step
|
||||||
// but if *something else* happened, it will still be there ready to
|
// but if *something else* happened, it will still be there ready to
|
||||||
@@ -1356,7 +1356,7 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
if (single_step_thread != 0){
|
if (single_step_thread != 0){
|
||||||
// TODO(allen): possibly buggy
|
// TODO(allen): possibly buggy
|
||||||
switch (single_step_thread->arch){
|
switch (single_step_thread->arch){
|
||||||
case Arch_x86:
|
case Architecture_x86:
|
||||||
{
|
{
|
||||||
SYMS_RegX86 regs = {0};
|
SYMS_RegX86 regs = {0};
|
||||||
demon_os_read_regs_x86(single_step_thread, ®s);
|
demon_os_read_regs_x86(single_step_thread, ®s);
|
||||||
@@ -1364,7 +1364,7 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){
|
|||||||
demon_os_write_regs_x86(single_step_thread, ®s);
|
demon_os_write_regs_x86(single_step_thread, ®s);
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case Arch_x64:
|
case Architecture_x64:
|
||||||
{
|
{
|
||||||
SYMS_RegX64 regs = {0};
|
SYMS_RegX64 regs = {0};
|
||||||
demon_os_read_regs_x64(single_step_thread, ®s);
|
demon_os_read_regs_x64(single_step_thread, ®s);
|
||||||
@@ -1555,7 +1555,7 @@ demon_os_launch_process(OS_LaunchOptions *options){
|
|||||||
else{
|
else{
|
||||||
result = pid;
|
result = pid;
|
||||||
|
|
||||||
Arch arch = demon_lnx_arch_from_pid(pid);
|
Architecture arch = demon_lnx_arch_from_pid(pid);
|
||||||
|
|
||||||
// process entity
|
// process entity
|
||||||
DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, pid);
|
DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, pid);
|
||||||
@@ -1688,7 +1688,7 @@ demon_os_attach_process(U32 pid){
|
|||||||
|
|
||||||
// initialize new entities on success
|
// initialize new entities on success
|
||||||
if (result){
|
if (result){
|
||||||
Arch arch = demon_lnx_arch_from_pid(the_process->pid);
|
Architecture arch = demon_lnx_arch_from_pid(the_process->pid);
|
||||||
|
|
||||||
// process entity
|
// process entity
|
||||||
DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, the_process->pid);
|
DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, the_process->pid);
|
||||||
@@ -1816,15 +1816,15 @@ internal U64
|
|||||||
demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread){
|
demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread){
|
||||||
U64 result = 0;
|
U64 result = 0;
|
||||||
switch (thread->arch){
|
switch (thread->arch){
|
||||||
case Arch_x64:
|
case Architecture_x64:
|
||||||
case Arch_x86:
|
case Architecture_x86:
|
||||||
{
|
{
|
||||||
U32 fsbase = 0;
|
U32 fsbase = 0;
|
||||||
pid_t tid = (pid_t)thread->id;
|
pid_t tid = (pid_t)thread->id;
|
||||||
if (ptrace(PT_GETFSBASE, tid, (void*)&fsbase, 0) != -1){
|
if (ptrace(PT_GETFSBASE, tid, (void*)&fsbase, 0) != -1){
|
||||||
result = (U64)fsbase;
|
result = (U64)fsbase;
|
||||||
}
|
}
|
||||||
if (thread->arch == Arch_x64){
|
if (thread->arch == Architecture_x64){
|
||||||
result += 8;
|
result += 8;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|||||||
@@ -198,8 +198,8 @@ internal B32 demon_lnx_attach_pid(Arena *arena, pid_t pid, DEM
|
|||||||
internal String8 demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid);
|
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 int demon_lnx_open_memory_fd_for_pid(pid_t pid);
|
||||||
|
|
||||||
internal Arch demon_lnx_arch_from_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, Arch arch);
|
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,
|
internal DEMON_LNX_PhdrInfo demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit,
|
||||||
U64 phvaddr, U64 phstride, U64 phcount);
|
U64 phvaddr, U64 phstride, U64 phcount);
|
||||||
internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process);
|
internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process);
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef DEBUG_FRONTEND_INC_H
|
||||||
|
#define DEBUG_FRONTEND_INC_H
|
||||||
|
|
||||||
|
#include "df/core/df_core.h"
|
||||||
|
#include "df/gfx/df_gfx.h"
|
||||||
|
#include "df/gfx/df_views.h"
|
||||||
|
#include "df/gfx/df_view_rule_hooks.h"
|
||||||
|
|
||||||
|
#endif // DEBUG_FRONTEND_INC_H
|
||||||
+12081
File diff suppressed because it is too large
Load Diff
+1072
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,723 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Embedded Data
|
||||||
|
|
||||||
|
@embed_file df_g_icon_font_bytes: "../data/icons.ttf"
|
||||||
|
@embed_file df_g_default_main_font_bytes: "../data/Roboto-Regular.ttf"
|
||||||
|
@embed_file df_g_default_code_font_bytes: "../data/liberation-mono.ttf"
|
||||||
|
//@embed_file df_g_default_code_font_bytes: "../data/Inconsolata-Regular.ttf"
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Default Bindings
|
||||||
|
|
||||||
|
@table(name key ctrl shift alt)
|
||||||
|
DF_DefaultBindingTable:
|
||||||
|
{
|
||||||
|
//- rjf: low-level target control operations
|
||||||
|
{ "kill_all" F5 0 shift 0 }
|
||||||
|
{ "step_into_inst" F11 0 0 alt }
|
||||||
|
{ "step_over_inst" F10 0 0 alt }
|
||||||
|
{ "step_out" F11 0 shift 0 }
|
||||||
|
{ "halt" X ctrl shift 0 }
|
||||||
|
{ "halt" Pause 0 0 0 }
|
||||||
|
{ "soft_halt_refresh" R 0 0 alt }
|
||||||
|
|
||||||
|
//- rjf: high-level composite target control operations
|
||||||
|
{ "run" F5 0 0 0 }
|
||||||
|
{ "restart" F5 ctrl shift 0 }
|
||||||
|
{ "step_into" F11 0 0 0 }
|
||||||
|
{ "step_over" F10 0 0 0 }
|
||||||
|
{ "run_to_cursor" F10 ctrl 0 0 }
|
||||||
|
{ "set_next_statement" F10 ctrl shift 0 }
|
||||||
|
|
||||||
|
//- rjf: font sizes
|
||||||
|
{ "inc_ui_font_scale" Equal 0 0 alt }
|
||||||
|
{ "dec_ui_font_scale" Minus 0 0 alt }
|
||||||
|
{ "inc_code_font_scale" Equal 0 shift alt }
|
||||||
|
{ "dec_code_font_scale" Minus 0 shift alt }
|
||||||
|
|
||||||
|
//- rjf: windows
|
||||||
|
{ "window" N ctrl shift 0 }
|
||||||
|
{ "toggle_fullscreen" Return ctrl 0 0 }
|
||||||
|
|
||||||
|
//- rjf: panel splitting
|
||||||
|
{ "new_panel_right" P ctrl 0 0 }
|
||||||
|
{ "new_panel_down" Minus ctrl 0 0 }
|
||||||
|
|
||||||
|
//- rjf: panel rotation
|
||||||
|
{ "rotate_panel_columns" 2 ctrl 0 0 }
|
||||||
|
|
||||||
|
//- rjf: focused panel changing
|
||||||
|
{ "next_panel" Comma ctrl 0 0 }
|
||||||
|
{ "prev_panel" Comma ctrl shift 0 }
|
||||||
|
{ "focus_panel_right" Right ctrl 0 alt }
|
||||||
|
{ "focus_panel_left" Left ctrl 0 alt }
|
||||||
|
{ "focus_panel_up" Up ctrl 0 alt }
|
||||||
|
{ "focus_panel_down" Down ctrl 0 alt }
|
||||||
|
|
||||||
|
//- rjf: undo/redo
|
||||||
|
//{ "undo" Z ctrl 0 0 }
|
||||||
|
//{ "redo" Y ctrl 0 0 }
|
||||||
|
|
||||||
|
//- rjf: focus history
|
||||||
|
//{ "go_back" Left 0 0 alt }
|
||||||
|
//{ "go_forward" Right 0 0 alt }
|
||||||
|
|
||||||
|
//- rjf: panel removal
|
||||||
|
{ "close_panel" P ctrl shift 0 }
|
||||||
|
|
||||||
|
//- rjf: panel tab
|
||||||
|
{ "next_tab" PageDown ctrl 0 0 }
|
||||||
|
{ "prev_tab" PageUp ctrl 0 0 }
|
||||||
|
{ "next_tab" Tab ctrl 0 0 }
|
||||||
|
{ "prev_tab" Tab ctrl shift 0 }
|
||||||
|
{ "move_tab_right" PageDown ctrl shift 0 }
|
||||||
|
{ "move_tab_left" PageUp ctrl shift 0 }
|
||||||
|
{ "close_tab" W ctrl 0 0 }
|
||||||
|
{ "tab_bar_top" Up ctrl shift alt }
|
||||||
|
{ "tab_bar_bottom" Down ctrl shift alt }
|
||||||
|
|
||||||
|
//- rjf: files
|
||||||
|
{ "open" O ctrl 0 0 }
|
||||||
|
{ "reload_active" R ctrl shift 0 }
|
||||||
|
{ "switch" I ctrl 0 0 }
|
||||||
|
{ "switch_to_partner_file" O 0 0 alt }
|
||||||
|
|
||||||
|
//- rjf: setting config paths
|
||||||
|
{ "load_user" O ctrl shift alt }
|
||||||
|
{ "load_profile" O ctrl 0 alt }
|
||||||
|
|
||||||
|
//- rjf: directional movement & text controls
|
||||||
|
{ "move_left" Left 0 0 0 }
|
||||||
|
{ "move_right" Right 0 0 0 }
|
||||||
|
{ "move_up" Up 0 0 0 }
|
||||||
|
{ "move_down" Down 0 0 0 }
|
||||||
|
{ "move_left_select" Left 0 shift 0 }
|
||||||
|
{ "move_right_select" Right 0 shift 0 }
|
||||||
|
{ "move_up_select" Up 0 shift 0 }
|
||||||
|
{ "move_down_select" Down 0 shift 0 }
|
||||||
|
{ "move_left_chunk" Left ctrl 0 0 }
|
||||||
|
{ "move_right_chunk" Right ctrl 0 0 }
|
||||||
|
{ "move_up_chunk" Up ctrl 0 0 }
|
||||||
|
{ "move_down_chunk" Down ctrl 0 0 }
|
||||||
|
{ "move_up_page" PageUp 0 0 0 }
|
||||||
|
{ "move_down_page" PageDown 0 0 0 }
|
||||||
|
{ "move_up_whole" Home ctrl 0 0 }
|
||||||
|
{ "move_down_whole" End ctrl 0 0 }
|
||||||
|
{ "move_left_chunk_select" Left ctrl shift 0 }
|
||||||
|
{ "move_right_chunk_select" Right ctrl shift 0 }
|
||||||
|
{ "move_up_chunk_select" Up ctrl shift 0 }
|
||||||
|
{ "move_down_chunk_select" Down ctrl shift 0 }
|
||||||
|
{ "move_up_page_select" PageUp 0 shift 0 }
|
||||||
|
{ "move_down_page_select" PageDown 0 shift 0 }
|
||||||
|
{ "move_up_whole_select" Home ctrl shift 0 }
|
||||||
|
{ "move_down_whole_select" End ctrl shift 0 }
|
||||||
|
{ "move_home" Home 0 0 0 }
|
||||||
|
{ "move_end" End 0 0 0 }
|
||||||
|
{ "move_home_select" Home 0 shift 0 }
|
||||||
|
{ "move_end_select" End 0 shift 0 }
|
||||||
|
{ "select_all" A ctrl 0 0 }
|
||||||
|
{ "delete_single" Delete 0 0 0 }
|
||||||
|
{ "delete_chunk" Delete ctrl 0 0 }
|
||||||
|
{ "backspace_single" Backspace 0 0 0 }
|
||||||
|
{ "backspace_chunk" Backspace ctrl 0 0 }
|
||||||
|
{ "copy" C ctrl 0 0 }
|
||||||
|
{ "cut" X ctrl 0 0 }
|
||||||
|
{ "paste" V ctrl 0 0 }
|
||||||
|
{ "insert_text" Null 0 0 0 }
|
||||||
|
|
||||||
|
//- rjf: code navigation
|
||||||
|
{ "goto_line" G ctrl 0 0 }
|
||||||
|
{ "goto_address" G 0 0 alt }
|
||||||
|
{ "find_text_forward" F ctrl 0 0 }
|
||||||
|
{ "find_text_backward" R ctrl 0 0 }
|
||||||
|
{ "find_next" F3 0 0 0 }
|
||||||
|
{ "find_prev" F3 shift 0 0 }
|
||||||
|
|
||||||
|
//- rjf: thread finding
|
||||||
|
{ "find_selected_thread" F4 0 0 0 }
|
||||||
|
|
||||||
|
//- rjf: name finding
|
||||||
|
{ "goto_name" J ctrl 0 0 }
|
||||||
|
{ "goto_name_at_cursor" F12 0 0 0 }
|
||||||
|
|
||||||
|
//- rjf: watch expressions
|
||||||
|
{ "toggle_watch_expr_at_cursor" W 0 0 alt }
|
||||||
|
{ "toggle_watch_pin_at_cursor" F9 ctrl 0 0 }
|
||||||
|
|
||||||
|
//- rjf: breakpoints
|
||||||
|
{ "toggle_breakpoint_cursor" F9 0 0 0 }
|
||||||
|
|
||||||
|
//- rjf: targets
|
||||||
|
{ "add_target" T ctrl 0 0 }
|
||||||
|
|
||||||
|
//- rjf: attaching
|
||||||
|
{ "attach" F6 0 shift 0 }
|
||||||
|
|
||||||
|
//- rjf: filtering
|
||||||
|
{ "filter" Slash ctrl 0 0 }
|
||||||
|
|
||||||
|
//- rjf: command lister
|
||||||
|
{ "run_command" F1 0 0 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Binding Version Remap Table
|
||||||
|
|
||||||
|
@table(old_name new_name)
|
||||||
|
DF_BindingVersionRemapTable:
|
||||||
|
{
|
||||||
|
{"commands" "run_command"}
|
||||||
|
{"load_user" "open_user"}
|
||||||
|
{"load_profile" "open_profile"}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Gfx Layer View Kinds
|
||||||
|
|
||||||
|
@table(name, name_lower, display_string, name_kind, icon, parameterized_by_entity, can_serialize, can_serialize_entity_path, can_filter, filter_is_code, typing_automatically_filters, inc_in_docs, docs_desc)
|
||||||
|
DF_GfxViewTable:
|
||||||
|
{
|
||||||
|
{ Null "null" "" Null Null 0 0 0 0 0 0 0 "" }
|
||||||
|
{ Empty "empty" "" Null Null 0 0 0 0 0 0 0 "" }
|
||||||
|
{ Commands "commands" "Commands" Null List 0 0 0 0 0 0 0 "" }
|
||||||
|
{ FileSystem "file_system" "File System" Null FileOutline 0 0 0 0 0 0 0 "" }
|
||||||
|
{ SystemProcesses "system_processes" "System Processes" Null Null 0 0 0 0 0 0 0 "" }
|
||||||
|
{ EntityLister "entity_lister" "Entity List" EntityKindName Null 0 0 0 0 0 0 0 "" }
|
||||||
|
{ SymbolLister "symbol_lister" "Symbols" Null Null 0 0 0 0 0 0 0 "" }
|
||||||
|
{ Target "target" "Target" EntityName Target 1 0 0 0 0 0 0 "" }
|
||||||
|
{ Targets "targets" "Targets" Null Target 0 1 0 1 0 1 1 "Displays a list of all targets, as well as controls for enabling, disabling, launching, editing, or deleting each target. For more information on targets, read the `Targets` section." }
|
||||||
|
{ FilePathMap "file_path_map" "File Path Map" Null FileOutline 0 1 0 0 0 0 1 "Displays a table of *path maps*. Each path map is a pair of file or folder paths, one being a 'source' path, and one being a 'destination' path. These pairs are used by the debugger when automatically searching for specific files - for instance, when attempting to snap to a source code location specified by debug info. If debug info refers to a path on the machine on which a target executable was originally built, but that path is not valid on the debugger machine, but some alternative path exists, then path maps may be used to redirect the debugger from the debug info's specified paths to the associated appropriate debugger machine file paths." }
|
||||||
|
{ Scheduler "scheduler" "Scheduler" Null Scheduler 0 1 0 1 1 1 1 "Displays all processes and threads to which the debugger is currently attached, and contains controls for selecting and freezing threads." }
|
||||||
|
{ CallStack "call_stack" "Call Stack" Null Thread 0 1 0 0 0 0 1 "Displays the call stack of the currently selected thread. Each frame in the call stack contains the associated module, function name, and return address. Allows selection of a particular call stack frame other than the top." }
|
||||||
|
{ Modules "modules" "Modules" Null Module 0 1 0 1 0 1 1 "Displays a table of all modules currently loaded by any process to which the debugger is attached. This table displays each module's name, virtual address range in the containing process' address space, and which debug info file is being used by the debugger for the associated module." }
|
||||||
|
{ PendingEntity "pending_entity" "Pending Entity" EntityName FileOutline 1 0 0 0 0 0 0 "" }
|
||||||
|
{ Code "code" "Code" EntityName FileOutline 1 1 1 0 0 0 0 "" }
|
||||||
|
{ Disassembly "disassembly" "Disassembly" Null Glasses 0 1 0 0 0 0 1 "Displays disassembled instructions in a textual form from the selected thread's containing process virtual address space." }
|
||||||
|
{ Watch "watch" "Watch" Null Binoculars 0 1 0 1 1 1 1 "The familiar 'watch window' debugger interface. Allows the inputting of a number of expressions. Each expression in the table is evaluated within the context of the selected thread's selected call stack frame. If applicable (depending on visualization rules and the expression's type), these expressions may be hierarchically expanded, which displays children as more rows in the table. The values of these expressions may also be edited, and if possible, can be used to write to registers or memory in attached processes. Also contains a new *view rule* column, not found in other major debuggers, which allows per-row specification of various visualization rules. These view rules may be used to visualize and inspect the evaluation of expressions in a variety of ways. To learn more, read the 'View Rules' section." }
|
||||||
|
{ Locals "locals" "Locals" Null Binoculars 0 1 0 1 1 1 1 "Nearly identical to `Watch`, but automatically filled with local variables found within the selected call stack frame of the selected thread, according to the associated debug info. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." }
|
||||||
|
{ Registers "registers" "Registers" Null Binoculars 0 1 0 1 1 1 1 "Nearly identical to `Watch`, but automatically filled with all register names according to the selected thread's architecture. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." }
|
||||||
|
{ Globals "globals" "Globals" Null Binoculars 0 1 0 1 1 1 1 "Nearly identical to `Watch`, but automatically filled with all global variables within the selected thread's module. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." }
|
||||||
|
{ ThreadLocals "thread_locals" "Thread Locals" Null Binoculars 0 1 0 1 1 1 1 "Nearly identical to `Watch`, but automatically filled with all thread local variables within the selected thread's module. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." }
|
||||||
|
{ Types "types" "Types" Null Binoculars 0 1 0 1 1 1 1 "Nearly identical to `Watch`, but automatically filled with all types within the selected thread's module. View rules can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." }
|
||||||
|
{ Procedures "procedures" "Procedures" Null Binoculars 0 1 0 1 1 1 1 "Nearly identical to `Watch`, but automatically filled with all procedures within the selected thread's module. View rules can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." }
|
||||||
|
{ Output "output" "Output" Null List 0 1 0 0 0 0 1 "Displays textual output from the selected thread's containing process." }
|
||||||
|
{ Memory "memory" "Memory" Null Grid 0 1 1 0 0 0 1 "A familiar hex-editor-like interface for viewing memory of attached processes." }
|
||||||
|
{ Breakpoints "breakpoints" "Breakpoints" Null CircleFilled 0 1 0 1 0 1 1 "Displays a table of all breakpoints, containing information about each breakpoint's name, location, and hit count. Also contains per-breakpoint controls for enabling, deleting, or editing each breakpoint. For more information on breakpoints and their features, read the 'Breakpoints' section." }
|
||||||
|
{ WatchPins "watch_pins" "Watch Pins" Null Pin 0 1 0 1 1 1 1 "Displays a table of all watch pins (watched expressions, like those found in `Watch`, but instead of being within a table, being pinned to some source code location, like breakpoints). This table contains each pin's name, location, and controls for editing or deleting each pin." }
|
||||||
|
{ ExceptionFilters "exception_filters" "Exception Filters" Null Gear 0 1 0 1 0 1 1 "An interface which controls whether or not the debugger will halt attached processes upon encountering specific exception codes for the first time." }
|
||||||
|
{ Theme "theme" "Theme" Null Palette 0 1 0 0 0 0 1 "An interface for modifying the colors used in the debugger's UI. Allows selecting a theme preset, loading a theme from a file, and modifying individual colors within a theme." }
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Command Parameter Slot -> View
|
||||||
|
|
||||||
|
@table(slot view_spec opt_cmd_spec)
|
||||||
|
DF_CmdParamSlot2ViewSpecMap:
|
||||||
|
{
|
||||||
|
{Entity "entity_lister" "" }
|
||||||
|
{EntityList "entity_lister" "" }
|
||||||
|
{FilePath "file_system" "" }
|
||||||
|
{CmdSpec "commands" "" }
|
||||||
|
{ID "system_processes" "" }
|
||||||
|
{String "symbol_lister" "goto_name" }
|
||||||
|
{String "symbol_lister" "function_breakpoint" }
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Built-In Graphical View Rule Extensions
|
||||||
|
//
|
||||||
|
// NOTE(rjf): see @view_rule_info
|
||||||
|
|
||||||
|
@table(string vr ls ru bu)
|
||||||
|
DF_GfxViewRuleTable:
|
||||||
|
{
|
||||||
|
{"array" - - - -}
|
||||||
|
{"list" x - - -}
|
||||||
|
{"dec" - x - -}
|
||||||
|
{"bin" - x - -}
|
||||||
|
{"oct" - x - -}
|
||||||
|
{"hex" - x - -}
|
||||||
|
{"only" x x - -}
|
||||||
|
{"omit" x x - -}
|
||||||
|
{"no_addr" - x - -}
|
||||||
|
{"rgba" - - x x}
|
||||||
|
{"text" - - - x}
|
||||||
|
{"disasm" - - - x}
|
||||||
|
{"bitmap" - - x x}
|
||||||
|
{"geo" - - x x}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Theme Color Codes
|
||||||
|
|
||||||
|
@table(name display_name name_lower)
|
||||||
|
DF_ThemeTable:
|
||||||
|
{
|
||||||
|
{Null "Null" null }
|
||||||
|
{PlainText "Plain Text" plain_text }
|
||||||
|
{PlainBackground "Plain Background" plain_background }
|
||||||
|
{PlainBorder "Plain Border" plain_border }
|
||||||
|
{PlainOverlay "Plain Overlay" plain_overlay }
|
||||||
|
{CodeDefault "Code (Default)" code_default }
|
||||||
|
{CodeFunction "Code (Function)" code_function }
|
||||||
|
{CodeType "Code (Type)" code_type }
|
||||||
|
{CodeLocal "Code (Local)" code_local }
|
||||||
|
{CodeKeyword "Code (Keyword)" code_keyword }
|
||||||
|
{CodeSymbol "Code (Symbol)" code_symbol }
|
||||||
|
{CodeNumeric "Code (Numeric)" code_numeric }
|
||||||
|
{CodeString "Code (String)" code_string }
|
||||||
|
{CodeMeta "Code (Meta)" code_meta }
|
||||||
|
{CodeComment "Code (Comment)" code_comment }
|
||||||
|
{LineInfo0 "Line Info (0)" line_info_0 }
|
||||||
|
{LineInfo1 "Line Info (1)" line_info_1 }
|
||||||
|
{LineInfo2 "Line Info (2)" line_info_2 }
|
||||||
|
{LineInfo3 "Line Info (3)" line_info_3 }
|
||||||
|
{AltText "Alt Text" alt_text }
|
||||||
|
{AltBackground "Alt Background" alt_background }
|
||||||
|
{AltBorder "Alt Border" alt_border }
|
||||||
|
{AltOverlay "Alt Overlay" alt_overlay }
|
||||||
|
{TabInactive "Inactive Tab" tab_inactive }
|
||||||
|
{TabActive "Active Tab" tab_active }
|
||||||
|
{EntityBackground "Entity Background" entity_background }
|
||||||
|
{QueryBar "Query Bar" query_bar }
|
||||||
|
{WeakText "Weak Text" weak_text }
|
||||||
|
{TextSelection "Text Selection" text_selection }
|
||||||
|
{Cursor "Cursor" cursor }
|
||||||
|
{Highlight0 "Highlight (0)" highlight_0 }
|
||||||
|
{Highlight1 "Highlight (1)" highlight_1 }
|
||||||
|
{SuccessText "Success Text" success_text }
|
||||||
|
{SuccessBackground "Success Background" success_background }
|
||||||
|
{SuccessBorder "Success Border" success_border }
|
||||||
|
{FailureText "Failure Text" failure_text }
|
||||||
|
{FailureBackground "Failure Background" failure_background }
|
||||||
|
{FailureBorder "Failure Border" failure_border }
|
||||||
|
{ActionText "Action Text" action_text }
|
||||||
|
{ActionBackground "Action Background" action_background }
|
||||||
|
{ActionBorder "Action Border" action_border }
|
||||||
|
{DropSiteOverlay "Drop Site Overlay" drop_site_overlay }
|
||||||
|
{Thread0 "Thread (0)" thread_0 }
|
||||||
|
{Thread1 "Thread (1)" thread_1 }
|
||||||
|
{Thread2 "Thread (2)" thread_2 }
|
||||||
|
{Thread3 "Thread (3)" thread_3 }
|
||||||
|
{Thread4 "Thread (4)" thread_4 }
|
||||||
|
{Thread5 "Thread (5)" thread_5 }
|
||||||
|
{Thread6 "Thread (6)" thread_6 }
|
||||||
|
{Thread7 "Thread (7)" thread_7 }
|
||||||
|
{ThreadUnwound "Thread (Unwound)" thread_unwound }
|
||||||
|
{InactivePanelOverlay "Inactive Panel Overlay" inactive_panel_overlay }
|
||||||
|
{DropShadow "Drop Shadow" drop_shadow }
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Theme Color Version Remap Table
|
||||||
|
|
||||||
|
@table(old_name new_name)
|
||||||
|
DF_ThemeColorVersionRemapTable:
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Theme Presets
|
||||||
|
|
||||||
|
@table(name_upper name_lower display_string)
|
||||||
|
DF_ThemePresetTable:
|
||||||
|
{
|
||||||
|
{ DefaultDark default_dark "Default (Dark)" }
|
||||||
|
{ DefaultLight default_light "Default (Light)" }
|
||||||
|
{ VSDark vs_dark "VS (Dark)" }
|
||||||
|
{ VSLight vs_light "VS (Light)" }
|
||||||
|
{ SolarizedDark solarized_dark "Solarized (Dark)" }
|
||||||
|
{ SolarizedLight solarized_light "Solarized (Light)" }
|
||||||
|
{ HandmadeHero handmade_hero "Handmade Hero" }
|
||||||
|
{ FourCoder four_coder "4coder" }
|
||||||
|
{ FarManager far_manager "Far Manager" }
|
||||||
|
}
|
||||||
|
|
||||||
|
@table(name default_dark default_light vs_dark vs_light solarized_dark solarized_light handmade_hero four_coder far_manager)
|
||||||
|
DF_ThemePresetColorTable:
|
||||||
|
{
|
||||||
|
(null 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff )
|
||||||
|
(plain_text 0xe5e5e5ff 0x383838ff 0xe5e5e5ff 0x1e1e1eff 0xe5e5e5ff 0x1e1e1eff 0xa08563ff 0x90b080ff 0x00ffffff )
|
||||||
|
(plain_background 0x3333337f 0xedededfe 0x1e1e1eff 0xffffffff 0x002b36ff 0xfcf6e2ff 0x0c0c0cff 0x0c0c0cff 0x000082ff )
|
||||||
|
(plain_border 0xffffff19 0x0000001d 0xffffff19 0xcccedb1d 0xffffff19 0xcccedb1d 0xffffff19 0x181818a0 0xffffff19 )
|
||||||
|
(plain_overlay 0xffffff33 0x00000033 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 )
|
||||||
|
(code_default 0xe5e5e5ff 0x282828ff 0xd4d4d4ff 0x000000ff 0x839496ff 0x74878cff 0xa08563ff 0x90b080ff 0x00ffffff )
|
||||||
|
(code_function 0x7fcc99ff 0x2a7a45ff 0xdcdcaaff 0x74531fff 0x1c7dd1ff 0xc39d36ff 0xcc5735ff 0x7fcc99ff 0x49b2ffff )
|
||||||
|
(code_type 0x66b2e5ff 0x2c688fff 0x4ec9b0ff 0x2b91afff 0x1c7dd1ff 0x66b2e5ff 0xd8a51dff 0x66b2e5ff 0x49b2ffff )
|
||||||
|
(code_local 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff )
|
||||||
|
(code_keyword 0xf7bf5eff 0xa47729ff 0x569cd6ff 0x0000ffff 0x63980fff 0xc39d36ff 0xac7b0bff 0xd08f20ff 0xff0000ff )
|
||||||
|
(code_symbol 0x994c32ff 0x6c2d18ff 0xb4b4b4ff 0x000000ff 0x839496ff 0x2e5256ff 0x994c32ff 0x994c32ff 0xffffffff )
|
||||||
|
(code_numeric 0x4ce54cff 0x2c7d2cff 0xb5cea8ff 0x000000ff 0xcb4b20ff 0x657b83ff 0x6b8e23ff 0x50ff30ff 0x2cff50ff )
|
||||||
|
(code_string 0xe5cc66ff 0xcc5a0fff 0xd69d85ff 0xc11515ff 0x2aa198ff 0x5ab4a9ff 0x6b8e23ff 0x50ff30ff 0xe5cc66ff )
|
||||||
|
(code_meta 0xe54c4cff 0x8a0c0cff 0x9b9b9bff 0x808080ff 0xe54c4cff 0xe54c4cff 0xdab98fff 0x50ff30ff 0xffff00ff )
|
||||||
|
(code_comment 0x7f7f7fff 0x7f7f7fff 0x6a9955ff 0x008000ff 0x7f7f7fff 0xadafb2ff 0x686868ff 0x2090f0ff 0x7f7f7fff )
|
||||||
|
(line_info_0 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f )
|
||||||
|
(line_info_1 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f )
|
||||||
|
(line_info_2 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f )
|
||||||
|
(line_info_3 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f )
|
||||||
|
(alt_text 0xe5e5e5ff 0x535353ff 0xf1f1f1ff 0x535353ff 0xe5e5e5ff 0x535353ff 0xa08563ff 0x90b080ff 0x000000ff )
|
||||||
|
(alt_background 0x42474c7f 0xfefefebc 0x1b1b1cff 0xfefefebc 0x002b36ff 0xfcf6e2ff 0x0c0c0cff 0x0c0c0cff 0x008184ff )
|
||||||
|
(alt_border 0xffffff19 0xffffff19 0x333337ff 0xffffff19 0xffffff19 0xffffff19 0xffffff19 0xffffff19 0xffffff19 )
|
||||||
|
(alt_overlay 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 )
|
||||||
|
(tab_inactive 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f )
|
||||||
|
(tab_active 0xa87a4c99 0xc7a27dff 0x007accff 0x007accff 0x28515eff 0xa87a4c99 0xa87a4c99 0xa87a4c99 0xa87a4c99 )
|
||||||
|
(entity_background 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 )
|
||||||
|
(query_bar 0x8e2d4ccc 0xd76489cc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc )
|
||||||
|
(weak_text 0xffffff7f 0x0000007f 0xffffff7f 0x0000007f 0xffffff7f 0x0000007f 0xa08563af 0x90b080af 0xffffff7f )
|
||||||
|
(text_selection 0x99ccff4c 0x7d98b34c 0x99ccff4c 0x7d98b34c 0x99ccff4c 0x7d98b34c 0x99ccff4c 0x99ccff4c 0x99ccff4c )
|
||||||
|
(cursor 0x66e566e5 0x101010ff 0x66e566e5 0x101010ff 0x66e566e5 0x101010ff 0x66e566e5 0x66e566e5 0x66e566e5 )
|
||||||
|
(highlight_0 0xb27219ff 0xb272189b 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff )
|
||||||
|
(highlight_1 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff )
|
||||||
|
(success_text 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff )
|
||||||
|
(success_background 0x32b219ff 0x75db61ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff )
|
||||||
|
(success_border 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 )
|
||||||
|
(failure_text 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff )
|
||||||
|
(failure_background 0xb23219ff 0xf27961ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff )
|
||||||
|
(failure_border 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 )
|
||||||
|
(action_text 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff )
|
||||||
|
(action_background 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff )
|
||||||
|
(action_border 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 )
|
||||||
|
(drop_site_overlay 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c )
|
||||||
|
(thread_0 0xffcb7fff 0xad7c34ff 0xffcb7fff 0xad7c34ff 0xffcb7fff 0xad7c34ff 0xffcb7fff 0xffcb7fff 0xffcb7fff )
|
||||||
|
(thread_1 0xb2ff65ff 0x639b2aff 0xb2ff65ff 0x639b2aff 0xb2ff65ff 0x639b2aff 0xb2ff65ff 0xb2ff65ff 0xb2ff65ff )
|
||||||
|
(thread_2 0xff99e5ff 0xa94c91ff 0xff99e5ff 0xa94c91ff 0xff99e5ff 0xa94c91ff 0xff99e5ff 0xff99e5ff 0xff99e5ff )
|
||||||
|
(thread_3 0x6598ffff 0x305398ff 0x6598ffff 0x305398ff 0x6598ffff 0x305398ff 0x6598ffff 0x6598ffff 0x6598ffff )
|
||||||
|
(thread_4 0x65ffcbff 0x339574ff 0x65ffcbff 0x339574ff 0x65ffcbff 0x339574ff 0x65ffcbff 0x65ffcbff 0x65ffcbff )
|
||||||
|
(thread_5 0xff9819ff 0xbf7416ff 0xff9819ff 0xbf7416ff 0xff9819ff 0xbf7416ff 0xff9819ff 0xff9819ff 0xff9819ff )
|
||||||
|
(thread_6 0x9932ffff 0x57238bff 0x9932ffff 0x57238bff 0x9932ffff 0x57238bff 0x9932ffff 0x9932ffff 0x9932ffff )
|
||||||
|
(thread_7 0x65ff4cff 0x2a7e1cff 0x65ff4cff 0x2a7e1cff 0x65ff4cff 0x2a7e1cff 0x65ff4cff 0x65ff4cff 0x65ff4cff )
|
||||||
|
(thread_unwound 0xb2ccd8ff 0x236481ff 0xb2ccd8ff 0x236481ff 0xb2ccd8ff 0x236481ff 0xb2ccd8ff 0xb2ccd8ff 0xb2ccd8ff )
|
||||||
|
(inactive_panel_overlay 0x0000003f 0x0000000d 0x0000003f 0x0000000d 0x0000003f 0x0000000d 0x0000003f 0x0000003f 0x0000003f )
|
||||||
|
(drop_shadow 0x0000007f 0x0000003b 0x0000007f 0x0000003b 0x0000007f 0x0000003b 0x0000007f 0x0000007f 0x0000007f )
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Generators
|
||||||
|
|
||||||
|
//- rjf: enums
|
||||||
|
|
||||||
|
@table_gen_enum
|
||||||
|
DF_GfxViewKind:
|
||||||
|
{
|
||||||
|
@expand(DF_GfxViewTable a)
|
||||||
|
`DF_GfxViewKind_$(a.name),`
|
||||||
|
`DF_GfxViewKind_COUNT`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_enum
|
||||||
|
DF_ThemeColor:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemeTable, a)
|
||||||
|
`DF_ThemeColor_$(a.name),`;
|
||||||
|
`DF_ThemeColor_COUNT`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_enum
|
||||||
|
DF_ThemePreset:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetTable a)
|
||||||
|
`DF_ThemePreset_$(a.name),`;
|
||||||
|
`DF_ThemePreset_COUNT`;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: theme preset color tables
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback: `{0}`)
|
||||||
|
df_g_theme_preset_display_string_table:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetTable a) `str8_lit_comp("$(a.display_string)"),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback: `{0}`)
|
||||||
|
df_g_theme_preset_code_string_table:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetTable a) `str8_lit_comp("$(a.name_lower)"),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__default_dark:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_dark)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__default_light:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_light)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__vs_dark:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_dark)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__vs_light:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_light)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__solarized_dark:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_dark)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__solarized_light:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_light)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__handmade_hero:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.handmade_hero)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__four_coder:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.four_coder)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`)
|
||||||
|
df_g_theme_preset_colors__far_manager:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.far_manager)),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: `Vec4F32 *`, fallback: `0`)
|
||||||
|
df_g_theme_preset_colors_table:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemePresetTable a) `df_g_theme_preset_colors__$(a.name_lower),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: cmd param slot -> view spec tables
|
||||||
|
|
||||||
|
@table_gen_data(type: DF_CmdParamSlot, fallback:`DF_CmdParamSlot_Null`)
|
||||||
|
df_g_cmd_param_slot_2_view_spec_src_map:
|
||||||
|
{
|
||||||
|
@expand(DF_CmdParamSlot2ViewSpecMap a) `DF_CmdParamSlot_$(a.slot),`
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback:`{0}`)
|
||||||
|
df_g_cmd_param_slot_2_view_spec_dst_map:
|
||||||
|
{
|
||||||
|
@expand(DF_CmdParamSlot2ViewSpecMap a) `str8_lit_comp("$(a.view_spec)"),`
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback:`{0}`)
|
||||||
|
df_g_cmd_param_slot_2_view_spec_cmd_map:
|
||||||
|
{
|
||||||
|
@expand(DF_CmdParamSlot2ViewSpecMap a) `str8_lit_comp("$(a.opt_cmd_spec)"),`
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: default bindings table
|
||||||
|
|
||||||
|
@table_gen_data(type: DF_StringBindingPair, fallback: `{0}`)
|
||||||
|
df_g_default_binding_table:
|
||||||
|
{
|
||||||
|
@expand(DF_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_EventFlag_Ctrl`) $(a.shift != 0 -> `|OS_EventFlag_Shift`) $(a.alt != 0 -> `|OS_EventFlag_Alt`)}},```;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: binding version remap tables
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback: `{0}`)
|
||||||
|
df_g_binding_version_remap_old_name_table:
|
||||||
|
{
|
||||||
|
@expand(DF_BindingVersionRemapTable a) `str8_lit_comp("$(a.old_name)"),`
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback: `{0}`)
|
||||||
|
df_g_binding_version_remap_new_name_table:
|
||||||
|
{
|
||||||
|
@expand(DF_BindingVersionRemapTable a) `str8_lit_comp("$(a.new_name)"),`
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: view hook forward declares
|
||||||
|
|
||||||
|
@table_gen
|
||||||
|
{
|
||||||
|
@expand(DF_GfxViewTable a) `DF_VIEW_SETUP_FUNCTION_DEF($(a.name));`;
|
||||||
|
@expand(DF_GfxViewTable a) `DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF($(a.name));`;
|
||||||
|
@expand(DF_GfxViewTable a) `DF_VIEW_CMD_FUNCTION_DEF($(a.name));`;
|
||||||
|
@expand(DF_GfxViewTable a) `DF_VIEW_UI_FUNCTION_DEF($(a.name));`;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: gfx view rule function forward declares
|
||||||
|
|
||||||
|
@table_gen
|
||||||
|
{
|
||||||
|
``;
|
||||||
|
@expand(DF_GfxViewRuleTable a)
|
||||||
|
`$(a.vr == "x" -> "DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(" .. a.name_lower .. ");")`;
|
||||||
|
@expand(DF_GfxViewRuleTable a)
|
||||||
|
`$(a.ls == "x" -> "DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(" .. a.name_lower .. ");")`;
|
||||||
|
@expand(DF_GfxViewRuleTable a)
|
||||||
|
`$(a.ru == "x" -> "DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(" .. a.name_lower .. ");")`;
|
||||||
|
@expand(DF_GfxViewRuleTable a)
|
||||||
|
`$(a.bu == "x" -> "DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(" .. a.name_lower .. ");")`;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: gfx view rule tables
|
||||||
|
|
||||||
|
@table_gen_data(type: DF_GfxViewRuleSpecInfo, fallback: `{0}`) @c_file
|
||||||
|
df_g_gfx_view_rule_spec_info_table:
|
||||||
|
{
|
||||||
|
@expand(DF_GfxViewRuleTable a)
|
||||||
|
```{ str8_lit_comp("$(a.string)"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*$(a.vr == "x"))|(DF_GfxViewRuleSpecInfoFlag_LineStringize*$(a.ls == "x"))|(DF_GfxViewRuleSpecInfoFlag_RowUI*$(a.ru == "x"))|(DF_GfxViewRuleSpecInfoFlag_BlockUI*$(a.bu == "x")), $(a.vr == "x" -> "DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vr != "x" -> 0), $(a.ls == "x" -> "DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME("..a.name_lower..")") $(a.ls != "x" -> 0), $(a.ru == "x" -> "DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME("..a.name_lower..")") $(a.ru != "x" -> 0), $(a.bu == "x" -> "DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME("..a.name_lower..")") $(a.bu != "x" -> 0), },```;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: default view spec info table
|
||||||
|
|
||||||
|
@table_gen_data(type: DF_ViewSpecInfo, fallback: `{0}`)
|
||||||
|
df_g_gfx_view_kind_spec_info_table:
|
||||||
|
{
|
||||||
|
@expand(DF_GfxViewTable a) ```{(0|$(a.parameterized_by_entity)*DF_ViewSpecFlag_ParameterizedByEntity|$(a.can_serialize)*DF_ViewSpecFlag_CanSerialize|$(a.can_serialize_entity_path)*DF_ViewSpecFlag_CanSerializeEntityPath|$(a.can_filter)*DF_ViewSpecFlag_CanFilter|$(a.filter_is_code)*DF_ViewSpecFlag_FilterIsCode|$(a.typing_automatically_filters)*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("$(a.name_lower)"), str8_lit_comp("$(a.display_string)"), DF_NameKind_$(a.name_kind), DF_IconKind_$(a.icon), DF_VIEW_SETUP_FUNCTION_NAME($(a.name)), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME($(a.name)), DF_VIEW_CMD_FUNCTION_NAME($(a.name)), DF_VIEW_UI_FUNCTION_NAME($(a.name))},```;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: theme color tables
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback: `str8_lit_comp("")`)
|
||||||
|
df_g_theme_color_display_string_table:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemeTable a) `str8_lit_comp("$(a.display_name)"),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@table_gen_data(type: String8, fallback: `str8_lit_comp("")`)
|
||||||
|
df_g_theme_color_cfg_string_table:
|
||||||
|
{
|
||||||
|
@expand(DF_ThemeTable a) `str8_lit_comp("$(a.name_lower)"),`;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Help/Docs/README
|
||||||
|
|
||||||
|
@markdown
|
||||||
|
raddbg_readme:
|
||||||
|
{
|
||||||
|
@title "The RAD Debugger (ALPHA)";
|
||||||
|
@p "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.";
|
||||||
|
|
||||||
|
@subtitle "Getting Started";
|
||||||
|
@p "To launch the RAD Debugger with your executable and command line arguments, run `raddbg` from the command line like so:";
|
||||||
|
@p "```raddbg my_program.exe --foo --bar --baz```";
|
||||||
|
@p "For more information, see the 'Command-Line Usage' section.";
|
||||||
|
@p "Default keyboard shortcuts for common debugger controls include:";
|
||||||
|
@unordered_list
|
||||||
|
{
|
||||||
|
@p "**Ctrl + O**: Open Source Code File";
|
||||||
|
@p "**F10**: Step Over";
|
||||||
|
@p "**F11**: Step Into";
|
||||||
|
@p "**Shift + F11**: Step Out";
|
||||||
|
@p "**F5**: Run";
|
||||||
|
@p "**Ctrl + Shift + X**, or **Pause**: Halt All Processes";
|
||||||
|
@p "**Shift + F5**: Kill All Processes";
|
||||||
|
@p "**Shift + F6**: Attach To Process";
|
||||||
|
@p "**Ctrl + F**: Search For Text (Forwards)";
|
||||||
|
@p "**F9**: Toggle Breakpoint At Cursor";
|
||||||
|
@p "**Ctrl + Comma**: Focus Next Panel";
|
||||||
|
@p "**Ctrl + Shift + Comma**: Focus Previous Panel";
|
||||||
|
@p "**Ctrl + Shift + Alt + Arrow Key**: Focus Panel In Direction";
|
||||||
|
@p "**Ctrl + Tab**: Focus Next Tab";
|
||||||
|
@p "**Ctrl + Shift + Tab**: Focus Previous Tab";
|
||||||
|
@p "**Ctrl + W**: Close Tab";
|
||||||
|
@p "**F1**: Open Command Palette";
|
||||||
|
}
|
||||||
|
@p "For more information, see the 'Commands' section.";
|
||||||
|
@p "View rules can be used to visualize expressions differently in the watch window. Here are some examples:";
|
||||||
|
@unordered_list
|
||||||
|
{
|
||||||
|
@p "`array:16`: Visualize a pointer as pointing to a 16-element array.";
|
||||||
|
@p "`array:(count*2)`: Visualize a pointer as pointing to a `count*2`-element array.";
|
||||||
|
@p "`list:next`: Visualize a linked list flatly, where each node has a `next` pointer, which points to the next node in the list.";
|
||||||
|
@p "`hex`: Visualize numeric literals as base-16 (hexadecimal).";
|
||||||
|
@p "`dec`: Visualize numeric literals as base-10 (decimal).";
|
||||||
|
@p "`oct`: Visualize numeric literals as base-8 (octal).";
|
||||||
|
@p "`bin`: Visualize numeric literals as base-2 (binary).";
|
||||||
|
@p "`omit:(foo bar baz)`: Prohibits members named `foo`, `bar`, and `baz` from being displayed.";
|
||||||
|
@p "`only:(foo bar baz)`: Only allows members named `foo`, `bar`, and `baz` to be displayed.";
|
||||||
|
}
|
||||||
|
@p "Multiple view rules can be specified on one line, so they can be combined like so:";
|
||||||
|
@p "```list:next, hex, omit:next```";
|
||||||
|
@p "For more information, see the 'View Rules' section.";
|
||||||
|
|
||||||
|
@subtitle "Command-Line Usage";
|
||||||
|
@p "When run normally, either by launching through a file explorer or running from a command line without arguments, `raddbg` will open a new instance of the debugger. But it also supports a number of command line options for a number of other purposes. These options are specified with a `-` or `--` prefix, followed by the name of the option, and if the option requires a parameter, followed by a `:` or `=`, followed by the parameter's content. A list of the possible options follows:";
|
||||||
|
@unordered_list
|
||||||
|
{
|
||||||
|
@p "`--help` Displays a help menu which documents the possible command line options.";
|
||||||
|
@p "`--user:<path>` Specifies a path to the user file which the debugger should use instead of the default. The default user file is stored at `%appdata%/raddbg/default.raddbg_user`. For more information on user files, read the 'User & Profile Files' section.";
|
||||||
|
@p "`--profile:<path>` Specifies a path to the profile file which the debugger should use instead of the default. The default profile file is stored at `%appdata%/raddbg/default.raddbg_profile`. For more information on profile files, read the 'User & Profile Files' section.";
|
||||||
|
@p "`--auto_run` Specifies that the debugger should immediately run its selected targets upon launching.";
|
||||||
|
@p "`--auto_step` Specifies that the debugger should immediately step into its selected targets upon launching.";
|
||||||
|
//@p "`--ipc` Specifies that the launched debugger instance is for communicating a command to another instance of the debugger. In this mode, any non-argument command line contents will be used to express a command. For more information on commands, read the 'Commands' section. For more information on driving another debugger instance with this argument, read the 'Driving Another Debugger Instance' section."
|
||||||
|
}
|
||||||
|
@p "On the command line, non-options (meaning any command line arguments *not* prefixed with a `-` or `--`) can also be specified. with normal usage, they are interpreted as the command line for a target (see the 'Targets' section)."
|
||||||
|
// add when --ipc support is ready: "When driving another debugger instance (using the `--ipc` argument), this additional command line text is used to encode a debugger command.";
|
||||||
|
@p "The debugger will stop parsing `-` and `--` prefixes as arguments after seeing a standalone `--`, *or* after seeing the first non-option argument, when reading the command line left-to-right. Some examples of command line usage and their interpretations are below:";
|
||||||
|
@unordered_list
|
||||||
|
{
|
||||||
|
@p "`raddbg --foo --bar --a:b --c=d test.exe` All options are used to configure `raddbg`. `test.exe` is interpreted as a target executable. `b` is interpreted as the parameter for the `a` option. `d` is interpreted as the parameter for the `c` option.";
|
||||||
|
@p "`raddbg test.exe --foo --bar` `test.exe` is interpreted as a target executable. `--foo --bar` is interpreted as arguments for `test.exe`, and thus are *not* used to configure `raddbg`.";
|
||||||
|
@p "`raddbg -- test.exe` `test.exe` is interpreted as a target executable.";
|
||||||
|
//@p "`raddbg --ipc find_code_location \"c:/foo/bar/baz.c:123:1\"` `--ipc` configures `raddbg` to drive another instance of `raddbg`. The remainder of the text is interpreted as a command.";
|
||||||
|
@p "`raddbg \"C:/path with spaces/test.exe\" --foo --bar` A target is formed from the `test.exe` path, and `--foo --bar` are interpreted as arguments to the `test.exe` target.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@subtitle "Windows, Panels, & Tabs";
|
||||||
|
@p "Each opened *window* in the debugger frontend is subdivided into *panels*. Panels subdivide regions of their window without overlapping. Each panel can contain multiple *tabs*, and can have one tab selected at any time. Tabs can be dragged and dropped between panels. Each tab is used to view one of the many supported debugger interfaces, including source code, disassembly, memory, or watches. When a tab is selected, that interface will fill the tab's containing panel's region of the containing window.";
|
||||||
|
@p "There are no 'special' windows, panels, or tabs; the debugger is written such that the number of windows, each window's panel organization, and the placement and arrangement of tabs can all be organized in a large variety of ways.";
|
||||||
|
@p "A list of debugger interfaces, which can occupy tabs, are below:";
|
||||||
|
@unordered_list
|
||||||
|
{
|
||||||
|
@expand(DF_GfxViewTable a) @p "$(a.inc_in_docs -> '`'..a.display_string..'` '..a.docs_desc)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@subtitle "Commands";
|
||||||
|
@p "The debugger is operated with *commands*. Commands may be manually executed in the debugger UI through the `Commands` menu (which you can open either in the `View` menu bar list, or by using the keybinding, which is F1 by default). Operations in the debugger UI are implemented with commands, so if it's ever unclear how to accomplish some operation through the UI, a useful fallback is searching for and running the command through the command menu.";
|
||||||
|
//@p "Commands are also how a debugger instance launched with `--ipc` may communicate with a primary debugger instance.";
|
||||||
|
//@p "A list of commands, how they're referred to textually (for the purposes of `--ipc` debugger instances), and their descriptions are below:";
|
||||||
|
@p "A list of commands and their descriptions are below:";
|
||||||
|
@unordered_list
|
||||||
|
{
|
||||||
|
@expand(DF_CoreCmdTable a) @p "$(a.lister_omit == 0 -> '`'..a.display_name..'` '..'(`'..a.string..'`) '..a.desc)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@subtitle "Targets";
|
||||||
|
@p "A *target* is one executable and configuration for launching that executable, including command line arguments and working directory (the directory from which the executable is launched). Each target may also have a custom label (replaces the executable path when visualizing the target), and the name of a custom entry point function (when the default entry points - `main`, `WinMain`, etc. - are not desired when stepping into the program upon launch). The debugger can have several targets at once. Each target can also be enabled or disabled. Some operations work on all enabled targets - for instance, the `Run` or `Kill All` commands (standardly bound as F5 or Shift + F5). Enabling and disabling targets allows one to filter which targets are currently being worked with.";
|
||||||
|
@p "To add a target, you can run the `Add Target` command. A target is also created automatically from command line arguments - the rules for how this happens can be found in the `Command-Line Usage` section.";
|
||||||
|
@p "Targets created through command line usage are temporary, meaning they are not persistently saved across runs of the debugger. To change this, you can right click the command-line-created target in the `Targets` view, and click `Save To Profile`. After doing so, the target will be restored across runs, and will no longer need to be specified on the command-line.";
|
||||||
|
|
||||||
|
@subtitle "View Rules";
|
||||||
|
@p "*View Rules* are used to transform the way that evaluations in the debugger are visualized. An evaluation is produced by taking an expression string - for instance, the name of a variable - and using debug info and information from an attached process' live runtime (memory, registers, and so on) to interpret it.";
|
||||||
|
@p "Evaluations may be visualized in a variety of ways. A 64-bit unsigned integer may be visualized as a textual representation of the value with a radix of 10. A 32-bit floating-point value may be visualized as a textual representation of the value. An array of 32-bit floating-point values can be visualized as a list of textual representations of those values.";
|
||||||
|
@p "But all of these cases may be visualized in a number of other ways, as well. A 64-bit unsigned integer may be more usefully represented with a radix of 16, 8, or 2. An array of 32-bit floating-point values may encode the R, G, B, and A components of a color, or vertex positions for 3D geometry, or samples for a waveform. An array of bytes may encode raw pixel data for an image, or image data in a compressed format. A struct may have several members which are not useful to look at all the time. A struct may form the head of a linked list, and a flat linked list representation may be more preferable than the traditional watch view representation, which adds an additional layer of hierarchical nesting with the expansion of each 'next' pointer in a linked list. When designing the debugger, we felt that the traditional memory view and watch view representations of data in a debugged-process were not sufficient. View rules were added to the traditional watch view structure to allow per-row specification of extra visualization parameters.";
|
||||||
|
@p "View rules are specified with the name of a view rule, and depending on the view rule, a `:`, followed by parameters for the view rule. These parameters may be whitespace delimited, but importantly, multiple view rules may be specified per-row in a watch view. To explicitly separate the parameters of one view rule from the name of another - for instance, in a case like `array:16 bin`, where `bin` will not be interpreted as a view rule, but as a parameter of `array` - then commas and semicolons may be used to separate the two view rules (`array:16, bin`), or parentheses/braces/brackets may also be used to explicitly delimit the view rule parameters (`array:(16) bin`).";
|
||||||
|
@p "A list of currently-supported view rules are below:";
|
||||||
|
@unordered_list
|
||||||
|
{
|
||||||
|
@expand(DF_CoreViewRuleTable a) @p "$(a.docs == 'x' -> '`'..a.string..'` ('..a.display_name..') '..a.description)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@subtitle "Breakpoints";
|
||||||
|
@p "Breakpoints interrupt execution of attached processes. They may be placed on specific code addresses, lines of source code, on specific symbol names. In the latter two cases, the higher level locations are resolved to code addresses. If there is no code associated with a line of source code, then the resolution path chooses to use the next closest line of source code in the same file. A symbol name breakpoint will only work if the symbol name is found within loaded debug info.";
|
||||||
|
@p "Breakpoints may have stop conditions attached to them. When a breakpoint is hit by a thread, before it stops execution, the stop condition is evaluated, and if it evaluates to a nonzero value, only then is execution stopped.";
|
||||||
|
@p "Each breakpoint has a hit count. Every time a breakpoint causes execution to stop, this counter is increased.";
|
||||||
|
@p "Processor breakpoints are not currently supported, but planned to be in the future.";
|
||||||
|
|
||||||
|
@subtitle "User & Profile Files";
|
||||||
|
@p "Applicable state controlling the debugger's appearance, behavior, targets, breakpoints, and other configurations is saved and reloaded across runs of the debugger through both *user files* and *profile files*. These files are auto-saved. These files are written in a textual format which can be hand-edited as necessary, but they're also continuously re-read and re-written by the debugger. By default, the debugger uses `%appdata%/raddbg/default.raddbg_user` for its user file path, and `%appdata%/raddbg/default.raddbg_profile` for its profile file path. These paths can be overridden on the command line (see the 'Command-Line Usage' section).";
|
||||||
|
@p "The *user file* defaultly stores file path maps, windows (including their preferred monitor, placement, and size), each window's panel layout and tabs, keybindings, theme colors, and fonts.";
|
||||||
|
@p "The *profile file* defaultly stores targets, breakpoints, watch pins, and exception code filters.";
|
||||||
|
@p "Because both can be hand-edited, however, if you want to store something normally stored in a user file in a profile file, or vice versa, this can be done by hand transferring the textual data from one file to another. There is no path in the debugger's UI to support this transfer, currently, although this is planned.";
|
||||||
|
|
||||||
|
//@subtitle "Driving Another Debugger Instance";
|
||||||
|
//@p "When the debugger is launched with the `--ipc` command-line argument, it does not launch another instance of the graphical debugger. Instead, it launches, sends a string encoding a command to a running instance of the graphical debugger, and then terminates. The set of commands which can be sent are identical to those which can be run from the debugger's UI itself, but these commands must be encoded textually (through the other command-line arguments). These commands are described in the 'Commands' section.";
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef DF_VIEW_RULE_HOOKS_H
|
||||||
|
#define DF_VIEW_RULE_HOOKS_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helper Types
|
||||||
|
|
||||||
|
typedef struct DF_BitmapTopologyInfo DF_BitmapTopologyInfo;
|
||||||
|
struct DF_BitmapTopologyInfo
|
||||||
|
{
|
||||||
|
U64 width;
|
||||||
|
U64 height;
|
||||||
|
R_Tex2DFormat fmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DF_GeoTopologyInfo DF_GeoTopologyInfo;
|
||||||
|
struct DF_GeoTopologyInfo
|
||||||
|
{
|
||||||
|
U64 index_count;
|
||||||
|
Rng1U64 vertices_vaddr_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DF_TxtTopologyInfo DF_TxtTopologyInfo;
|
||||||
|
struct DF_TxtTopologyInfo
|
||||||
|
{
|
||||||
|
TXT_LangKind lang;
|
||||||
|
U64 size_cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helpers
|
||||||
|
|
||||||
|
internal Vec4F32 df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_Entity *process);
|
||||||
|
internal void df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba);
|
||||||
|
internal DF_BitmapTopologyInfo df_view_rule_hooks__bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||||
|
internal DF_GeoTopologyInfo df_view_rule_hooks__geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||||
|
internal DF_TxtTopologyInfo df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg);
|
||||||
|
|
||||||
|
#endif //DF_VIEW_RULE_HOOKS_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user