Author SHA1 Message Date
Nikita Smith b99e10224f simplified chunk size tracking 2024-11-15 16:14:00 -08:00
Nikita Smith 435f6c4ef6 append .lib to defaultlibs 2024-11-15 16:14:00 -08:00
Nikita Smith b631d431fa create section layout without copying chunk data and perform chunk data
copy in parallel given layout
2024-11-15 16:14:00 -08:00
Nikita Smith 2562d04fbf changed build.bat to handle extra natvis for radlink and removed
'Unset' part since we use setlocal that prevents local variable
from leaking to the environment.
2024-11-15 16:14:00 -08:00
Nikita Smith b52a008748 remove debug trap 2024-11-15 16:14:00 -08:00
Nikita Smith b16d930d13 natvis for linker types 2024-11-15 16:14:00 -08:00
Ryan Fleury 26be351354 eliminate per-build version numbers, just use base layer to define defaults; bump to 14 2024-11-15 15:36:12 -08:00
Ryan Fleury 77b2172a85 restrict cursor line info committing by selected module 2024-11-15 15:00:15 -08:00
Ryan Fleury f1c5c97a1b fix stale detection in background fuzzy search results 2024-11-15 14:53:03 -08:00
Ryan Fleury 6be2792659 search cache eviction 2024-11-15 14:40:05 -08:00
Ryan Fleury c42e7837ac fix 64-bit bitfield type value evaluation mask/shift 2024-11-15 11:44:51 -08:00
Ryan Fleury fe657987d6 restrict module for line info visualization; it is not generally useful to do all modules, and in large projects it is too slow to do serially: 2024-11-15 11:19:46 -08:00
Ryan Fleury 48c7bb788e fix incorrect completion parameters hash storage in dbgi matching work, pt. 2 2024-11-15 11:15:25 -08:00
Ryan Fleury 080a001183 fix incorrect completion parameters hash storage in dbgi matching work 2024-11-15 11:12:58 -08:00
Ryan Fleury 81c7c7a7c4 per-target option of automatically debugging subprocesses, or not 2024-11-14 14:18:35 -08:00
Ryan Fleury 95fe497056 fix incorrect advance logic on invalid page reads in cached process memory reading path 2024-11-14 13:08:17 -08:00
Ryan Fleury 8994cb04bc adjust default font size settings by dpi relative to standard 2024-11-14 12:07:19 -08:00
Ryan Fleury ce90b63079 oops........ 2024-11-14 10:58:52 -08:00
Ryan Fleury 6cf9b82857 strip out completion counter from dbgi parsing layer 2024-11-14 10:47:45 -08:00
Ryan Fleury cefbd40e2c fix rw lock r/w mismatch 2024-11-14 10:26:51 -08:00
Ryan Fleury 420f089fda eliminate incorrect cases of async_push_work, where pushes which could occur on worker threads may try to write to a cache that is currently being held, when the push occurs (when all threads are saturated) - async_push_work must never be called from within a cache locking mechanism 2024-11-14 09:55:03 -08:00
Ryan Fleury ff45952f07 re-introduce timeout-based re-requests for dbgi & fs layers; further adjust pre-emptive conversion heuristic 2024-11-14 09:29:01 -08:00
Ryan Fleury fa4f9621b0 adjust pre-emptive conversion heuristics; fix deadlock scenario in match work 2024-11-14 09:10:07 -08:00
Ryan Fleury 4c0ebc851c async priorities, strip out incorrect ring position calculations 2024-11-13 18:23:18 -08:00
Ryan Fleury 5a79518dcb fix debug directory tree cache clearing rule 2024-11-13 16:05:22 -08:00
Ryan Fleury 713cc2c693 entering the 7th circle of DLL hell 2024-11-13 15:48:38 -08:00
Ryan Fleury dcec3c07d9 pass over pre-emptive debug info conversion heuristic, to be friendlier to ue-style root project directories, with what feels like 1000s and 1000s of sub-directories with DLLs hidden in various folders 2024-11-13 14:40:08 -08:00
Ryan Fleury b03c1766c6 just make commit granularity 64 bit; it matches the expected usage pattern in a few spots 2024-11-13 12:18:48 -08:00
Ryan Fleury 4278f7db1e extend pre-emptive conversion rule to do limited children directory checking as well 2024-11-13 11:47:17 -08:00
Ryan Fleury ff90a90744 fix lru eviction in async name match store 2024-11-12 14:36:40 -08:00
Ryan Fleury 626665911d fix incorrect order of work queueing in file stream task kickoff 2024-11-12 14:15:28 -08:00
Ryan Fleury f09f059af2 eliminate thread expression strings in scheduler process expansion 2024-11-12 13:47:04 -08:00
Ryan Fleury e95afcd5aa fix ring buffer stomping in async match 2024-11-12 13:20:42 -08:00
Nikita Smith a8b1805749 updated prof markup usage sites 2024-11-12 13:18:17 -08:00
Nikita Smith a8b2266fc0 added macro for sending notes to telemetry 2024-11-12 13:18:17 -08:00
Nikita Smith bc446d8520 dynamic profile zone with raddbg sprintf 2024-11-12 13:18:17 -08:00
Ryan Fleury 9808157f45 switch match tasks to atomically update match nodes, rather than push results into a queue 2024-11-12 13:00:23 -08:00
Ryan Fleury 0ec6b8e8a8 more work on match store experiment; consume ring buffer results on begin - this experiment is not exactly the right approach, though. because the ui thread definitionally learns about these identifiers faster than the matches can (always) be completed, there is a permanent writer-going-faster-than-reader problem. the correct approach will need to account for this. 2024-11-12 13:00:23 -08:00
Ryan Fleury 3e0c150ccb more work on background name matching & plugging it into syntax highlighting path 2024-11-12 13:00:23 -08:00
Nikita Smith fd1906b034 safe cast commit size 2024-11-12 10:36:45 -08:00
Nikita Smith 2bbf3ff987 switch to data size formatter 2024-11-12 10:36:45 -08:00
Nikita Smith 880d7a4139 data size formatter for stb_sprintf 2024-11-12 10:36:45 -08:00
Nikita Smith c6caec657d moved cstring and find needle string ops to the main layer 2024-11-12 10:36:45 -08:00
Nikita Smith 3d7fc6fce5 moved memory and count string formatters to the main layer and
replaced str8_from_memory_size with more accurate data size units
2024-11-12 10:36:44 -08:00
Nikita Smith 0d0951bf08 squash some image-related steps into finalize image 2024-11-12 10:36:44 -08:00
Nikita Smith 3a190ae2c3 show an early warning for /DEBUG:FASTLINK 2024-11-12 10:36:44 -08:00
Ryan Fleury 420c2ec208 fix dbgi key array copy 2024-11-11 16:15:15 -08:00
Ryan Fleury f9abd3efb9 first half of first pass at asynchronous name matching; simplify current name matching path used in syntax highlighting & deduplicate between code slice & code labels 2024-11-11 16:06:01 -08:00
Ryan Fleury 5893ab94cb cancellation mechanism for debug info fuzzy searching 2024-11-11 10:38:52 -08:00
Ryan Fleury ff2e9df705 fix incorrect match range list copying in new searcher threads 2024-11-11 10:02:06 -08:00
Ryan Fleury 5aeee47f98 oops - fix busted render handle compare 2024-11-11 09:48:11 -08:00
Ryan Fleury 31f25d0fe7 eliminate attempts at clever read-only synchronization in file stream & ctrl layer, just fall back to simple locking mechanism 2024-11-10 11:25:55 -08:00
Nikita Smith bd4f82c8e8 cursed early return 2024-11-08 16:46:11 -08:00
Nikita Smith 680ea2ffdc added /RAD_IDLE_WORKERS 2024-11-08 16:09:56 -08:00
Nikita Smith f7d7f6633f expose file API to enable IO detouring 2024-11-08 16:09:56 -08:00
Ryan Fleury 04c1488cd4 xxhash for ev & ui hashes 2024-11-08 15:02:52 -08:00
Ryan Fleury 5232ba298d cache cons type byte size, and more generally, do not require full type calculation in order to calculate byte sizes 2024-11-08 15:02:52 -08:00
Ryan Fleury 65ada18d1d fix render layer guid linking w/out font provider layer; eliminate generation number on render handles; sketch out tester scratch program for text drawing performance 2024-11-08 15:02:52 -08:00
Nikita Smith 8e6a0ae4db errors and warnings fixes 2024-11-08 11:43:05 -08:00
Nikita Smith e297460697 add necessary Linux impls for linker
NOTE: Current OS API for semaphores doesn't work well with Linux/pthreads
way, for example, on Linux it's up to user program to allocate shared memory
and store there sem_t and detect when to release it. (Windows does this under
the hood when process that created shared semaphore exits)
2024-11-08 11:43:05 -08:00
Nikita Smith cf8c0e7442 clang and gcc bit ops 2024-11-08 11:43:05 -08:00
Nikita Smith 776c8daa27 updated build.sh to define git hash 2024-11-08 11:43:05 -08:00
Nikita Smith 69b43c76d4 default to llvm-mt on non-windows platforms 2024-11-08 11:43:05 -08:00
Nikita Smith d114a0e961 tidy up guid on linux 2024-11-08 11:43:05 -08:00
Nikita Smith d177e39a54 build.sh add radlink target 2024-11-08 11:43:05 -08:00
Ryan Fleury 158dd742ad eliminate entry point 'mode'/type; just gather argc/argv as part of command line parse 2024-11-08 10:33:28 -08:00
Ryan Fleury 0773b6d282 switch to xxhash for font cache hashes 2024-11-08 09:04:16 -08:00
Nikita Smith 15d43d7c99 removed dependency on os_ext 2024-11-07 14:12:41 -08:00
Nikita Smith 7650a83d1e further simplify linker/os_ext/os_core.c 2024-11-07 14:08:21 -08:00
Nikita Smith daeb08e79f moved os_folder_exists to the main layer and deleted win32 layer from linker folder 2024-11-07 13:55:15 -08:00
Nikita Smith ef5287d2a9 switch to os_full_path_from_path 2024-11-07 13:41:47 -08:00
Nikita Smith db04792073 moved getter for process start time w32 2024-11-07 13:33:37 -08:00
Nikita Smith 4091373517 moved operating system -> string to base 2024-11-07 11:54:25 -08:00
Nikita Smith 214be8c433 moved Guid struct and related helpers to base 2024-11-07 11:54:25 -08:00
Nikita Smith f807dc4785 override entry point 2024-11-07 11:54:25 -08:00
Nikita Smith 0dd05169ee add ability to override entry point type 2024-11-07 11:54:25 -08:00
Nikita Smith ce9d43a92e pass over coff header 2024-11-07 11:54:25 -08:00
Nikita Smith 0886963d93 promote section definition number to 32-bit when linking big obj 2024-11-07 11:54:25 -08:00
Nikita Smith 27cd7a21a3 coff section definition for big obj 2024-11-07 11:54:24 -08:00
Nikita Smith 7bb88f480e mask compute typo 2024-11-07 11:54:24 -08:00
Nikita Smith fad817fb9e apply communal variable rule for largest comdat only 2024-11-07 11:54:24 -08:00
Nikita Smith 1d42f1bd66 speed up export table build with hash table 2024-11-07 11:54:24 -08:00
Ryan Fleury a5dd35b874 eliminate dbgi search layer usage 2024-11-07 10:14:17 -08:00
Ryan Fleury a89af7f6fd scratch that - *now* fix the arrayification 2024-11-07 10:07:36 -08:00
Ryan Fleury 5a19ab9c31 fix new search path arrayification 2024-11-07 10:06:49 -08:00
Ryan Fleury e204fe28c1 eliminate deadlocking mechanism in dbgi search cache lookup/mutation; replace with simpler but possibly worse mechanism for now 2024-11-07 09:57:25 -08:00
Ryan Fleury d036eb9fc5 eliminate old dbgi_search layer 2024-11-05 15:08:58 -08:00
Ryan Fleury 1621e504ce first half pass at new dbgi fuzzy searching functionality; distributes search amongst sub-tasks 2024-11-05 15:07:06 -08:00
Ryan Fleury 44b8c9e87c eliminate r/w lock promotion concept 2024-11-04 13:30:10 -08:00
Ryan Fleury 4a0e21d447 collapse user clock indices into base-layer-provided clock counter; fuzzy_search -> dbgi_search 2024-11-04 13:12:52 -08:00
Ryan Fleury 3cd32fa235 correctly prepare paths for windows launches in demon 2024-11-03 14:45:21 -08:00
Ryan Fleury c3a672cd02 fix incorrect async work ordering in dbgi layer 2024-11-03 12:48:34 -08:00
Ryan Fleury 9ce0bc5dbf [geo] move to async layer 2024-11-03 12:17:18 -08:00
Ryan Fleury ffb21277e9 [tex] move to async layer 2024-11-03 12:13:20 -08:00
Ryan Fleury a40edbba51 dasm, ctrl memstream, & more moving to async layer, rather than per-layer thread pools 2024-11-03 12:11:24 -08:00
Ryan Fleury c2855a9a46 eliminate txt layer parsing threads; use async layer 2024-11-03 11:12:24 -08:00
Ryan Fleury 61e7aaadeb implement 'work stealing' mechanism for falling back to synchronous task execution, if all work threads are taken 2024-11-01 16:41:43 -07:00
Ryan Fleury 5a0efe1261 move dbgi layer to async task layer 2024-11-01 15:30:17 -07:00
Ryan Fleury 6d55d21643 fix clang builds 2024-11-01 15:22:26 -07:00
Ryan Fleury 4164b30aac move breakpad converter to async layer; eliminate task system 2024-11-01 15:18:40 -07:00
Ryan Fleury aded54c97f fix pointer stability of async task output slot; finish moving converter to async system 2024-11-01 15:02:45 -07:00
Ryan Fleury 79bcbe4b39 switch rdi_from_pdb to new async layer, off of old task system 2024-11-01 14:44:56 -07:00
Ryan Fleury 86d9b792d8 shift file streaming layer to using async layer for background work, remove file stream layer thread pool 2024-10-31 11:44:54 -07:00
Nikita Smith f3a36ece13 rebase fixes 2024-10-30 15:56:55 -07:00
Nikita Smith c5d198e3e9 build linker with branch name and full commit hash 2024-10-30 15:56:10 -07:00
Nikita Smith eba7500f73 /rad_pdb_hash_type_names:lenient
Less aggressive optimization for type names. When lenient enabled, linker
replaces only mangled names and compiler generated lambda types.
2024-10-30 15:56:10 -07:00
Nikita Smith 339f43919c remove bogus leaf align 2024-10-30 15:56:09 -07:00
Nikita Smith f3fbf10754 replace type names with hashes 2024-10-30 15:56:09 -07:00
Nikita Smith 4a2e1dd8d0 switch to thread safe hash trie map
Initial implementation of the symbol table allowed us to push symbols
from one thread at a time and required a wonky lock-step and spread out
logic for replacing symbols. And because it was a externally chained
hash table we had to guesstimate optimal capacity for small and big targets.
We erred on the side of larger capacity to prevent degradation and
rehashing, however this meant small targets had to spent unreasonable
amount of time memory allocing slots. With hash trie we can dynamically
scale up to 4 ^ 32 items and atomically replace symbols when needed. Neat!
2024-10-30 15:43:53 -07:00
Nikita Smith ee65ea3692 fast-path for string matching 2024-10-30 15:42:39 -07:00
Nikita Smith baead67a99 minor fixes 2024-10-30 15:42:39 -07:00
Nikita Smith e085dae636 pass over atomic operations
- use cast to volatile trick for atomic loads on x64 windows
- removed unnecessary includes on windows
- upgraded clang and gcc code paths to use modern atomics

Removed WIN32_LEAN_AND_MEAN because we were already compiling without it
and there is code path in os_gfx_win32.c that relies on including full
windows.h
2024-10-30 15:42:39 -07:00
Nikita Smith eba6765541 set LF endings for shell scripts so they are executable after checkout 2024-10-30 15:42:39 -07:00
Nikita Smith 002e479a2d index on dev: 62880e6 set explicitly heap and stack reserve and size 2024-10-30 15:42:39 -07:00
Nikita Smith 8848080729 set explicitly heap and stack reserve and size 2024-10-30 15:42:39 -07:00
Nikita Smith e1166abc63 typo in str8 compar name 2024-10-30 15:42:39 -07:00
Nikita Smith 6ffc065712 set dynamic base on /fixed:no 2024-10-30 15:42:39 -07:00
Nikita Smith 15b1ebcd21 coff section align from byte size helper 2024-10-30 15:42:39 -07:00
Ryan Fleury 37b27a9cff correctly bounds-check cursor before doing snapping operations 2024-10-30 06:20:11 -07:00
Ryan Fleury 327fec3155 fix rdi_from_pdb build 2024-10-29 16:50:37 -07:00
Ryan Fleury d0b97a3010 first pass at more comprehensive async layer, for replacing task system & providing single mechanism for async work, which is currently done ad-hoc in various layers 2024-10-29 16:27:21 -07:00
Ryan Fleury 1b5321ad8e fix incorrect tooltip 2024-10-28 21:38:09 -07:00
Ryan Fleury 4769d0a8d4 narrow scope of name resolution for debugger collections; default launching to not attach to child processes, set up msgs to parameterize this 2024-10-28 15:37:28 -07:00
Ryan Fleury 41cddf96b8 preemptive adjacent pdb conversion on initial module load; tighten up c/c++ lexer for smaller string lexes 2024-10-28 13:52:36 -07:00
Ryan Fleury 100d3523d3 clamp floating root positions by window lower bound as well 2024-10-24 11:48:45 -07:00
Ryan Fleury f0b1b46840 clamp thread tooltip callstack symbol names 2024-10-24 11:45:45 -07:00
Ryan Fleury e9666e2edd adjust disasm lexer to account for compiler-autogenerated symbol names 2024-10-24 11:41:59 -07:00
Ryan Fleury 8f932bdbf7 oops 2024-10-24 11:29:13 -07:00
Ryan Fleury c3c9539f9b prioritize string/symbol content in single-line pointer visualization; only use address-first when descending. also fix signed/unsigned visualization of character numeric values 2024-10-24 11:25:27 -07:00
Ryan Fleury 13341a458a fix incorrect kill-single-process ui path 2024-10-23 13:23:22 -07:00
Ryan Fleury 62659c5161 introduce dedicated kill-all path; fix exit conditions for single-stepping stuck threads to be robust toward unexpected kills; fix exit conditions for kill-single-process path, to be more robust to halts; correctly report stop cause 2024-10-23 13:19:37 -07:00
Ryan Fleury 1ecabff7b6 prefer usage of pdbs in dbgi layer, if rdi path is not baked in, but pdb path *is* - otherwise the dbgi layer can simply choose a stale rdi file with no way to generate a new one. 2024-10-23 11:49:47 -07:00
Ryan Fleury 45f5a2d18f accept / command line arguments on windows 2024-10-23 11:19:07 -07:00
Ryan Fleury bcd16a4f29 only plug in jumping immediates to jump_dest_vaddr paths in stepping; ctrl flow info analysis path stops when it has to read memory or registers 2024-10-23 11:07:51 -07:00
Ryan Fleury 6d7858d445 parameterize tester with test data root folder; wrap tester run in top-levels cript 2024-10-22 17:51:21 -07:00
Ryan Fleury c67f1a8b4a fix empty file edge case in hash store / text cache 2024-10-22 16:19:11 -07:00
Nikita Smith 340396f9f7 fix arena usage 2024-10-22 15:07:49 -07:00
Nikita Smith eb6aabe2d1 set block base pos 2024-10-22 15:06:39 -07:00
Nikita Smith 9ec7fb61ed implemented /noimplib /noexp 2024-10-22 11:02:59 -07:00
Nikita Smith dcffefd0c6 typo in string table lookup 2024-10-22 10:58:41 -07:00
Nikita Smith 5be2b5dfd9 alias for amd64 machine 2024-10-22 10:19:37 -07:00
Nikita Smith 7260baea85 implemented /PDBALTPATH and /RAD_DEBUGALTPATH 2024-10-21 18:03:28 -07:00
Nikita Smith a802f2186b actually push new block to list 2024-10-21 14:35:55 -07:00
Nikita Smith a43678e311 voff -> line search fix
when line table contains duplicate virtual offsets we have to return
index of last virtual offset so following property is true:
'line_length = virtual_offsets[index + 1] - virtual_offsets[index]'
2024-10-21 13:32:04 -07:00
Ryan Fleury edee84dd03 fix maximum munch rule application in text cache lexers 2024-10-21 10:37:04 -07:00
Ryan Fleury 4a211de2b3 do not bake path normalization into eval string <-> file path; this incorrectly assumes the normalization base directory, which is not correct when serializing/deserializing/etc. instead, just normalize on find-code-location. 2024-10-21 09:56:32 -07:00
Ryan Fleury d0915ec9a7 eval expressions: unary +, correctly lex exponentiated numerics 2024-10-21 09:23:31 -07:00
Ryan Fleury 52245a8e5a maintain explicit casts in cstring -> string paths 2024-10-21 08:51:19 -07:00
Nikita Smith dbcecd99af fix sizeof array types 2024-10-19 20:39:40 -07:00
Nikita Smith 68c0906570 print register name 2024-10-19 20:39:40 -07:00
Nikita Smith 26611c5454 moved IO related code to stand-alone file, piped all read/and writes
through new API, /rad_log now can enable read and/or write logs with
"io", "io_reads", "io_writes" parameters.
2024-10-19 16:36:32 -07:00
Nikita Smith 05d4faeb49 remove unsued func 2024-10-19 15:13:10 -07:00
Nikita Smith d5c2e50e9a rename import table regular -> static 2024-10-19 15:11:51 -07:00
Nikita Smith 800a2349e5 pass over COFF resource reader and writer 2024-10-19 13:44:36 -07:00
Nikita Smith 46390ba0b8 reworked manifest handling
- manifest files wont be created unless symbols are resolved
- delay mt.exe presence check until we launch it
- create explicit case that writes manifests to disk
- moved manifest dependency collection step to happen after obj input
- removed /rad_delete_manifest
2024-10-18 23:37:30 -07:00
Nikita Smith f1a0e7233d cstring helper for wide chars 2024-10-18 22:56:55 -07:00
Nikita Smith 9d60dcc099 updated radlink benches in readme 2024-10-18 17:12:31 -07:00
140 changed files with 9257 additions and 7708 deletions
+1
View File
@@ -0,0 +1 @@
*.sh text=auto eol=lf
+3 -3
View File
@@ -193,7 +193,7 @@ If build was successful linker executable is placed in `build` folder under `rad
## Benchmarks ## Benchmarks
![AMD Ryzen Threadripper PRO 3995WX 64-Cores, 256 GiB RAM (Windows x64)](https://github.com/user-attachments/assets/39d95fdf-9f0b-45d3-9fb8-90d8ac624168) ![AMD Ryzen Threadripper PRO 3995WX 64-Cores, 256 GiB RAM (Windows x64)](https://github.com/user-attachments/assets/a95b382a-76b4-4a4c-b809-b61fe25e667a)
--- ---
@@ -241,6 +241,8 @@ not depend on any other layers in the codebase. The folders which contain these
layers are prefixed with `lib_`, like `lib_rdi_format`. 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:
- `async` (`ASYNC_`): Implements a system for asynchronous work to be queued
and executed on a thread pool.
- `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.
@@ -375,8 +377,6 @@ A list of the layers in the codebase and their associated namespaces is below:
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 programs.
- `task_system` (`TS_`): Implements a system for kicking off asynchronous tasks
and obtaining artifacts from those tasks once they've completed.
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU - `texture_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 visualization.
+19 -14
View File
@@ -1,5 +1,5 @@
@echo off @echo off
setlocal setlocal enabledelayedexpansion
cd /D "%~dp0" cd /D "%~dp0"
:: --- Usage Notes (2024/1/10) ------------------------------------------------ :: --- Usage Notes (2024/1/10) ------------------------------------------------
@@ -48,11 +48,21 @@ set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_fl
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" /pdbaltpath:%%%%_PDB%%%% set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%%
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 /pdbaltpath:%%%%_PDB%%%%
set cl_out= /out: set cl_out= /out:
set clang_out= -o set clang_out= -o
:: --- NATVIS -----------------------------------------------------------------
set natvis= /NATVIS:"%~dp0\src\natvis\base.natvis"
if "%radlink%"=="1" set natvis= %natvis% /NATVIS:"%~dp0\src\linker\linker.natvis"
if "%clang%"=="1" (
set result=
for %%n in (%natvis%) do set result= !result! -Xlinker %%n
set natvis= !result!
)
:: --- Per-Build Settings ----------------------------------------------------- :: --- Per-Build Settings -----------------------------------------------------
set link_dll=-DLL set link_dll=-DLL
set link_icon=logo.res set link_icon=logo.res
@@ -77,6 +87,9 @@ if "%clang%"=="1" set out=%clang_out%
if "%debug%"=="1" set compile=%compile_debug% if "%debug%"=="1" set compile=%compile_debug%
if "%release%"=="1" set compile=%compile_release% if "%release%"=="1" set compile=%compile_release%
:: --- Append NATVIS to link line ---------------------------------------------
set compile_link= %compile_link% %natvis%
:: --- Prep Directories ------------------------------------------------------- :: --- Prep Directories -------------------------------------------------------
if not exist build mkdir build if not exist build mkdir build
if not exist local mkdir local if not exist local mkdir local
@@ -87,7 +100,8 @@ 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% -DBUILD_GIT_HASH=\"%%i\"
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
:: --- Build & Run Metaprogram ------------------------------------------------ :: --- Build & Run Metaprogram ------------------------------------------------
if "%no_meta%"=="1" echo [skipping metagen] if "%no_meta%"=="1" echo [skipping metagen]
@@ -108,6 +122,7 @@ if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_du
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 "%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 "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1 if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1 if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
if "%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 "%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_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_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
@@ -122,16 +137,6 @@ if "%mule_peb_trample%"=="1" (
) )
popd popd
:: --- Unset ------------------------------------------------------------------
for %%a in (%*) do set "%%a=0"
set raddbg=
set compile=
set compile_link=
set out=
set msvc=
set debug=
set release=
:: --- Warn On No Builds ------------------------------------------------------ :: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" ( 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`. 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`.
+7 -2
View File
@@ -14,13 +14,17 @@ if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
# --- Unpack Command Line Build Arguments ------------------------------------- # --- Unpack Command Line Build Arguments -------------------------------------
auto_compile_flags='' auto_compile_flags=''
# --- Get Current Git Commit Id -----------------------------------------------
git_hash=$(git rev-parse HEAD)
git_hash_full=$(git rev-parse HEAD)
# --- Compile/Link Line Definitions ------------------------------------------- # --- 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_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}" clang_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_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
clang_link="-lpthread -lm -lrt -ldl" clang_link="-lpthread -lm -lrt -ldl"
clang_out="-o" 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_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}" gcc_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_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
gcc_link="-lpthread -lm -lrt -ldl" gcc_link="-lpthread -lm -lrt -ldl"
@@ -59,6 +63,7 @@ fi
# --- Build Everything (@build_targets) --------------------------------------- # --- Build Everything (@build_targets) ---------------------------------------
cd build cd build
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $out raddbg; fi if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $out raddbg; fi
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi if [ -v rdi_from_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_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_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
+2
View File
@@ -49,6 +49,8 @@ commands =
.f1 = { .win = "build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, .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, }, .f2 = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f3 = { .win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --project:local_dev.raddbg_project --xuto_run && popd",.linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, .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, },
// .f1 = { .win = "build textperf release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "pushd build && textperf.exe --capture && popd",.linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: local target builds //- rjf: local target builds
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, .build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+21
View File
@@ -0,0 +1,21 @@
@echo off
setlocal
cd /D "%~dp0"
echo --- getting test data folder path ---------------------------------------------
if not exist .\local\test_data_path.txt (
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
goto :EOF
)
set /p test_data_folder=<.\local\test_data_path.txt
echo test data path: %test_data_folder%
echo:
echo --- building all testing executables ------------------------------------------
call build rdi_from_pdb rdi_dump raddbg radlink tester
echo:
echo --- running tests -------------------------------------------------------------
pushd build
call tester.exe --test_data:%test_data_folder%
popd
+240
View File
@@ -0,0 +1,240 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Top-Level Layer Initialization
internal void
async_init(void)
{
Arena *arena = arena_alloc();
async_shared = push_array(arena, ASYNC_Shared, 1);
async_shared->arena = arena;
for EachEnumVal(ASYNC_Priority, p)
{
ASYNC_Ring *ring = &async_shared->rings[p];
ring->ring_size = MB(8);
ring->ring_base = push_array_no_zero(arena, U8, ring->ring_size);
ring->ring_mutex = os_mutex_alloc();
ring->ring_cv = os_condition_variable_alloc();
}
async_shared->ring_mutex = os_mutex_alloc();
async_shared->ring_cv = os_condition_variable_alloc();
async_shared->work_threads_count = Max(1, os_get_system_info()->logical_processor_count-1);
async_shared->work_threads = push_array(arena, OS_Handle, async_shared->work_threads_count);
for EachIndex(idx, async_shared->work_threads_count)
{
async_shared->work_threads[idx] = os_thread_launch(async_work_thread__entry_point, (void *)idx, 0);
}
}
////////////////////////////////
//~ rjf: Top-Level Accessors
internal U64
async_thread_count(void)
{
return async_shared->work_threads_count;
}
////////////////////////////////
//~ rjf: Work Kickoffs
internal B32
async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
{
// rjf: choose ring
ASYNC_Ring *ring = &async_shared->rings[params->priority];
// rjf: build work package
ASYNC_Work work = {0};
work.work_function = work_function;
work.input = params->input;
work.output = params->output;
work.semaphore = params->semaphore;
work.completion_counter = params->completion_counter;
// rjf: loop; try to write into user -> writer ring buffer. if we're on a
// worker thread, determine if we need to execute this task locally on this
// thread, and skip ring buffer if so.
B32 queued_in_ring_buffer = 0;
B32 need_to_execute_on_this_thread = 0;
OS_MutexScope(ring->ring_mutex) for(;;)
{
U64 num_available_work_threads = (async_shared->work_threads_count - ins_atomic_u64_eval(&async_shared->work_threads_live_count));
if(num_available_work_threads == 0 && async_work_thread_depth > 0)
{
need_to_execute_on_this_thread = 1;
break;
}
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
U64 available_size = ring->ring_size - unconsumed_size;
if(available_size >= sizeof(work))
{
queued_in_ring_buffer = 1;
if(!os_handle_match(params->semaphore, os_handle_zero()))
{
os_semaphore_take(params->semaphore, max_U64);
}
ring->ring_write_pos += ring_write_struct(ring->ring_base, ring->ring_size, ring->ring_write_pos, &work);
break;
}
if(os_now_microseconds() >= params->endt_us)
{
break;
}
os_condition_variable_wait(ring->ring_cv, ring->ring_mutex, params->endt_us);
}
// rjf: broadcast ring buffer cv if we wrote successfully
if(queued_in_ring_buffer)
{
os_condition_variable_broadcast(ring->ring_cv);
os_condition_variable_broadcast(async_shared->ring_cv);
}
// rjf: if we did not queue successfully, and we have determined that
// we need to execute this work on the current thread, then execute the
// work before returning
if(need_to_execute_on_this_thread)
{
async_execute_work(work);
}
// rjf: return success signal
B32 result = (queued_in_ring_buffer || need_to_execute_on_this_thread);
return result;
}
////////////////////////////////
//~ rjf: Task-Based Work Helper
internal void
async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t)
{
ASYNC_TaskNode *n = push_array(arena, ASYNC_TaskNode, 1);
SLLQueuePush(list->first, list->last, n);
n->v = t;
list->count += 1;
}
internal ASYNC_Task *
async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
{
ASYNC_Task *task = push_array(arena, ASYNC_Task, 1);
task->semaphore = os_semaphore_alloc(1, 1, str8_zero());
ASYNC_WorkParams params_refined = {0};
MemoryCopyStruct(&params_refined, params);
params_refined.endt_us = max_U64;
params_refined.semaphore = task->semaphore;
if(params_refined.output == 0)
{
params_refined.output = &task->output;
}
async_push_work_(work_function, &params_refined);
return task;
}
internal void *
async_task_join(ASYNC_Task *task)
{
void *result = 0;
if(task != 0 && !os_handle_match(task->semaphore, os_handle_zero()))
{
os_semaphore_take(task->semaphore, max_U64);
os_semaphore_release(task->semaphore);
MemoryZeroStruct(&task->semaphore);
result = (void *)ins_atomic_u64_eval(&task->output);
}
return result;
}
////////////////////////////////
//~ rjf: Work Execution
internal ASYNC_Work
async_pop_work(void)
{
ProfBeginFunction();
ASYNC_Work work = {0};
B32 done = 0;
ASYNC_Priority taken_priority = ASYNC_Priority_Low;
OS_MutexScope(async_shared->ring_mutex) for(;!done;)
{
for(ASYNC_Priority priority = ASYNC_Priority_High;; priority = (ASYNC_Priority)(priority - 1))
{
ASYNC_Ring *ring = &async_shared->rings[priority];
OS_MutexScope(ring->ring_mutex)
{
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
if(unconsumed_size >= sizeof(work))
{
ring->ring_read_pos += ring_read_struct(ring->ring_base, ring->ring_size, ring->ring_read_pos, &work);
done = 1;
taken_priority = priority;
}
}
if(done)
{
break;
}
if(priority == ASYNC_Priority_Low)
{
break;
}
}
if(!done)
{
os_condition_variable_wait(async_shared->ring_cv, async_shared->ring_mutex, max_U64);
}
}
os_condition_variable_broadcast(async_shared->ring_cv);
os_condition_variable_broadcast(async_shared->rings[taken_priority].ring_cv);
ProfEnd();
return work;
}
internal void
async_execute_work(ASYNC_Work work)
{
//- rjf: run work
async_work_thread_depth += 1;
void *work_out = work.work_function(async_work_thread_idx, work.input);
async_work_thread_depth -= 1;
//- rjf: store output
if(work.output != 0)
{
ins_atomic_u64_eval_assign((U64 *)work.output, (U64)work_out);
}
//- rjf: release semaphore
if(!os_handle_match(work.semaphore, os_handle_zero()))
{
os_semaphore_drop(work.semaphore);
}
//- rjf: increment completion counter
if(work.completion_counter != 0)
{
ins_atomic_u64_inc_eval(work.completion_counter);
}
}
////////////////////////////////
//~ rjf: Work Thread Entry Point
internal void
async_work_thread__entry_point(void *p)
{
U64 thread_idx = (U64)p;
ThreadNameF("[async] work thread #%I64u", thread_idx);
async_work_thread_idx = thread_idx;
for(;;)
{
ASYNC_Work work = async_pop_work();
ins_atomic_u64_inc_eval(&async_shared->work_threads_live_count);
async_execute_work(work);
ins_atomic_u64_dec_eval(&async_shared->work_threads_live_count);
}
}
+144
View File
@@ -0,0 +1,144 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ASYNC_H
#define ASYNC_H
////////////////////////////////
//~ rjf: Work Function Type
#define ASYNC_WORK_SIG(name) void *name(U64 thread_idx, void *input)
#define ASYNC_WORK_DEF(name) internal ASYNC_WORK_SIG(name)
typedef ASYNC_WORK_SIG(ASYNC_WorkFunctionType);
////////////////////////////////
//~ rjf: Work Types
typedef enum ASYNC_Priority
{
ASYNC_Priority_Low,
ASYNC_Priority_High,
ASYNC_Priority_COUNT
}
ASYNC_Priority;
typedef struct ASYNC_WorkParams ASYNC_WorkParams;
struct ASYNC_WorkParams
{
void *input;
void **output;
OS_Handle semaphore;
U64 *completion_counter;
U64 endt_us;
ASYNC_Priority priority;
};
typedef struct ASYNC_Work ASYNC_Work;
struct ASYNC_Work
{
ASYNC_WorkFunctionType *work_function;
void *input;
void **output;
OS_Handle semaphore;
U64 *completion_counter;
};
////////////////////////////////
//~ rjf: Task-Based Work Types
typedef struct ASYNC_Task ASYNC_Task;
struct ASYNC_Task
{
OS_Handle semaphore;
void *output;
};
typedef struct ASYNC_TaskNode ASYNC_TaskNode;
struct ASYNC_TaskNode
{
ASYNC_TaskNode *next;
ASYNC_Task *v;
};
typedef struct ASYNC_TaskList ASYNC_TaskList;
struct ASYNC_TaskList
{
ASYNC_TaskNode *first;
ASYNC_TaskNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Shared State Bundle
typedef struct ASYNC_Ring ASYNC_Ring;
struct ASYNC_Ring
{
U64 ring_size;
U8 *ring_base;
U64 ring_write_pos;
U64 ring_read_pos;
OS_Handle ring_mutex;
OS_Handle ring_cv;
};
typedef struct ASYNC_Shared ASYNC_Shared;
struct ASYNC_Shared
{
Arena *arena;
// rjf: user -> work thread ring buffers
ASYNC_Ring rings[ASYNC_Priority_COUNT];
OS_Handle ring_mutex;
OS_Handle ring_cv;
// rjf: work threads
OS_Handle *work_threads;
U64 work_threads_count;
U64 work_threads_live_count;
};
////////////////////////////////
//~ rjf: Globals
thread_static B32 async_work_thread_depth = 0;
thread_static U64 async_work_thread_idx = 0;
global ASYNC_Shared *async_shared = 0;
////////////////////////////////
//~ rjf: Top-Level Layer Initialization
internal void async_init(void);
////////////////////////////////
//~ rjf: Top-Level Accessors
internal U64 async_thread_count(void);
////////////////////////////////
//~ rjf: Work Kickoffs
internal B32 async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
#define async_push_work(function, ...) async_push_work_((function), &(ASYNC_WorkParams){.endt_us = max_U64, .priority = ASYNC_Priority_High, __VA_ARGS__})
////////////////////////////////
//~ rjf: Task-Based Work Helper
internal void async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t);
internal ASYNC_Task *async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
#define async_task_launch(arena, work_function, ...) async_task_launch_((arena), (work_function), &(ASYNC_WorkParams){.endt_us = max_U64, __VA_ARGS__})
internal void *async_task_join(ASYNC_Task *task);
#define async_task_join_struct(task, T) (T *)async_task_join(task)
////////////////////////////////
//~ rjf: Work Execution
internal ASYNC_Work async_pop_work(void);
internal void async_execute_work(ASYNC_Work work);
////////////////////////////////
//~ rjf: Work Thread Entry Point
internal void async_work_thread__entry_point(void *p);
#endif // ASYNC_H
+9 -8
View File
@@ -52,7 +52,7 @@ arena_alloc_(ArenaParams *params)
Arena *arena = (Arena *)base; Arena *arena = (Arena *)base;
arena->current = arena; arena->current = arena;
arena->flags = params->flags; arena->flags = params->flags;
arena->cmt_size = (U32)params->commit_size; arena->cmt_size = params->commit_size;
arena->res_size = params->reserve_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;
@@ -90,7 +90,7 @@ arena_push(Arena *arena, U64 size, U64 align)
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain)) if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
{ {
Arena *new_block = 0; Arena *new_block = 0;
#if ARENA_FREE_LIST #if ARENA_FREE_LIST
Arena *prev_block; Arena *prev_block;
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev) for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
@@ -106,12 +106,12 @@ arena_push(Arena *arena, U64 size, U64 align)
arena->free_last = new_block->prev; arena->free_last = new_block->prev;
} }
arena->free_size -= new_block->res_size; arena->free_size -= new_block->res_size;
AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE); AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE);
break; break;
} }
} }
#endif #endif
if(new_block == 0) if(new_block == 0)
{ {
U64 res_size = current->res_size; U64 res_size = current->res_size;
@@ -124,10 +124,11 @@ arena_push(Arena *arena, U64 size, U64 align)
new_block = arena_alloc(.reserve_size = res_size, new_block = arena_alloc(.reserve_size = res_size,
.commit_size = cmt_size, .commit_size = cmt_size,
.flags = current->flags); .flags = current->flags);
new_block->base_pos = current->base_pos + current->res;
SLLStackPush_N(arena->current, new_block, prev);
} }
new_block->base_pos = current->base_pos + current->res;
SLLStackPush_N(arena->current, new_block, prev);
current = new_block; current = new_block;
pos_pre = AlignPow2(current->pos, align); pos_pre = AlignPow2(current->pos, align);
pos_pst = pos_pre + size; pos_pst = pos_pre + size;
@@ -186,7 +187,7 @@ arena_pop_to(Arena *arena, U64 pos)
{ {
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos); U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
Arena *current = arena->current; Arena *current = arena->current;
#if ARENA_FREE_LIST #if ARENA_FREE_LIST
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev) for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{ {
+3 -7
View File
@@ -7,16 +7,12 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: Constants //~ rjf: Constants
#if ARENA_FREE_LIST #define ARENA_HEADER_SIZE 128
# define ARENA_HEADER_SIZE 128
#else
# define ARENA_HEADER_SIZE 64
#endif
//////////////////////////////// ////////////////////////////////
//~ rjf: Types //~ rjf: Types
typedef U32 ArenaFlags; typedef U64 ArenaFlags;
enum enum
{ {
ArenaFlag_NoChain = (1<<0), ArenaFlag_NoChain = (1<<0),
@@ -38,7 +34,7 @@ struct Arena
Arena *prev; // previous arena in chain Arena *prev; // previous arena in chain
Arena *current; // current arena in chain Arena *current; // current arena in chain
ArenaFlags flags; ArenaFlags flags;
U32 cmt_size; U64 cmt_size;
U64 res_size; U64 res_size;
U64 base_pos; U64 base_pos;
U64 pos; U64 pos;
+21 -3
View File
@@ -98,9 +98,10 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
next = node->next; next = node->next;
String8 option_name = node->string; String8 option_name = node->string;
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's // NOTE(rjf): Look at --, -, or / (only on Windows) at the start of an
// a flag option. All arguments after a single "--" (with no trailing string // argument to determine if it's a flag option. All arguments after a
// on the command line will be considered as input files. // single "--" (with no trailing string on the command line will be
// considered as input files.
B32 is_option = 1; B32 is_option = 1;
if(after_passthrough_option == 0) if(after_passthrough_option == 0)
{ {
@@ -117,6 +118,11 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
{ {
option_name = str8_skip(option_name, 1); option_name = str8_skip(option_name, 1);
} }
else if(operating_system_from_context() == OperatingSystem_Windows &&
str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0))
{
option_name = str8_skip(option_name, 1);
}
else else
{ {
is_option = 0; is_option = 0;
@@ -184,6 +190,18 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
} }
} }
// rjf: fill argc/argv
parsed.argc = command_line.node_count;
parsed.argv = push_array(arena, char *, parsed.argc);
{
U64 idx = 0;
for(String8Node *n = command_line.first; n != 0; n = n->next)
{
parsed.argv[idx] = (char *)push_str8_copy(arena, n->string).str;
idx += 1;
}
}
return parsed; return parsed;
} }
+2
View File
@@ -34,6 +34,8 @@ struct CmdLine
String8List inputs; String8List inputs;
U64 option_table_size; U64 option_table_size;
CmdLineOpt **option_table; CmdLineOpt **option_table;
U64 argc;
char **argv;
}; };
//////////////////////////////// ////////////////////////////////
+2 -2
View File
@@ -155,11 +155,11 @@
#endif #endif
#if !defined(BUILD_VERSION_MINOR) #if !defined(BUILD_VERSION_MINOR)
# define BUILD_VERSION_MINOR 0 # define BUILD_VERSION_MINOR 9
#endif #endif
#if !defined(BUILD_VERSION_PATCH) #if !defined(BUILD_VERSION_PATCH)
# define BUILD_VERSION_PATCH 0 # define BUILD_VERSION_PATCH 14
#endif #endif
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH) #define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
+11 -23
View File
@@ -143,12 +143,6 @@ bswap_u64(U64 x)
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS) #if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
internal U64
count_bits_set16(U16 val)
{
return __popcnt16(val);
}
internal U64 internal U64
count_bits_set32(U32 val) count_bits_set32(U32 val)
{ {
@@ -195,46 +189,40 @@ clz64(U64 mask)
#elif COMPILER_CLANG || COMPILER_GCC #elif COMPILER_CLANG || COMPILER_GCC
internal U64
count_bits_set16(U16 val)
{
NotImplemented;
return 0;
}
internal U64 internal U64
count_bits_set32(U32 val) count_bits_set32(U32 val)
{ {
NotImplemented; return __builtin_popcount(val);
return 0;
} }
internal U64 internal U64
count_bits_set64(U64 val) count_bits_set64(U64 val)
{ {
NotImplemented; return __builtin_popcountll(val);
return 0;
} }
internal U64 internal U64
ctz32(U32 val) ctz32(U32 val)
{ {
NotImplemented; return __builtin_ctz(val);
return 0;
} }
internal U64 internal U64
clz32(U32 val) clz32(U32 val)
{ {
NotImplemented; return __builtin_clz(val);
return 0; }
internal U64
ctz64(U64 val)
{
return __builtin_ctzll(val);
} }
internal U64 internal U64
clz64(U64 val) clz64(U64 val)
{ {
NotImplemented; return __builtin_clzll(val);
return 0;
} }
#else #else
+59 -30
View File
@@ -40,6 +40,12 @@
# define thread_static __thread # define thread_static __thread
#endif #endif
#if COMPILER_MSVC
# define force_inline __forceinline
#elif COMPILER_CLANG || COMPILER_GCC
# define force_inline __attribute__((always_inline))
#endif
//////////////////////////////// ////////////////////////////////
//~ rjf: Linkage Keyword Macros //~ rjf: Linkage Keyword Macros
@@ -172,42 +178,49 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: Atomic Operations //~ rjf: Atomic Operations
#if OS_WINDOWS #if COMPILER_MSVC
# include <windows.h>
# include <tmmintrin.h>
# include <wmmintrin.h>
# include <intrin.h> # include <intrin.h>
# if ARCH_X64 # if ARCH_X64
# define ins_atomic_u64_eval(x) InterlockedAdd64((volatile __int64 *)(x), 0) # define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x)) # define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x)) # define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c)) # 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_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_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(x) *((volatile U32 *)(x))
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c)) # define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x)
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c)) # define ins_atomic_u32_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)) # define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
# else # else
# error Atomic intrinsics not defined for this operating system / architecture combination. # error Atomic intrinsics not defined for this compiler / architecture combination.
# endif
#elif OS_LINUX
# if ARCH_X64
# define ins_atomic_u64_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 0)
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
# define ins_atomic_u64_dec_eval(x) __sync_fetch_and_sub((volatile U64 *)(x), 1)
# define ins_atomic_u64_eval_assign(x,c) __sync_lock_test_and_set((volatile U64 *)(x),(c))
# define ins_atomic_u64_add_eval(x,c) __sync_fetch_and_add((volatile U64 *)(x), c)
# define ins_atomic_u64_eval_cond_assign(x,k,c) __sync_val_compare_and_swap((volatile U64 *)(x),(c),(k))
# define ins_atomic_u32_eval(x,c) __sync_fetch_and_add((volatile U32 *)(x), 0)
# define ins_atomic_u32_eval_assign(x,c) __sync_lock_test_and_set((volatile U32 *)(x),(c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) __sync_val_compare_and_swap((volatile U32 *)(x),(c),(k))
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
# else
# error Atomic intrinsics not defined for this operating system / architecture combination.
# endif # endif
#elif COMPILER_CLANG || COMPILER_GCC
# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((volatile U64 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((volatile U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((volatile U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((volatile U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
#else #else
# error Atomic intrinsics not defined for this operating system. # error Atomic intrinsics not defined for this compiler / architecture.
#endif
#if ARCH_64BIT
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u64_eval_cond_assign((volatile U64 *)(x), (U64)(k), (U64)(c))
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u64_eval((volatile U64 *)x)
#elif ARCH_32BIT
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u32_eval_cond_assign((volatile U32 *)(x), (U32)(k), (U32)(c))
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u32_eval_assign((volatile U32 *)(x), (U32)(c))
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u32_eval((volatile U32 *)x)
#else
# error Atomic intrinsics for pointers not defined for this architecture.
#endif #endif
//////////////////////////////// ////////////////////////////////
@@ -479,6 +492,23 @@ struct TxtRng
TxtPt max; TxtPt max;
}; };
////////////////////////////////
//~ Globally Unique Ids
typedef union Guid Guid;
union Guid
{
struct
{
U32 data1;
U16 data2;
U16 data3;
U8 data4[8];
};
U8 v[16];
};
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
//////////////////////////////// ////////////////////////////////
//~ NOTE(allen): Constants //~ NOTE(allen): Constants
@@ -745,7 +775,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_set32(U32 val);
internal U64 count_bits_set64(U64 val); internal U64 count_bits_set64(U64 val);
+25 -22
View File
@@ -1,22 +1,24 @@
// 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/)
global U64 global_update_tick_idx = 0;
internal void internal void
main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count) main_thread_base_entry_point(int arguments_count, char **arguments)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
ThreadNameF("[main thread]"); ThreadNameF("[main thread]");
//- rjf: set up telemetry //- rjf: set up telemetry
#if PROFILE_TELEMETRY #if PROFILE_TELEMETRY
local_persist U8 tm_data[MB(64)]; local_persist char tm_data[MB(64)];
tmLoadLibrary(TM_RELEASE); tmLoadLibrary(TM_RELEASE);
tmSetMaxThreadCount(256); tmSetMaxThreadCount(256);
tmInitialize(sizeof(tm_data), (char *)tm_data); tmInitialize(sizeof(tm_data), tm_data);
#endif #endif
//- rjf: parse command line //- rjf: parse command line
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments); String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, arguments_count, arguments);
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings); CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
//- rjf: begin captures //- rjf: begin captures
@@ -26,9 +28,16 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
ProfBeginCapture(arguments[0]); ProfBeginCapture(arguments[0]);
} }
#if PROFILE_TELEMETRY
tmMessage(0, TMMF_ICON_NOTE, BUILD_TITLE);
#endif
//- rjf: initialize all included layers //- rjf: initialize all included layers
#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL) #if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
ts_init(); async_init();
#endif
#if defined(RDI_FROM_PDB_H) && !defined(P2R_INIT_MANUAL)
p2r_init();
#endif #endif
#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL) #if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL)
hs_init(); hs_init();
@@ -45,12 +54,9 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL) #if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL)
dasm_init(); dasm_init();
#endif #endif
#if defined(DBGI_H) && !defined(DBGI_INIT_MANUAL) #if defined(DBGI_H) && !defined(DI_INIT_MANUAL)
di_init(); di_init();
#endif #endif
#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL)
fzy_init();
#endif
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
dmn_init(); dmn_init();
#endif #endif
@@ -90,6 +96,7 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
{ {
ProfEndCapture(); ProfEndCapture();
} }
scratch_end(scratch); scratch_end(scratch);
} }
@@ -102,22 +109,18 @@ supplement_thread_base_entry_point(void (*entry_point)(void *params), void *para
tctx_release(); tctx_release();
} }
internal U64
update_tick_idx(void)
{
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
return result;
}
internal B32 internal B32
update(void) update(void)
{ {
ProfTick(0); ProfTick(0);
#if defined(TEXT_CACHE_H) ins_atomic_u64_inc_eval(&global_update_tick_idx);
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 #if OS_FEATURE_GRAPHICAL
B32 result = frame(); B32 result = frame();
#else #else
+2 -1
View File
@@ -4,8 +4,9 @@
#ifndef BASE_ENTRY_POINT_H #ifndef BASE_ENTRY_POINT_H
#define 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 main_thread_base_entry_point(int argc, char **argv);
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params); internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
internal U64 update_tick_idx(void);
internal B32 update(void); internal B32 update(void);
#endif // BASE_ENTRY_POINT_H #endif // BASE_ENTRY_POINT_H
+24
View File
@@ -195,6 +195,30 @@ read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, st
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")}; 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 F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")}; read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
read_only global Type *type_kind_type_table[] =
{
&type_nil,
type(void),
type(U8),
type(U16),
type(U32),
type(U64),
type(S8),
type(S16),
type(S32),
type(S64),
type(B8),
type(B16),
type(B32),
type(B64),
type(F32),
type(F64),
&type_nil,
&type_nil,
&type_nil,
&type_nil,
&type_nil,
};
//- rjf: Rng1U64 //- rjf: Rng1U64
struct_members(Rng1U64) struct_members(Rng1U64)
+36 -14
View File
@@ -43,26 +43,48 @@
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__) # define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) # define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
# define ProfColor(color) tmZoneColorSticky(color) # define ProfColor(color) tmZoneColorSticky(color)
# define ProfBeginV(...) \
if (TM_API_PTR) { \
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
Temp scratch = scratch_begin(0,0); \
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
scratch_end(scratch); \
}
# define ProfNoteV(...) \
if (TM_API_PTR) { \
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
Temp scratch = scratch_begin(0,0); \
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
scratch_end(scratch); \
}
#endif #endif
//////////////////////////////// ////////////////////////////////
//~ rjf: Zeroify Undefined Defines //~ rjf: Zeroify Undefined Defines
#if !defined(ProfBegin) #if !defined(ProfBegin)
# define ProfBegin(...) (0) # define ProfBegin(...) (0)
# define ProfBeginDynamic(...) (0) # define ProfBeginDynamic(...) (0)
# define ProfEnd(...) (0) # define ProfEnd(...) (0)
# define ProfTick(...) (0) # define ProfTick(...) (0)
# define ProfIsCapturing(...) (0) # define ProfIsCapturing(...) (0)
# define ProfBeginCapture(...) (0) # define ProfBeginCapture(...) (0)
# define ProfEndCapture(...) (0) # define ProfEndCapture(...) (0)
# define ProfThreadName(...) (0) # define ProfThreadName(...) (0)
# define ProfMsg(...) (0) # define ProfMsg(...) (0)
# define ProfBeginLockWait(...) (0) # define ProfBeginLockWait(...) (0)
# define ProfEndLockWait(...) (0) # define ProfEndLockWait(...) (0)
# define ProfLockTake(...) (0) # define ProfLockTake(...) (0)
# define ProfLockDrop(...) (0) # define ProfLockDrop(...) (0)
# define ProfColor(...) (0) # define ProfColor(...) (0)
# define ProfBeginV(...) (0)
# define ProfNoteV(...) (0)
#endif #endif
//////////////////////////////// ////////////////////////////////
+297 -42
View File
@@ -215,12 +215,42 @@ str32_cstring(U32 *c){
internal String8 internal String8
str8_cstring_capped(void *cstr, void *cap) str8_cstring_capped(void *cstr, void *cap)
{ {
char *ptr = (char*)cstr; char *ptr = (char *)cstr;
char *opl = (char*)cap; char *opl = (char *)cap;
for (;ptr < opl && *ptr != 0; ptr += 1); for (;ptr < opl && *ptr != 0; ptr += 1);
U64 size = (U64)(ptr - (char *)cstr); U64 size = (U64)(ptr - (char *)cstr);
String8 result = {(U8*)cstr, size}; String8 result = str8((U8*)cstr, size);
return(result); return result;
}
internal String16
str16_cstring_capped(void *cstr, void *cap)
{
U16 *ptr = (U16 *)cstr;
U16 *opl = (U16 *)cap;
for (;ptr < opl && *ptr != 0; ptr += 1);
U64 size = (U64)(ptr - (U16 *)cstr);
String16 result = str16(cstr, size);
return result;
}
internal String8
str8_cstring_capped_reverse(void *raw_start, void *raw_cap)
{
U8 *start = raw_start;
U8 *ptr = raw_cap;
for(; ptr > start; )
{
ptr -= 1;
if (*ptr == '\0')
{
break;
}
}
U64 size = (U64)(ptr - start);
String8 result = str8(start, size);
return result;
} }
//////////////////////////////// ////////////////////////////////
@@ -263,31 +293,41 @@ backslashed_from_str8(Arena *arena, String8 string)
//~ rjf: String Matching //~ rjf: String Matching
internal B32 internal B32
str8_match(String8 a, String8 b, StringMatchFlags flags){ str8_match(String8 a, String8 b, StringMatchFlags flags)
{
B32 result = 0; B32 result = 0;
if (a.size == b.size || (flags & StringMatchFlag_RightSideSloppy)){ if(a.size == b.size && flags == 0)
B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive); {
result = MemoryMatch(a.str, b.str, b.size);
}
else if(a.size == b.size || (flags & StringMatchFlag_RightSideSloppy))
{
B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
B32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive); B32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive);
U64 size = Min(a.size, b.size); U64 size = Min(a.size, b.size);
result = 1; result = 1;
for (U64 i = 0; i < size; i += 1){ for(U64 i = 0; i < size; i += 1)
{
U8 at = a.str[i]; U8 at = a.str[i];
U8 bt = b.str[i]; U8 bt = b.str[i];
if (case_insensitive){ if(case_insensitive)
{
at = char_to_upper(at); at = char_to_upper(at);
bt = char_to_upper(bt); bt = char_to_upper(bt);
} }
if (slash_insensitive){ if(slash_insensitive)
{
at = char_to_correct_slash(at); at = char_to_correct_slash(at);
bt = char_to_correct_slash(bt); bt = char_to_correct_slash(bt);
} }
if (at != bt){ if(at != bt)
{
result = 0; result = 0;
break; break;
} }
} }
} }
return(result); return result;
} }
internal U64 internal U64
@@ -322,6 +362,22 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
return(result); return(result);
} }
internal U64
str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
{
U64 result = 0;
for(S64 i = string.size - start_pos - needle.size; i >= 0; --i)
{
String8 haystack = str8_substr(string, rng_1u64(i, i + needle.size));
if(str8_match(haystack, needle, flags))
{
result = (U64)i + needle.size;
break;
}
}
return result;
}
internal B32 internal B32
str8_ends_with(String8 string, String8 end, StringMatchFlags flags){ str8_ends_with(String8 string, String8 end, StringMatchFlags flags){
String8 postfix = str8_postfix(string, end.size); String8 postfix = str8_postfix(string, end.size);
@@ -544,21 +600,121 @@ try_s64_from_str8_c_rules(String8 string, S64 *x){
//- rjf: integer -> string //- rjf: integer -> string
internal String8 internal String8
str8_from_memory_size(Arena *arena, U64 z){ str8_from_memory_size(Arena *arena, U64 size)
String8 result = {0}; {
if (z < KB(1)){ String8 result;
result = push_str8f(arena, "%llu b", z);
if(size < KB(1))
{
result = push_str8f(arena, "%llu Bytes", size);
} }
else if (z < MB(1)){ else if(size < MB(1))
result = push_str8f(arena, "%llu.%02llu Kb", z/KB(1), ((100*z)/KB(1))%100); {
result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100);
} }
else if (z < GB(1)){ else if(size < GB(1))
result = push_str8f(arena, "%llu.%02llu Mb", z/MB(1), ((100*z)/MB(1))%100); {
result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100);
} }
else{ else if(size < TB(1))
result = push_str8f(arena, "%llu.%02llu Gb", z/GB(1), ((100*z)/GB(1))%100); {
result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100);
} }
return(result); else
{
result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100);
}
return result;
}
internal String8
str8_from_count(Arena *arena, U64 count)
{
String8 result;
if(count < 1 * 1000)
{
result = push_str8f(arena, "%llu", count);
}
else if(count < 1000000)
{
U64 frac = ((count * 100) / 1000) % 100;
if(frac > 0)
{
result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac);
}
else
{
result = push_str8f(arena, "%lluK", count / 1000);
}
}
else if(count < 1000000000)
{
U64 frac = ((count * 100) / 1000000) % 100;
if(frac > 0)
{
result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac);
}
else
{
result = push_str8f(arena, "%lluM", count / 1000000);
}
}
else
{
U64 frac = ((count * 100) * 1000000000) % 100;
if(frac > 0)
{
result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac);
}
else
{
result = push_str8f(arena, "%lluB", count / 1000000000, frac);
}
}
return result;
}
internal String8
str8_from_bits_u32(Arena *arena, U32 x)
{
U8 c0 = 'a' + ((x >> 28) & 0xf);
U8 c1 = 'a' + ((x >> 24) & 0xf);
U8 c2 = 'a' + ((x >> 20) & 0xf);
U8 c3 = 'a' + ((x >> 16) & 0xf);
U8 c4 = 'a' + ((x >> 12) & 0xf);
U8 c5 = 'a' + ((x >> 8) & 0xf);
U8 c6 = 'a' + ((x >> 4) & 0xf);
U8 c7 = 'a' + ((x >> 0) & 0xf);
String8 result = push_str8f(arena, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
return result;
}
internal String8
str8_from_bits_u64(Arena *arena, U64 x)
{
U8 c0 = 'a' + ((x >> 60) & 0xf);
U8 c1 = 'a' + ((x >> 56) & 0xf);
U8 c2 = 'a' + ((x >> 52) & 0xf);
U8 c3 = 'a' + ((x >> 48) & 0xf);
U8 c4 = 'a' + ((x >> 44) & 0xf);
U8 c5 = 'a' + ((x >> 40) & 0xf);
U8 c6 = 'a' + ((x >> 36) & 0xf);
U8 c7 = 'a' + ((x >> 32) & 0xf);
U8 c8 = 'a' + ((x >> 28) & 0xf);
U8 c9 = 'a' + ((x >> 24) & 0xf);
U8 ca = 'a' + ((x >> 20) & 0xf);
U8 cb = 'a' + ((x >> 16) & 0xf);
U8 cc = 'a' + ((x >> 12) & 0xf);
U8 cd = 'a' + ((x >> 8) & 0xf);
U8 ce = 'a' + ((x >> 4) & 0xf);
U8 cf = 'a' + ((x >> 0) & 0xf);
String8 result = push_str8f(arena,
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf);
return result;
} }
internal String8 internal String8
@@ -685,27 +841,28 @@ f64_from_str8(String8 string)
{ {
// rjf: find starting pos of numeric string, as well as sign // rjf: find starting pos of numeric string, as well as sign
F64 sign = +1.0; F64 sign = +1.0;
//U64 first_numeric = 0;
if(string.str[0] == '-') if(string.str[0] == '-')
{ {
//first_numeric = 1;
sign = -1.0; sign = -1.0;
} }
else if(string.str[0] == '+') else if(string.str[0] == '+')
{ {
//first_numeric = 1;
sign = 1.0; sign = 1.0;
} }
// rjf: gather numerics // rjf: gather numerics
U64 num_valid_chars = 0; U64 num_valid_chars = 0;
char buffer[64]; char buffer[64];
B32 exp = 0;
for(U64 idx = 0; idx < string.size && num_valid_chars < sizeof(buffer)-1; idx += 1) for(U64 idx = 0; idx < string.size && num_valid_chars < sizeof(buffer)-1; idx += 1)
{ {
if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.') if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.' || string.str[idx] == 'e' ||
(exp && (string.str[idx] == '+' || string.str[idx] == '-')))
{ {
buffer[num_valid_chars] = string.str[idx]; buffer[num_valid_chars] = string.str[idx];
num_valid_chars += 1; num_valid_chars += 1;
exp = 0;
exp = (string.str[idx] == 'e');
} }
} }
@@ -1138,7 +1295,9 @@ str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){
internal String8 internal String8
str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){ str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){
StringJoin params = {0}; StringJoin params = {0};
switch (style){ switch(style)
{
case PathStyle_Null:{}break;
case PathStyle_Relative: case PathStyle_Relative:
case PathStyle_WindowsAbsolute: case PathStyle_WindowsAbsolute:
{ {
@@ -1151,9 +1310,8 @@ str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){
params.sep = str8_lit("/"); params.sep = str8_lit("/");
}break; }break;
} }
String8 result = str8_list_join(arena, path, &params); String8 result = str8_list_join(arena, path, &params);
return(result); return result;
} }
internal String8TxtPtPair internal String8TxtPtPair
@@ -1412,6 +1570,35 @@ str32_from_8(Arena *arena, String8 in){
return(str32(str, size)); return(str32(str, size));
} }
////////////////////////////////
//~ String -> Enum Conversions
read_only global struct
{
String8 string;
OperatingSystem os;
} g_os_enum_map[] =
{
{ str8_lit_comp(""), OperatingSystem_Null },
{ str8_lit_comp("Windows"), OperatingSystem_Windows, },
{ str8_lit_comp("Linux"), OperatingSystem_Linux, },
{ str8_lit_comp("Mac"), OperatingSystem_Mac, },
};
StaticAssert(ArrayCount(g_os_enum_map) == OperatingSystem_COUNT, g_os_enum_map_count_check);
internal OperatingSystem
operating_system_from_string(String8 string)
{
for(U64 i = 0; i < ArrayCount(g_os_enum_map); ++i)
{
if(str8_match(g_os_enum_map[i].string, string, StringMatchFlag_CaseInsensitive))
{
return g_os_enum_map[i].os;
}
}
return OperatingSystem_Null;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Types & Space Enum -> String Conversions //~ rjf: Basic Types & Space Enum -> String Conversions
@@ -1444,18 +1631,14 @@ string_from_side(Side side){
} }
internal String8 internal String8
string_from_operating_system(OperatingSystem os){ string_from_operating_system(OperatingSystem os)
local_persist String8 strings[] = { {
str8_lit_comp("Null"), String8 result = g_os_enum_map[OperatingSystem_Null].string;
str8_lit_comp("Windows"), if(os < ArrayCount(g_os_enum_map))
str8_lit_comp("Linux"), {
str8_lit_comp("Mac"), result = g_os_enum_map[os].string;
};
String8 result = str8_lit("error");
if (os < OperatingSystem_COUNT){
result = strings[os];
} }
return(result); return result;
} }
internal String8 internal String8
@@ -1565,6 +1748,78 @@ string_from_elapsed_time(Arena *arena, DateTime dt){
return(result); return(result);
} }
////////////////////////////////
//~ Globally UNique Ids
internal String8
string_from_guid(Arena *arena, Guid guid)
{
String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.data1,
guid.data2,
guid.data3,
guid.data4[0],
guid.data4[1],
guid.data4[2],
guid.data4[3],
guid.data4[4],
guid.data4[5],
guid.data4[6],
guid.data4[7]);
return result;
}
internal B32
try_guid_from_string(String8 string, Guid *guid_out)
{
Temp scratch = scratch_begin(0,0);
B32 is_parsed = 0;
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("-"), StringSplitFlag_KeepEmpties);
if(list.node_count == 5)
{
String8 data1_str = list.first->string;
String8 data2_str = list.first->next->string;
String8 data3_str = list.first->next->next->string;
String8 data4_hi_str = list.first->next->next->next->string;
String8 data4_lo_str = list.first->next->next->next->next->string;
if(str8_is_integer(data1_str, 16) &&
str8_is_integer(data2_str, 16) &&
str8_is_integer(data3_str, 16) &&
str8_is_integer(data4_hi_str, 16) &&
str8_is_integer(data4_lo_str, 16))
{
U64 data1 = u64_from_str8(data1_str, 16);
U64 data2 = u64_from_str8(data2_str, 16);
U64 data3 = u64_from_str8(data3_str, 16);
U64 data4_hi = u64_from_str8(data4_hi_str, 16);
U64 data4_lo = u64_from_str8(data4_lo_str, 16);
if(data1 <= max_U32 &&
data2 <= max_U16 &&
data3 <= max_U16 &&
data4_hi <= max_U16 &&
data4_lo <= 0xffffffffffff)
{
guid_out->data1 = (U32)data1;
guid_out->data2 = (U16)data2;
guid_out->data3 = (U16)data3;
U64 data4 = (data4_hi << 48) | data4_lo;
MemoryCopy(&guid_out->data4[0], &data4, sizeof(data4));
is_parsed = 1;
}
}
}
scratch_end(scratch);
return is_parsed;
}
internal Guid
guid_from_string(String8 string)
{
Guid guid = {0};
try_guid_from_string(string, &guid);
return guid;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Text Indentation //~ rjf: Basic Text Indentation
+19 -1
View File
@@ -193,6 +193,8 @@ internal String8 str8_cstring(char *c);
internal String16 str16_cstring(U16 *c); internal String16 str16_cstring(U16 *c);
internal String32 str32_cstring(U32 *c); internal String32 str32_cstring(U32 *c);
internal String8 str8_cstring_capped(void *cstr, void *cap); internal String8 str8_cstring_capped(void *cstr, void *cap);
internal String16 str16_cstring_capped(void *cstr, void *cap);
internal String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
//////////////////////////////// ////////////////////////////////
//~ rjf: String Stylization //~ rjf: String Stylization
@@ -206,6 +208,7 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags); internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags); internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
//////////////////////////////// ////////////////////////////////
@@ -238,7 +241,10 @@ internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x); internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
//- rjf: integer -> string //- rjf: integer -> string
internal String8 str8_from_memory_size(Arena *arena, U64 z); internal String8 str8_from_memory_size(Arena *arena, U64 size);
internal String8 str8_from_count(Arena *arena, U64 count);
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator); internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
@@ -310,6 +316,11 @@ internal String16 str16_from_8(Arena *arena, String8 in);
internal String8 str8_from_32(Arena *arena, String32 in); internal String8 str8_from_32(Arena *arena, String32 in);
internal String32 str32_from_8(Arena *arena, String8 in); internal String32 str32_from_8(Arena *arena, String8 in);
////////////////////////////////
//~ String -> Enum Conversions
internal OperatingSystem operating_system_from_string(String8 string);
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Types & Space Enum -> String Conversions //~ rjf: Basic Types & Space Enum -> String Conversions
@@ -327,6 +338,13 @@ 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);
////////////////////////////////
//~ Globally Unique Ids
internal String8 string_from_guid(Arena *arena, Guid guid);
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
internal Guid guid_from_string(String8 string);
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Text Indentation //~ rjf: Basic Text Indentation
+10 -8
View File
@@ -490,12 +490,8 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
CV_C13SubSecLinesHeader *hdr = (CV_C13SubSecLinesHeader*)(first + read_off); CV_C13SubSecLinesHeader *hdr = (CV_C13SubSecLinesHeader*)(first + read_off);
read_off += sizeof(*hdr); read_off += sizeof(*hdr);
// extract top level info // rjf: extract section index
U32 sec_idx = hdr->sec; 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 // rjf: bad section index -> skip
if(sec_idx < 1 || sections.count < sec_idx) if(sec_idx < 1 || sections.count < sec_idx)
@@ -503,6 +499,12 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
continue; continue;
} }
// extract top level info
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;
// read files // read files
for(;read_off+sizeof(CV_C13File) <= read_off_opl;) for(;read_off+sizeof(CV_C13File) <= read_off_opl;)
{ {
@@ -519,7 +521,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off); CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off);
U32 name_off = checksum->name_off; U32 name_off = checksum->name_off;
file_name = str8_cstring_capped((char*)(strtbl.str + name_off), file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
(char*)(strtbl.str + strtbl.size)); (char*)(strtbl.str + strtbl.size));
} }
// array layouts // array layouts
@@ -596,7 +598,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off); CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off);
U32 name_off = checksum->name_off; U32 name_off = checksum->name_off;
file_name = str8_cstring_capped((char*)(strtbl.str + name_off), file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
(char*)(strtbl.str + strtbl.size)); (char*)(strtbl.str + strtbl.size));
} }
// rjf: parse extra files // rjf: parse extra files
@@ -617,7 +619,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n); SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n);
n->v.inlinee = hdr->inlinee; n->v.inlinee = hdr->inlinee;
n->v.file_name = file_name; n->v.file_name = file_name;
n->v.file_off = hdr->file_off; n->v.file_off = hdr->file_off;
n->v.first_source_ln = hdr->first_source_ln; n->v.first_source_ln = hdr->first_source_ln;
n->v.extra_file_count = extra_file_count; n->v.extra_file_count = extra_file_count;
n->v.extra_files = extra_files; n->v.extra_files = extra_files;
+160 -142
View File
@@ -97,15 +97,17 @@ coff_header_info_from_data(String8 data)
COFF_HeaderInfo info = {0}; COFF_HeaderInfo info = {0};
if (coff_is_big_obj(data)) { if (coff_is_big_obj(data)) {
COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)data.str; COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)data.str;
info.machine = big_header->machine; info.type = COFF_DataType_BIG_OBJ;
info.section_array_off = sizeof(COFF_HeaderBigObj); info.machine = big_header->machine;
info.section_count_no_null = big_header->section_count; info.section_array_off = sizeof(COFF_HeaderBigObj);
info.string_table_off = big_header->pointer_to_symbol_table + sizeof(COFF_Symbol32) * big_header->number_of_symbols; info.section_count_no_null = big_header->section_count;
info.symbol_size = sizeof(COFF_Symbol32); info.string_table_off = big_header->pointer_to_symbol_table + sizeof(COFF_Symbol32) * big_header->number_of_symbols;
info.symbol_off = big_header->pointer_to_symbol_table; info.symbol_size = sizeof(COFF_Symbol32);
info.symbol_count = big_header->number_of_symbols; info.symbol_off = big_header->pointer_to_symbol_table;
info.symbol_count = big_header->number_of_symbols;
} else if (coff_is_obj(data)) { } else if (coff_is_obj(data)) {
COFF_Header *header = (COFF_Header*)data.str; COFF_Header *header = (COFF_Header*)data.str;
info.type = COFF_DataType_OBJ;
info.machine = header->machine; info.machine = header->machine;
info.section_array_off = sizeof(COFF_Header); info.section_array_off = sizeof(COFF_Header);
info.section_count_no_null = header->section_count; info.section_count_no_null = header->section_count;
@@ -143,6 +145,30 @@ coff_align_size_from_section_flags(COFF_SectionFlags flags)
return align; return align;
} }
internal COFF_SectionFlags
coff_section_flag_from_align_size(U64 align)
{
COFF_SectionFlags flags = 0;
switch (align) {
case 1: flags = COFF_SectionAlign_1BYTES; break;
case 2: flags = COFF_SectionAlign_2BYTES; break;
case 4: flags = COFF_SectionAlign_4BYTES; break;
case 8: flags = COFF_SectionAlign_8BYTES; break;
case 16: flags = COFF_SectionAlign_16BYTES; break;
case 32: flags = COFF_SectionAlign_32BYTES; break;
case 64: flags = COFF_SectionAlign_64BYTES; break;
case 128: flags = COFF_SectionAlign_128BYTES; break;
case 256: flags = COFF_SectionAlign_256BYTES; break;
case 512: flags = COFF_SectionAlign_512BYTES; break;
case 1024: flags = COFF_SectionAlign_1024BYTES; break;
case 2048: flags = COFF_SectionAlign_2048BYTES; break;
case 4096: flags = COFF_SectionAlign_4096BYTES; break;
case 8192: flags = COFF_SectionAlign_8192BYTES; break;
}
flags <<= COFF_SectionFlag_ALIGN_SHIFT;
return flags;
}
internal COFF_SymbolValueInterpType internal COFF_SymbolValueInterpType
coff_interp_symbol(COFF_Symbol32 *symbol) coff_interp_symbol(COFF_Symbol32 *symbol)
{ {
@@ -550,6 +576,39 @@ coff_make_import_header_by_ordinal(Arena *arena,
} }
//////////////////////////////// ////////////////////////////////
//~ Resources
internal String8
coff_resource_string_from_str16(Arena *arena, String16 string)
{
AssertAlways(string.size <= max_U16);
U16 size16 = (U16)string.size;
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
MemoryCopy(buffer + 0, &size16, sizeof(size16));
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
return str8_array(buffer, size16 + 1);
}
internal String8
coff_resource_string_from_str8(Arena *arena, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String16 string16 = str16_from_8(scratch.arena, string);
String8 result = coff_resource_string_from_str16(arena, string16);
scratch_end(scratch);
return result;
}
internal String8
coff_resource_number_from_u16(Arena *arena, U16 number)
{
U16 *buffer = push_array_no_zero(arena, U16, 2);
buffer[0] = max_U16;
buffer[1] = number;
return str8_array(buffer, 2);
}
internal 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)
@@ -567,47 +626,9 @@ coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b)
} }
internal COFF_ResourceID internal COFF_ResourceID
coff_resource_id_copy(Arena *arena, COFF_ResourceID id) coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16)
{ {
COFF_ResourceID result = zero_struct; COFF_ResourceID id = {0};
switch (id.type) {
case COFF_ResourceIDType_NULL: break;
case COFF_ResourceIDType_NUMBER: {
result.type = COFF_ResourceIDType_NUMBER;
result.u.number = id.u.number;
} break;
case COFF_ResourceIDType_STRING: {
result.type = COFF_ResourceIDType_STRING;
result.u.string = id.u.string;
} break;
default: Assert(!"invalid resource id type");
}
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
coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
{
COFF_ResourceID id;
id.type = id_16->type; id.type = id_16->type;
switch (id_16->type) { switch (id_16->type) {
case COFF_ResourceIDType_NULL: break; case COFF_ResourceIDType_NULL: break;
@@ -617,23 +638,22 @@ coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
case COFF_ResourceIDType_STRING: { case COFF_ResourceIDType_STRING: {
id.u.string = str8_from_16(arena, id_16->u.string); id.u.string = str8_from_16(arena, id_16->u.string);
} break; } break;
default: Assert(!"invalid resource id type"); default: InvalidPath;
} }
return id; return id;
} }
internal U64 internal U64
coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out) coff_read_resource_id_utf16(String8 data, U64 off, COFF_ResourceID_16 *id_out)
{ {
U64 cursor = off; U64 cursor = off;
U16 flag = 0; U16 flag = 0;
str8_deserial_read_struct(data, cursor, &flag); str8_deserial_read_struct(data, cursor, &flag);
B32 is_number = flag == max_U16; if (flag == max_U16) {
if (is_number) {
cursor += sizeof(flag);
id_out->type = COFF_ResourceIDType_NUMBER; id_out->type = COFF_ResourceIDType_NUMBER;
cursor += sizeof(flag);
cursor += str8_deserial_read_struct(data, cursor, &id_out->u.number); cursor += str8_deserial_read_struct(data, cursor, &id_out->u.number);
} else { } else {
id_out->type = COFF_ResourceIDType_STRING; id_out->type = COFF_ResourceIDType_STRING;
@@ -641,93 +661,81 @@ coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out)
} }
U64 read_size = cursor - off; U64 read_size = cursor - off;
read_size = AlignPow2(read_size, COFF_RES_ALIGN);
return read_size; return read_size;
} }
internal U64 internal U64
coff_read_resource(String8 raw_res, U64 off, Arena *arena, COFF_Resource *res_out) coff_read_resource(String8 raw_res, U64 off, Arena *arena, COFF_Resource *res_out)
{ {
// parse header String8 raw_header = str8_skip(raw_res, off);
COFF_ResourceHeaderPrefix prefix; MemoryZeroStruct(&prefix); U64 header_cursor = 0;
U64 cursor = str8_deserial_read_struct(raw_res, off, &prefix);
String8 header_data = str8_substr(raw_res, rng_1u64(off, off + prefix.header_size)); // prefix
COFF_ResourceHeaderPrefix prefix = {0};
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
raw_header = str8_prefix(raw_header, prefix.header_size);
// header
COFF_ResourceID_16 type_16 = {0};
COFF_ResourceID_16 name_16 = {0};
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
Assert(prefix.header_size == header_cursor);
// convert utf-16 resource ids to utf-8
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
// read data
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
Assert(prefix.data_size == data_read_size);
COFF_ResourceID_16 type_16; MemoryZeroStruct(&type_16); // compute read size
cursor += coff_read_resource_id(header_data, cursor, &type_16); U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_RES_ALIGN);
cursor = AlignPow2(cursor, COFF_RES_ALIGN); return read_size;
COFF_ResourceID_16 name_16; MemoryZeroStruct(&name_16);
cursor += coff_read_resource_id(header_data, cursor, &name_16);
cursor = AlignPow2(cursor, COFF_RES_ALIGN);
U32 data_version = 0;
cursor += str8_deserial_read_struct(header_data, cursor, &data_version);
COFF_ResourceMemoryFlags memory_flags = 0;
cursor += str8_deserial_read_struct(header_data, cursor, &memory_flags);
U16 language_id = 0;
cursor += str8_deserial_read_struct(header_data, cursor, &language_id);
U32 version = 0;
cursor += str8_deserial_read_struct(header_data, cursor, &version);
U32 characteristics = 0;
cursor += str8_deserial_read_struct(header_data, cursor, &characteristics);
String8 data;
cursor += str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &data);
// was resource parsed?
Assert(cursor >= prefix.data_size + prefix.header_size);
// fill out result
res_out->type = coff_convert_resource_id(arena, &type_16);
res_out->name = coff_convert_resource_id(arena, &name_16);
res_out->language_id = language_id;
res_out->data_version = data_version;
res_out->version = version;
res_out->memory_flags = memory_flags;
res_out->data = data;
U64 resource_size = AlignPow2(prefix.data_size + prefix.header_size, COFF_RES_ALIGN);
return resource_size;
} }
internal COFF_ResourceList internal COFF_ResourceList
coff_resource_list_from_data(Arena *arena, String8 data) coff_resource_list_from_data(Arena *arena, String8 data)
{ {
COFF_ResourceList list; MemoryZeroStruct(&list); COFF_ResourceList list = {0};
for (U64 cursor = 0, stride; cursor < data.size; cursor += stride) { U64 cursor;
for (cursor = 0 ; cursor < data.size; ) {
COFF_ResourceNode *node = push_array(arena, COFF_ResourceNode, 1); COFF_ResourceNode *node = push_array(arena, COFF_ResourceNode, 1);
stride = coff_read_resource(data, cursor, arena, &node->data); cursor += coff_read_resource(data, cursor, arena, &node->data);
list.count += 1;
SLLQueuePush(list.first, list.last, node); SLLQueuePush(list.first, list.last, node);
++list.count;
} }
Assert(cursor == data.size);
return list; return list;
} }
internal void internal String8
coff_write_resource_id(Arena *arena, String8List *srl, COFF_ResourceID id) coff_write_resource_id(Arena *arena, COFF_ResourceID id)
{ {
String8 result = str8_zero();
switch (id.type) { switch (id.type) {
case COFF_ResourceIDType_NULL: break; case COFF_ResourceIDType_NULL: break;
case COFF_ResourceIDType_NUMBER: { case COFF_ResourceIDType_NUMBER: {
str8_serial_push_u16(arena, srl, max_U16); result = coff_resource_number_from_u16(arena, id.u.number);
str8_serial_push_u16(arena, srl, id.u.number);
} break; } break;
case COFF_ResourceIDType_STRING: { case COFF_ResourceIDType_STRING: {
String16 str16 = str16_from_8(arena, id.u.string); result = coff_resource_string_from_str8(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; } break;
default: InvalidPath; default: InvalidPath;
} }
str8_serial_push_align(arena, srl, COFF_RES_ALIGN); return result;
} }
internal String8List internal String8
coff_write_resource(Arena *arena, coff_write_resource(Arena *arena,
COFF_ResourceID type, COFF_ResourceID type,
COFF_ResourceID name, COFF_ResourceID name,
@@ -738,34 +746,43 @@ coff_write_resource(Arena *arena,
U32 characteristics, U32 characteristics,
String8 data) String8 data)
{ {
U64 header_size = sizeof(COFF_ResourceHeaderPrefix) + Temp scratch = scratch_begin(&arena, 1);
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); String8List list = {0};
header->data_size = safe_cast_u32(data.size);
header->header_size = safe_cast_u32(header_size);
String8List srl = {0}; COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
str8_serial_begin(arena, &srl); String8 packed_type = coff_write_resource_id(scratch.arena, type);
str8_serial_push_data(arena, &srl, &g_coff_res_magic[0], sizeof(g_coff_res_magic)); String8 packed_name = coff_write_resource_id(scratch.arena, name);
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; // prefix + header
str8_list_push(scratch.arena, &list, str8_struct(prefix));
str8_list_push(scratch.arena, &list, packed_type);
str8_list_push(scratch.arena, &list, packed_name);
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
str8_list_push(scratch.arena, &list, str8_struct(&version));
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
prefix->data_size = safe_cast_u32(data.size);
prefix->header_size = safe_cast_u32(list.total_size);
// data
str8_list_push(scratch.arena, &list, data);
// magic
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
// align
U64 align_size = AlignPow2(list.total_size, COFF_RES_ALIGN) - list.total_size;
U8 *align = push_array(scratch.arena, U8, align_size);
str8_list_push(scratch.arena, &list, str8(align, align_size));
// join
String8 res = str8_list_join(arena, &list, 0);
scratch_end(scratch);
return res;
} }
//////////////////////////////// ////////////////////////////////
@@ -777,12 +794,10 @@ coff_data_type_from_data(String8 data)
if (is_big_obj) { if (is_big_obj) {
return COFF_DataType_BIG_OBJ; return COFF_DataType_BIG_OBJ;
} }
B32 is_import = coff_is_import(data); B32 is_import = coff_is_import(data);
if (is_import) { if (is_import) {
return COFF_DataType_IMPORT; return COFF_DataType_IMPORT;
} }
return COFF_DataType_OBJ; return COFF_DataType_OBJ;
} }
@@ -1207,6 +1222,7 @@ read_only struct
} g_coff_machine_map[] = { } g_coff_machine_map[] = {
{ str8_lit_comp(""), COFF_MachineType_UNKNOWN }, { str8_lit_comp(""), COFF_MachineType_UNKNOWN },
{ str8_lit_comp("X86"), COFF_MachineType_X86 }, { str8_lit_comp("X86"), COFF_MachineType_X86 },
{ str8_lit_comp("AMD64"), COFF_MachineType_X64 },
{ str8_lit_comp("X64"), COFF_MachineType_X64 }, { str8_lit_comp("X64"), COFF_MachineType_X64 },
{ str8_lit_comp("AM33"), COFF_MachineType_AM33 }, { str8_lit_comp("AM33"), COFF_MachineType_AM33 },
{ str8_lit_comp("ARM"), COFF_MachineType_ARM }, { str8_lit_comp("ARM"), COFF_MachineType_ARM },
@@ -1259,10 +1275,12 @@ 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)); for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
Assert(machine == g_coff_machine_map[machine].machine); if (g_coff_machine_map[i].machine == machine) {
String8 string = g_coff_machine_map[machine].string; return g_coff_machine_map[i].string;
return string; }
}
return str8_zero();
} }
internal String8 internal String8
+272 -298
View File
@@ -77,12 +77,12 @@ typedef struct COFF_Header COFF_Header;
struct COFF_Header struct COFF_Header
{ {
COFF_MachineType machine; COFF_MachineType machine;
U16 section_count; U16 section_count;
COFF_TimeStamp time_stamp; COFF_TimeStamp time_stamp;
U32 symbol_table_foff; U32 symbol_table_foff;
U32 symbol_count; U32 symbol_count;
U16 optional_header_size; U16 optional_header_size;
COFF_Flags flags; COFF_Flags flags;
}; };
typedef U32 COFF_SectionAlign; typedef U32 COFF_SectionAlign;
@@ -108,35 +108,36 @@ enum
typedef U32 COFF_SectionFlags; typedef U32 COFF_SectionFlags;
enum enum
{ {
COFF_SectionFlag_TYPE_NO_PAD = (1 << 3), COFF_SectionFlag_TYPE_NO_PAD = (1 << 3),
COFF_SectionFlag_CNT_CODE = (1 << 5), COFF_SectionFlag_CNT_CODE = (1 << 5),
COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6), COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6),
COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7), COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7),
COFF_SectionFlag_LNK_OTHER = (1 << 8), COFF_SectionFlag_LNK_OTHER = (1 << 8),
COFF_SectionFlag_LNK_INFO = (1 << 9), COFF_SectionFlag_LNK_INFO = (1 << 9),
COFF_SectionFlag_LNK_REMOVE = (1 << 11), COFF_SectionFlag_LNK_REMOVE = (1 << 11),
COFF_SectionFlag_LNK_COMDAT = (1 << 12), COFF_SectionFlag_LNK_COMDAT = (1 << 12),
COFF_SectionFlag_GPREL = (1 << 15), COFF_SectionFlag_GPREL = (1 << 15),
COFF_SectionFlag_MEM_16BIT = (1 << 17), COFF_SectionFlag_MEM_16BIT = (1 << 17),
COFF_SectionFlag_MEM_LOCKED = (1 << 18), COFF_SectionFlag_MEM_LOCKED = (1 << 18),
COFF_SectionFlag_MEM_PRELOAD = (1 << 19), COFF_SectionFlag_MEM_PRELOAD = (1 << 19),
COFF_SectionFlag_ALIGN_SHIFT = 20, COFF_SectionFlag_ALIGN_MASK = 0xf, COFF_SectionFlag_ALIGN_SHIFT = 20,
COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24), COFF_SectionFlag_ALIGN_MASK = 0xf,
COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25), COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24),
COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26), COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25),
COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27), COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26),
COFF_SectionFlag_MEM_SHARED = (1 << 28), COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27),
COFF_SectionFlag_MEM_EXECUTE = (1 << 29), COFF_SectionFlag_MEM_SHARED = (1 << 28),
COFF_SectionFlag_MEM_READ = (1 << 30), COFF_SectionFlag_MEM_EXECUTE = (1 << 29),
COFF_SectionFlag_MEM_WRITE = (1 << 31), COFF_SectionFlag_MEM_READ = (1 << 30),
COFF_SectionFlag_MEM_WRITE = (1 << 31),
}; };
#define COFF_SectionFlags_Extract_ALIGN(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_ALIGN_SHIFT) & COFF_SectionFlag_ALIGN_MASK) #define COFF_SectionFlags_Extract_ALIGN(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_ALIGN_SHIFT) & COFF_SectionFlag_ALIGN_MASK)
#define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL) #define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL)
typedef struct COFF_SectionHeader COFF_SectionHeader; typedef struct COFF_SectionHeader COFF_SectionHeader;
struct COFF_SectionHeader struct COFF_SectionHeader
{ {
U8 name[8]; U8 name[8];
U32 vsize; U32 vsize;
U32 voff; U32 voff;
U32 fsize; U32 fsize;
@@ -151,112 +152,99 @@ struct COFF_SectionHeader
typedef U16 COFF_RelocTypeX64; typedef U16 COFF_RelocTypeX64;
enum enum
{ {
COFF_RelocTypeX64_ABS = 0x0, COFF_RelocTypeX64_ABS = 0x0,
COFF_RelocTypeX64_ADDR64 = 0x1, COFF_RelocTypeX64_ADDR64 = 0x1,
COFF_RelocTypeX64_ADDR32 = 0x2, COFF_RelocTypeX64_ADDR32 = 0x2,
COFF_RelocTypeX64_ADDR32NB = 0x3, COFF_RelocTypeX64_ADDR32NB = 0x3, // NB => No Base
// NB => No Base COFF_RelocTypeX64_REL32 = 0x4,
COFF_RelocTypeX64_REL32 = 0x4, COFF_RelocTypeX64_REL32_1 = 0x5,
COFF_RelocTypeX64_REL32_1 = 0x5, COFF_RelocTypeX64_REL32_2 = 0x6,
COFF_RelocTypeX64_REL32_2 = 0x6, COFF_RelocTypeX64_REL32_3 = 0x7,
COFF_RelocTypeX64_REL32_3 = 0x7, COFF_RelocTypeX64_REL32_4 = 0x8,
COFF_RelocTypeX64_REL32_4 = 0x8, COFF_RelocTypeX64_REL32_5 = 0x9,
COFF_RelocTypeX64_REL32_5 = 0x9, COFF_RelocTypeX64_SECTION = 0xA,
COFF_RelocTypeX64_SECTION = 0xA, COFF_RelocTypeX64_SECREL = 0xB,
COFF_RelocTypeX64_SECREL = 0xB, COFF_RelocTypeX64_SECREL7 = 0xC, // TODO(nick): MSDN doesn't specify size for CLR token
COFF_RelocTypeX64_SECREL7 = 0xC, COFF_RelocTypeX64_TOKEN = 0xD,
// TODO(nick): MSDN doesn't specify size for CLR token COFF_RelocTypeX64_SREL32 = 0xE, // TODO(nick): MSDN doesn't specify size for PAIR
COFF_RelocTypeX64_TOKEN = 0xD, COFF_RelocTypeX64_PAIR = 0xF,
COFF_RelocTypeX64_SREL32 = 0xE, COFF_RelocTypeX64_SSPAN32 = 0x10,
// TODO(nick): MSDN doesn't specify size for PAIR COFF_RelocTypeX64_COUNT = 17
COFF_RelocTypeX64_PAIR = 0xF,
COFF_RelocTypeX64_SSPAN32 = 0x10,
COFF_RelocTypeX64_COUNT = 17
}; };
typedef U16 COFF_RelocTypeX86; typedef U16 COFF_RelocTypeX86;
enum enum
{ {
COFF_RelocTypeX86_ABS = 0x0, COFF_RelocTypeX86_ABS = 0x0, // relocation is ignored
// relocation is ignored COFF_RelocTypeX86_DIR16 = 0x1, // no support
COFF_RelocTypeX86_DIR16 = 0x1, COFF_RelocTypeX86_REL16 = 0x2, // no support
// no support COFF_RelocTypeX86_UNKNOWN0 = 0x3,
COFF_RelocTypeX86_REL16 = 0x2, COFF_RelocTypeX86_UNKNOWN2 = 0x4,
// no support COFF_RelocTypeX86_UNKNOWN3 = 0x5,
COFF_RelocTypeX86_UNKNOWN0 = 0x3, COFF_RelocTypeX86_DIR32 = 0x6, // 32-bit virtual address
COFF_RelocTypeX86_UNKNOWN2 = 0x4, COFF_RelocTypeX86_DIR32NB = 0x7, // 32-bit virtual offset
COFF_RelocTypeX86_UNKNOWN3 = 0x5, COFF_RelocTypeX86_SEG12 = 0x9, // no support
COFF_RelocTypeX86_DIR32 = 0x6, COFF_RelocTypeX86_SECTION = 0xA, // 16-bit section index, used for debug info purposes
// 32-bit virtual address COFF_RelocTypeX86_SECREL = 0xB, // 32-bit offset from start of a section
COFF_RelocTypeX86_DIR32NB = 0x7, COFF_RelocTypeX86_TOKEN = 0xC, // CLR token? (for managed languages)
// 32-bit virtual offset COFF_RelocTypeX86_SECREL7 = 0xD, // 7-bit offset from the base of the section that contains the target.
COFF_RelocTypeX86_SEG12 = 0x9, COFF_RelocTypeX86_UNKNOWN4 = 0xE,
// no support COFF_RelocTypeX86_UNKNOWN5 = 0xF,
COFF_RelocTypeX86_SECTION = 0xA, COFF_RelocTypeX86_UNKNOWN6 = 0x10,
// 16-bit section index, used for debug info purposes COFF_RelocTypeX86_UNKNOWN7 = 0x11,
COFF_RelocTypeX86_SECREL = 0xB, COFF_RelocTypeX86_UNKNOWN8 = 0x12,
// 32-bit offset from start of a section COFF_RelocTypeX86_UNKNOWN9 = 0x13,
COFF_RelocTypeX86_TOKEN = 0xC, COFF_RelocTypeX86_REL32 = 0x14,
// CLR token? (for managed languages) COFF_RelocTypeX86_COUNT = 20
COFF_RelocTypeX86_SECREL7 = 0xD,
// 7-bit offset from the base of the section that contains the target.
COFF_RelocTypeX86_UNKNOWN4 = 0xE,
COFF_RelocTypeX86_UNKNOWN5 = 0xF,
COFF_RelocTypeX86_UNKNOWN6 = 0x10,
COFF_RelocTypeX86_UNKNOWN7 = 0x11,
COFF_RelocTypeX86_UNKNOWN8 = 0x12,
COFF_RelocTypeX86_UNKNOWN9 = 0x13,
COFF_RelocTypeX86_REL32 = 0x14,
COFF_RelocTypeX86_COUNT = 20
}; };
typedef U16 COFF_RelocTypeARM; typedef U16 COFF_RelocTypeARM;
enum enum
{ {
COFF_RelocTypeARM_ABS = 0x0, COFF_RelocTypeARM_ABS = 0x0,
COFF_RelocTypeARM_ADDR32 = 0x1, COFF_RelocTypeARM_ADDR32 = 0x1,
COFF_RelocTypeARM_ADDR32NB = 0x2, COFF_RelocTypeARM_ADDR32NB = 0x2,
COFF_RelocTypeARM_BRANCH24 = 0x3, COFF_RelocTypeARM_BRANCH24 = 0x3,
COFF_RelocTypeARM_BRANCH11 = 0x4, COFF_RelocTypeARM_BRANCH11 = 0x4,
COFF_RelocTypeARM_UNKNOWN1 = 0x5, COFF_RelocTypeARM_UNKNOWN1 = 0x5,
COFF_RelocTypeARM_UNKNOWN2 = 0x6, COFF_RelocTypeARM_UNKNOWN2 = 0x6,
COFF_RelocTypeARM_UNKNOWN3 = 0x7, COFF_RelocTypeARM_UNKNOWN3 = 0x7,
COFF_RelocTypeARM_UNKNOWN4 = 0x8, COFF_RelocTypeARM_UNKNOWN4 = 0x8,
COFF_RelocTypeARM_UNKNOWN5 = 0x9, COFF_RelocTypeARM_UNKNOWN5 = 0x9,
COFF_RelocTypeARM_REL32 = 0xA, COFF_RelocTypeARM_REL32 = 0xA,
COFF_RelocTypeARM_SECTION = 0xE, COFF_RelocTypeARM_SECTION = 0xE,
COFF_RelocTypeARM_SECREL = 0xF, COFF_RelocTypeARM_SECREL = 0xF,
COFF_RelocTypeARM_MOV32 = 0x10, COFF_RelocTypeARM_MOV32 = 0x10,
COFF_RelocTypeARM_THUMB_MOV32 = 0x11, COFF_RelocTypeARM_THUMB_MOV32 = 0x11,
COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12, COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12,
COFF_RelocTypeARM_UNUSED = 0x13, COFF_RelocTypeARM_UNUSED = 0x13,
COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14, COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14,
COFF_RelocTypeARM_THUMB_BLX23 = 0x15, COFF_RelocTypeARM_THUMB_BLX23 = 0x15,
COFF_RelocTypeARM_PAIR = 0x16, COFF_RelocTypeARM_PAIR = 0x16,
COFF_RelocTypeARM_COUNT = 20 COFF_RelocTypeARM_COUNT = 20
}; };
typedef U16 COFF_RelocTypeARM64; typedef U16 COFF_RelocTypeARM64;
enum enum
{ {
COFF_RelocTypeARM64_ABS = 0x0, COFF_RelocTypeARM64_ABS = 0x0,
COFF_RelocTypeARM64_ADDR32 = 0x1, COFF_RelocTypeARM64_ADDR32 = 0x1,
COFF_RelocTypeARM64_ADDR32NB = 0x2, COFF_RelocTypeARM64_ADDR32NB = 0x2,
COFF_RelocTypeARM64_BRANCH26 = 0x3, COFF_RelocTypeARM64_BRANCH26 = 0x3,
COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4, COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4,
COFF_RelocTypeARM64_REL21 = 0x5, COFF_RelocTypeARM64_REL21 = 0x5,
COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6, COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6,
COFF_RelocTypeARM64_SECREL = 0x8, COFF_RelocTypeARM64_SECREL = 0x8,
COFF_RelocTypeARM64_SECREL_LOW12A = 0x9, COFF_RelocTypeARM64_SECREL_LOW12A = 0x9,
COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA, COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA,
COFF_RelocTypeARM64_SECREL_LOW12L = 0xB, COFF_RelocTypeARM64_SECREL_LOW12L = 0xB,
COFF_RelocTypeARM64_TOKEN = 0xC, COFF_RelocTypeARM64_TOKEN = 0xC,
COFF_RelocTypeARM64_SECTION = 0xD, COFF_RelocTypeARM64_SECTION = 0xD,
COFF_RelocTypeARM64_ADDR64 = 0xE, COFF_RelocTypeARM64_ADDR64 = 0xE,
COFF_RelocTypeARM64_BRANCH19 = 0xF, COFF_RelocTypeARM64_BRANCH19 = 0xF,
COFF_RelocTypeARM64_BRANCH14 = 0x10, COFF_RelocTypeARM64_BRANCH14 = 0x10,
COFF_RelocTypeARM64_REL32 = 0x11, COFF_RelocTypeARM64_REL32 = 0x11,
COFF_RelocTypeARM64_COUNT = 17 COFF_RelocTypeARM64_COUNT = 17
}; };
typedef U8 COFF_SymType; typedef U8 COFF_SymType;
@@ -273,8 +261,7 @@ enum
COFF_SymType_STRUCT, COFF_SymType_STRUCT,
COFF_SymType_UNION, COFF_SymType_UNION,
COFF_SymType_ENUM, COFF_SymType_ENUM,
COFF_SymType_MOE, COFF_SymType_MOE, // member of enumeration
// member of enumeration
COFF_SymType_BYTE, COFF_SymType_BYTE,
COFF_SymType_WORD, COFF_SymType_WORD,
COFF_SymType_UINT, COFF_SymType_UINT,
@@ -285,100 +272,100 @@ enum
typedef U8 COFF_SymStorageClass; typedef U8 COFF_SymStorageClass;
enum enum
{ {
COFF_SymStorageClass_END_OF_FUNCTION = 0xff, COFF_SymStorageClass_END_OF_FUNCTION = 0xff,
COFF_SymStorageClass_NULL = 0, COFF_SymStorageClass_NULL = 0,
COFF_SymStorageClass_AUTOMATIC = 1, COFF_SymStorageClass_AUTOMATIC = 1,
COFF_SymStorageClass_EXTERNAL = 2, COFF_SymStorageClass_EXTERNAL = 2,
COFF_SymStorageClass_STATIC = 3, COFF_SymStorageClass_STATIC = 3,
COFF_SymStorageClass_REGISTER = 4, COFF_SymStorageClass_REGISTER = 4,
COFF_SymStorageClass_EXTERNAL_DEF = 5, COFF_SymStorageClass_EXTERNAL_DEF = 5,
COFF_SymStorageClass_LABEL = 6, COFF_SymStorageClass_LABEL = 6,
COFF_SymStorageClass_UNDEFINED_LABEL = 7, COFF_SymStorageClass_UNDEFINED_LABEL = 7,
COFF_SymStorageClass_MEMBER_OF_STRUCT = 8, COFF_SymStorageClass_MEMBER_OF_STRUCT = 8,
COFF_SymStorageClass_ARGUMENT = 9, COFF_SymStorageClass_ARGUMENT = 9,
COFF_SymStorageClass_STRUCT_TAG = 10, COFF_SymStorageClass_STRUCT_TAG = 10,
COFF_SymStorageClass_MEMBER_OF_UNION = 11, COFF_SymStorageClass_MEMBER_OF_UNION = 11,
COFF_SymStorageClass_UNION_TAG = 12, COFF_SymStorageClass_UNION_TAG = 12,
COFF_SymStorageClass_TYPE_DEFINITION = 13, COFF_SymStorageClass_TYPE_DEFINITION = 13,
COFF_SymStorageClass_UNDEFINED_STATIC = 14, COFF_SymStorageClass_UNDEFINED_STATIC = 14,
COFF_SymStorageClass_ENUM_TAG = 15, COFF_SymStorageClass_ENUM_TAG = 15,
COFF_SymStorageClass_MEMBER_OF_ENUM = 16, COFF_SymStorageClass_MEMBER_OF_ENUM = 16,
COFF_SymStorageClass_REGISTER_PARAM = 17, COFF_SymStorageClass_REGISTER_PARAM = 17,
COFF_SymStorageClass_BIT_FIELD = 18, COFF_SymStorageClass_BIT_FIELD = 18,
COFF_SymStorageClass_BLOCK = 100, COFF_SymStorageClass_BLOCK = 100,
COFF_SymStorageClass_FUNCTION = 101, COFF_SymStorageClass_FUNCTION = 101,
COFF_SymStorageClass_END_OF_STRUCT = 102, COFF_SymStorageClass_END_OF_STRUCT = 102,
COFF_SymStorageClass_FILE = 103, COFF_SymStorageClass_FILE = 103,
COFF_SymStorageClass_SECTION = 104, COFF_SymStorageClass_SECTION = 104,
COFF_SymStorageClass_WEAK_EXTERNAL = 105, COFF_SymStorageClass_WEAK_EXTERNAL = 105,
COFF_SymStorageClass_CLR_TOKEN = 107, COFF_SymStorageClass_CLR_TOKEN = 107,
COFF_SymStorageClass_COUNT = 27 COFF_SymStorageClass_COUNT = 27
}; };
typedef U16 COFF_SymSecNumber; typedef U16 COFF_SymSecNumber;
enum enum
{ {
COFF_SymSecNumber_NUMBER_UNDEFINED = 0, COFF_SymSecNumber_NUMBER_UNDEFINED = 0,
COFF_SymSecNumber_ABSOLUTE = 0xffff, COFF_SymSecNumber_ABSOLUTE = 0xffff,
COFF_SymSecNumber_DEBUG = 0xfffe, COFF_SymSecNumber_DEBUG = 0xfffe,
COFF_SymSecNumber_COUNT = 3 COFF_SymSecNumber_COUNT = 3
}; };
typedef U8 COFF_SymDType; typedef U8 COFF_SymDType;
enum enum
{ {
COFF_SymDType_NULL = 0, COFF_SymDType_NULL = 0,
COFF_SymDType_PTR = 16, COFF_SymDType_PTR = 16,
COFF_SymDType_FUNC = 32, COFF_SymDType_FUNC = 32,
COFF_SymDType_ARRAY = 48, COFF_SymDType_ARRAY = 48,
COFF_SymDType_COUNT = 4 COFF_SymDType_COUNT = 4
}; };
typedef U32 COFF_WeakExtType; typedef U32 COFF_WeakExtType;
enum enum
{ {
COFF_WeakExtType_NOLIBRARY = 1, COFF_WeakExtType_NOLIBRARY = 1,
COFF_WeakExtType_SEARCH_LIBRARY = 2, COFF_WeakExtType_SEARCH_LIBRARY = 2,
COFF_WeakExtType_SEARCH_ALIAS = 3, COFF_WeakExtType_SEARCH_ALIAS = 3,
COFF_WeakExtType_COUNT = 3 COFF_WeakExtType_COUNT = 3
}; };
typedef U32 COFF_ImportHeaderType; typedef U32 COFF_ImportHeaderType;
enum enum
{ {
COFF_ImportHeaderType_CODE = 0, COFF_ImportHeaderType_CODE = 0,
COFF_ImportHeaderType_DATA = 1, COFF_ImportHeaderType_DATA = 1,
COFF_ImportHeaderType_CONST = 2, COFF_ImportHeaderType_CONST = 2,
COFF_ImportHeaderType_COUNT = 3 COFF_ImportHeaderType_COUNT = 3
}; };
typedef U32 COFF_ImportHeaderNameType; typedef U32 COFF_ImportHeaderNameType;
enum enum
{ {
COFF_ImportHeaderNameType_ORDINAL = 0, COFF_ImportHeaderNameType_ORDINAL = 0,
COFF_ImportHeaderNameType_NAME = 1, COFF_ImportHeaderNameType_NAME = 1,
COFF_ImportHeaderNameType_NAME_NOPREFIX = 2, COFF_ImportHeaderNameType_NAME_NOPREFIX = 2,
COFF_ImportHeaderNameType_UNDECORATE = 3, COFF_ImportHeaderNameType_UNDECORATE = 3,
COFF_ImportHeaderNameType_COUNT = 4 COFF_ImportHeaderNameType_COUNT = 4
}; };
#define COFF_IMPORT_HEADER_TYPE_MASK 0x03 #define COFF_IMPORT_HEADER_TYPE_MASK 0x03
#define COFF_IMPORT_HEADER_TYPE_SHIFT 0 #define COFF_IMPORT_HEADER_TYPE_SHIFT 0
#define COFF_IMPORT_HEADER_NAME_TYPE_MASK 0x1c #define COFF_IMPORT_HEADER_NAME_TYPE_MASK 0x1c
#define COFF_IMPORT_HEADER_NAME_TYPE_SHIFT 2 #define COFF_IMPORT_HEADER_NAME_TYPE_SHIFT 2
#define COFF_IMPORT_HEADER_GET_TYPE(x) (((x) & COFF_IMPORT_HEADER_TYPE_MASK) >> COFF_IMPORT_HEADER_TYPE_SHIFT) #define COFF_IMPORT_HEADER_GET_TYPE(x) (((x) & COFF_IMPORT_HEADER_TYPE_MASK) >> COFF_IMPORT_HEADER_TYPE_SHIFT)
#define COFF_IMPORT_HEADER_GET_NAME_TYPE(x) (((x) & COFF_IMPORT_HEADER_NAME_TYPE_MASK) >> COFF_IMPORT_HEADER_NAME_TYPE_SHIFT) #define COFF_IMPORT_HEADER_GET_NAME_TYPE(x) (((x) & COFF_IMPORT_HEADER_NAME_TYPE_MASK) >> COFF_IMPORT_HEADER_NAME_TYPE_SHIFT)
typedef struct COFF_ImportHeader typedef struct COFF_ImportHeader
{ {
U16 sig1; U16 sig1;
U16 sig2; U16 sig2;
U16 version; U16 version;
U16 machine; U16 machine;
COFF_TimeStamp time_stamp; COFF_TimeStamp time_stamp;
U32 data_size; U32 data_size;
U16 hint; U16 hint;
U16 type; U16 type;
U16 name_type; U16 name_type;
// type : 2 // type : 2
// name type : 3 // name type : 3
// reserved : 11 // reserved : 11
@@ -390,30 +377,18 @@ typedef struct COFF_ImportHeader
typedef U8 COFF_ComdatSelectType; typedef U8 COFF_ComdatSelectType;
enum enum
{ {
COFF_ComdatSelectType_NULL = 0, COFF_ComdatSelectType_NULL = 0, // Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown.
// Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown. COFF_ComdatSelectType_NODUPLICATES = 1, // Select any symbol, even if there are multiple definitions. (we default to first declaration)
COFF_ComdatSelectType_NODUPLICATES = 1, COFF_ComdatSelectType_ANY = 2, // Sections that symbols reference must match in size, otherwise multiply definition error is thrown.
// Select any symbol, even if there are multiple definitions. (we default to first declaration) COFF_ComdatSelectType_SAME_SIZE = 3, // Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown.
COFF_ComdatSelectType_ANY = 2, COFF_ComdatSelectType_EXACT_MATCH = 4, // Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number')
// Sections that symbols reference must match in size, otherwise multiply definition error is thrown. COFF_ComdatSelectType_ASSOCIATIVE = 5, // Linker selects section with largest size.
COFF_ComdatSelectType_SAME_SIZE = 3, COFF_ComdatSelectType_LARGEST = 6,
// Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown. COFF_ComdatSelectType_COUNT = 7
COFF_ComdatSelectType_EXACT_MATCH = 4,
// Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number')
COFF_ComdatSelectType_ASSOCIATIVE = 5,
// Linker selects section with largest size.
COFF_ComdatSelectType_LARGEST = 6,
COFF_ComdatSelectType_COUNT = 7
}; };
#define COFF_MIN_BIG_OBJ_VERSION 2 #define COFF_MIN_BIG_OBJ_VERSION 2
global U8 coff_big_obj_magic[] =
{
0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B,
0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8,
};
typedef struct COFF_HeaderBigObj COFF_HeaderBigObj; typedef struct COFF_HeaderBigObj COFF_HeaderBigObj;
struct COFF_HeaderBigObj struct COFF_HeaderBigObj
{ {
@@ -422,7 +397,7 @@ struct COFF_HeaderBigObj
U16 version; U16 version;
U16 machine; U16 machine;
U32 time_stamp; U32 time_stamp;
U8 magic[16]; U8 magic[16];
U32 unused[4]; U32 unused[4];
U32 section_count; U32 section_count;
U32 pointer_to_symbol_table; U32 pointer_to_symbol_table;
@@ -454,8 +429,8 @@ typedef struct COFF_Symbol16 COFF_Symbol16;
struct COFF_Symbol16 struct COFF_Symbol16
{ {
COFF_SymbolName name; COFF_SymbolName name;
U32 value; U32 value;
U16 section_number; U16 section_number;
union union
{ {
struct struct
@@ -473,8 +448,8 @@ typedef struct COFF_Symbol32 COFF_Symbol32;
struct COFF_Symbol32 struct COFF_Symbol32
{ {
COFF_SymbolName name; COFF_SymbolName name;
U32 value; U32 value;
U32 section_number; U32 section_number;
union union
{ {
struct struct
@@ -494,11 +469,11 @@ struct COFF_Symbol32
// storage class: FUNCTION // storage class: FUNCTION
typedef struct COFF_SymbolFunc typedef struct COFF_SymbolFunc
{ {
U8 unused[4]; U8 unused[4];
U16 ln; U16 ln;
U8 unused2[2]; U8 unused2[2];
U32 ptr_to_next_func; U32 ptr_to_next_func;
U8 unused3[2]; U8 unused3[2];
} COFF_SymbolFunc; } COFF_SymbolFunc;
// storage class: WEAK_EXTERNAL // storage class: WEAK_EXTERNAL
@@ -506,7 +481,7 @@ typedef struct COFF_SymbolWeakExt
{ {
U32 tag_index; U32 tag_index;
U32 characteristics; U32 characteristics;
U8 unused[10]; U8 unused[10];
} COFF_SymbolWeakExt; } COFF_SymbolWeakExt;
typedef struct COFF_SymbolFile typedef struct COFF_SymbolFile
@@ -522,9 +497,10 @@ typedef struct COFF_SymbolSecDef
U16 number_of_relocations; U16 number_of_relocations;
U16 number_of_ln; U16 number_of_ln;
U32 check_sum; U32 check_sum;
U16 number; // one-based section index U16 number_lo; // one-based section index
U8 selection; U8 selection;
U8 unused[3]; U8 unused;
U16 number_hi;
} COFF_SymbolSecDef; } COFF_SymbolSecDef;
// specifies how section data should be modified when placed in the image file. // specifies how section data should be modified when placed in the image file.
@@ -556,11 +532,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;
@@ -589,7 +560,7 @@ typedef struct COFF_ResourceID_16
COFF_ResourceIDType type; COFF_ResourceIDType type;
union union
{ {
U16 number; U16 number;
String16 string; String16 string;
} u; } u;
} COFF_ResourceID_16; } COFF_ResourceID_16;
@@ -599,20 +570,21 @@ typedef struct COFF_ResourceID
COFF_ResourceIDType type; COFF_ResourceIDType type;
union union
{ {
U16 number; U16 number;
String8 string; String8 string;
} u; } u;
} COFF_ResourceID; } COFF_ResourceID;
typedef struct COFF_Resource typedef struct COFF_Resource
{ {
COFF_ResourceID type; COFF_ResourceID type;
COFF_ResourceID name; COFF_ResourceID name;
U16 language_id; U32 data_version;
U32 data_version;
U32 version;
COFF_ResourceMemoryFlags memory_flags; COFF_ResourceMemoryFlags memory_flags;
String8 data; U16 language_id;
U32 version;
U32 characteristics;
String8 data;
} COFF_Resource; } COFF_Resource;
typedef struct COFF_ResourceDataEntry typedef struct COFF_ResourceDataEntry
@@ -625,12 +597,12 @@ typedef struct COFF_ResourceDataEntry
typedef struct COFF_ResourceDirTable typedef struct COFF_ResourceDirTable
{ {
U32 characteristics; U32 characteristics;
COFF_TimeStamp time_stamp; COFF_TimeStamp time_stamp;
U16 major_version; U16 major_version;
U16 minor_version; U16 minor_version;
U16 name_entry_count; U16 name_entry_count;
U16 id_entry_count; U16 id_entry_count;
} COFF_ResourceDirTable; } COFF_ResourceDirTable;
#define COFF_RESOURCE_SUB_DIR_FLAG (1u << 31u) #define COFF_RESOURCE_SUB_DIR_FLAG (1u << 31u)
@@ -648,22 +620,19 @@ typedef struct COFF_ResourceDirEntry
//////////////////////////////// ////////////////////////////////
read_only global U8 g_coff_archive_sig[8] = "!<arch>\n";
read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
#define COFF_ARCHIVE_ALIGN 2 #define COFF_ARCHIVE_ALIGN 2
#define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15 #define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15
#define COFF_ARCHIVE_MEMBER_HEADER_SIZE 60 #define COFF_ARCHIVE_MEMBER_HEADER_SIZE 60
typedef struct COFF_ArchiveMemberHeader typedef struct COFF_ArchiveMemberHeader
{ {
String8 name; // padded to 16 bytes with spaces String8 name; // padded to 16 bytes with spaces
U32 date; // unix time U32 date; // unix time
U32 user_id; // unix artifact that does not have meaning on windows U32 user_id; // unix artifact that does not have meaning on windows
U32 group_id; // unix artifact that does not have meaning on windows U32 group_id; // unix artifact that does not have meaning on windows
String8 mode; // octal representation the members file mode String8 mode; // octal representation the members file mode
U32 size; // size of the member data, not including header U32 size; // size of the member data, not including header
B32 is_end_correct; // set to true if found correct signature after header B32 is_end_correct; // set to true if found correct signature after header
} COFF_ArchiveMemberHeader; } COFF_ArchiveMemberHeader;
//////////////////////////////// ////////////////////////////////
@@ -681,71 +650,61 @@ typedef U32 COFF_DataType;
typedef struct COFF_HeaderInfo typedef struct COFF_HeaderInfo
{ {
COFF_MachineType machine; COFF_MachineType machine;
U64 section_array_off; COFF_DataType type;
U64 section_count_no_null; U64 section_array_off;
U64 string_table_off; U64 section_count_no_null;
U64 symbol_size; U64 string_table_off;
U64 symbol_off; U64 symbol_size;
U64 symbol_count; U64 symbol_off;
U64 symbol_count;
} COFF_HeaderInfo; } COFF_HeaderInfo;
enum enum
{ {
// symbol has section and offset. COFF_SymbolValueInterp_REGULAR, // symbol has section and offset.
COFF_SymbolValueInterp_REGULAR, COFF_SymbolValueInterp_WEAK, // symbol is overridable
COFF_SymbolValueInterp_UNDEFINED, // symbol doesn't have a reference section.
// symbol is overridable COFF_SymbolValueInterp_COMMON, // symbol has no section but still has size.
COFF_SymbolValueInterp_WEAK, COFF_SymbolValueInterp_ABS, // symbol has an absolute (non-relocatable) value and is not an address.
COFF_SymbolValueInterp_DEBUG // symbol is used to provide general type of debugging information.
// symbol doesn't have a reference section.
COFF_SymbolValueInterp_UNDEFINED,
// symbol has no section but still has size.
COFF_SymbolValueInterp_COMMON,
// symbol has an absolute (non-relocatable) value and is not an address.
COFF_SymbolValueInterp_ABS,
// symbol is used to provide general type of debugging information.
COFF_SymbolValueInterp_DEBUG
}; };
typedef U32 COFF_SymbolValueInterpType; typedef U32 COFF_SymbolValueInterpType;
typedef struct COFF_Symbol16Node typedef struct COFF_Symbol16Node
{ {
struct COFF_Symbol16Node *next; struct COFF_Symbol16Node *next;
COFF_Symbol16 data; COFF_Symbol16 data;
} COFF_Symbol16Node; } COFF_Symbol16Node;
typedef struct COFF_Symbol16List typedef struct COFF_Symbol16List
{ {
U64 count; U64 count;
COFF_Symbol16Node *first; COFF_Symbol16Node *first;
COFF_Symbol16Node *last; COFF_Symbol16Node *last;
} COFF_Symbol16List; } COFF_Symbol16List;
typedef struct COFF_Symbol32Array typedef struct COFF_Symbol32Array
{ {
U64 count; U64 count;
COFF_Symbol32 *v; COFF_Symbol32 *v;
} COFF_Symbol32Array; } COFF_Symbol32Array;
typedef struct COFF_RelocNode typedef struct COFF_RelocNode
{ {
struct COFF_RelocNode *next; struct COFF_RelocNode *next;
COFF_Reloc data; COFF_Reloc data;
} COFF_RelocNode; } COFF_RelocNode;
typedef struct COFF_RelocList typedef struct COFF_RelocList
{ {
U64 count; U64 count;
COFF_RelocNode *first; COFF_RelocNode *first;
COFF_RelocNode *last; COFF_RelocNode *last;
} COFF_RelocList; } COFF_RelocList;
typedef struct COFF_RelocArray typedef struct COFF_RelocArray
{ {
U64 count; U64 count;
COFF_Reloc *v; COFF_Reloc *v;
} COFF_RelocArray; } COFF_RelocArray;
@@ -758,12 +717,12 @@ typedef struct COFF_RelocInfo
typedef struct COFF_ResourceNode typedef struct COFF_ResourceNode
{ {
struct COFF_ResourceNode *next; struct COFF_ResourceNode *next;
COFF_Resource data; COFF_Resource data;
} COFF_ResourceNode; } COFF_ResourceNode;
typedef struct COFF_ResourceList typedef struct COFF_ResourceList
{ {
U64 count; U64 count;
COFF_ResourceNode *first; COFF_ResourceNode *first;
COFF_ResourceNode *last; COFF_ResourceNode *last;
} COFF_ResourceList; } COFF_ResourceList;
@@ -773,21 +732,21 @@ typedef struct COFF_ResourceList
typedef struct COFF_ArchiveMember typedef struct COFF_ArchiveMember
{ {
COFF_ArchiveMemberHeader header; COFF_ArchiveMemberHeader header;
U64 offset; U64 offset;
String8 data; String8 data;
} COFF_ArchiveMember; } COFF_ArchiveMember;
typedef struct COFF_ArchiveFirstMember typedef struct COFF_ArchiveFirstMember
{ {
U32 symbol_count; U32 symbol_count;
String8 member_offsets; String8 member_offsets;
String8 string_table; String8 string_table;
} COFF_ArchiveFirstMember; } COFF_ArchiveFirstMember;
typedef struct COFF_ArchiveSecondMember typedef struct COFF_ArchiveSecondMember
{ {
U32 member_count; U32 member_count;
U32 symbol_count; U32 symbol_count;
String8 member_offsets; String8 member_offsets;
String8 symbol_indices; String8 symbol_indices;
String8 string_table; String8 string_table;
@@ -796,12 +755,12 @@ typedef struct COFF_ArchiveSecondMember
typedef struct COFF_ArchiveMemberNode typedef struct COFF_ArchiveMemberNode
{ {
struct COFF_ArchiveMemberNode *next; struct COFF_ArchiveMemberNode *next;
COFF_ArchiveMember data; COFF_ArchiveMember data;
} COFF_ArchiveMemberNode; } COFF_ArchiveMemberNode;
typedef struct COFF_ArchiveMemberList typedef struct COFF_ArchiveMemberList
{ {
U64 count; U64 count;
COFF_ArchiveMemberNode *first; COFF_ArchiveMemberNode *first;
COFF_ArchiveMemberNode *last; COFF_ArchiveMemberNode *last;
} COFF_ArchiveMemberList; } COFF_ArchiveMemberList;
@@ -815,22 +774,37 @@ typedef enum
typedef struct COFF_ArchiveParse typedef struct COFF_ArchiveParse
{ {
COFF_ArchiveFirstMember first_member; COFF_ArchiveFirstMember first_member;
COFF_ArchiveSecondMember second_member; COFF_ArchiveSecondMember second_member;
String8 long_names; String8 long_names;
} COFF_ArchiveParse; } COFF_ArchiveParse;
//////////////////////////////// ////////////////////////////////
typedef struct COFF_SectionHeaderArray typedef struct COFF_SectionHeaderArray
{ {
U64 count; U64 count;
COFF_SectionHeader *v; COFF_SectionHeader *v;
} COFF_SectionHeaderArray; } COFF_SectionHeaderArray;
//////////////////////////////// ////////////////////////////////
//~ rjf: Globals //~ rjf: Globals
read_only global U8 coff_big_obj_magic[] =
{
0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B,
0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8,
};
read_only global U8 g_coff_archive_sig[8] = "!<arch>\n";
read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
read_only global 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
};
read_only global COFF_SectionHeader coff_section_header_nil = {0}; read_only global COFF_SectionHeader coff_section_header_nil = {0};
//////////////////////////////// ////////////////////////////////
@@ -840,6 +814,7 @@ internal B32 coff_is_big_obj(String8 data);
internal B32 coff_is_obj(String8 data); internal B32 coff_is_obj(String8 data);
internal COFF_HeaderInfo coff_header_info_from_data(String8 data); internal COFF_HeaderInfo coff_header_info_from_data(String8 data);
internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags); internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags);
internal COFF_SectionFlags coff_section_flag_from_align_size(U64 align);
internal COFF_SymbolValueInterpType coff_interp_symbol(COFF_Symbol32 *symbol); internal COFF_SymbolValueInterpType coff_interp_symbol(COFF_Symbol32 *symbol);
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff); internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
@@ -877,25 +852,24 @@ internal String8 coff_make_import_header_by_ordinal(Arena *arena,
U16 ordinal, U16 ordinal,
COFF_ImportHeaderType type); COFF_ImportHeaderType type);
////////////////////////////////
//~ Resources
internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b); internal String8 coff_resource_string_from_str16(Arena *arena, String16 string);
internal COFF_ResourceID coff_resource_id_copy(Arena *arena, COFF_ResourceID id); internal String8 coff_resource_string_from_str8(Arena *arena, String8 string);
internal U64 coff_sizeof_resource_id(COFF_ResourceID id); internal String8 coff_resource_number_from_u16(Arena *arena, U16 number);
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 B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b);
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16);
internal U64 coff_read_resource_id_utf16(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 String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
internal String8List coff_write_resource(Arena *arena, internal String8 coff_write_resource(Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
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);
+494 -246
View File
@@ -81,6 +81,7 @@ ctrl_string_from_msg_kind(CTRL_MsgKind kind)
case CTRL_MsgKind_Launch: {result = str8_lit("Launch");}break; case CTRL_MsgKind_Launch: {result = str8_lit("Launch");}break;
case CTRL_MsgKind_Attach: {result = str8_lit("Attach");}break; case CTRL_MsgKind_Attach: {result = str8_lit("Attach");}break;
case CTRL_MsgKind_Kill: {result = str8_lit("Kill");}break; case CTRL_MsgKind_Kill: {result = str8_lit("Kill");}break;
case CTRL_MsgKind_KillAll: {result = str8_lit("KillAll");}break;
case CTRL_MsgKind_Detach: {result = str8_lit("Detach");}break; case CTRL_MsgKind_Detach: {result = str8_lit("Detach");}break;
case CTRL_MsgKind_Run: {result = str8_lit("Run");}break; case CTRL_MsgKind_Run: {result = str8_lit("Run");}break;
case CTRL_MsgKind_SingleStep: {result = str8_lit("SingleStep");}break; case CTRL_MsgKind_SingleStep: {result = str8_lit("SingleStep");}break;
@@ -270,6 +271,7 @@ ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs)
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->entity_id); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->entity_id);
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->exit_code); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->exit_code);
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->env_inherit); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->env_inherit);
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->debug_subprocesses);
str8_serial_push_array (scratch.arena, &msgs_srlzed, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters)); str8_serial_push_array (scratch.arena, &msgs_srlzed, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters));
// rjf: write path string // rjf: write path string
@@ -370,6 +372,7 @@ ctrl_msg_list_from_serialized_string(Arena *arena, String8 string)
read_off += str8_deserial_read_struct(string, read_off, &msg->entity_id); read_off += str8_deserial_read_struct(string, read_off, &msg->entity_id);
read_off += str8_deserial_read_struct(string, read_off, &msg->exit_code); read_off += str8_deserial_read_struct(string, read_off, &msg->exit_code);
read_off += str8_deserial_read_struct(string, read_off, &msg->env_inherit); read_off += str8_deserial_read_struct(string, read_off, &msg->env_inherit);
read_off += str8_deserial_read_struct(string, read_off, &msg->debug_subprocesses);
read_off += str8_deserial_read_array (string, read_off, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters)); read_off += str8_deserial_read_array (string, read_off, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters));
// rjf: read path string // rjf: read path string
@@ -1283,6 +1286,7 @@ ctrl_init(void)
ctrl_state->dmn_event_arena = arena_alloc(); ctrl_state->dmn_event_arena = arena_alloc();
ctrl_state->user_entry_point_arena = arena_alloc(); ctrl_state->user_entry_point_arena = arena_alloc();
ctrl_state->user_meta_eval_arena = arena_alloc(); ctrl_state->user_meta_eval_arena = arena_alloc();
ctrl_state->dbg_dir_arena = arena_alloc();
for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1))
{ {
if(ctrl_exception_code_kind_default_enable_table[k]) if(ctrl_exception_code_kind_default_enable_table[k])
@@ -1296,12 +1300,6 @@ ctrl_init(void)
ctrl_state->u2ms_ring_cv = os_condition_variable_alloc(); ctrl_state->u2ms_ring_cv = os_condition_variable_alloc();
ctrl_state->ctrl_thread_log = log_alloc(); ctrl_state->ctrl_thread_log = log_alloc();
ctrl_state->ctrl_thread = os_thread_launch(ctrl_thread__entry_point, 0, 0); ctrl_state->ctrl_thread = os_thread_launch(ctrl_thread__entry_point, 0, 0);
ctrl_state->ms_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
ctrl_state->ms_threads = push_array(arena, OS_Handle, ctrl_state->ms_thread_count);
for(U64 idx = 0; idx < ctrl_state->ms_thread_count; idx += 1)
{
ctrl_state->ms_threads[idx] = os_thread_launch(ctrl_mem_stream_thread__entry_point, (void *)idx, 0);
}
} }
//////////////////////////////// ////////////////////////////////
@@ -1447,24 +1445,28 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B3
//- rjf: not good, or is stale -> submit hash request //- rjf: not good, or is stale -> submit hash request
if((!is_good || is_stale) && os_now_microseconds() >= last_time_requested_us+100000) if((!is_good || is_stale) && os_now_microseconds() >= last_time_requested_us+100000)
{ {
if(ctrl_u2ms_enqueue_req(process, range, zero_terminated, endt_us)) OS_MutexScopeW(process_stripe->rw_mutex) if(ctrl_u2ms_enqueue_req(process, range, zero_terminated, endt_us))
{ {
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) OS_MutexScopeW(process_stripe->rw_mutex)
{ {
if(ctrl_handle_match(n->handle, process)) for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
{ {
U64 range_slot_idx = range_hash%n->range_hash_slots_count; if(ctrl_handle_match(n->handle, process))
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
{ {
if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) U64 range_slot_idx = range_hash%n->range_hash_slots_count;
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
{ {
range_n->last_time_requested_us = os_now_microseconds(); if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated)
break; {
range_n->last_time_requested_us = os_now_microseconds();
break;
}
} }
} }
} }
} }
async_push_work(ctrl_mem_stream_work);
} }
} }
@@ -1613,12 +1615,12 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_Handle proces
} }
// rjf: increment past this chunk // rjf: increment past this chunk
write_off += in_range_data.size; U64 bytes_to_skip = page_size;
if(data.size < page_size) if(page_idx == 0 && range.min > data_vaddr_range.min)
{ {
U64 missed_byte_count = page_size-data.size; bytes_to_skip -= (range.min-data_vaddr_range.min);
write_off += missed_byte_count;
} }
write_off += bytes_to_skip;
} }
} }
@@ -1781,7 +1783,7 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C
CTRL_ThreadRegCacheSlot *slot = &cache->slots[slot_idx]; CTRL_ThreadRegCacheSlot *slot = &cache->slots[slot_idx];
CTRL_ThreadRegCacheStripe *stripe = &cache->stripes[stripe_idx]; CTRL_ThreadRegCacheStripe *stripe = &cache->stripes[stripe_idx];
void *result = push_array(arena, U8, reg_block_size); void *result = push_array(arena, U8, reg_block_size);
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeW(stripe->rw_mutex)
{ {
// rjf: find existing node // rjf: find existing node
CTRL_ThreadRegCacheNode *node = 0; CTRL_ThreadRegCacheNode *node = 0;
@@ -1797,33 +1799,11 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C
// rjf: allocate existing node // rjf: allocate existing node
if(!node) if(!node)
{ {
OS_MutexScopeRWPromote(stripe->rw_mutex) node = push_array(stripe->arena, CTRL_ThreadRegCacheNode, 1);
{ DLLPushBack(slot->first, slot->last, node);
for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) node->handle = handle;
{ node->block_size = reg_block_size;
if(ctrl_handle_match(n->handle, handle)) node->block = push_array(stripe->arena, U8, reg_block_size);
{
node = n;
break;
}
}
if(!node)
{
node = push_array(stripe->arena, CTRL_ThreadRegCacheNode, 1);
DLLPushBack(slot->first, slot->last, node);
node->handle = handle;
node->block_size = reg_block_size;
node->block = push_array(stripe->arena, U8, reg_block_size);
}
}
for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next)
{
if(ctrl_handle_match(n->handle, handle))
{
node = n;
break;
}
}
} }
// rjf: copy from node // rjf: copy from node
@@ -1833,22 +1813,11 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C
B32 need_stale = 1; B32 need_stale = 1;
if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(handle.dmn_handle, result)) if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(handle.dmn_handle, result))
{ {
OS_MutexScopeRWPromote(stripe->rw_mutex) if(node != 0)
{ {
for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) need_stale = 0;
{ node->reg_gen = current_reg_gen;
if(ctrl_handle_match(n->handle, handle)) MemoryCopy(node->block, result, reg_block_size);
{
node = n;
break;
}
}
if(node != 0)
{
need_stale = 0;
node->reg_gen = current_reg_gen;
MemoryCopy(node->block, result, reg_block_size);
}
} }
} }
if(need_stale) if(need_stale)
@@ -3108,12 +3077,11 @@ ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us)
{ {
U64 unconsumed_size = (ctrl_state->u2c_ring_write_pos-ctrl_state->u2c_ring_read_pos); U64 unconsumed_size = (ctrl_state->u2c_ring_write_pos-ctrl_state->u2c_ring_read_pos);
U64 available_size = ctrl_state->u2c_ring_size-unconsumed_size; U64 available_size = ctrl_state->u2c_ring_size-unconsumed_size;
if(available_size >= sizeof(U64) + msgs_srlzed_baked.size) U64 needed_size = sizeof(msgs_srlzed_baked.size) + msgs_srlzed_baked.size;
if(available_size >= needed_size)
{ {
ctrl_state->u2c_ring_write_pos += ring_write_struct(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, &msgs_srlzed_baked.size); ctrl_state->u2c_ring_write_pos += ring_write_struct(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, &msgs_srlzed_baked.size);
ctrl_state->u2c_ring_write_pos += ring_write(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, msgs_srlzed_baked.str, msgs_srlzed_baked.size); ctrl_state->u2c_ring_write_pos += ring_write(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, msgs_srlzed_baked.str, msgs_srlzed_baked.size);
ctrl_state->u2c_ring_write_pos += 7;
ctrl_state->u2c_ring_write_pos -= ctrl_state->u2c_ring_write_pos%8;
good = 1; good = 1;
break; break;
} }
@@ -3146,8 +3114,6 @@ ctrl_u2c_pop_msgs(Arena *arena)
msgs_srlzed_baked.size = size_to_decode; msgs_srlzed_baked.size = size_to_decode;
msgs_srlzed_baked.str = push_array_no_zero(scratch.arena, U8, msgs_srlzed_baked.size); msgs_srlzed_baked.str = push_array_no_zero(scratch.arena, U8, msgs_srlzed_baked.size);
ctrl_state->u2c_ring_read_pos += ring_read(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_read_pos, msgs_srlzed_baked.str, size_to_decode); ctrl_state->u2c_ring_read_pos += ring_read(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_read_pos, msgs_srlzed_baked.str, size_to_decode);
ctrl_state->u2c_ring_read_pos += 7;
ctrl_state->u2c_ring_read_pos -= ctrl_state->u2c_ring_read_pos%8;
break; break;
} }
os_condition_variable_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, max_U64); os_condition_variable_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, max_U64);
@@ -3174,12 +3140,11 @@ ctrl_c2u_push_events(CTRL_EventList *events)
{ {
U64 unconsumed_size = (ctrl_state->c2u_ring_write_pos-ctrl_state->c2u_ring_read_pos); U64 unconsumed_size = (ctrl_state->c2u_ring_write_pos-ctrl_state->c2u_ring_read_pos);
U64 available_size = ctrl_state->c2u_ring_size-unconsumed_size; U64 available_size = ctrl_state->c2u_ring_size-unconsumed_size;
if(available_size >= sizeof(U64) + event_srlzed.size) U64 needed_size = sizeof(event_srlzed.size) + event_srlzed.size;
if(available_size >= needed_size)
{ {
ctrl_state->c2u_ring_write_pos += ring_write_struct(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, &event_srlzed.size); ctrl_state->c2u_ring_write_pos += ring_write_struct(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, &event_srlzed.size);
ctrl_state->c2u_ring_write_pos += ring_write(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, event_srlzed.str, event_srlzed.size); ctrl_state->c2u_ring_write_pos += ring_write(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, event_srlzed.str, event_srlzed.size);
ctrl_state->c2u_ring_write_pos += 7;
ctrl_state->c2u_ring_write_pos -= ctrl_state->c2u_ring_write_pos%8;
break; break;
} }
os_condition_variable_wait(ctrl_state->c2u_ring_cv, ctrl_state->c2u_ring_mutex, os_now_microseconds()+100); os_condition_variable_wait(ctrl_state->c2u_ring_cv, ctrl_state->c2u_ring_mutex, os_now_microseconds()+100);
@@ -3211,8 +3176,6 @@ ctrl_c2u_pop_events(Arena *arena)
event_srlzed.size = size_to_decode; event_srlzed.size = size_to_decode;
event_srlzed.str = push_array_no_zero(scratch.arena, U8, event_srlzed.size); event_srlzed.str = push_array_no_zero(scratch.arena, U8, event_srlzed.size);
ctrl_state->c2u_ring_read_pos += ring_read(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_read_pos, event_srlzed.str, event_srlzed.size); ctrl_state->c2u_ring_read_pos += ring_read(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_read_pos, event_srlzed.str, event_srlzed.size);
ctrl_state->c2u_ring_read_pos += 7;
ctrl_state->c2u_ring_read_pos -= ctrl_state->c2u_ring_read_pos%8;
CTRL_Event *new_event = ctrl_event_list_push(arena, &events); CTRL_Event *new_event = ctrl_event_list_push(arena, &events);
*new_event = ctrl_event_from_serialized_string(arena, event_srlzed); *new_event = ctrl_event_from_serialized_string(arena, event_srlzed);
} }
@@ -3250,8 +3213,7 @@ ctrl_thread__entry_point(void *p)
//- rjf: process messages //- rjf: process messages
DMN_CtrlExclusiveAccessScope DMN_CtrlExclusiveAccessScope
{ {
B32 done = 0; for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next)
for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next)
{ {
CTRL_Msg *msg = &msg_n->v; CTRL_Msg *msg = &msg_n->v;
{ {
@@ -3275,9 +3237,10 @@ ctrl_thread__entry_point(void *p)
case CTRL_MsgKind_Launch: {ctrl_thread__launch (ctrl_ctx, msg);}break; case CTRL_MsgKind_Launch: {ctrl_thread__launch (ctrl_ctx, msg);}break;
case CTRL_MsgKind_Attach: {ctrl_thread__attach (ctrl_ctx, msg);}break; case CTRL_MsgKind_Attach: {ctrl_thread__attach (ctrl_ctx, msg);}break;
case CTRL_MsgKind_Kill: {ctrl_thread__kill (ctrl_ctx, msg);}break; case CTRL_MsgKind_Kill: {ctrl_thread__kill (ctrl_ctx, msg);}break;
case CTRL_MsgKind_KillAll: {ctrl_thread__kill_all (ctrl_ctx, msg);}break;
case CTRL_MsgKind_Detach: {ctrl_thread__detach (ctrl_ctx, msg);}break; case CTRL_MsgKind_Detach: {ctrl_thread__detach (ctrl_ctx, msg);}break;
case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg); done = 1;}break; case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg);}break;
case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg); done = 1;}break; case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg);}break;
//- rjf: configuration //- rjf: configuration
case CTRL_MsgKind_SetUserEntryPoints: case CTRL_MsgKind_SetUserEntryPoints:
@@ -3474,10 +3437,10 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
Rng1U64 tls_vaddr_range = {0}; Rng1U64 tls_vaddr_range = {0};
U32 pdb_dbg_time = 0; U32 pdb_dbg_time = 0;
U32 pdb_dbg_age = 0; U32 pdb_dbg_age = 0;
OS_Guid pdb_dbg_guid = {0}; Guid pdb_dbg_guid = {0};
String8 pdb_dbg_path = str8_zero(); String8 pdb_dbg_path = str8_zero();
U32 rdi_dbg_time = 0; U32 rdi_dbg_time = 0;
OS_Guid rdi_dbg_guid = {0}; Guid rdi_dbg_guid = {0};
String8 rdi_dbg_path = str8_zero(); String8 rdi_dbg_path = str8_zero();
ProfScope("unpack relevant PE info") ProfScope("unpack relevant PE info")
{ {
@@ -3614,7 +3577,6 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32)); tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32));
// rjf: grab data about debug info // rjf: grab data about debug info
if(data_dir_count > PE_DataDirectoryIndex_DEBUG) if(data_dir_count > PE_DataDirectoryIndex_DEBUG)
{ {
// rjf: read data dir // rjf: read data dir
@@ -3683,27 +3645,28 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
String8 exe_folder = str8_chop_last_slash(path); String8 exe_folder = str8_chop_last_slash(path);
String8 rdi_path__absolute = rdi_dbg_path; String8List dbg_path_candidates = {0};
String8 rdi_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, rdi_dbg_path); if(rdi_dbg_path.size != 0)
String8 pdb_path__absolute = pdb_dbg_path;
String8 pdb_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, pdb_dbg_path);
String8 dbg_path_candidates[] =
{ {
/* inferred (treated as absolute): */ rdi_path__absolute, str8_list_push(scratch.arena, &dbg_path_candidates, rdi_dbg_path);
/* inferred (treated as relative): */ rdi_path__relative, str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, rdi_dbg_path);
/* inferred (treated as absolute): */ pdb_path__absolute, }
/* inferred (treated as relative): */ pdb_path__relative, if(pdb_dbg_path.size != 0)
/* "foo.exe" -> "foo.rdi" */ push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(path)),
/* "foo.exe" -> "foo.exe.rdi" */ push_str8f(scratch.arena, "%S.rdi", path),
/* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(path)),
/* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", path),
};
for(U64 idx = 0; idx < ArrayCount(dbg_path_candidates); idx += 1)
{ {
FileProperties props = os_properties_from_file_path(dbg_path_candidates[idx]); str8_list_push(scratch.arena, &dbg_path_candidates, pdb_dbg_path);
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, pdb_dbg_path);
}
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", str8_chop_last_dot(path));
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", path);
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", str8_chop_last_dot(path));
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", path);
for(String8Node *n = dbg_path_candidates.first; n != 0; n = n->next)
{
String8 candidate_path = n->string;
FileProperties props = os_properties_from_file_path(candidate_path);
if(props.modified != 0 && props.size != 0) if(props.modified != 0 && props.size != 0)
{ {
initial_debug_info_path = push_str8_copy(arena, dbg_path_candidates[idx]); initial_debug_info_path = push_str8_copy(arena, candidate_path);
break; break;
} }
} }
@@ -4146,6 +4109,196 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
} }
ctrl_c2u_push_events(&evts); ctrl_c2u_push_events(&evts);
//- rjf: if this is the first process in a session, clear the debug directory
// cache state
if(ctrl_state->process_counter == 1 && event->kind == DMN_EventKind_CreateProcess)
{
arena_clear(ctrl_state->dbg_dir_arena);
ctrl_state->dbg_dir_root = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
}
//- rjf: when a new module is loaded, pre-emptively try to open all adjacent
// debug infos. with debug events, we learn about loaded modules serially,
// and we need to completely load debug info before continuing. for massive
// projects, this is a problem, because completely loading debug info isn't a
// trivial cost, and there are often 1000s of DLLs.
//
// an imperfect but usually reasonable heuristic is to look at adjacent
// debug info files, in the same or under the directory as the initially
// loaded, and pre-emptively convert all of them (which for us is the
// heaviest part of debug info loading, if native RDI is not used).
//
// only do this on the first ever loaded module, *or* once we get beyond 256
// modules (a very bad heuristic that may or may not inform us that we are
// dealing with insane-town projects)
//
if(event->kind == DMN_EventKind_LoadModule &&
(ctrl_state->ctrl_thread_entity_store->entity_kind_counts[CTRL_EntityKind_Module] > 256 ||
ctrl_state->ctrl_thread_entity_store->entity_kind_counts[CTRL_EntityKind_Module] == 1))
{
//- rjf: unpack event
CTRL_Handle process_handle = ctrl_handle_make(CTRL_MachineID_Local, event->process);
CTRL_Handle loaded_module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module);
CTRL_Entity *process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, process_handle);
CTRL_Entity *loaded_module = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, loaded_module_handle);
//- rjf: for each module, use its full path as the start to a new limited recursive
// directory search. cache each directory once traversed in the dbg_dir tree. if any
// node is not cached, then scan it & pre-emptively convert debug info.
ProfScope("pre-emptively load adjacent debug info for %.*s", str8_varg(loaded_module->string))
{
//- rjf: calculate seed path
DI_Key loaded_di_key = ctrl_dbgi_key_from_module(loaded_module);
String8 loaded_di_name = str8_skip_last_slash(loaded_di_key.path);
String8 debug_info_ext = str8_skip_last_dot(loaded_di_key.path);
String8 seed_folder_path = str8_chop_last_slash(loaded_di_key.path);
if(seed_folder_path.size == 0)
{
String8 module_path = loaded_module->string;
seed_folder_path = str8_chop_last_slash(module_path);
}
//- rjf: split seed path
String8List seed_path_parts = str8_split_path(scratch.arena, seed_folder_path);
//- rjf: find parent dir node for this module's debug info; build tree leading to this dir
CTRL_DbgDirNode *parent_dir_node = ctrl_state->dbg_dir_root;
for(String8Node *n = seed_path_parts.first; n != 0; n = n->next)
{
String8 name = n->string;
CTRL_DbgDirNode *next_child = 0;
for(CTRL_DbgDirNode *child = parent_dir_node->first; child != 0; child = child->next)
{
if(str8_match(child->name, name, StringMatchFlag_CaseInsensitive))
{
next_child = child;
break;
}
}
if(next_child == 0)
{
next_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
DLLPushBack(parent_dir_node->first, parent_dir_node->last, next_child);
next_child->parent = parent_dir_node;
next_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, name);
parent_dir_node->child_count += 1;
}
parent_dir_node = next_child;
}
//- rjf: count modules
{
parent_dir_node->module_direct_count += 1;
}
//- rjf: iterate from dir node up its ancestor chain - do recursive
// searches if this is an ancestor of loaded modules, it has not been
// searched yet, but it has >4 child branches, meaning it looks like
// project directory
//
DI_KeyList preemptively_loaded_keys = {0};
for(CTRL_DbgDirNode *dir_node = parent_dir_node; dir_node != 0; dir_node = dir_node->parent)
{
if(dir_node->search_count == 0 && dir_node->module_direct_count >= 1)
{
//- rjf: form full path of this directory node
String8List dir_node_path_parts = {0};
for(CTRL_DbgDirNode *n = dir_node; n != 0; n = n->parent)
{
if(n->name.size != 0)
{
str8_list_push_front(scratch.arena, &dir_node_path_parts, n->name);
}
}
String8 dir_node_path = str8_list_join(scratch.arena, &dir_node_path_parts, &(StringJoin){.sep = str8_lit("/")});
//- rjf: iterate downwards from this directory recursively, locate
// debug infos, and pre-emptively convert
typedef struct Task Task;
struct Task
{
Task *next;
CTRL_DbgDirNode *node;
String8 path;
};
Task start_task = {0, dir_node, dir_node_path};
Task *first_task = &start_task;
Task *last_task = first_task;
U64 task_count = 0;
for(Task *t = first_task; t != 0; t = t->next)
{
ProfBegin("search task %.*s", str8_varg(t->path));
// rjf: increment search counter
t->node->search_count += 1;
// rjf: iterate this directory. if debug infos are encountered,
// kick off pre-emptive conversion, and gather key. if folders
// are encountered, then add them to the tree, and kick off a
// sub-search if needed.
OS_FileIter *it = os_file_iter_begin(scratch.arena, t->path, 0);
U64 idx = 0;
for(OS_FileInfo info = {0}; idx < 16384 && os_file_iter_next(scratch.arena, it, &info); idx += 1)
{
// rjf: folder -> do sub-search if not duplicative
if(info.props.flags & FilePropertyFlag_IsFolder && task_count < 16384 && !str8_match(str8_prefix(info.name, 1), str8_lit("."), 0))
{
CTRL_DbgDirNode *existing_dir_child = 0;
for(CTRL_DbgDirNode *child = t->node->first; child != 0; child = child->next)
{
if(str8_match(child->name, info.name, StringMatchFlag_CaseInsensitive))
{
existing_dir_child = child;
break;
}
}
if(existing_dir_child == 0)
{
existing_dir_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
DLLPushBack(t->node->first, t->node->last, existing_dir_child);
existing_dir_child->parent = t->node;
existing_dir_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, info.name);
t->node->child_count += 1;
}
if(existing_dir_child->search_count == 0)
{
Task *task = push_array(scratch.arena, Task, 1);
task->node = existing_dir_child;
task->path = push_str8f(scratch.arena, "%S/%S", t->path, info.name);
SLLQueuePush(first_task, last_task, task);
task_count += 1;
}
}
// rjf: debug info file -> kick off open
else if(preemptively_loaded_keys.count < 4096 &&
!(info.props.flags & FilePropertyFlag_IsFolder) &&
str8_match(str8_skip_last_dot(info.name), debug_info_ext, StringMatchFlag_CaseInsensitive) &&
!str8_match(loaded_di_name, info.name, StringMatchFlag_CaseInsensitive))
{
DI_Key key = {push_str8f(scratch.arena, "%S/%S", t->path, info.name), info.props.modified};
di_open(&key);
di_key_list_push(scratch.arena, &preemptively_loaded_keys, &key);
}
}
os_file_iter_end(it);
ProfEnd();
}
}
}
//- rjf: for each pre-emptively loaded key, wait for the initial
// load task to be done
for(DI_KeyNode *n = preemptively_loaded_keys.first; n != 0; n = n->next)
{
DI_Scope *di_scope = di_scope_open();
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &n->v, max_U64);
di_scope_close(di_scope);
di_close(&n->v);
}
}
}
//- rjf: clear process memory cache, if we've just started a lone process //- rjf: clear process memory cache, if we've just started a lone process
if(event->kind == DMN_EventKind_CreateProcess && ctrl_state->process_counter == 1) if(event->kind == DMN_EventKind_CreateProcess && ctrl_state->process_counter == 1)
{ {
@@ -4301,13 +4454,14 @@ ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
//- rjf: launch //- rjf: launch
OS_ProcessLaunchParams params = {0}; OS_ProcessLaunchParams params = {0};
{ {
params.cmd_line = msg->cmd_line_string_list; params.cmd_line = msg->cmd_line_string_list;
params.path = msg->path; params.path = msg->path;
params.env = msg->env_string_list; params.env = msg->env_string_list;
params.inherit_env = msg->env_inherit; params.inherit_env = msg->env_inherit;
params.stdout_file = stdout_handle; params.debug_subprocesses = msg->debug_subprocesses;
params.stderr_file = stderr_handle; params.stdout_file = stdout_handle;
params.stdin_file = stdin_handle; params.stderr_file = stderr_handle;
params.stdin_file = stdin_handle;
} }
U32 id = dmn_ctrl_launch(ctrl_ctx, &params); U32 id = dmn_ctrl_launch(ctrl_ctx, &params);
@@ -4391,6 +4545,7 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, process, exit_code); B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, process, exit_code);
//- rjf: wait for process to be dead //- rjf: wait for process to be dead
CTRL_EventCause cause = CTRL_EventCause_Finished;
if(kill_worked) if(kill_worked)
{ {
DMN_RunCtrls run_ctrls = {0}; DMN_RunCtrls run_ctrls = {0};
@@ -4401,12 +4556,102 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
for(B32 done = 0; done == 0;) for(B32 done = 0; done == 0;)
{ {
DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0);
if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) switch(event->kind)
{ {
done = 1; default:{}break;
case DMN_EventKind_ExitProcess:
if(dmn_handle_match(event->process, process))
{
done = 1;
}break;
case DMN_EventKind_Error:{done = 1; cause = CTRL_EventCause_Error;}break;
case DMN_EventKind_Halt: {done = 1; cause = CTRL_EventCause_InterruptedByHalt;}break;
} }
if(event->kind == DMN_EventKind_Null || }
event->kind == DMN_EventKind_Error) }
//- rjf: record stop
{
CTRL_EventList evts = {0};
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
event->kind = CTRL_EventKind_Stopped;
event->cause = cause;
event->msg_id = msg->msg_id;
if(kill_worked)
{
event->entity = msg->entity;
}
ctrl_c2u_push_events(&evts);
}
scratch_end(scratch);
ProfEnd();
}
internal void
ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
{
ProfBeginFunction();
Temp scratch = scratch_begin(0, 0);
U32 exit_code = msg->exit_code;
//- rjf: gather all currently existing processes
CTRL_EntityList initial_processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process);
typedef struct Task Task;
struct Task
{
Task *next;
Task *prev;
CTRL_Entity *process;
};
Task *first_task = 0;
Task *last_task = 0;
for(CTRL_EntityNode *n = initial_processes.first; n != 0; n = n->next)
{
Task *t = push_array(scratch.arena, Task, 1);
t->process = n->v;
DLLPushBack(first_task, last_task, t);
}
//- rjf: kill processes as needed, wait for all processes to be dead
CTRL_EventCause cause = CTRL_EventCause_Finished;
if(first_task != 0)
{
DMN_RunCtrls run_ctrls = {0};
for(B32 done = 0; !done;)
{
// rjf: kill remaining processes
for(Task *t = first_task, *next = 0; t != 0; t = next)
{
next = t->next;
B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, t->process->handle.dmn_handle, exit_code);
if(kill_worked)
{
DLLRemove(first_task, last_task, t);
}
}
// rjf: get next event
DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0);
// rjf: process event
switch(event->kind)
{
default:{}break;
case DMN_EventKind_CreateProcess:
{
CTRL_Entity *new_process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, event->process));
Task *t = push_array(scratch.arena, Task, 1);
t->process = new_process;
DLLPushBack(first_task, last_task, t);
}break;
case DMN_EventKind_Error:{done = 1; cause = CTRL_EventCause_Error;}break;
case DMN_EventKind_Halt: {done = 1; cause = CTRL_EventCause_InterruptedByHalt;}break;
}
// rjf: end if all processes are gone
CTRL_EntityList processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process);
if(processes.count == 0)
{ {
done = 1; done = 1;
} }
@@ -4418,12 +4663,8 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
CTRL_EventList evts = {0}; CTRL_EventList evts = {0};
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
event->kind = CTRL_EventKind_Stopped; event->kind = CTRL_EventKind_Stopped;
event->cause = CTRL_EventCause_Finished; event->cause = cause;
event->msg_id = msg->msg_id; event->msg_id = msg->msg_id;
if(kill_worked)
{
event->entity = msg->entity;
}
ctrl_c2u_push_events(&evts); ctrl_c2u_push_events(&evts);
} }
@@ -4623,6 +4864,12 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
switch(event->kind) switch(event->kind)
{ {
default:{}break; default:{}break;
case DMN_EventKind_ExitThread:
if(dmn_handle_match(event->thread, thread))
{
stop_cause = CTRL_EventCause_Error;
goto stop;
}break;
case DMN_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop; case DMN_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop;
case DMN_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop; case DMN_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop;
case DMN_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop; case DMN_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop;
@@ -5700,167 +5947,168 @@ ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *o
//- rjf: entry point //- rjf: entry point
internal void ASYNC_WORK_DEF(ctrl_mem_stream_work)
ctrl_mem_stream_thread__entry_point(void *p)
{ {
ProfBeginFunction();
CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache;
for(;;) //- rjf: unpack next request
CTRL_Handle process = {0};
Rng1U64 vaddr_range = {0};
B32 zero_terminated = 0;
ctrl_u2ms_dequeue_req(&process, &vaddr_range, &zero_terminated);
U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, vaddr_range, zero_terminated);
ProfBegin("memory stream request");
//- rjf: unpack process memory cache key
U64 process_hash = ctrl_hash_from_string(str8_struct(&process));
U64 process_slot_idx = process_hash%cache->slots_count;
U64 process_stripe_idx = process_slot_idx%cache->stripes_count;
CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx];
CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx];
//- rjf: unpack address range hash cache key
U64 range_hash = ctrl_hash_from_string(str8_struct(&vaddr_range));
//- rjf: take task
B32 got_task = 0;
U64 preexisting_mem_gen = 0;
U128 preexisting_hash = {0};
Rng1U64 vaddr_range_clamped = {0};
OS_MutexScopeW(process_stripe->rw_mutex)
{ {
//- rjf: unpack next request for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
CTRL_Handle process = {0};
Rng1U64 vaddr_range = {0};
B32 zero_terminated = 0;
ctrl_u2ms_dequeue_req(&process, &vaddr_range, &zero_terminated);
U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, vaddr_range, zero_terminated);
//- rjf: unpack process memory cache key
U64 process_hash = ctrl_hash_from_string(str8_struct(&process));
U64 process_slot_idx = process_hash%cache->slots_count;
U64 process_stripe_idx = process_slot_idx%cache->stripes_count;
CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx];
CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx];
//- rjf: unpack address range hash cache key
U64 range_hash = ctrl_hash_from_string(str8_struct(&vaddr_range));
//- rjf: take task
B32 got_task = 0;
U64 preexisting_mem_gen = 0;
U128 preexisting_hash = {0};
Rng1U64 vaddr_range_clamped = {0};
OS_MutexScopeW(process_stripe->rw_mutex)
{ {
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) if(ctrl_handle_match(n->handle, process))
{ {
if(ctrl_handle_match(n->handle, process)) U64 range_slot_idx = range_hash%n->range_hash_slots_count;
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
{ {
U64 range_slot_idx = range_hash%n->range_hash_slots_count; if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
{ {
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated) got_task = !ins_atomic_u32_eval_cond_assign(&range_n->is_taken, 1, 0);
{ preexisting_mem_gen = range_n->mem_gen;
got_task = !ins_atomic_u32_eval_cond_assign(&range_n->is_taken, 1, 0); preexisting_hash = range_n->hash;
preexisting_mem_gen = range_n->mem_gen; vaddr_range_clamped = range_n->vaddr_range_clamped;
preexisting_hash = range_n->hash; goto take_task__break_all;
vaddr_range_clamped = range_n->vaddr_range_clamped;
goto take_task__break_all;
}
} }
} }
} }
take_task__break_all:;
} }
take_task__break_all:;
//- rjf: task was taken -> read memory }
U64 range_size = 0;
Arena *range_arena = 0; //- rjf: task was taken -> read memory
void *range_base = 0; U64 range_size = 0;
U64 zero_terminated_size = 0; Arena *range_arena = 0;
U64 pre_read_mem_gen = dmn_mem_gen(); void *range_base = 0;
U64 post_read_mem_gen = 0; U64 zero_terminated_size = 0;
if(got_task && pre_read_mem_gen != preexisting_mem_gen) U64 pre_read_mem_gen = dmn_mem_gen();
U64 post_read_mem_gen = 0;
if(got_task && pre_read_mem_gen != preexisting_mem_gen)
{
range_size = dim_1u64(vaddr_range_clamped);
U64 page_size = os_get_system_info()->page_size;
U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size);
range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE);
if(range_arena == 0)
{ {
range_size = dim_1u64(vaddr_range_clamped); range_size = 0;
U64 page_size = os_get_system_info()->page_size; }
U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); else
range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); {
if(range_arena == 0) range_base = push_array_no_zero(range_arena, U8, range_size);
U64 bytes_read = 0;
U64 retry_count = 0;
U64 retry_limit = range_size > page_size ? 64 : 0;
for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped;
retry_count <= retry_limit;
retry_count += 1)
{ {
range_size = 0; bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base);
} if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min)
else
{
range_base = push_array_no_zero(range_arena, U8, range_size);
U64 bytes_read = 0;
U64 retry_count = 0;
U64 retry_limit = range_size > page_size ? 64 : 0;
for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped;
retry_count <= retry_limit;
retry_count += 1)
{ {
bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base); U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2;
if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) vaddr_range_clamped_retry.max -= diff;
{ vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size);
U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; if(diff == 0)
vaddr_range_clamped_retry.max -= diff;
vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size);
if(diff == 0)
{
break;
}
}
else
{ {
break; break;
} }
} }
if(bytes_read == 0) else
{ {
arena_release(range_arena); break;
range_base = 0;
range_size = 0;
range_arena = 0;
}
else if(bytes_read < range_size)
{
MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read);
}
zero_terminated_size = range_size;
if(zero_terminated)
{
for(U64 idx = 0; idx < bytes_read; idx += 1)
{
if(((U8 *)range_base)[idx] == 0)
{
zero_terminated_size = idx;
break;
}
}
} }
} }
post_read_mem_gen = dmn_mem_gen(); if(bytes_read == 0)
}
//- rjf: read successful -> submit to hash store
U128 hash = {0};
if(got_task && range_base != 0 && pre_read_mem_gen == post_read_mem_gen)
{
hash = hs_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size));
}
else if(range_arena != 0)
{
arena_release(range_arena);
}
//- rjf: commit hash to cache
if(got_task) OS_MutexScopeW(process_stripe->rw_mutex)
{
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
{ {
if(ctrl_handle_match(n->handle, process)) arena_release(range_arena);
range_base = 0;
range_size = 0;
range_arena = 0;
}
else if(bytes_read < range_size)
{
MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read);
}
zero_terminated_size = range_size;
if(zero_terminated)
{
for(U64 idx = 0; idx < bytes_read; idx += 1)
{ {
U64 range_slot_idx = range_hash%n->range_hash_slots_count; if(((U8 *)range_base)[idx] == 0)
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
{ {
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated) zero_terminated_size = idx;
{ break;
if(!u128_match(u128_zero(), hash))
{
range_n->hash = hash;
range_n->mem_gen = post_read_mem_gen;
}
ins_atomic_u32_eval_assign(&range_n->is_taken, 0);
goto commit__break_all;
}
} }
} }
} }
commit__break_all:;
} }
post_read_mem_gen = dmn_mem_gen();
//- rjf: broadcast changes
os_condition_variable_broadcast(process_stripe->cv);
} }
//- rjf: read successful -> submit to hash store
U128 hash = {0};
if(got_task && range_base != 0 && pre_read_mem_gen == post_read_mem_gen)
{
hash = hs_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size));
}
else if(range_arena != 0)
{
arena_release(range_arena);
}
//- rjf: commit hash to cache
if(got_task) OS_MutexScopeW(process_stripe->rw_mutex)
{
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
{
if(ctrl_handle_match(n->handle, process))
{
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
{
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
{
if(!u128_match(u128_zero(), hash))
{
range_n->hash = hash;
range_n->mem_gen = post_read_mem_gen;
}
ins_atomic_u32_eval_assign(&range_n->is_taken, 0);
goto commit__break_all;
}
}
}
}
commit__break_all:;
}
//- rjf: broadcast changes
os_condition_variable_broadcast(process_stripe->cv);
ProfEnd();
ProfEnd();
return 0;
} }
+45 -10
View File
@@ -15,6 +15,20 @@ typedef U64 CTRL_MachineID;
//////////////////////////////// ////////////////////////////////
//~ rjf: Meta Evaluation Types //~ rjf: Meta Evaluation Types
//- rjf: auto-checkbox b32s
typedef struct CTRL_CheckB32 CTRL_CheckB32;
struct CTRL_CheckB32
{
B32 b32;
};
struct_members(CTRL_CheckB32)
{
member_lit_comp(CTRL_CheckB32, type(B32), b32),
};
struct_type(CTRL_CheckB32);
//- rjf: styled string types //- rjf: styled string types
ptr_type(CTRL_PlainString8__str_ptr_type, type(U8), .flags = TypeFlag_IsPlainText,.count_delimiter_name = str8_lit_comp("size")); ptr_type(CTRL_PlainString8__str_ptr_type, type(U8), .flags = TypeFlag_IsPlainText,.count_delimiter_name = str8_lit_comp("size"));
@@ -74,12 +88,13 @@ typedef struct CTRL_MetaEval CTRL_MetaEval;
struct CTRL_MetaEval struct CTRL_MetaEval
{ {
#define CTRL_MetaEval_MemberXList \ #define CTRL_MetaEval_MemberXList \
X(B32, enabled, "Enabled")\ X(B32, enabled, "Enabled")\
X(B32, frozen, "Frozen")\ X(B32, frozen, "Frozen")\
X(U64, hit_count, "Hit Count")\ X(U64, hit_count, "Hit Count")\
X(U64, id, "ID")\ X(U64, id, "ID")\
X(Rng1U64, vaddr_range, "Address Range")\ X(Rng1U64, vaddr_range, "Address Range")\
X(U32, color, "Color")\ X(U32, color, "Color")\
X(CTRL_CheckB32, debug_subprocesses,"Debug Subprocesses")\
Y(String8, type(CTRL_CodeString8), label, "Label")\ Y(String8, type(CTRL_CodeString8), label, "Label")\
Y(String8, type(CTRL_PathString8), exe, "Executable Path")\ Y(String8, type(CTRL_PathString8), exe, "Executable Path")\
Y(String8, type(CTRL_PathString8), dbg, "Debug Info Path")\ Y(String8, type(CTRL_PathString8), dbg, "Debug Info Path")\
@@ -138,6 +153,7 @@ struct_members(CTRL_TargetMetaEval)
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdout_path, .pretty_name = str8_lit_comp("Standard Output Path")), member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdout_path, .pretty_name = str8_lit_comp("Standard Output Path")),
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stderr_path, .pretty_name = str8_lit_comp("Standard Error Path")), member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stderr_path, .pretty_name = str8_lit_comp("Standard Error Path")),
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdin_path, .pretty_name = str8_lit_comp("Standard Input Path")), member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdin_path, .pretty_name = str8_lit_comp("Standard Input Path")),
member_lit_comp(CTRL_MetaEval, type(CTRL_CheckB32), debug_subprocesses, .pretty_name = str8_lit_comp("Debug Subprocesses")),
}; };
struct_members(CTRL_PinMetaEval) struct_members(CTRL_PinMetaEval)
@@ -517,6 +533,7 @@ typedef enum CTRL_MsgKind
CTRL_MsgKind_Launch, CTRL_MsgKind_Launch,
CTRL_MsgKind_Attach, CTRL_MsgKind_Attach,
CTRL_MsgKind_Kill, CTRL_MsgKind_Kill,
CTRL_MsgKind_KillAll,
CTRL_MsgKind_Detach, CTRL_MsgKind_Detach,
CTRL_MsgKind_Run, CTRL_MsgKind_Run,
CTRL_MsgKind_SingleStep, CTRL_MsgKind_SingleStep,
@@ -545,6 +562,7 @@ struct CTRL_Msg
U32 entity_id; U32 entity_id;
U32 exit_code; U32 exit_code;
B32 env_inherit; B32 env_inherit;
B32 debug_subprocesses;
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
String8 path; String8 path;
String8List entry_points; String8List entry_points;
@@ -822,6 +840,23 @@ struct CTRL_ModuleImageInfoCache
CTRL_ModuleImageInfoCacheStripe *stripes; CTRL_ModuleImageInfoCacheStripe *stripes;
}; };
////////////////////////////////
//~ rjf: Touched Debug Info Directory Cache
typedef struct CTRL_DbgDirNode CTRL_DbgDirNode;
struct CTRL_DbgDirNode
{
CTRL_DbgDirNode *first;
CTRL_DbgDirNode *last;
CTRL_DbgDirNode *next;
CTRL_DbgDirNode *prev;
CTRL_DbgDirNode *parent;
String8 name;
U64 search_count;
U64 child_count;
U64 module_direct_count;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Wakeup Hook Function Types //~ rjf: Wakeup Hook Function Types
@@ -878,6 +913,8 @@ struct CTRL_State
CTRL_MetaEvalArray user_meta_evals; CTRL_MetaEvalArray user_meta_evals;
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
U64 process_counter; U64 process_counter;
Arena *dbg_dir_arena;
CTRL_DbgDirNode *dbg_dir_root;
// rjf: user -> memstream ring buffer // rjf: user -> memstream ring buffer
U64 u2ms_ring_size; U64 u2ms_ring_size;
@@ -886,10 +923,6 @@ struct CTRL_State
U64 u2ms_ring_read_pos; U64 u2ms_ring_read_pos;
OS_Handle u2ms_ring_mutex; OS_Handle u2ms_ring_mutex;
OS_Handle u2ms_ring_cv; OS_Handle u2ms_ring_cv;
// rjf: memory stream threads
U64 ms_thread_count;
OS_Handle *ms_threads;
}; };
//////////////////////////////// ////////////////////////////////
@@ -1141,6 +1174,7 @@ internal void ctrl_thread__end_and_flush_info_log(void);
internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
@@ -1153,6 +1187,7 @@ internal B32 ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32
internal void ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); internal void ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated);
//- rjf: entry point //- rjf: entry point
ASYNC_WORK_DEF(ctrl_mem_stream_work);
internal void ctrl_mem_stream_thread__entry_point(void *p); internal void ctrl_mem_stream_thread__entry_point(void *p);
#endif // CTRL_CORE_H #endif // CTRL_CORE_H
+281 -300
View File
@@ -41,7 +41,14 @@ dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Synta
ZydisDecodedOperand *first_visible_op = (zinst.info.operand_count_visible > 0 ? &zinst.operands[0] : 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 *first_op = (zinst.info.operand_count > 0 ? &zinst.operands[0] : 0);
ZydisDecodedOperand *second_op = (zinst.info.operand_count > 1 ? &zinst.operands[1] : 0); ZydisDecodedOperand *second_op = (zinst.info.operand_count > 1 ? &zinst.operands[1] : 0);
if(first_visible_op != 0) if(first_visible_op != 0 &&
(first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM8 ||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16 ||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM32 ||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM64 ||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16_32_64 ||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM32_32_64 ||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16_32_32))
{ {
ZydisCalcAbsoluteAddress(&zinst.info, first_visible_op, vaddr, &jump_dest_vaddr); ZydisCalcAbsoluteAddress(&zinst.info, first_visible_op, vaddr, &jump_dest_vaddr);
} }
@@ -267,31 +274,9 @@ dasm_init(void)
dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size); 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_cv = os_condition_variable_alloc();
dasm_shared->u2p_ring_mutex = os_mutex_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); 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 //~ rjf: Scoped Access
@@ -341,7 +326,7 @@ dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node)
DASM_Touch *touch = push_array(dasm_tctx->arena, DASM_Touch, 1); DASM_Touch *touch = push_array(dasm_tctx->arena, DASM_Touch, 1);
ins_atomic_u64_inc_eval(&node->scope_ref_count); 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_time_touched_us, os_now_microseconds());
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx()); ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx());
touch->hash = node->hash; touch->hash = node->hash;
MemoryCopyStruct(&touch->params, &node->params); MemoryCopyStruct(&touch->params, &node->params);
touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key); touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key);
@@ -423,6 +408,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
if(node_is_new) if(node_is_new)
{ {
dasm_u2p_enqueue_req(hash, params, max_U64); dasm_u2p_enqueue_req(hash, params, max_U64);
async_push_work(dasm_parse_work);
} }
} }
return info; return info;
@@ -471,8 +457,6 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us)
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, &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, &params->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(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, &params->dbgi_key.min_timestamp); 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, &params->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; break;
} }
if(os_now_microseconds() >= endt_us) if(os_now_microseconds() >= endt_us)
@@ -506,8 +490,6 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
params_out->dbgi_key.path.str = push_array(arena, U8, params_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(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, &params_out->dbgi_key.min_timestamp); 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, &params_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; break;
} }
os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64); os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64);
@@ -515,284 +497,282 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
os_condition_variable_broadcast(dasm_shared->u2p_ring_cv); os_condition_variable_broadcast(dasm_shared->u2p_ring_cv);
} }
internal void ASYNC_WORK_DEF(dasm_parse_work)
dasm_parse_thread__entry_point(void *p)
{ {
ThreadNameF("[dasm] parse thread #%I64u", (U64)p); ProfBeginFunction();
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, &params);
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)
{ {
Temp scratch = scratch_begin(0, 0); for(DASM_Node *n = slot->first; n != 0; n = n->next)
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, &params);
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, &params))
{ {
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, &params)) got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
{ break;
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, &params.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, &params))
{
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: 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, &params.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, &params))
{
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);
ProfEnd();
return 0;
} }
//////////////////////////////// ////////////////////////////////
@@ -806,7 +786,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
{ {
U64 change_gen = fs_change_gen(); U64 change_gen = fs_change_gen();
U64 check_time_us = os_now_microseconds(); U64 check_time_us = os_now_microseconds();
U64 check_time_user_clocks = dasm_user_clock_idx(); U64 check_time_user_clocks = update_tick_idx();
U64 evict_threshold_us = 10*1000000; U64 evict_threshold_us = 10*1000000;
U64 retry_threshold_us = 1*1000000; U64 retry_threshold_us = 1*1000000;
U64 evict_threshold_user_clocks = 10; U64 evict_threshold_user_clocks = 10;
@@ -863,6 +843,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
{ {
if(dasm_u2p_enqueue_req(n->hash, &n->params, max_U64)) if(dasm_u2p_enqueue_req(n->hash, &n->params, max_U64))
{ {
async_push_work(dasm_parse_work);
n->last_time_requested_us = os_now_microseconds(); n->last_time_requested_us = os_now_microseconds();
n->last_user_clock_idx_requested = check_time_user_clocks; n->last_user_clock_idx_requested = check_time_user_clocks;
} }
+1 -14
View File
@@ -246,9 +246,6 @@ struct DASM_Shared
{ {
Arena *arena; Arena *arena;
// rjf: user clock
U64 user_clock_idx;
// rjf: cache // rjf: cache
U64 slots_count; U64 slots_count;
U64 stripes_count; U64 stripes_count;
@@ -263,10 +260,6 @@ struct DASM_Shared
OS_Handle u2p_ring_cv; OS_Handle u2p_ring_cv;
OS_Handle u2p_ring_mutex; OS_Handle u2p_ring_mutex;
// rjf: parse threads
U64 parse_thread_count;
OS_Handle *parse_threads;
// rjf: evictor/detector thread // rjf: evictor/detector thread
OS_Handle evictor_detector_thread; OS_Handle evictor_detector_thread;
}; };
@@ -305,12 +298,6 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx);
internal void dasm_init(void); 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 //~ rjf: Scoped Access
@@ -329,7 +316,7 @@ internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_P
internal B32 dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us); 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_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out);
internal void dasm_parse_thread__entry_point(void *p); ASYNC_WORK_DEF(dasm_parse_work);
//////////////////////////////// ////////////////////////////////
//~ rjf: Evictor/Detector Thread //~ rjf: Evictor/Detector Thread
-1
View File
@@ -107,7 +107,6 @@ D_ViewRuleTable:
@table(name) @table(name)
D_DevToggleTable: D_DevToggleTable:
{ {
{telemetry_capture}
{simulate_lag} {simulate_lag}
{draw_ui_text_pos} {draw_ui_text_pos}
{draw_ui_focus_debug} {draw_ui_focus_debug}
+118 -27
View File
@@ -942,6 +942,100 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
// TODO(rjf): this depends on file path maps, needs to move // TODO(rjf): this depends on file path maps, needs to move
internal D_LineListArray
d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range)
{
D_LineListArray array = {0};
{
array.count = dim_1s64(line_num_range)+1;
array.v = push_array(arena, D_LineList, array.count);
di_key_list_push(arena, &array.dbgi_keys, &dbgi_key);
}
Temp scratch = scratch_begin(&arena, 1);
U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count);
DI_Scope *scope = di_scope_open();
String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path);
for(String8Node *override_n = overrides.first;
override_n != 0;
override_n = override_n->next)
{
String8 file_path = override_n->string;
String8 file_path_normalized = lower_from_str8(scratch.arena, file_path);
// rjf: binary -> rdi
RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0);
// rjf: file_path_normalized * rdi -> src_id
B32 good_src_id = 0;
U32 src_id = 0;
if(rdi != &di_rdi_parsed_nil) ProfScope("file_path_normalized * rdi -> src_id")
{
RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths);
RDI_ParsedNameMap map = {0};
rdi_parsed_from_name_map(rdi, mapptr, &map);
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, file_path_normalized.str, file_path_normalized.size);
if(node != 0)
{
U32 id_count = 0;
U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count);
if(id_count > 0)
{
good_src_id = 1;
src_id = ids[0];
}
}
}
// rjf: good src-id -> look up line info for visible range
if(good_src_id) ProfScope("good src-id -> look up line info for visible range")
{
RDI_SourceFile *src = rdi_element_from_name_idx(rdi, SourceFiles, src_id);
RDI_SourceLineMap *src_line_map = rdi_element_from_name_idx(rdi, SourceLineMaps, src->source_line_map_idx);
RDI_ParsedSourceLineMap line_map = {0};
rdi_parsed_from_source_line_map(rdi, src_line_map, &line_map);
U64 line_idx = 0;
for(S64 line_num = line_num_range.min;
line_num <= line_num_range.max;
line_num += 1, line_idx += 1)
{
D_LineList *list = &array.v[line_idx];
U32 voff_count = 0;
U64 *voffs = rdi_line_voffs_from_num(&line_map, u32_from_u64_saturate((U64)line_num), &voff_count);
if(lines_num_voffs[line_idx] < 8) ProfScope("iterate voffs (%i)", voff_count) for(U64 idx = 0; idx < voff_count; idx += 1)
{
U64 base_voff = voffs[idx];
U64 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, base_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, base_voff);
if(unit_line_info.voffs != 0)
{
Rng1U64 range = r1u64(base_voff, unit_line_info.voffs[line_info_idx+1]);
S64 actual_line = (S64)unit_line_info.lines[line_info_idx].line_num;
D_LineNode *n = push_array(arena, D_LineNode, 1);
n->v.voff_range = range;
n->v.pt.line = (S64)actual_line;
n->v.pt.column = 1;
n->v.dbgi_key = dbgi_key;
SLLQueuePush(list->first, list->last, n);
list->count += 1;
lines_num_voffs[line_idx] += 1;
if(lines_num_voffs[line_idx] >= 8)
{
break;
}
}
}
}
}
}
di_scope_close(scope);
scratch_end(scratch);
return array;
}
internal D_LineListArray internal D_LineListArray
d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range) d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range)
{ {
@@ -1047,6 +1141,18 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
return array; return array;
} }
internal D_LineList
d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num)
{
D_LineListArray array = d_lines_array_from_dbgi_key_file_path_line_range(arena, dbgi_key, file_path, r1s64(line_num, line_num+1));
D_LineList list = {0};
if(array.count != 0)
{
list = array.v[0];
}
return list;
}
internal D_LineList internal D_LineList
d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num) d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num)
{ {
@@ -1974,21 +2080,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
} }
} }
//////////////////////////////
//- rjf: start/stop telemetry captures
//
ProfScope("start/stop telemetry captures")
{
if(!ProfIsCapturing() && DEV_telemetry_capture)
{
ProfBeginCapture("raddbg");
}
if(ProfIsCapturing() && !DEV_telemetry_capture)
{
ProfEndCapture();
}
}
////////////////////////////// //////////////////////////////
//- rjf: process top-level commands //- rjf: process top-level commands
// //
@@ -2083,6 +2174,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->stdout_path = stdout_path; msg->stdout_path = stdout_path;
msg->stderr_path = stderr_path; msg->stderr_path = stderr_path;
msg->stdin_path = stdin_path; msg->stdin_path = stdin_path;
msg->debug_subprocesses = target->debug_subprocesses;
msg->env_inherit = 1; msg->env_inherit = 1;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters); MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
MemoryCopyStruct(&msg->meta_evals, meta_evals); MemoryCopyStruct(&msg->meta_evals, meta_evals);
@@ -2123,16 +2215,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
}break; }break;
case D_CmdKind_KillAll: case D_CmdKind_KillAll:
{ {
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs);
for(CTRL_EntityNode *n = processes.first; n != 0; n = n->next) msg->kind = CTRL_MsgKind_KillAll;
{ msg->exit_code = 1;
CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs); MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->kind = CTRL_MsgKind_Kill; MemoryCopyStruct(&msg->meta_evals, meta_evals);
msg->exit_code = 1;
msg->entity = n->v->handle;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
MemoryCopyStruct(&msg->meta_evals, meta_evals);
}
}break; }break;
case D_CmdKind_Detach: case D_CmdKind_Detach:
{ {
@@ -2320,8 +2407,12 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
}break; }break;
case D_CmdKind_Restart: case D_CmdKind_Restart:
{ {
d_cmd(D_CmdKind_KillAll); CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
d_cmd(D_CmdKind_LaunchAndRun); if(processes.count != 0)
{
d_cmd(D_CmdKind_KillAll);
d_cmd(D_CmdKind_LaunchAndRun);
}
}break; }break;
case D_CmdKind_StepInto: case D_CmdKind_StepInto:
case D_CmdKind_StepOver: case D_CmdKind_StepOver:
+4
View File
@@ -17,6 +17,7 @@ struct D_Target
String8 stdout_path; String8 stdout_path;
String8 stderr_path; String8 stderr_path;
String8 stdin_path; String8 stdin_path;
B32 debug_subprocesses;
String8List env; String8List env;
}; };
@@ -443,7 +444,10 @@ internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U
//- rjf: file:line -> line info //- rjf: file:line -> line info
// TODO(rjf): this depends on file path maps, needs to move // TODO(rjf): this depends on file path maps, needs to move
// TODO(rjf): need to clean this up & dedup
internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range);
internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range); internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range);
internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num);
internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num); internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num);
//////////////////////////////// ////////////////////////////////
@@ -71,7 +71,6 @@ D_ViewRuleKind_Geo3D,
D_ViewRuleKind_COUNT, D_ViewRuleKind_COUNT,
} D_ViewRuleKind; } D_ViewRuleKind;
global B32 DEV_telemetry_capture = 0;
global B32 DEV_simulate_lag = 0; global B32 DEV_simulate_lag = 0;
global B32 DEV_draw_ui_text_pos = 0; global B32 DEV_draw_ui_text_pos = 0;
global B32 DEV_draw_ui_focus_debug = 0; global B32 DEV_draw_ui_focus_debug = 0;
@@ -83,7 +82,6 @@ global B32 DEV_scratch_mouse_draw = 0;
global B32 DEV_updating_indicator = 0; global B32 DEV_updating_indicator = 0;
struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = 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_simulate_lag, str8_lit_comp("simulate_lag")},
{&DEV_draw_ui_text_pos, str8_lit_comp("draw_ui_text_pos")}, {&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_focus_debug, str8_lit_comp("draw_ui_focus_debug")},
+1199 -290
View File
File diff suppressed because it is too large Load Diff
+226 -9
View File
@@ -72,7 +72,7 @@ struct DI_EventList
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: Cache Types //~ rjf: Debug Info Cache Types
typedef struct DI_StringChunkNode DI_StringChunkNode; typedef struct DI_StringChunkNode DI_StringChunkNode;
struct DI_StringChunkNode struct DI_StringChunkNode
@@ -92,7 +92,6 @@ struct DI_Node
U64 ref_count; U64 ref_count;
U64 touch_count; U64 touch_count;
U64 is_working; U64 is_working;
U64 last_time_requested_us;
// rjf: key // rjf: key
DI_Key key; DI_Key key;
@@ -126,6 +125,91 @@ struct DI_Stripe
OS_Handle cv; OS_Handle cv;
}; };
////////////////////////////////
//~ rjf: Search Cache Types
typedef struct DI_SearchItem DI_SearchItem;
struct DI_SearchItem
{
U64 idx;
U64 dbgi_idx;
U64 missed_size;
FuzzyMatchRangeList match_ranges;
};
typedef struct DI_SearchItemChunk DI_SearchItemChunk;
struct DI_SearchItemChunk
{
DI_SearchItemChunk *next;
DI_SearchItem *v;
U64 count;
U64 cap;
};
typedef struct DI_SearchItemChunkList DI_SearchItemChunkList;
struct DI_SearchItemChunkList
{
DI_SearchItemChunk *first;
DI_SearchItemChunk *last;
U64 chunk_count;
U64 total_count;
};
typedef struct DI_SearchItemArray DI_SearchItemArray;
struct DI_SearchItemArray
{
DI_SearchItem *v;
U64 count;
};
typedef struct DI_SearchParams DI_SearchParams;
struct DI_SearchParams
{
RDI_SectionKind target;
DI_KeyArray dbgi_keys;
};
typedef struct DI_SearchBucket DI_SearchBucket;
struct DI_SearchBucket
{
Arena *arena;
String8 query;
U64 params_hash;
DI_SearchParams params;
};
typedef struct DI_SearchNode DI_SearchNode;
struct DI_SearchNode
{
DI_SearchNode *next;
DI_SearchNode *prev;
U128 key;
U64 scope_refcount;
U64 work_refcount;
U64 last_update_tick_idx;
U64 bucket_read_gen;
U64 bucket_write_gen;
U64 bucket_items_gen;
DI_SearchBucket buckets[6];
DI_SearchItemArray items;
};
typedef struct DI_SearchSlot DI_SearchSlot;
struct DI_SearchSlot
{
DI_SearchNode *first;
DI_SearchNode *last;
};
typedef struct DI_SearchStripe DI_SearchStripe;
struct DI_SearchStripe
{
Arena *arena;
DI_SearchNode *free_node;
OS_Handle rw_mutex;
OS_Handle cv;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Scoped Access Types //~ rjf: Scoped Access Types
@@ -134,6 +218,7 @@ struct DI_Touch
{ {
DI_Touch *next; DI_Touch *next;
DI_Node *node; DI_Node *node;
DI_SearchNode *search_node;
}; };
typedef struct DI_Scope DI_Scope; typedef struct DI_Scope DI_Scope;
@@ -152,6 +237,98 @@ struct DI_TCTX
DI_Touch *free_touch; DI_Touch *free_touch;
}; };
////////////////////////////////
//~ rjf: Search Thread State Types
typedef struct DI_SearchThread DI_SearchThread;
struct DI_SearchThread
{
OS_Handle thread;
OS_Handle ring_mutex;
OS_Handle ring_cv;
U64 ring_size;
U8 *ring_base;
U64 ring_write_pos;
U64 ring_read_pos;
};
////////////////////////////////
//~ rjf: Match Cache State Types
typedef struct DI_Match DI_Match;
struct DI_Match
{
DI_Match *next;
DI_Match *prev;
U64 dbgi_idx;
RDI_SectionKind section;
U32 idx;
};
typedef struct DI_MatchNameNode DI_MatchNameNode;
struct DI_MatchNameNode
{
// rjf: synchronously written by usage code
DI_MatchNameNode *next;
DI_MatchNameNode *prev;
DI_MatchNameNode *lru_next;
DI_MatchNameNode *lru_prev;
U64 alloc_gen;
U64 first_gen_touched;
U64 last_gen_touched;
U64 req_params_hash;
U64 req_count;
String8 name;
U64 hash;
// rjf: atomically written by match work
U64 cmp_count;
U64 cmp_params_hash;
RDI_SectionKind section_kind;
// DI_Match *first_match;
// DI_Match *last_match;
};
typedef struct DI_MatchNameSlot DI_MatchNameSlot;
struct DI_MatchNameSlot
{
DI_MatchNameNode *first;
DI_MatchNameNode *last;
};
typedef struct DI_MatchStore DI_MatchStore;
struct DI_MatchStore
{
Arena *arena;
U64 gen;
Arena *gen_arenas[2];
// rjf: parameters
Arena *params_arena;
OS_Handle params_rw_mutex;
U64 params_hash;
DI_KeyArray params_keys;
// rjf: match cache
U64 match_name_slots_count;
DI_MatchNameSlot *match_name_slots;
DI_MatchNameNode *first_free_match_name;
DI_Match *first_free_match;
DI_MatchNameNode *first_lru_match_name;
DI_MatchNameNode *last_lru_match_name;
U64 active_match_name_nodes_count;
OS_Handle match_rw_mutex;
OS_Handle match_cv;
// rjf: user -> match work ring buffer
OS_Handle u2m_ring_cv;
OS_Handle u2m_ring_mutex;
U64 u2m_ring_size;
U8 *u2m_ring_base;
U64 u2m_ring_write_pos;
U64 u2m_ring_read_pos;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Shared State Types //~ rjf: Shared State Types
@@ -160,12 +337,18 @@ struct DI_Shared
{ {
Arena *arena; Arena *arena;
// rjf: node cache // rjf: debug info cache
U64 slots_count; U64 slots_count;
DI_Slot *slots; DI_Slot *slots;
U64 stripes_count; U64 stripes_count;
DI_Stripe *stripes; DI_Stripe *stripes;
// rjf: search cache
U64 search_slots_count;
DI_SearchSlot *search_slots;
U64 search_stripes_count;
DI_SearchStripe *search_stripes;
// rjf: user -> parse ring // rjf: user -> parse ring
OS_Handle u2p_ring_mutex; OS_Handle u2p_ring_mutex;
OS_Handle u2p_ring_cv; OS_Handle u2p_ring_cv;
@@ -182,9 +365,10 @@ struct DI_Shared
U64 p2u_ring_write_pos; U64 p2u_ring_write_pos;
U64 p2u_ring_read_pos; U64 p2u_ring_read_pos;
// rjf: threads // rjf: search threads
U64 parse_thread_count; U64 search_threads_count;
OS_Handle *parse_threads; DI_SearchThread *search_threads;
OS_Handle search_evictor_thread;
}; };
//////////////////////////////// ////////////////////////////////
@@ -197,6 +381,7 @@ global RDI_Parsed di_rdi_parsed_nil = {0};
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Helpers //~ rjf: Basic Helpers
internal U64 di_hash_from_seed_string(U64 seed, String8 string, StringMatchFlags match_flags);
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags); internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
internal U64 di_hash_from_key(DI_Key *k); internal U64 di_hash_from_key(DI_Key *k);
internal DI_Key di_key_zero(void); internal DI_Key di_key_zero(void);
@@ -205,6 +390,12 @@ internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src); internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src);
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key); internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key);
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list); internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
internal DI_KeyArray di_key_array_copy(Arena *arena, DI_KeyArray *src);
internal DI_SearchParams di_search_params_copy(Arena *arena, DI_SearchParams *src);
internal U64 di_hash_from_search_params(DI_SearchParams *params);
internal void di_search_item_chunk_list_concat_in_place(DI_SearchItemChunkList *dst, DI_SearchItemChunkList *to_push);
internal U64 di_search_item_num_from_array_element_idx__linear_search(DI_SearchItemArray *array, U64 element_idx);
internal String8 di_search_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx);
//////////////////////////////// ////////////////////////////////
//~ rjf: Main Layer Initialization //~ rjf: Main Layer Initialization
@@ -217,6 +408,7 @@ internal void di_init(void);
internal DI_Scope *di_scope_open(void); internal DI_Scope *di_scope_open(void);
internal void di_scope_close(DI_Scope *scope); internal void di_scope_close(DI_Scope *scope);
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node); internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node);
internal void di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchNode *node);
//////////////////////////////// ////////////////////////////////
//~ rjf: Per-Slot Functions //~ rjf: Per-Slot Functions
@@ -237,12 +429,17 @@ internal void di_open(DI_Key *key);
internal void di_close(DI_Key *key); internal void di_close(DI_Key *key);
//////////////////////////////// ////////////////////////////////
//~ rjf: Cache Lookups //~ rjf: Debug Info Cache Lookups
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us); internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us);
//////////////////////////////// ////////////////////////////////
//~ rjf: Parse Threads //~ rjf: Search Cache Lookups
internal DI_SearchItemArray di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams *params, String8 query, U64 endt_us, B32 *stale_out);
////////////////////////////////
//~ rjf: Asynchronous Parse Work
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us); internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key); internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
@@ -250,6 +447,26 @@ internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
internal void di_p2u_push_event(DI_Event *event); internal void di_p2u_push_event(DI_Event *event);
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us); internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
internal void di_parse_thread__entry_point(void *p); ASYNC_WORK_DEF(di_parse_work);
////////////////////////////////
//~ rjf: Search Threads
internal B32 di_u2s_enqueue_req(U128 key, U64 endt_us);
internal U128 di_u2s_dequeue_req(U64 thread_idx);
ASYNC_WORK_DEF(di_search_work);
internal int di_qsort_compare_search_items(DI_SearchItem *a, DI_SearchItem *b);
internal void di_search_thread__entry_point(void *p);
internal void di_search_evictor_thread__entry_point(void *p);
////////////////////////////////
//~ rjf: Match Store
internal DI_MatchStore *di_match_store_alloc(void);
internal void di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys);
internal RDI_SectionKind di_match_store_section_kind_from_name(DI_MatchStore *store, String8 name, U64 endt_us);
ASYNC_WORK_DEF(di_match_work);
#endif // DBGI_H #endif // DBGI_H
+11 -1
View File
@@ -1217,6 +1217,8 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
{ {
String8List args = {0}; String8List args = {0};
String8 exe_path = params->cmd_line.first->string; String8 exe_path = params->cmd_line.first->string;
String8List exe_path_parts = str8_split_path(scratch.arena, exe_path);
exe_path = str8_list_join(scratch.arena, &exe_path_parts, &(StringJoin){.sep = str8_lit("\\")});
str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path);
for(String8Node *n = params->cmd_line.first->next; n != 0; n = n->next) for(String8Node *n = params->cmd_line.first->next; n != 0; n = n->next)
{ {
@@ -1256,7 +1258,15 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
String16 env16 = str16_from_8(scratch.arena, env); String16 env16 = str16_from_8(scratch.arena, env);
//- rjf: launch //- rjf: launch
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT;
if(params->debug_subprocesses)
{
creation_flags |= DEBUG_PROCESS;
}
else
{
creation_flags |= DEBUG_ONLY_THIS_PROCESS;
}
BOOL inherit_handles = 0; BOOL inherit_handles = 0;
STARTUPINFOW startup_info = {sizeof(startup_info)}; STARTUPINFOW startup_info = {sizeof(startup_info)};
if(!os_handle_match(params->stdout_file, os_handle_zero())) if(!os_handle_match(params->stdout_file, os_handle_zero()))
+2
View File
@@ -609,6 +609,7 @@ dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FancyRunList *list, F32 max_x
internal void internal void
dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run) dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run)
{ {
ProfBeginFunction();
F32 advance = 0; F32 advance = 0;
FNT_Piece *piece_first = run.pieces.v; FNT_Piece *piece_first = run.pieces.v;
FNT_Piece *piece_opl = piece_first + run.pieces.count; FNT_Piece *piece_opl = piece_first + run.pieces.count;
@@ -629,6 +630,7 @@ dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run)
} }
advance += piece->advance; advance += piece->advance;
} }
ProfEnd();
} }
internal void internal void
+1 -1
View File
@@ -132,7 +132,7 @@ internal DR_Bucket *dr_bucket_make(void);
internal void dr_push_bucket(DR_Bucket *bucket); internal void dr_push_bucket(DR_Bucket *bucket);
internal void dr_pop_bucket(void); internal void dr_pop_bucket(void);
internal DR_Bucket *dr_top_bucket(void); internal DR_Bucket *dr_top_bucket(void);
#define D_BucketScope(b) DeferLoop(dr_push_bucket(b), dr_pop_bucket()) #define DR_BucketScope(b) DeferLoop(dr_push_bucket(b), dr_pop_bucket())
//////////////////////////////// ////////////////////////////////
//~ rjf: Bucket Stacks //~ rjf: Bucket Stacks
+1
View File
@@ -90,6 +90,7 @@ E_ExprKindTable:
{ Typeof UnaryPrefix 1 "typeof" "typeof" "(" ")"} { Typeof UnaryPrefix 1 "typeof" "typeof" "(" ")"}
{ ByteSwap UnaryPrefix 1 "bswap" "bswap" "(" ")"} { ByteSwap UnaryPrefix 1 "bswap" "bswap" "(" ")"}
{ Pos UnaryPrefix 2 "+" "+" "" "" }
{ Neg UnaryPrefix 2 "-" "-" "" "" } { Neg UnaryPrefix 2 "-" "-" "" "" }
{ LogNot UnaryPrefix 2 "!" "!" "" "" } { LogNot UnaryPrefix 2 "!" "!" "" "" }
{ BitNot UnaryPrefix 2 "~" "~" "" "" } { BitNot UnaryPrefix 2 "~" "~" "" "" }
+1 -1
View File
@@ -170,7 +170,7 @@ e_value_eval_from_eval(E_Eval eval)
U64 valid_bits_mask = 0; U64 valid_bits_mask = 0;
for(U64 idx = 0; idx < type->count; idx += 1) for(U64 idx = 0; idx < type->count; idx += 1)
{ {
valid_bits_mask |= (1<<idx); valid_bits_mask |= (1ull<<idx);
} }
eval.value.u64 = eval.value.u64 >> type->off; eval.value.u64 = eval.value.u64 >> type->off;
eval.value.u64 = eval.value.u64 & valid_bits_mask; eval.value.u64 = eval.value.u64 & valid_bits_mask;
+4
View File
@@ -846,6 +846,10 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr)
}break; }break;
//- rjf: unary operations //- rjf: unary operations
case E_ExprKind_Pos:
{
result = e_irtree_and_type_from_expr(arena, expr->first);
}break;
case E_ExprKind_Neg: case E_ExprKind_Neg:
case E_ExprKind_LogNot: case E_ExprKind_LogNot:
case E_ExprKind_BitNot: case E_ExprKind_BitNot:
+19 -10
View File
@@ -389,6 +389,7 @@ e_token_array_from_text(Arena *arena, String8 text)
E_TokenKind active_token_kind = E_TokenKind_Null; E_TokenKind active_token_kind = E_TokenKind_Null;
B32 active_token_kind_started_with_tick = 0; B32 active_token_kind_started_with_tick = 0;
B32 escaped = 0; B32 escaped = 0;
B32 exp = 0;
for(U64 idx = 0, advance = 0; idx <= text.size; idx += advance) for(U64 idx = 0, advance = 0; idx <= text.size; idx += advance)
{ {
U8 byte = (idx+0 < text.size) ? text.str[idx+0] : 0; U8 byte = (idx+0 < text.size) ? text.str[idx+0] : 0;
@@ -486,11 +487,17 @@ e_token_array_from_text(Arena *arena, String8 text)
}break; }break;
case E_TokenKind_Numeric: case E_TokenKind_Numeric:
{ {
if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.' && byte != ':') if(exp && (byte == '+' || byte == '-')){}
else if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.' && byte != ':')
{ {
advance = 0; advance = 0;
token_formed = 1; token_formed = 1;
} }
else
{
exp = 0;
exp = (byte == 'e');
}
}break; }break;
case E_TokenKind_StringLiteral: case E_TokenKind_StringLiteral:
{ {
@@ -1357,7 +1364,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try members //- rjf: try members
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("member"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("member"), 0))) ProfScope("try to map name as member")
{ {
U64 data_member_num = e_num_from_string(e_parse_ctx->member_map, token_string); U64 data_member_num = e_num_from_string(e_parse_ctx->member_map, token_string);
if(data_member_num != 0) if(data_member_num != 0)
@@ -1368,7 +1375,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try locals //- rjf: try locals
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("local"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("local"), 0))) ProfScope("try to map name as local")
{ {
E_Module *module = e_parse_ctx->primary_module; E_Module *module = e_parse_ctx->primary_module;
RDI_Parsed *rdi = module->rdi; RDI_Parsed *rdi = module->rdi;
@@ -1432,7 +1439,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try registers //- rjf: try registers
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) ProfScope("try to map name as register")
{ {
U64 reg_num = e_num_from_string(e_parse_ctx->regs_map, token_string); U64 reg_num = e_num_from_string(e_parse_ctx->regs_map, token_string);
if(reg_num != 0) if(reg_num != 0)
@@ -1446,7 +1453,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try register aliases //- rjf: try register aliases
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) ProfScope("try to map name as register alias")
{ {
U64 alias_num = e_num_from_string(e_parse_ctx->reg_alias_map, token_string); U64 alias_num = e_num_from_string(e_parse_ctx->reg_alias_map, token_string);
if(alias_num != 0) if(alias_num != 0)
@@ -1460,7 +1467,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try global variables //- rjf: try global variables
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("global"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("global"), 0))) ProfScope("try to map name as global variable")
{ {
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1) for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
{ {
@@ -1504,7 +1511,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try thread variables //- rjf: try thread variables
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("thread_variable"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("thread_variable"), 0))) ProfScope("try to map name as thread variable")
{ {
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1) for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
{ {
@@ -1544,7 +1551,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try procedures //- rjf: try procedures
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("procedure"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("procedure"), 0))) ProfScope("try to map name as procedure")
{ {
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1) for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
{ {
@@ -1586,7 +1593,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: try types //- rjf: try types
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("type"), 0))) if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("type"), 0))) ProfScope("try to map name as type")
{ {
type_key = e_leaf_type_from_name(token_string); type_key = e_leaf_type_from_name(token_string);
if(!e_type_key_match(e_type_key_zero(), type_key)) if(!e_type_key_match(e_type_key_zero(), type_key))
@@ -1615,7 +1622,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
} }
//- rjf: attach on map //- rjf: attach on map
if(mapped_identifier != 0) if(mapped_identifier != 0) ProfScope("attach on map")
{ {
it += 1; it += 1;
@@ -2106,7 +2113,9 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
internal E_Parse internal E_Parse
e_parse_expr_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) e_parse_expr_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens)
{ {
ProfBegin("parse '%.*s'", str8_varg(text));
E_Parse parse = e_parse_expr_from_text_tokens__prec(arena, text, tokens, e_max_precedence); E_Parse parse = e_parse_expr_from_text_tokens__prec(arena, text, tokens, e_max_precedence);
ProfEnd();
return parse; return parse;
} }
+42 -17
View File
@@ -403,6 +403,8 @@ e_type_key_cons_(E_ConsTypeParams *params)
{ {
node->params.members[idx].name = push_str8_copy(e_type_state->arena, node->params.members[idx].name); node->params.members[idx].name = push_str8_copy(e_type_state->arena, node->params.members[idx].name);
node->params.members[idx].inheritance_key_chain = e_type_key_list_copy(e_type_state->arena, &node->params.members[idx].inheritance_key_chain); node->params.members[idx].inheritance_key_chain = e_type_key_list_copy(e_type_state->arena, &node->params.members[idx].inheritance_key_chain);
U64 opl_off = (node->params.members[idx].off + e_type_byte_size_from_key(node->params.members[idx].type_key));
node->byte_size = Max(node->byte_size, opl_off);
} }
} }
else if(params->enum_vals != 0) else if(params->enum_vals != 0)
@@ -413,6 +415,23 @@ e_type_key_cons_(E_ConsTypeParams *params)
{ {
node->params.enum_vals[idx].name = push_str8_copy(e_type_state->arena, node->params.enum_vals[idx].name); node->params.enum_vals[idx].name = push_str8_copy(e_type_state->arena, node->params.enum_vals[idx].name);
} }
node->byte_size = e_type_byte_size_from_key(node->params.direct_key);
}
else switch(params->kind)
{
default:
{
node->byte_size = e_type_byte_size_from_key(node->params.direct_key);
}break;
case E_TypeKind_Ptr:
{
node->byte_size = bit_size_from_arch(node->params.arch)/8;
}break;
case E_TypeKind_Array:
{
U64 ptee_size = e_type_byte_size_from_key(node->params.direct_key);
node->byte_size = ptee_size * node->params.count;
}break;
} }
result = key; result = key;
} }
@@ -604,21 +623,9 @@ e_type_from_key(Arena *arena, E_TypeKey key)
type->name = push_str8_copy(arena, node->params.name); type->name = push_str8_copy(arena, node->params.name);
type->direct_type_key = node->params.direct_key; type->direct_type_key = node->params.direct_key;
type->count = node->params.count; type->count = node->params.count;
type->byte_size = node->byte_size;
switch(type->kind) switch(type->kind)
{ {
default:
{
type->byte_size = e_type_byte_size_from_key(type->direct_type_key);
}break;
case E_TypeKind_Ptr:
{
type->byte_size = bit_size_from_arch(node->params.arch)/8;
}break;
case E_TypeKind_Array:
{
U64 ptee_size = e_type_byte_size_from_key(node->params.direct_key);
type->byte_size = ptee_size * type->count;
}break;
case E_TypeKind_Struct: case E_TypeKind_Struct:
case E_TypeKind_Union: case E_TypeKind_Union:
case E_TypeKind_Class: case E_TypeKind_Class:
@@ -1123,6 +1130,7 @@ e_type_from_key(Arena *arena, E_TypeKey key)
internal U64 internal U64
e_type_byte_size_from_key(E_TypeKey key) e_type_byte_size_from_key(E_TypeKey key)
{ {
ProfBeginFunction();
U64 result = 0; U64 result = 0;
switch(key.kind) switch(key.kind)
{ {
@@ -1133,14 +1141,31 @@ e_type_byte_size_from_key(E_TypeKey key)
result = e_kind_basic_byte_size_table[kind]; result = e_kind_basic_byte_size_table[kind];
}break; }break;
case E_TypeKeyKind_Ext: case E_TypeKeyKind_Ext:
{
U64 type_node_idx = key.u32[1];
U32 rdi_idx = key.u32[2];
RDI_Parsed *rdi = e_type_state->ctx->modules[rdi_idx].rdi;
RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx);
result = rdi_type->byte_size;
}break;
case E_TypeKeyKind_Cons: case E_TypeKeyKind_Cons:
{ {
Temp scratch = scratch_begin(0, 0); U64 key_hash = e_hash_from_string(5381, str8_struct(&key));
E_Type *type = e_type_from_key(scratch.arena, key); U64 key_slot_idx = key_hash%e_type_state->cons_key_slots_count;
result = type->byte_size; E_ConsTypeSlot *key_slot = &e_type_state->cons_key_slots[key_slot_idx];
scratch_end(scratch); for(E_ConsTypeNode *node = key_slot->first;
node != 0;
node = node->key_next)
{
if(e_type_key_match(node->key, key))
{
result = node->byte_size;
break;
}
}
}break; }break;
} }
ProfEnd();
return result; return result;
} }
+1
View File
@@ -162,6 +162,7 @@ struct E_ConsTypeNode
E_ConsTypeNode *content_next; E_ConsTypeNode *content_next;
E_TypeKey key; E_TypeKey key;
E_ConsTypeParams params; E_ConsTypeParams params;
U64 byte_size;
}; };
typedef struct E_ConsTypeSlot E_ConsTypeSlot; typedef struct E_ConsTypeSlot E_ConsTypeSlot;
+4 -2
View File
@@ -14,7 +14,7 @@ str8_lit_comp("CharLiteral"),
str8_lit_comp("Symbol"), str8_lit_comp("Symbol"),
}; };
String8 e_expr_kind_strings[47] = String8 e_expr_kind_strings[48] =
{ {
str8_lit_comp("Nil"), str8_lit_comp("Nil"),
str8_lit_comp("Ref"), str8_lit_comp("Ref"),
@@ -26,6 +26,7 @@ str8_lit_comp("Cast"),
str8_lit_comp("Sizeof"), str8_lit_comp("Sizeof"),
str8_lit_comp("Typeof"), str8_lit_comp("Typeof"),
str8_lit_comp("ByteSwap"), str8_lit_comp("ByteSwap"),
str8_lit_comp("Pos"),
str8_lit_comp("Neg"), str8_lit_comp("Neg"),
str8_lit_comp("LogNot"), str8_lit_comp("LogNot"),
str8_lit_comp("BitNot"), str8_lit_comp("BitNot"),
@@ -80,7 +81,7 @@ str8_lit_comp("Insufficient evaluation machine stack space."),
str8_lit_comp("Malformed bytecode."), str8_lit_comp("Malformed bytecode."),
}; };
E_OpInfo e_expr_kind_op_info_table[47] = E_OpInfo e_expr_kind_op_info_table[48] =
{ {
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
@@ -92,6 +93,7 @@ E_OpInfo e_expr_kind_op_info_table[47] =
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("sizeof"), str8_lit_comp("("), str8_lit_comp(")") }, { E_OpKind_UnaryPrefix, 1, str8_lit_comp("sizeof"), str8_lit_comp("("), str8_lit_comp(")") },
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("typeof"), str8_lit_comp("("), str8_lit_comp(")") }, { E_OpKind_UnaryPrefix, 1, str8_lit_comp("typeof"), str8_lit_comp("("), str8_lit_comp(")") },
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("bswap"), str8_lit_comp("("), str8_lit_comp(")") }, { E_OpKind_UnaryPrefix, 1, str8_lit_comp("bswap"), str8_lit_comp("("), str8_lit_comp(")") },
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp("") },
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 2, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp("") },
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("!"), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 2, str8_lit_comp("!"), str8_lit_comp(""), str8_lit_comp("") },
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("~"), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 2, str8_lit_comp("~"), str8_lit_comp(""), str8_lit_comp("") },
+3 -2
View File
@@ -101,6 +101,7 @@ E_ExprKind_Cast,
E_ExprKind_Sizeof, E_ExprKind_Sizeof,
E_ExprKind_Typeof, E_ExprKind_Typeof,
E_ExprKind_ByteSwap, E_ExprKind_ByteSwap,
E_ExprKind_Pos,
E_ExprKind_Neg, E_ExprKind_Neg,
E_ExprKind_LogNot, E_ExprKind_LogNot,
E_ExprKind_BitNot, E_ExprKind_BitNot,
@@ -159,9 +160,9 @@ E_InterpretationCode_COUNT,
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
extern String8 e_token_kind_strings[6]; extern String8 e_token_kind_strings[6];
extern String8 e_expr_kind_strings[47]; extern String8 e_expr_kind_strings[48];
extern String8 e_interpretation_code_display_strings[11]; extern String8 e_interpretation_code_display_strings[11];
extern E_OpInfo e_expr_kind_op_info_table[47]; extern E_OpInfo e_expr_kind_op_info_table[48];
extern U8 e_kind_basic_byte_size_table[56]; extern U8 e_kind_basic_byte_size_table[56];
extern String8 e_kind_basic_string_table[56]; extern String8 e_kind_basic_string_table[56];
@@ -39,6 +39,12 @@ EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity)
//////////////////////////////// ////////////////////////////////
//~ rjf: Key Functions //~ rjf: Key Functions
#if !defined(XXH_IMPLEMENTATION)
# define XXH_IMPLEMENTATION
# define XXH_STATIC_LINKING_ONLY
# include "linker/third_party_ext/xxHash/xxhash.h"
#endif
internal EV_Key internal EV_Key
ev_key_make(U64 parent_hash, U64 child_id) ev_key_make(U64 parent_hash, U64 child_id)
{ {
@@ -74,11 +80,7 @@ ev_key_match(EV_Key a, EV_Key b)
internal U64 internal U64
ev_hash_from_seed_string(U64 seed, String8 string) ev_hash_from_seed_string(U64 seed, String8 string)
{ {
U64 result = seed; U64 result = XXH3_64bits_withSeed(string.str, string.size, seed);
for(U64 i = 0; i < string.size; i += 1)
{
result = ((result << 5) + result) + string.str[i];
}
return result; return result;
} }
@@ -819,7 +821,7 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str
} }
// rjf: gather children expansions from inverse of expansion state // rjf: gather children expansions from inverse of expansion state
if(!child_count && (expand_info.rows_default_expanded || expand_node == 0 && !expand_info.rows_default_expanded)) if(!child_count && (expand_info.rows_default_expanded || (expand_node == 0 && !expand_info.rows_default_expanded)))
{ {
child_count = expand_info.row_count; child_count = expand_info.row_count;
child_keys = push_array(scratch.arena, EV_Key, child_count); child_keys = push_array(scratch.arena, EV_Key, child_count);
@@ -1533,12 +1535,15 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
case E_TypeKind_UChar16: case E_TypeKind_UChar16:
case E_TypeKind_UChar32: case E_TypeKind_UChar32:
{ {
B32 type_is_unsigned = (E_TypeKind_UChar8 <= type_kind && type_kind <= E_TypeKind_UChar32);
String8 char_str = ev_string_from_ascii_value(arena, eval.value.s64); String8 char_str = ev_string_from_ascii_value(arena, eval.value.s64);
if(char_str.size != 0) if(char_str.size != 0)
{ {
if(flags & EV_StringFlag_ReadOnlyDisplayRules) if(flags & EV_StringFlag_ReadOnlyDisplayRules)
{ {
String8 imm_string = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator); String8 imm_string = (type_is_unsigned
? str8_from_u64(arena, eval.value.u64, radix, min_digits, digit_group_separator)
: str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator));
result = push_str8f(arena, "'%S' (%S)", char_str, imm_string); result = push_str8f(arena, "'%S' (%S)", char_str, imm_string);
} }
else else
@@ -1548,7 +1553,9 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
} }
else else
{ {
result = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator); result = (type_is_unsigned
? str8_from_u64(arena, eval.value.u64, radix, min_digits, digit_group_separator)
: str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator));
} }
}break; }break;
+114 -140
View File
@@ -53,12 +53,6 @@ fs_init(void)
fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size); fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size);
fs_shared->u2s_ring_cv = os_condition_variable_alloc(); fs_shared->u2s_ring_cv = os_condition_variable_alloc();
fs_shared->u2s_ring_mutex = os_mutex_alloc(); fs_shared->u2s_ring_mutex = os_mutex_alloc();
fs_shared->streamer_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
fs_shared->streamers = push_array(arena, OS_Handle, 1);
for(U64 idx = 0; idx < fs_shared->streamer_count; idx += 1)
{
fs_shared->streamers[idx] = os_thread_launch(fs_streamer_thread__entry_point, (void *)idx, 0);
}
fs_shared->detector_thread = os_thread_launch(fs_detector_thread__entry_point, 0, 0); fs_shared->detector_thread = os_thread_launch(fs_detector_thread__entry_point, 0, 0);
} }
@@ -106,7 +100,7 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx]; FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
// rjf: loop: request, check for results, return until we can't // rjf: loop: request, check for results, return until we can't
OS_MutexScopeR(path_stripe->rw_mutex) for(;;) OS_MutexScopeW(path_stripe->rw_mutex) for(;;)
{ {
// rjf: path -> node // rjf: path -> node
FS_Node *node = 0; FS_Node *node = 0;
@@ -119,25 +113,14 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
} }
} }
// rjf: node does not exist? -> create & store (we must re-search after promoting r -> w) // rjf: node does not exist? -> create & store
if(node == 0) OS_MutexScopeRWPromote(path_stripe->rw_mutex) if(node == 0)
{ {
for(FS_Node *n = path_slot->first; n != 0; n = n->next) node = push_array(path_stripe->arena, FS_Node, 1);
{ SLLQueuePush(path_slot->first, path_slot->last, node);
if(str8_match(path, n->path, 0)) node->path = push_str8_copy(path_stripe->arena, path);
{ node->slots_count = 64;
node = n; node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
break;
}
}
if(node == 0)
{
node = push_array(path_stripe->arena, FS_Node, 1);
SLLQueuePush(path_slot->first, path_slot->last, node);
node->path = push_str8_copy(path_stripe->arena, path);
node->slots_count = 64;
node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
}
} }
// rjf: range -> node // rjf: range -> node
@@ -154,30 +137,25 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
} }
} }
// rjf: range node does not exist? create & store (we must re-search after promoting r -> w) // rjf: range node does not exist? create & store
if(range_node == 0) OS_MutexScopeRWPromote(path_stripe->rw_mutex) if(range_node == 0)
{ {
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next) range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
{ SLLQueuePush(range_slot->first, range_slot->last, range_node);
if(MemoryMatchStruct(&n->range, &range)) range_node->range = range;
{
range_node = n;
break;
}
}
if(range_node == 0)
{
range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
SLLQueuePush(range_slot->first, range_slot->last, range_node);
range_node->range = range;
}
} }
// rjf: try to send stream request // rjf: try to send stream request
if(!ins_atomic_u32_eval_cond_assign(&range_node->is_working, 1, 0) && if((ins_atomic_u64_eval(&range_node->request_count) == ins_atomic_u64_eval(&range_node->completion_count) ||
!fs_u2s_enqueue_req(range, path, endt_us)) ins_atomic_u64_eval(&range_node->last_time_requested_us)+100000 < os_now_microseconds()) &&
fs_u2s_enqueue_req(range, path, endt_us))
{ {
ins_atomic_u32_eval_assign(&range_node->is_working, 0); ins_atomic_u64_eval_assign(&range_node->last_time_requested_us, os_now_microseconds());
ins_atomic_u64_inc_eval(&range_node->request_count);
DeferLoop(os_rw_mutex_drop_w(path_stripe->rw_mutex), os_rw_mutex_take_w(path_stripe->rw_mutex))
{
async_push_work(fs_stream_work, .completion_counter = &range_node->completion_count);
}
} }
// rjf: try to reobtain results // rjf: try to reobtain results
@@ -186,7 +164,7 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
// rjf: have time to wait? -> wait on this stripe; otherwise exit // rjf: have time to wait? -> wait on this stripe; otherwise exit
if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us) if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us)
{ {
os_condition_variable_wait_rw_r(path_stripe->cv, path_stripe->rw_mutex, endt_us); os_condition_variable_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us);
} }
else else
{ {
@@ -275,15 +253,14 @@ fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us)
{ {
U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos; U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos;
U64 available_size = fs_shared->u2s_ring_size - unconsumed_size; U64 available_size = fs_shared->u2s_ring_size - unconsumed_size;
if(available_size >= sizeof(U64) + path.size) U64 needed_size = sizeof(range.min) + sizeof(range.max) + sizeof(path.size) + path.size;
if(available_size >= needed_size)
{ {
result = 1; result = 1;
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.min); fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.min);
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.max); fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.max);
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size); fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size);
fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size); fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size);
fs_shared->u2s_ring_write_pos += 7;
fs_shared->u2s_ring_write_pos -= fs_shared->u2s_ring_write_pos%8;
break; break;
} }
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us); os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us);
@@ -308,8 +285,6 @@ fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out)
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path_out->size); fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path_out->size);
path_out->str = push_array(arena, U8, path_out->size); path_out->str = push_array(arena, U8, path_out->size);
fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path_out->str, path_out->size); fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path_out->str, path_out->size);
fs_shared->u2s_ring_read_pos += 7;
fs_shared->u2s_ring_read_pos -= fs_shared->u2s_ring_read_pos%8;
break; break;
} }
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64); os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64);
@@ -317,108 +292,105 @@ fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out)
os_condition_variable_broadcast(fs_shared->u2s_ring_cv); os_condition_variable_broadcast(fs_shared->u2s_ring_cv);
} }
internal void ASYNC_WORK_DEF(fs_stream_work)
fs_streamer_thread__entry_point(void *p)
{ {
ThreadNameF("[fs] streamer #%I64u", (U64)p); ProfBeginFunction();
for(;;) Temp scratch = scratch_begin(0, 0);
//- rjf: get next request
Rng1U64 range = {0};
String8 path = {0};
fs_u2s_dequeue_req(scratch.arena, &range, &path);
//- rjf: unpack request
U128 key = fs_big_hash_from_string_range(path, range);
U64 path_hash = fs_little_hash_from_string(path);
U64 path_slot_idx = path_hash%fs_shared->slots_count;
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
//- rjf: load
ProfBegin("load \"%.*s\"", str8_varg(path));
FileProperties pre_props = os_properties_from_file_path(path);
U64 range_size = dim_1u64(range);
U64 read_size = Min(pre_props.size, range_size);
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path);
U64 data_arena_size = read_size+ARENA_HEADER_SIZE;
data_arena_size += KB(4)-1;
data_arena_size -= data_arena_size%KB(4);
ProfBegin("allocate");
Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size);
ProfEnd();
ProfBegin("read");
String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size));
ProfEnd();
os_file_close(file);
FileProperties post_props = os_properties_from_file_path(path);
//- rjf: abort if modification timestamps differ - we did not successfully read the file
if(pre_props.modified != post_props.modified)
{ {
Temp scratch = scratch_begin(0, 0); ProfScope("abort")
//- rjf: get next request
Rng1U64 range = {0};
String8 path = {0};
fs_u2s_dequeue_req(scratch.arena, &range, &path);
//- rjf: unpack request
U128 key = fs_big_hash_from_string_range(path, range);
U64 path_hash = fs_little_hash_from_string(path);
U64 path_slot_idx = path_hash%fs_shared->slots_count;
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
//- rjf: load
ProfBegin("load \"%.*s\"", str8_varg(path));
FileProperties pre_props = os_properties_from_file_path(path);
U64 range_size = dim_1u64(range);
U64 read_size = Min(pre_props.size, range_size);
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path);
U64 data_arena_size = read_size+ARENA_HEADER_SIZE;
data_arena_size += KB(4)-1;
data_arena_size -= data_arena_size%KB(4);
ProfBegin("allocate");
Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size);
ProfEnd();
ProfBegin("read");
String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size));
ProfEnd();
os_file_close(file);
FileProperties post_props = os_properties_from_file_path(path);
//- rjf: abort if modification timestamps differ - we did not successfully read the file
if(pre_props.modified != post_props.modified)
{ {
ProfScope("abort") arena_release(data_arena);
MemoryZeroStruct(&data);
data_arena = 0;
}
}
//- rjf: submit
else
{
ProfScope("submit")
{
hs_submit_data(key, &data_arena, data);
}
}
//- rjf: commit info to cache
ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex)
{
FS_Node *node = 0;
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
{
if(str8_match(n->path, path, 0))
{ {
arena_release(data_arena); node = n;
MemoryZeroStruct(&data); break;
data_arena = 0;
} }
} }
if(node != 0)
//- rjf: submit
else
{ {
ProfScope("submit") if(node->timestamp != 0)
{ {
hs_submit_data(key, &data_arena, data); ins_atomic_u64_inc_eval(&fs_shared->change_gen);
} }
} if(post_props.modified == pre_props.modified)
//- rjf: commit info to cache
ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex)
{
FS_Node *node = 0;
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
{ {
if(str8_match(n->path, path, 0)) node->timestamp = post_props.modified;
node->size = post_props.size;
}
U64 range_hash = fs_little_hash_from_string(str8_struct(&range));
U64 range_slot_idx = range_hash%node->slots_count;
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
FS_RangeNode *range_node = 0;
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
{
if(MemoryMatchStruct(&n->range, &range))
{ {
node = n; range_node = n;
break; break;
} }
} }
if(node != 0)
{
if(node->timestamp != 0)
{
ins_atomic_u64_inc_eval(&fs_shared->change_gen);
}
if(post_props.modified == pre_props.modified)
{
node->timestamp = post_props.modified;
node->size = post_props.size;
}
U64 range_hash = fs_little_hash_from_string(str8_struct(&range));
U64 range_slot_idx = range_hash%node->slots_count;
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
FS_RangeNode *range_node = 0;
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
{
if(MemoryMatchStruct(&n->range, &range))
{
range_node = n;
break;
}
}
ins_atomic_u32_eval_assign(&range_node->is_working, 0);
}
} }
os_condition_variable_broadcast(path_stripe->cv);
ProfEnd();
scratch_end(scratch);
} }
os_condition_variable_broadcast(path_stripe->cv);
ProfEnd();
scratch_end(scratch);
ProfEnd();
return 0;
} }
//////////////////////////////// ////////////////////////////////
@@ -427,7 +399,7 @@ fs_streamer_thread__entry_point(void *p)
internal void internal void
fs_detector_thread__entry_point(void *p) fs_detector_thread__entry_point(void *p)
{ {
ThreadNameF("[fs] detector"); ThreadNameF("[fs] detector thread");
for(;;) for(;;)
{ {
U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count; U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count;
@@ -449,10 +421,12 @@ fs_detector_thread__entry_point(void *p)
range_n != 0; range_n != 0;
range_n = range_n->next) range_n = range_n->next)
{ {
if(!ins_atomic_u32_eval_cond_assign(&range_n->is_working, 1, 0) && if(ins_atomic_u64_eval(&range_n->request_count) == ins_atomic_u64_eval(&range_n->completion_count) &&
!fs_u2s_enqueue_req(range_n->range, n->path, os_now_microseconds()+100000)) fs_u2s_enqueue_req(range_n->range, n->path, os_now_microseconds()+100000))
{ {
ins_atomic_u32_eval_assign(&range_n->is_working, 0); ins_atomic_u64_eval_assign(&range_n->last_time_requested_us, os_now_microseconds());
ins_atomic_u64_inc_eval(&range_n->request_count);
async_push_work(fs_stream_work, .completion_counter = &range_n->completion_count);
} }
} }
} }
+5 -8
View File
@@ -12,7 +12,9 @@ struct FS_RangeNode
{ {
FS_RangeNode *next; FS_RangeNode *next;
Rng1U64 range; Rng1U64 range;
B32 is_working; U64 request_count;
U64 completion_count;
U64 last_time_requested_us;
}; };
typedef struct FS_RangeSlot FS_RangeSlot; typedef struct FS_RangeSlot FS_RangeSlot;
@@ -75,10 +77,6 @@ struct FS_Shared
OS_Handle u2s_ring_cv; OS_Handle u2s_ring_cv;
OS_Handle u2s_ring_mutex; OS_Handle u2s_ring_mutex;
// rjf: streamer threads
U64 streamer_count;
OS_Handle *streamers;
// rjf: change detector threads // rjf: change detector threads
OS_Handle detector_thread; OS_Handle detector_thread;
}; };
@@ -114,12 +112,11 @@ internal U64 fs_timestamp_from_path(String8 path);
internal U64 fs_size_from_path(String8 path); internal U64 fs_size_from_path(String8 path);
//////////////////////////////// ////////////////////////////////
//~ rjf: Streamer Threads //~ rjf: Streaming Work
internal B32 fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us); internal B32 fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us);
internal void fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out); internal void fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out);
ASYNC_WORK_DEF(fs_stream_work);
internal void fs_streamer_thread__entry_point(void *p);
//////////////////////////////// ////////////////////////////////
//~ rjf: Change Detector Thread //~ rjf: Change Detector Thread
+31 -28
View File
@@ -4,28 +4,29 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Functions //~ rjf: Basic Functions
#if !defined(BLAKE2_H) #if !defined(XXH_IMPLEMENTATION)
#define HAVE_SSE2 # define XXH_IMPLEMENTATION
#include "third_party/blake2/blake2.h" # define XXH_STATIC_LINKING_ONLY
#include "third_party/blake2/blake2b.c" # include "linker/third_party_ext/xxHash/xxhash.h"
#endif #endif
internal U128 internal U128
fnt_hash_from_string(String8 string) fnt_hash_from_string(String8 string)
{ {
U128 result = {0}; union
blake2b((U8 *)&result.u64[0], sizeof(result), string.str, string.size, 0, 0); {
return result; XXH128_hash_t xxhash;
U128 u128;
}
hash;
hash.xxhash = XXH3_128bits(string.str, string.size);
return hash.u128;
} }
internal U64 internal U64
fnt_little_hash_from_string(String8 string) fnt_little_hash_from_string(String8 string)
{ {
U64 result = 5381; U64 result = XXH3_64bits(string.str, string.size);
for(U64 i = 0; i < string.size; i += 1)
{
result = ((result << 5) + result) + string.str[i];
}
return result; return result;
} }
@@ -575,46 +576,48 @@ fnt_push_run_from_string(Arena *arena, FNT_Tag tag, F32 size, F32 base_align_px,
FNT_Hash2StyleRasterCacheNode *hash2style_node = fnt_hash2style_from_tag_size_flags(tag, size, flags); FNT_Hash2StyleRasterCacheNode *hash2style_node = fnt_hash2style_from_tag_size_flags(tag, size, flags);
//- rjf: decode string & produce run pieces //- rjf: decode string & produce run pieces
B32 first = 1;
FNT_PieceChunkList piece_chunks = {0}; FNT_PieceChunkList piece_chunks = {0};
Vec2F32 dim = {0}; Vec2F32 dim = {0};
B32 font_handle_mapped_on_miss = 0; B32 font_handle_mapped_on_miss = 0;
FP_Handle font_handle = {0}; FP_Handle font_handle = {0};
U64 piece_substring_start_idx = 0; U64 piece_substring_start_idx = 0;
for(U64 idx = 0; idx < string.size; first = 0) U64 piece_substring_end_idx = 0;
for(U64 idx = 0; idx <= string.size;)
{ {
//- rjf: decode next codepoint & get piece substring, or continuation rule //- rjf: decode next codepoint & get piece substring, or continuation rule
String8 piece_substring; U8 byte = (idx < string.size ? string.str[idx] : 0);
B32 need_another_codepoint = 0; B32 need_another_codepoint = 0;
switch(utf8_class[string.str[idx]>>3]) if(byte == 0)
{
idx += 1;
}
else switch(utf8_class[byte>>3])
{ {
case 1: case 1:
{ {
piece_substring.str = &string.str[idx];
piece_substring.size = 1;
idx += 1; idx += 1;
piece_substring_end_idx += 1;
need_another_codepoint = 0;
}break; }break;
default: default:
{ {
UnicodeDecode decode = utf8_decode(string.str+idx, string.size-idx); UnicodeDecode decode = utf8_decode(string.str+idx, string.size-idx);
idx += decode.inc; idx += decode.inc;
if(decode.inc == 0) { break; } piece_substring_end_idx += decode.inc;
piece_substring.str = string.str + piece_substring_start_idx; need_another_codepoint = 0;
piece_substring.size = decode.inc;
// NOTE(rjf): assuming 1 codepoint per piece for now.
}break; }break;
} }
//- rjf: need another codepoint? -> continue //- rjf: need another codepoint, or have no substring? -> continue
if(need_another_codepoint) if(need_another_codepoint || piece_substring_end_idx == piece_substring_start_idx)
{ {
continue; continue;
} }
//- rjf: do not need another codepoint? -> bump piece start idx //- rjf: do not need another codepoint? -> grab substring, bump piece start idx
{ String8 piece_substring = str8_substr(string, r1u64(piece_substring_start_idx, piece_substring_end_idx));
piece_substring_start_idx = idx; piece_substring_start_idx = idx;
} piece_substring_end_idx = idx;
//- rjf: determine if this piece is a tab - if so, use space info to draw //- rjf: determine if this piece is a tab - if so, use space info to draw
B32 is_tab = (piece_substring.size == 1 && piece_substring.str[0] == '\t'); B32 is_tab = (piece_substring.size == 1 && piece_substring.str[0] == '\t');
-547
View File
@@ -1,547 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Helpers
internal U64
fzy_hash_from_string(U64 seed, String8 string)
{
U64 result = seed;
for(U64 i = 0; i < string.size; i += 1)
{
result = ((result << 5) + result) + string.str[i];
}
return result;
}
internal U64
fzy_hash_from_params(FZY_Params *params)
{
U64 hash = 5381;
hash = fzy_hash_from_string(hash, str8_struct(&params->target));
for(U64 idx = 0; idx < params->dbgi_keys.count; idx += 1)
{
hash = fzy_hash_from_string(hash, str8_struct(&params->dbgi_keys.v[idx].min_timestamp));
hash = fzy_hash_from_string(hash, params->dbgi_keys.v[idx].path);
}
return hash;
}
internal U64
fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx)
{
U64 fuzzy_item_num = 0;
for(U64 idx = 0; idx < array->count; idx += 1)
{
if(array->v[idx].idx == element_idx)
{
fuzzy_item_num = idx+1;
break;
}
}
return fuzzy_item_num;
}
internal String8
fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx)
{
String8 result = {0};
switch(target)
{
default:{}break;
case RDI_SectionKind_Procedures:
{
RDI_Procedure *proc = rdi_element_from_name_idx(rdi, Procedures, element_idx);
U64 name_size = 0;
U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size);
result = str8(name_base, name_size);
}break;
case RDI_SectionKind_GlobalVariables:
{
RDI_GlobalVariable *gvar = rdi_element_from_name_idx(rdi, GlobalVariables, element_idx);
U64 name_size = 0;
U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size);
result = str8(name_base, name_size);
}break;
case RDI_SectionKind_ThreadVariables:
{
RDI_ThreadVariable *tvar = rdi_element_from_name_idx(rdi, ThreadVariables, element_idx);
U64 name_size = 0;
U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size);
result = str8(name_base, name_size);
}break;
case RDI_SectionKind_UDTs:
{
RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, element_idx);
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx);
U64 name_size = 0;
U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size);
result = str8(name_base, name_size);
}break;
}
return result;
}
internal FZY_Params
fzy_params_copy(Arena *arena, FZY_Params *src)
{
FZY_Params dst = zero_struct;
MemoryCopyStruct(&dst, src);
dst.dbgi_keys.v = push_array(arena, DI_Key, dst.dbgi_keys.count);
MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(DI_Key)*src->dbgi_keys.count);
for(U64 idx = 0; idx < dst.dbgi_keys.count; idx += 1)
{
dst.dbgi_keys.v[idx].path = push_str8_copy(arena, dst.dbgi_keys.v[idx].path);
}
return dst;
}
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void
fzy_init(void)
{
Arena *arena = arena_alloc();
fzy_shared = push_array(arena, FZY_Shared, 1);
fzy_shared->arena = arena;
fzy_shared->slots_count = 256;
fzy_shared->stripes_count = os_get_system_info()->logical_processor_count;
fzy_shared->slots = push_array(arena, FZY_Slot, fzy_shared->slots_count);
fzy_shared->stripes = push_array(arena, FZY_Stripe, fzy_shared->stripes_count);
for(U64 idx = 0; idx < fzy_shared->stripes_count; idx += 1)
{
fzy_shared->stripes[idx].arena = arena_alloc();
fzy_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
fzy_shared->stripes[idx].cv = os_condition_variable_alloc();
}
fzy_shared->thread_count = Min(os_get_system_info()->logical_processor_count, 2);
fzy_shared->threads = push_array(arena, FZY_Thread, fzy_shared->thread_count);
for(U64 idx = 0; idx < fzy_shared->thread_count; idx += 1)
{
fzy_shared->threads[idx].u2f_ring_mutex = os_mutex_alloc();
fzy_shared->threads[idx].u2f_ring_cv = os_condition_variable_alloc();
fzy_shared->threads[idx].u2f_ring_size = KB(64);
fzy_shared->threads[idx].u2f_ring_base = push_array_no_zero(arena, U8, fzy_shared->threads[idx].u2f_ring_size);
fzy_shared->threads[idx].thread = os_thread_launch(fzy_search_thread__entry_point, (void *)idx, 0);
}
}
////////////////////////////////
//~ rjf: Scope Functions
internal FZY_Scope *
fzy_scope_open(void)
{
if(fzy_tctx == 0)
{
Arena *arena = arena_alloc();
fzy_tctx = push_array(arena, FZY_TCTX, 1);
fzy_tctx->arena = arena;
}
FZY_Scope *scope = fzy_tctx->free_scope;
if(scope != 0)
{
SLLStackPop(fzy_tctx->free_scope);
}
else
{
scope = push_array_no_zero(fzy_tctx->arena, FZY_Scope, 1);
}
MemoryZeroStruct(scope);
return scope;
}
internal void
fzy_scope_close(FZY_Scope *scope)
{
for(FZY_Touch *t = scope->first_touch, *next = 0; t != 0; t = next)
{
next = t->next;
SLLStackPush(fzy_tctx->free_touch, t);
if(t->node != 0)
{
ins_atomic_u64_dec_eval(&t->node->touch_count);
}
}
SLLStackPush(fzy_tctx->free_scope, scope);
}
internal void
fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node)
{
if(node != 0)
{
ins_atomic_u64_inc_eval(&node->touch_count);
}
FZY_Touch *touch = fzy_tctx->free_touch;
if(touch != 0)
{
SLLStackPop(fzy_tctx->free_touch);
}
else
{
touch = push_array_no_zero(fzy_tctx->arena, FZY_Touch, 1);
}
MemoryZeroStruct(touch);
SLLQueuePush(scope->first_touch, scope->last_touch, touch);
touch->node = node;
}
////////////////////////////////
//~ rjf: Cache Lookup Functions
internal FZY_ItemArray
fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out)
{
Temp scratch = scratch_begin(0, 0);
FZY_ItemArray items = {0};
//- rjf: hash parameters
U64 params_hash = fzy_hash_from_params(params);
//- rjf: unpack key
U64 slot_idx = key.u64[1]%fzy_shared->slots_count;
U64 stripe_idx = slot_idx%fzy_shared->stripes_count;
FZY_Slot *slot = &fzy_shared->slots[slot_idx];
FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx];
//- rjf: query and/or request
OS_MutexScopeR(stripe->rw_mutex) for(;;)
{
// rjf: map key -> node
FZY_Node *node = 0;
for(FZY_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->key, key))
{
node = n;
break;
}
}
// rjf: no node? -> allocate
if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex)
{
node = push_array(stripe->arena, FZY_Node, 1);
SLLQueuePush(slot->first, slot->last, node);
node->key = key;
for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1)
{
node->buckets[idx].arena = arena_alloc();
}
}
// rjf: try to grab last valid results for this key/query; determine if stale
B32 stale = 1;
if(params_hash == node->buckets[node->gen%ArrayCount(node->buckets)].params_hash &&
node->gen != 0)
{
fzy_scope_touch_node__stripe_mutex_r_guarded(scope, node);
items = node->gen_items;
stale = !str8_match(query, node->buckets[node->gen%ArrayCount(node->buckets)].query, 0);
if(stale_out != 0)
{
*stale_out = stale;
}
}
// rjf: if stale -> request again
if(stale) OS_MutexScopeRWPromote(stripe->rw_mutex)
{
if(node->gen <= node->submit_gen && node->submit_gen < node->gen + ArrayCount(node->buckets)-1)
{
node->submit_gen += 1;
arena_clear(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena);
node->buckets[node->submit_gen%ArrayCount(node->buckets)].query = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, query);
node->buckets[node->submit_gen%ArrayCount(node->buckets)].params = fzy_params_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, params);
node->buckets[node->submit_gen%ArrayCount(node->buckets)].params_hash = params_hash;
}
if((node->submit_gen > node->gen+1 || os_now_microseconds() >= node->last_time_submitted_us+100000) &&
fzy_u2s_enqueue_req(key, endt_us))
{
node->last_time_submitted_us = os_now_microseconds();
}
}
// rjf: not stale, or timeout -> break
if(!stale || os_now_microseconds() >= endt_us)
{
break;
}
// rjf: no results, but have time to wait -> wait
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
}
scratch_end(scratch);
return items;
}
////////////////////////////////
//~ rjf: Searcher Threads
internal B32
fzy_u2s_enqueue_req(U128 key, U64 endt_us)
{
B32 sent = 0;
FZY_Thread *thread = &fzy_shared->threads[key.u64[1]%fzy_shared->thread_count];
OS_MutexScope(thread->u2f_ring_mutex) for(;;)
{
U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos;
U64 available_size = thread->u2f_ring_size - unconsumed_size;
if(available_size >= sizeof(U128))
{
sent = 1;
thread->u2f_ring_write_pos += ring_write_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_write_pos, &key);
break;
}
os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, endt_us);
}
if(sent)
{
os_condition_variable_broadcast(thread->u2f_ring_cv);
}
return sent;
}
internal void
fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out)
{
OS_MutexScope(thread->u2f_ring_mutex) for(;;)
{
U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos;
if(unconsumed_size >= sizeof(U128))
{
thread->u2f_ring_read_pos += ring_read_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_read_pos, key_out);
break;
}
os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, max_U64);
}
os_condition_variable_broadcast(thread->u2f_ring_cv);
}
internal int
fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b)
{
int result = 0;
if(a->match_ranges.count > b->match_ranges.count)
{
result = -1;
}
else if(a->match_ranges.count < b->match_ranges.count)
{
result = +1;
}
else if(a->missed_size < b->missed_size)
{
result = -1;
}
else if(a->missed_size > b->missed_size)
{
result = +1;
}
return result;
}
internal void
fzy_search_thread__entry_point(void *p)
{
ThreadNameF("[fzy] searcher #%I64u", (U64)p);
FZY_Thread *thread = &fzy_shared->threads[(U64)p];
for(;;)
{
Temp scratch = scratch_begin(0, 0);
DI_Scope *di_scope = di_scope_open();
////////////////////////////
//- rjf: dequeue next request
//
U128 key = {0};
fzy_u2s_dequeue_req(scratch.arena, thread, &key);
U64 slot_idx = key.u64[1]%fzy_shared->slots_count;
U64 stripe_idx = slot_idx%fzy_shared->stripes_count;
FZY_Slot *slot = &fzy_shared->slots[slot_idx];
FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx];
////////////////////////////
//- rjf: grab next exe_path/query for this key
//
B32 task_is_good = 0;
Arena *task_arena = 0;
String8 query = {0};
FZY_Params params = {RDI_SectionKind_Procedures};
U64 initial_submit_gen = 0;
OS_MutexScopeW(stripe->rw_mutex)
{
for(FZY_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->key, key))
{
FZY_Bucket *bucket = &n->buckets[n->submit_gen%ArrayCount(n->buckets)];
task_is_good = 1;
initial_submit_gen = n->submit_gen;
task_arena = bucket->arena;
query = bucket->query;
params = bucket->params;
break;
}
}
}
////////////////////////////
//- rjf: params -> look up all rdis
//
U64 rdis_count = params.dbgi_keys.count;
RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count);
if(task_is_good)
{
for(U64 idx = 0; idx < rdis_count; idx += 1)
{
rdis[idx] = di_rdi_from_key(di_scope, &params.dbgi_keys.v[idx], max_U64);
}
}
////////////////////////////
//- rjf: search target -> info about search space
//
U64 element_name_idx_off = 0;
if(task_is_good)
{
switch(params.target)
{
default:{}break;
case RDI_SectionKind_Procedures:
{
element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx);
}break;
case RDI_SectionKind_GlobalVariables:
{
element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx);
}break;
case RDI_SectionKind_ThreadVariables:
{
element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx);
}break;
case RDI_SectionKind_UDTs:
{
// NOTE(rjf): name must be determined from self_type_idx
}break;
}
}
////////////////////////////
//- rjf: rdis * query * params -> item list
//
FZY_ItemChunkList items_list = {0};
if(task_is_good)
{
U64 base_idx = 0;
for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1)
{
RDI_Parsed *rdi = rdis[rdi_idx];
U64 element_count = 0;
void *table_base = rdi_section_raw_table_from_kind(rdi, params.target, &element_count);
U64 element_size = rdi_section_element_size_table[params.target];
for(U64 idx = 1; task_is_good && idx < element_count; idx += 1)
{
void *element = (U8 *)table_base + element_size*idx;
U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off);
if(params.target == RDI_SectionKind_UDTs)
{
RDI_UDT *udt = (RDI_UDT *)element;
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx);
name_idx_ptr = &type_node->user_defined.name_string_idx;
}
U32 name_idx = *name_idx_ptr;
U64 name_size = 0;
U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size);
String8 name = str8(name_base, name_size);
if(name.size == 0) { continue; }
FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name);
if(matches.count == matches.needle_part_count)
{
FZY_ItemChunk *chunk = items_list.last;
if(chunk == 0 || chunk->count >= chunk->cap)
{
chunk = push_array(scratch.arena, FZY_ItemChunk, 1);
chunk->cap = 1024;
chunk->count = 0;
chunk->v = push_array_no_zero(scratch.arena, FZY_Item, chunk->cap);
SLLQueuePush(items_list.first, items_list.last, chunk);
items_list.chunk_count += 1;
}
chunk->v[chunk->count].idx = base_idx + idx;
chunk->v[chunk->count].match_ranges = matches;
chunk->v[chunk->count].missed_size = (name_size > matches.total_dim) ? (name_size-matches.total_dim) : 0;
chunk->count += 1;
items_list.total_count += 1;
}
if(idx%100 == 99) OS_MutexScopeR(stripe->rw_mutex)
{
for(FZY_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->key, key) && n->submit_gen > initial_submit_gen)
{
task_is_good = 0;
break;
}
}
}
}
base_idx += element_count;
}
}
//- rjf: item list -> item array
FZY_ItemArray items = {0};
if(task_is_good)
{
items.count = items_list.total_count;
items.v = push_array_no_zero(task_arena, FZY_Item, items.count);
U64 idx = 0;
for(FZY_ItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next)
{
MemoryCopy(items.v+idx, chunk->v, sizeof(FZY_Item)*chunk->count);
idx += chunk->count;
}
}
//- rjf: sort item array
if(items.count != 0 && query.size != 0)
{
quick_sort(items.v, items.count, sizeof(FZY_Item), fzy_qsort_compare_items);
}
//- rjf: commit to cache - busyloop on scope touches
if(task_is_good)
{
for(B32 done = 0; !done;)
{
B32 found = 0;
OS_MutexScopeW(stripe->rw_mutex) for(FZY_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->key, key))
{
if(n->touch_count == 0)
{
n->gen = initial_submit_gen;
n->gen_items = items;
done = 1;
}
found = 1;
break;
}
}
if(!found)
{
break;
}
}
}
di_scope_close(di_scope);
scratch_end(scratch);
}
}
-192
View File
@@ -1,192 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef FUZZY_SEARCH_H
#define FUZZY_SEARCH_H
////////////////////////////////
//~ rjf: Result Types
typedef struct FZY_Item FZY_Item;
struct FZY_Item
{
U64 idx; // indexes into whole space of parameter tables. [rdis[0] element count) [rdis[1] element count) ... [rdis[n] element count)
U64 missed_size;
FuzzyMatchRangeList match_ranges;
};
typedef struct FZY_ItemChunk FZY_ItemChunk;
struct FZY_ItemChunk
{
FZY_ItemChunk *next;
FZY_Item *v;
U64 count;
U64 cap;
};
typedef struct FZY_ItemChunkList FZY_ItemChunkList;
struct FZY_ItemChunkList
{
FZY_ItemChunk *first;
FZY_ItemChunk *last;
U64 chunk_count;
U64 total_count;
};
typedef struct FZY_ItemArray FZY_ItemArray;
struct FZY_ItemArray
{
FZY_Item *v;
U64 count;
};
////////////////////////////////
//~ rjf: Search Parameter Types
typedef struct FZY_Params FZY_Params;
struct FZY_Params
{
RDI_SectionKind target;
DI_KeyArray dbgi_keys;
};
////////////////////////////////
//~ rjf: Cache Types
typedef struct FZY_Bucket FZY_Bucket;
struct FZY_Bucket
{
Arena *arena;
String8 query;
FZY_Params params;
U64 params_hash;
};
typedef struct FZY_Node FZY_Node;
struct FZY_Node
{
FZY_Node *next;
U128 key;
U64 touch_count;
U64 last_time_submitted_us;
FZY_Bucket buckets[3];
U64 gen;
U64 submit_gen;
FZY_ItemArray gen_items;
};
typedef struct FZY_Slot FZY_Slot;
struct FZY_Slot
{
FZY_Node *first;
FZY_Node *last;
};
typedef struct FZY_Stripe FZY_Stripe;
struct FZY_Stripe
{
Arena *arena;
OS_Handle rw_mutex;
OS_Handle cv;
};
////////////////////////////////
//~ rjf: Scoped Access Types
typedef struct FZY_Touch FZY_Touch;
struct FZY_Touch
{
FZY_Touch *next;
FZY_Node *node;
};
typedef struct FZY_Scope FZY_Scope;
struct FZY_Scope
{
FZY_Scope *next;
FZY_Touch *first_touch;
FZY_Touch *last_touch;
};
typedef struct FZY_TCTX FZY_TCTX;
struct FZY_TCTX
{
Arena *arena;
FZY_Scope *free_scope;
FZY_Touch *free_touch;
};
////////////////////////////////
//~ rjf: Shared State Types
typedef struct FZY_Thread FZY_Thread;
struct FZY_Thread
{
OS_Handle thread;
OS_Handle u2f_ring_mutex;
OS_Handle u2f_ring_cv;
U64 u2f_ring_size;
U8 *u2f_ring_base;
U64 u2f_ring_write_pos;
U64 u2f_ring_read_pos;
};
typedef struct FZY_Shared FZY_Shared;
struct FZY_Shared
{
Arena *arena;
// rjf: search artifact cache table
U64 slots_count;
U64 stripes_count;
FZY_Slot *slots;
FZY_Stripe *stripes;
// rjf: threads
U64 thread_count;
FZY_Thread *threads;
};
////////////////////////////////
//~ rjf: Globals
global FZY_Shared *fzy_shared = 0;
thread_static FZY_TCTX *fzy_tctx = 0;
////////////////////////////////
//~ rjf: Helpers
internal U64 fzy_hash_from_string(U64 seed, String8 string);
internal U64 fzy_hash_from_params(FZY_Params *params);
internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx);
internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx);
internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src);
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void fzy_init(void);
////////////////////////////////
//~ rjf: Scope Functions
internal FZY_Scope *fzy_scope_open(void);
internal void fzy_scope_close(FZY_Scope *scope);
internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node);
////////////////////////////////
//~ rjf: Cache Lookup Functions
internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out);
////////////////////////////////
//~ rjf: Searcher Threads
internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us);
internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out);
internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b);
internal void fzy_search_thread__entry_point(void *p);
#endif // FUZZY_SEARCH_H
+58 -78
View File
@@ -25,12 +25,6 @@ geo_init(void)
geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size); geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size);
geo_shared->u2x_ring_cv = os_condition_variable_alloc(); geo_shared->u2x_ring_cv = os_condition_variable_alloc();
geo_shared->u2x_ring_mutex = os_mutex_alloc(); geo_shared->u2x_ring_mutex = os_mutex_alloc();
geo_shared->xfer_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
geo_shared->xfer_threads = push_array(arena, OS_Handle, geo_shared->xfer_thread_count);
for(U64 idx = 0; idx < geo_shared->xfer_thread_count; idx += 1)
{
geo_shared->xfer_threads[idx] = os_thread_launch(geo_xfer_thread__entry_point, (void *)idx, 0);
}
geo_shared->evictor_thread = os_thread_launch(geo_evictor_thread__entry_point, 0, 0); geo_shared->evictor_thread = os_thread_launch(geo_evictor_thread__entry_point, 0, 0);
} }
@@ -48,21 +42,6 @@ geo_tctx_ensure_inited(void)
} }
} }
////////////////////////////////
//~ rjf: User Clock
internal void
geo_user_clock_tick(void)
{
ins_atomic_u64_inc_eval(&geo_shared->user_clock_idx);
}
internal U64
geo_user_clock_idx(void)
{
return ins_atomic_u64_eval(&geo_shared->user_clock_idx);
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Scoped Access //~ rjf: Scoped Access
@@ -116,7 +95,7 @@ geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node)
GEO_Touch *touch = geo_tctx->free_touch; GEO_Touch *touch = geo_tctx->free_touch;
ins_atomic_u64_inc_eval(&node->scope_ref_count); 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_time_touched_us, os_now_microseconds());
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, geo_user_clock_idx()); ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx());
if(touch != 0) if(touch != 0)
{ {
SLLStackPop(geo_tctx->free_touch); SLLStackPop(geo_tctx->free_touch);
@@ -192,6 +171,7 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash)
if(node_is_new) if(node_is_new)
{ {
geo_u2x_enqueue_req(hash, max_U64); geo_u2x_enqueue_req(hash, max_U64);
async_push_work(geo_xfer_work);
} }
} }
return handle; return handle;
@@ -259,68 +239,67 @@ geo_u2x_dequeue_req(U128 *hash_out)
os_condition_variable_broadcast(geo_shared->u2x_ring_cv); os_condition_variable_broadcast(geo_shared->u2x_ring_cv);
} }
internal void ASYNC_WORK_DEF(geo_xfer_work)
geo_xfer_thread__entry_point(void *p)
{ {
for(;;) ProfBeginFunction();
HS_Scope *scope = hs_scope_open();
//- rjf: decode
U128 hash = {0};
geo_u2x_dequeue_req(&hash);
//- rjf: unpack hash
U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
U64 stripe_idx = slot_idx%geo_shared->stripes_count;
GEO_Slot *slot = &geo_shared->slots[slot_idx];
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
//- rjf: take task
B32 got_task = 0;
OS_MutexScopeR(stripe->rw_mutex)
{ {
HS_Scope *scope = hs_scope_open(); for(GEO_Node *n = slot->first; n != 0; n = n->next)
//- rjf: decode
U128 hash = {0};
geo_u2x_dequeue_req(&hash);
//- rjf: unpack hash
U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
U64 stripe_idx = slot_idx%geo_shared->stripes_count;
GEO_Slot *slot = &geo_shared->slots[slot_idx];
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
//- rjf: take task
B32 got_task = 0;
OS_MutexScopeR(stripe->rw_mutex)
{ {
for(GEO_Node *n = slot->first; n != 0; n = n->next) if(u128_match(n->hash, hash))
{ {
if(u128_match(n->hash, hash)) got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
{ break;
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
break;
}
} }
} }
//- rjf: hash -> data
String8 data = {0};
if(got_task)
{
data = hs_data_from_hash(scope, hash);
}
//- rjf: data -> buffer
R_Handle buffer = {0};
if(got_task && data.size != 0)
{
buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str);
}
//- rjf: commit results to cache
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
{
for(GEO_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash))
{
n->buffer = buffer;
ins_atomic_u32_eval_assign(&n->is_working, 0);
ins_atomic_u64_inc_eval(&n->load_count);
break;
}
}
}
hs_scope_close(scope);
} }
//- rjf: hash -> data
String8 data = {0};
if(got_task)
{
data = hs_data_from_hash(scope, hash);
}
//- rjf: data -> buffer
R_Handle buffer = {0};
if(got_task && data.size != 0)
{
buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str);
}
//- rjf: commit results to cache
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
{
for(GEO_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash))
{
n->buffer = buffer;
ins_atomic_u32_eval_assign(&n->is_working, 0);
ins_atomic_u64_inc_eval(&n->load_count);
break;
}
}
}
hs_scope_close(scope);
ProfEnd();
return 0;
} }
//////////////////////////////// ////////////////////////////////
@@ -329,10 +308,11 @@ geo_xfer_thread__entry_point(void *p)
internal void internal void
geo_evictor_thread__entry_point(void *p) geo_evictor_thread__entry_point(void *p)
{ {
ThreadNameF("[geo] evictor thread");
for(;;) for(;;)
{ {
U64 check_time_us = os_now_microseconds(); U64 check_time_us = os_now_microseconds();
U64 check_time_user_clocks = geo_user_clock_idx(); U64 check_time_user_clocks = update_tick_idx();
U64 evict_threshold_us = 10*1000000; U64 evict_threshold_us = 10*1000000;
U64 evict_threshold_user_clocks = 10; U64 evict_threshold_user_clocks = 10;
for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1) for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1)
+1 -14
View File
@@ -72,9 +72,6 @@ struct GEO_Shared
{ {
Arena *arena; Arena *arena;
// rjf: user clock
U64 user_clock_idx;
// rjf: cache // rjf: cache
U64 slots_count; U64 slots_count;
U64 stripes_count; U64 stripes_count;
@@ -90,10 +87,6 @@ struct GEO_Shared
OS_Handle u2x_ring_cv; OS_Handle u2x_ring_cv;
OS_Handle u2x_ring_mutex; OS_Handle u2x_ring_mutex;
// rjf: transfer threads
U64 xfer_thread_count;
OS_Handle *xfer_threads;
// rjf: evictor thread // rjf: evictor thread
OS_Handle evictor_thread; OS_Handle evictor_thread;
}; };
@@ -114,12 +107,6 @@ internal void geo_init(void);
internal void geo_tctx_ensure_inited(void); internal void geo_tctx_ensure_inited(void);
////////////////////////////////
//~ rjf: User Clock
internal void geo_user_clock_tick(void);
internal U64 geo_user_clock_idx(void);
//////////////////////////////// ////////////////////////////////
//~ rjf: Scoped Access //~ rjf: Scoped Access
@@ -138,7 +125,7 @@ internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key);
internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us); internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us);
internal void geo_u2x_dequeue_req(U128 *hash_out); internal void geo_u2x_dequeue_req(U128 *hash_out);
internal void geo_xfer_thread__entry_point(void *p); ASYNC_WORK_DEF(geo_xfer_work);
//////////////////////////////// ////////////////////////////////
//~ rjf: Evictor Threads //~ rjf: Evictor Threads
+2 -4
View File
@@ -14,10 +14,7 @@ internal U128
hs_hash_from_data(String8 data) hs_hash_from_data(String8 data)
{ {
U128 u128 = {0}; U128 u128 = {0};
if(data.size != 0) blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0);
{
blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0);
}
return u128; return u128;
} }
@@ -299,6 +296,7 @@ hs_data_from_hash(HS_Scope *scope, U128 hash)
internal void internal void
hs_evictor_thread__entry_point(void *p) hs_evictor_thread__entry_point(void *p)
{ {
ThreadNameF("[hs] evictor thread");
for(;;) for(;;)
{ {
for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1) for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1)
+166
View File
@@ -589,6 +589,172 @@ X(NULL)\
X(X86)\ X(X86)\
X(X64)\ X(X64)\
#define RDI_RegCodeX86_XList \
X(nil, 0)\
X(eax, 1)\
X(ecx, 2)\
X(edx, 3)\
X(ebx, 4)\
X(esp, 5)\
X(ebp, 6)\
X(esi, 7)\
X(edi, 8)\
X(fsbase, 9)\
X(gsbase, 10)\
X(eflags, 11)\
X(eip, 12)\
X(dr0, 13)\
X(dr1, 14)\
X(dr2, 15)\
X(dr3, 16)\
X(dr4, 17)\
X(dr5, 18)\
X(dr6, 19)\
X(dr7, 20)\
X(fpr0, 21)\
X(fpr1, 22)\
X(fpr2, 23)\
X(fpr3, 24)\
X(fpr4, 25)\
X(fpr5, 26)\
X(fpr6, 27)\
X(fpr7, 28)\
X(st0, 29)\
X(st1, 30)\
X(st2, 31)\
X(st3, 32)\
X(st4, 33)\
X(st5, 34)\
X(st6, 35)\
X(st7, 36)\
X(fcw, 37)\
X(fsw, 38)\
X(ftw, 39)\
X(fop, 40)\
X(fcs, 41)\
X(fds, 42)\
X(fip, 43)\
X(fdp, 44)\
X(mxcsr, 45)\
X(mxcsr_mask, 46)\
X(ss, 47)\
X(cs, 48)\
X(ds, 49)\
X(es, 50)\
X(fs, 51)\
X(gs, 52)\
X(ymm0, 53)\
X(ymm1, 54)\
X(ymm2, 55)\
X(ymm3, 56)\
X(ymm4, 57)\
X(ymm5, 58)\
X(ymm6, 59)\
X(ymm7, 60)\
#define RDI_RegCodeX64_XList \
X(nil, 0)\
X(rax, 1)\
X(rcx, 2)\
X(rdx, 3)\
X(rbx, 4)\
X(rsp, 5)\
X(rbp, 6)\
X(rsi, 7)\
X(rdi, 8)\
X(r8, 9)\
X(r9, 10)\
X(r10, 11)\
X(r11, 12)\
X(r12, 13)\
X(r13, 14)\
X(r14, 15)\
X(r15, 16)\
X(es, 17)\
X(cs, 18)\
X(ss, 19)\
X(ds, 20)\
X(fs, 21)\
X(gs, 22)\
X(rip, 23)\
X(rflags, 24)\
X(dr0, 25)\
X(dr1, 26)\
X(dr2, 27)\
X(dr3, 28)\
X(dr4, 29)\
X(dr5, 30)\
X(dr6, 31)\
X(dr7, 32)\
X(st0, 33)\
X(st1, 34)\
X(st2, 35)\
X(st3, 36)\
X(st4, 37)\
X(st5, 38)\
X(st6, 39)\
X(st7, 40)\
X(fpr0, 41)\
X(fpr1, 42)\
X(fpr2, 43)\
X(fpr3, 44)\
X(fpr4, 45)\
X(fpr5, 46)\
X(fpr6, 47)\
X(fpr7, 48)\
X(zmm0, 49)\
X(zmm1, 50)\
X(zmm2, 51)\
X(zmm3, 52)\
X(zmm4, 53)\
X(zmm5, 54)\
X(zmm6, 55)\
X(zmm7, 56)\
X(zmm8, 57)\
X(zmm9, 58)\
X(zmm10, 59)\
X(zmm11, 60)\
X(zmm12, 61)\
X(zmm13, 62)\
X(zmm14, 63)\
X(zmm15, 64)\
X(zmm16, 65)\
X(zmm17, 66)\
X(zmm18, 67)\
X(zmm19, 68)\
X(zmm20, 69)\
X(zmm21, 70)\
X(zmm22, 71)\
X(zmm23, 72)\
X(zmm24, 73)\
X(zmm25, 74)\
X(zmm26, 75)\
X(zmm27, 76)\
X(zmm28, 77)\
X(zmm29, 78)\
X(zmm30, 79)\
X(zmm31, 80)\
X(k0, 81)\
X(k1, 82)\
X(k2, 83)\
X(k3, 84)\
X(k4, 85)\
X(k5, 86)\
X(k6, 87)\
X(k7, 88)\
X(mxcsr, 89)\
X(fsbase, 90)\
X(gsbase, 91)\
X(fcw, 92)\
X(fsw, 93)\
X(ftw, 94)\
X(fop, 95)\
X(fcs, 96)\
X(fds, 97)\
X(fip, 98)\
X(fdp, 99)\
X(mxcsr_mask, 100)\
#define RDI_TopLevelInfo_XList \ #define RDI_TopLevelInfo_XList \
X(RDI_Arch, arch)\ X(RDI_Arch, arch)\
X(RDI_U32, exe_name_string_idx)\ X(RDI_U32, exe_name_string_idx)\
+2 -2
View File
@@ -303,9 +303,9 @@ rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff)
{ {
RDI_U64 count = 0; RDI_U64 count = 0;
RDI_U64 result = rdi_line_info_idx_range_from_voff(line_info, voff, &count); RDI_U64 result = rdi_line_info_idx_range_from_voff(line_info, voff, &count);
for(RDI_U64 idx = 0; idx < count && result+idx < line_info->count; idx += 1) for(RDI_S64 idx = count-1; idx >= 0; idx -= 1)
{ {
if(line_info->lines[result+idx].file_idx != 0) if(result + idx < line_info->count && line_info->lines[result+idx].file_idx != 0)
{ {
result += idx; result += idx;
break; break;
-10
View File
@@ -23,16 +23,6 @@
#define BitExtract(x, count, shift) (((x) >> (shift)) & ((1 << (count)) - 1)) #define BitExtract(x, count, shift) (((x) >> (shift)) & ((1 << (count)) - 1))
////////////////////////////////
#if OS_WINDOWS
# define ins_atomic_ptr_eval_cond_assign(x,k,c) InterlockedCompareExchangePointer((volatile PVOID *)(x),(k),(c))
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x)
#else
# error "atomics are not defined for this system"
#endif
//////////////////////////////// ////////////////////////////////
// Linked List Helpers // Linked List Helpers
+3 -119
View File
@@ -1,33 +1,6 @@
// 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/)
global read_only String8 g_null_string;
internal String8
str8_cstring_capped_reverse(void *start, void *cap)
{
char *ptr = cap;
while (ptr > (char *)start) {
--ptr;
if (*ptr == '\0') break;
}
U64 null_offset = (U64)(ptr - (char *) start);
String8 result = str8((U8 *) start, null_offset);
return result;
}
internal U64
str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
{
for (S64 i = string.size - start_pos - needle.size; i >= 0; --i) {
String8 haystack = str8_substr(string, rng_1u64(i, i + needle.size));
if (str8_match(haystack, needle, flags)) {
return (U64)i + needle.size;
}
}
return 0;
}
internal int internal int
str8_compar(String8 a, String8 b, B32 ignore_case) str8_compar(String8 a, String8 b, B32 ignore_case)
{ {
@@ -76,15 +49,15 @@ str8_compar_ignore_case(const void *a, const void *b)
} }
internal int internal int
str8_compar_case_sensetive(const void *a, const void *b) str8_compar_case_sensitive(const void *a, const void *b)
{ {
return str8_compar(*(String8*)a, *(String8*)b, 0); return str8_compar(*(String8*)a, *(String8*)b, 0);
} }
internal int internal int
str8_is_before_case_sensetive(const void *a, const void *b) str8_is_before_case_sensitive(const void *a, const void *b)
{ {
int cmp = str8_compar_case_sensetive(a, b); int cmp = str8_compar_case_sensitive(a, b);
return cmp < 0; return cmp < 0;
} }
@@ -136,46 +109,6 @@ str8_list_push_many(Arena *arena, String8List *list, U64 count)
return arr; return arr;
} }
internal String8
str8_from_bits_u32(Arena *arena, U32 x)
{
U8 c0 = 'a' + ((x >> 28) & 0xf);
U8 c1 = 'a' + ((x >> 24) & 0xf);
U8 c2 = 'a' + ((x >> 20) & 0xf);
U8 c3 = 'a' + ((x >> 16) & 0xf);
U8 c4 = 'a' + ((x >> 12) & 0xf);
U8 c5 = 'a' + ((x >> 8) & 0xf);
U8 c6 = 'a' + ((x >> 4) & 0xf);
U8 c7 = 'a' + ((x >> 0) & 0xf);
String8 result = push_str8f(arena, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
return result;
}
internal String8
str8_from_bits_u64(Arena *arena, U64 x)
{
U8 c0 = 'a' + ((x >> 60) & 0xf);
U8 c1 = 'a' + ((x >> 56) & 0xf);
U8 c2 = 'a' + ((x >> 52) & 0xf);
U8 c3 = 'a' + ((x >> 48) & 0xf);
U8 c4 = 'a' + ((x >> 44) & 0xf);
U8 c5 = 'a' + ((x >> 40) & 0xf);
U8 c6 = 'a' + ((x >> 36) & 0xf);
U8 c7 = 'a' + ((x >> 32) & 0xf);
U8 c8 = 'a' + ((x >> 28) & 0xf);
U8 c9 = 'a' + ((x >> 24) & 0xf);
U8 ca = 'a' + ((x >> 20) & 0xf);
U8 cb = 'a' + ((x >> 16) & 0xf);
U8 cc = 'a' + ((x >> 12) & 0xf);
U8 cd = 'a' + ((x >> 8) & 0xf);
U8 ce = 'a' + ((x >> 4) & 0xf);
U8 cf = 'a' + ((x >> 0) & 0xf);
String8 result = push_str8f(arena,
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf);
return result;
}
internal String8Node * internal String8Node *
str8_list_pop_front(String8List *list) str8_list_pop_front(String8List *list)
{ {
@@ -190,55 +123,6 @@ str8_list_pop_front(String8List *list)
return node; return node;
} }
internal String8
str8_from_memory_size2(Arena *arena, U64 size)
{
String8 result;
if (size < KB(1)) {
result = push_str8f(arena, "%llu Bytes", size);
} else if (size < MB(1)) {
result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100);
} else if (size < GB(1)) {
result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100);
} else if (size < TB(1)) {
result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100);
} else {
result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100);
}
return result;
}
internal String8
str8_from_count(Arena *arena, U64 count)
{
String8 result;
if (count < 1000) {
result = push_str8f(arena, "%llu", count);
} else if (count < 1000000) {
U64 frac = ((count * 100) / 1000) % 100;
if (frac) {
result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac);
} else {
result = push_str8f(arena, "%lluK", count / 1000);
}
} else if (count < 1000000000) {
U64 frac = ((count * 100) / 1000000) % 100;
if (frac) {
result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac);
} else {
result = push_str8f(arena, "%lluM", count / 1000000);
}
} else {
U64 frac = ((count * 100) * 1000000000) % 100;
if (frac) {
result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac);
} else {
result = push_str8f(arena, "%lluB", count / 1000000000, frac);
}
}
return result;
}
internal U64 internal U64
hash_from_str8(String8 string) hash_from_str8(String8 string)
{ {
+1 -11
View File
@@ -5,13 +5,9 @@
#define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size) #define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size)
internal String8 str8_cstring_capped_reverse(void *start, void *cap);
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal int str8_compar(String8 a, String8 b, B32 ignore_case); internal int str8_compar(String8 a, String8 b, B32 ignore_case);
internal int str8_compar_ignore_case(const void *a, const void *b); internal int str8_compar_ignore_case(const void *a, const void *b);
internal int str8_compar_case_sensetive(const void *a, const void *b); internal int str8_compar_case_sensitive(const void *a, const void *b);
#define str8_list_push_struct(a,l,d) str8_list_push_raw(a, l, d, sizeof(*d)) #define str8_list_push_struct(a,l,d) str8_list_push_raw(a, l, d, sizeof(*d))
internal String8Node * str8_list_push_raw(Arena *arena, String8List *list, void *data_ptr, U64 data_size); internal String8Node * str8_list_push_raw(Arena *arena, String8List *list, void *data_ptr, U64 data_size);
@@ -20,14 +16,8 @@ internal U64 str8_list_push_pad_front(Arena *arena, String8List *list,
internal String8List str8_list_arr_concat(String8List *v, U64 count); internal String8List str8_list_arr_concat(String8List *v, U64 count);
internal String8Node * str8_list_push_many(Arena *arena, String8List *list, U64 count); internal String8Node * str8_list_push_many(Arena *arena, String8List *list, U64 count);
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
// TODO: remove // TODO: remove
internal String8Node * str8_list_pop_front(String8List *list); internal String8Node * str8_list_pop_front(String8List *list);
internal String8 str8_from_memory_size2(Arena *arena, U64 size);
internal String8 str8_from_count(Arena *arena, U64 count);
internal U64 hash_from_str8(String8 string); internal U64 hash_from_str8(String8 string);
+1 -1
View File
@@ -1628,7 +1628,7 @@ cv_string_hash_table_lookup(CV_StringHashTable ht, String8 string)
return ht.buckets[idx]; return ht.buckets[idx];
} }
idx = (idx + 1 % ht.bucket_cap); idx = (idx + 1) % ht.bucket_cap;
} while (idx != best_idx); } while (idx != best_idx);
return 0; return 0;
+1 -1
View File
@@ -208,7 +208,7 @@ typedef struct CV_UDTInfo
typedef struct CV_TypeServerInfo typedef struct CV_TypeServerInfo
{ {
String8 name; String8 name;
OS_Guid sig; Guid sig;
U32 age; U32 age;
} CV_TypeServerInfo; } CV_TypeServerInfo;
+107
View File
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="LNK_Section">
<DisplayString>{{ name={name} flags={flags} id={id} sort_index={sort_index} }}</DisplayString>
</Type>
<Type Name="U32Array">
<AlternativeType Name="U64Array"/>
<Expand>
<Item Name="[count]">count</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>v</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="LNK_SymbolList">
<AlternativeType Name="LNK_SectionList"/>
<AlternativeType Name="LNK_ChunkList"/>
<AlternativeType Name="CV_SymbolList"/>
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
<Expand>
<LinkedListItems>
<Size>count</Size>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>data</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="Rng1U64List">
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
<Expand>
<LinkedListItems>
<Size>count</Size>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>v</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="RDIB_LineTable">
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
<Expand>
<Item Name="[count]">count</Item>
<LinkedListItems>
<Size>count</Size>
<HeadPointer>first</HeadPointer>
<NextPointer>next_line_table</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="RDIB_VariableChunkList">
<AlternativeType Name="RDIB_UnitChunkList"/>
<AlternativeType Name="RDIB_LineTableChunkList"/>
<AlternativeType Name="RDIB_SourceFileChunkList"/>
<AlternativeType Name="RDIB_ProcedureChunkList"/>
<AlternativeType Name="RDIB_ScopeChunkList"/>
<AlternativeType Name="RDIB_InlineSiteChunkList"/>
<AlternativeType Name="RDIB_UDTMemberChunkList"/>
<AlternativeType Name="RDIB_TypeChunkList"/>
<Expand>
<Item Name="[chunk count]">count</Item>
<CustomListItems MaxItemsPerView="5000">
<Variable Name="node" InitialValue="first"/>
<Variable Name="idx" InitialValue="0"/>
<Loop>
<Break Condition="node == 0"/>
<Exec>idx = 0</Exec>
<Loop>
<Break Condition="idx >= node->count"/>
<Item>node->v[idx]</Item>
<Exec>idx += 1</Exec>
</Loop>
<Exec>node = node->next</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
<Type Name="RDIB_VariableChunk">
<AlternativeType Name="RDIB_UnitChunk"/>
<AlternativeType Name="RDIB_LineTableChunk"/>
<AlternativeType Name="RDIB_SourceFileChunk"/>
<AlternativeType Name="RDIB_ProcedureChunk"/>
<AlternativeType Name="RDIB_ScopeChunk"/>
<AlternativeType Name="RDIB_InlineSiteChunk"/>
<AlternativeType Name="RDIB_UDTMemberChunk"/>
<AlternativeType Name="RDIB_TypeChunk"/>
<DisplayString>{count,cap,v}</DisplayString>
<Expand>
<Item Name="[base]">base</Item>
<Item Name="[count]">count</Item>
<Item Name="[cap]">cap</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>v</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
+1435 -1705
View File
File diff suppressed because it is too large Load Diff
+25 -19
View File
@@ -172,13 +172,6 @@ typedef struct
HashTable **page_ht_arr; HashTable **page_ht_arr;
} LNK_ObjBaseRelocTask; } LNK_ObjBaseRelocTask;
typedef struct
{
Rng1U64 *range_arr;
LNK_LibNode *lib_arr;
LNK_Symbol **symbol_arr_arr;
} LNK_LazyIniter;
typedef struct typedef struct
{ {
LNK_InputObjList input_obj_list; LNK_InputObjList input_obj_list;
@@ -197,6 +190,16 @@ typedef struct
typedef struct typedef struct
{ {
LNK_SymbolTable *symtab;
union {
LNK_ObjNodeArray objs;
LNK_LibNodeArray libs;
} u;
} LNK_SymbolPusher;
typedef struct
{
String8 image_data;
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_SectionTable *st; LNK_SectionTable *st;
LNK_Section **sect_id_map; LNK_Section **sect_id_map;
@@ -207,6 +210,7 @@ typedef struct
typedef struct typedef struct
{ {
String8 image_data;
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_SectionTable *st; LNK_SectionTable *st;
LNK_Section **sect_id_map; LNK_Section **sect_id_map;
@@ -214,7 +218,6 @@ typedef struct
LNK_Obj **obj_arr; LNK_Obj **obj_arr;
} LNK_ObjRelocPatcher; } LNK_ObjRelocPatcher;
typedef struct typedef struct
{ {
String8 path; String8 path;
@@ -238,23 +241,19 @@ internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImport **ar
//////////////////////////////// ////////////////////////////////
// Helpers // Helpers
internal void lnk_write_data_list_to_file_path(String8 path, String8List list);
internal void lnk_write_data_to_file_path(String8 path, String8 data);
internal String8 lnk_make_full_path(Arena *arena, String8 work_dir, PathStyle system_path_style, String8 path); internal String8 lnk_make_full_path(Arena *arena, String8 work_dir, PathStyle system_path_style, String8 path);
internal String8 lnk_get_lib_name(String8 path); internal String8 lnk_get_lib_name(String8 path);
internal B32 lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path); internal B32 lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path);
internal B32 lnk_is_lib_loaded(HashTable *default_lib_ht, HashTable *loaded_lib_ht, LNK_InputSourceType input_source, String8 lib_path); internal B32 lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 lib_path);
internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path); internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path);
internal void lnk_push_loaded_lib(Arena *arena, HashTable *default_lib_ht, HashTable *loaded_lib_ht, String8 path); internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path);
//////////////////////////////// ////////////////////////////////
// Manifest // Manifest
internal String8List lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list); internal String8 lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list);
internal void lnk_merge_manifest_files(Arena *arena, String8 mt_path, String8 manifest_name, String8List manifest_path_list); internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest_path_list);
internal String8 lnk_res_from_data(Arena *arena, String8 data);
//////////////////////////////// ////////////////////////////////
// Resources // Resources
@@ -272,8 +271,8 @@ internal String8 lnk_make_linker_coff_obj(TP_Context *tp, Arena *arena, COFF_Tim
//////////////////////////////// ////////////////////////////////
// Win32 Image Helpers // Win32 Image Helpers
internal void lnk_build_debug_pdb(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, OS_Guid guid, U32 age, String8 pdb_path); internal void lnk_build_debug_pdb(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, U32 age, String8 pdb_path);
internal void lnk_build_debug_rdi(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, OS_Guid guid, String8 rdi_path); internal void lnk_build_debug_rdi(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, String8 rdi_path);
internal void lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag); internal void lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, LNK_ObjList obj_list); internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, LNK_ObjList obj_list);
internal LNK_Chunk * lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk); internal LNK_Chunk * lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk);
@@ -287,7 +286,9 @@ internal LNK_Chunk * lnk_build_win32_image_header(LNK_SymbolTable *symtab, LNK_S
//////////////////////////////// ////////////////////////////////
// Relocs // Relocs
internal void lnk_patch_relocs(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, U64 base_addr); internal void lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
internal void lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
internal void lnk_apply_reloc(U64 base_addr, U64 virt_align, U64 file_align, LNK_Section **sect_id_map, LNK_SymbolTable *symtab, String8 chunk_data, LNK_Reloc *reloc); internal void lnk_apply_reloc(U64 base_addr, U64 virt_align, U64 file_align, LNK_Section **sect_id_map, LNK_SymbolTable *symtab, String8 chunk_data, LNK_Reloc *reloc);
//////////////////////////////// ////////////////////////////////
@@ -296,3 +297,8 @@ internal void lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symt
internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *st); internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *st);
internal void lnk_log_timers(void); internal void lnk_log_timers(void);
////////////////////////////////
// Enum <-> String
internal String8 lnk_string_from_input_source(LNK_InputSourceType input_source);
+206 -235
View File
@@ -1,9 +1,6 @@
// 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/)
global read_only LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 };
global read_only LNK_Chunk *g_null_chunk_ptr = &g_null_chunk;
internal LNK_ChunkRef internal LNK_ChunkRef
lnk_chunk_ref(U64 sect_id, U64 chunk_id) lnk_chunk_ref(U64 sect_id, U64 chunk_id)
{ {
@@ -65,7 +62,7 @@ lnk_chunk_sort_index_is_before(void *raw_a, void *raw_b)
LNK_ChunkPtr *b = raw_b; LNK_ChunkPtr *b = raw_b;
// sort on section postfix // sort on section postfix
int cmp = str8_compar_case_sensetive(&(*a)->sort_idx, &(*b)->sort_idx); int cmp = str8_compar_case_sensitive(&(*a)->sort_idx, &(*b)->sort_idx);
// sort on obj position on command line // sort on obj position on command line
if (cmp == 0) { if (cmp == 0) {
@@ -346,307 +343,286 @@ lnk_chunk_list_get_node_count(LNK_Chunk *chunk)
} }
internal void internal void
lnk_chunk_op_list_push_node(LNK_ChunkOpList *list, LNK_ChunkOp *op) lnk_chunk_align_array_list_push(Arena *arena, Arena *scratch, LNK_ChunkAlignArrayList *list, U64 cap, U64 align_off, U64 align_size)
{ {
SLLQueuePush(list->first, list->last, op); if (align_size > 0) {
if (list->last == 0 || list->last->data.count >= list->last->cap) {
LNK_ChunkAlignArrayNode *node = push_array(scratch, LNK_ChunkAlignArrayNode, 1);
node->cap = cap;
node->data.v = push_array_no_zero(arena, LNK_ChunkAlign, cap);
SLLQueuePush(list->first, list->last, node);
++list->count;
}
LNK_ChunkAlignArray *last_array = &list->last->data;
LNK_ChunkAlign *align = &last_array->v[last_array->count++];
align->off = align_off;
align->size = align_size;
}
} }
internal LNK_ChunkOp * internal LNK_ChunkLayout
lnk_push_chunk_op_begin(Arena *arena, U64 chunk_id) lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count)
{ {
LNK_ChunkOp *begin_op = push_array_no_zero(arena, LNK_ChunkOp, 1); ProfBeginV("lnk_layout_from_chunk [total_chunk_count = %llu]", total_chunk_count);
begin_op->next = 0; Temp scratch = scratch_begin(&arena, 1);
begin_op->type = LNK_ChunkOp_Begin;
begin_op->u.chunk_id = chunk_id; LNK_ChunkLayout layout = {0};
return begin_op; layout.total_count = total_chunk_count;
} layout.chunk_ptr_array = push_array_no_zero(arena, LNK_ChunkPtr, total_chunk_count);
layout.chunk_off_array = push_array_no_zero(arena, U64, total_chunk_count);
layout.chunk_file_size_array = push_array_no_zero(arena, U64, total_chunk_count);
layout.chunk_virt_size_array = push_array_no_zero(arena, U64, total_chunk_count);
internal LNK_ChunkOp * ProfBegin("Init Arrays");
lnk_push_chunk_op_end_virt(Arena *arena) for (U64 i = 0; i < total_chunk_count; ++i) {
{ layout.chunk_ptr_array[i] = &g_null_chunk;
LNK_ChunkOp *end_virt_op = push_array_no_zero(arena, LNK_ChunkOp, 1); }
end_virt_op->next = 0; #if BUILD_DEBUG
end_virt_op->type = LNK_ChunkOp_EndVirt; MemorySet(layout.chunk_off_array, 0xff, total_chunk_count * sizeof(layout.chunk_off_array));
return end_virt_op; MemorySet(layout.chunk_file_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_file_size_array));
} MemorySet(layout.chunk_virt_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_virt_size_array));
#endif
ProfEnd();
internal LNK_ChunkOp * // handle null chunk
lnk_push_chunk_op_end_file(Arena *arena) layout.chunk_off_array[0] = 0;
{ layout.chunk_file_size_array[0] = 0;
LNK_ChunkOp *end_op = push_array_no_zero(arena, LNK_ChunkOp, 1); layout.chunk_virt_size_array[0] = 0;
end_op->next = 0;
end_op->type = LNK_ChunkOp_End;
return end_op;
}
internal LNK_ChunkOp * // setup stack
lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val)
{
LNK_ChunkOp *align_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
align_op->next = 0;
align_op->type = LNK_ChunkOp_Align;
align_op->u.align.x = align;
align_op->u.align.val = val;
return align_op;
}
internal LNK_ChunkOp *
lnk_push_chunk_op_write(Arena *arena, String8 string)
{
LNK_ChunkOp *write_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
write_op->next = 0;
write_op->type = LNK_ChunkOp_WriteString;
write_op->u.string = string;
return write_op;
}
internal LNK_ChunkOpList
lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 align_byte)
{
struct Stack { struct Stack {
struct Stack *next; struct Stack *next;
LNK_ChunkArray chunk_array; LNK_ChunkArray chunk_array;
U64 ichunk; U64 ichunk;
}; };
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
// setup stack
struct Stack *stack = push_array(scratch.arena, struct Stack, 1); struct Stack *stack = push_array(scratch.arena, struct Stack, 1);
stack->chunk_array.count = 1; stack->chunk_array.count = 1;
stack->chunk_array.v = &root; stack->chunk_array.v = &root;
// setup output list U64 align_cap = 4096;
LNK_ChunkOpList list = {0}; LNK_ChunkAlignArrayList align_list = {0};
list.total_chunk_count = total_chunk_count;
list.first = list.last = 0; U64 cursor = 0;
// write null ProfBegin("Traverse chunks from root");
LNK_ChunkOp *null_begin_op = lnk_push_chunk_op_begin(arena, 0); for (; stack != 0; ) {
LNK_ChunkOp *null_end_virt_op = lnk_push_chunk_op_end_virt(arena); for (; stack->ichunk < stack->chunk_array.count; ) {
LNK_ChunkOp *null_end_file_op = lnk_push_chunk_op_end_file(arena);;
lnk_chunk_op_list_push_node(&list, null_begin_op);
lnk_chunk_op_list_push_node(&list, null_end_virt_op);
lnk_chunk_op_list_push_node(&list, null_end_file_op);
// traverse chunks from root
while (stack) {
while (stack->ichunk < stack->chunk_array.count) {
LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++]; LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++];
// skip unused chunks // skip discarded chunk
if (lnk_chunk_is_discarded(chunk)) { if (lnk_chunk_is_discarded(chunk)) {
continue; continue;
} }
// push align
U64 align_size = AlignPadPow2(cursor, chunk->align);
lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
cursor += align_size;
// store id -> chunk
Assert(chunk->ref.chunk_id < total_chunk_count);
Assert(layout.chunk_ptr_array[chunk->ref.chunk_id] == &g_null_chunk);
layout.chunk_ptr_array[chunk->ref.chunk_id] = chunk;
// store id -> offset
Assert(layout.chunk_off_array[chunk->ref.chunk_id] == max_U64);
layout.chunk_off_array[chunk->ref.chunk_id] = cursor;
switch (chunk->type) { switch (chunk->type) {
case LNK_Chunk_Leaf: { case LNK_Chunk_Leaf: {
// align start in its own begin/end block so align bytes don't contribute to chunk size // store id -> file size
LNK_ChunkOp *pad_begin_op = lnk_push_chunk_op_begin(arena, list.total_chunk_count++); Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
LNK_ChunkOp *pad_align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte); layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
LNK_ChunkOp *pad_end_file_op = lnk_push_chunk_op_end_file(arena);
lnk_chunk_op_list_push_node(&list, pad_begin_op); // store id -> virt size
lnk_chunk_op_list_push_node(&list, pad_align_op); Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
lnk_chunk_op_list_push_node(&list, pad_end_file_op); layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
// write leaf // advance
LNK_ChunkOp *leaf_begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id); cursor += chunk->u.leaf.size;
LNK_ChunkOp *leaf_write_op = lnk_push_chunk_op_write(arena, chunk->u.leaf);
LNK_ChunkOp *leaf_align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
LNK_ChunkOp *leaf_end_virt_op = lnk_push_chunk_op_end_virt(arena);
LNK_ChunkOp *leaf_end_file_op = lnk_push_chunk_op_end_file(arena);
#if LNK_DUMP_CHUNK_LAYOUT
leaf_write_op->chunk = chunk;
#endif
lnk_chunk_op_list_push_node(&list, leaf_begin_op);
lnk_chunk_op_list_push_node(&list, leaf_write_op);
lnk_chunk_op_list_push_node(&list, leaf_align_op);
lnk_chunk_op_list_push_node(&list, leaf_end_virt_op);
lnk_chunk_op_list_push_node(&list, leaf_end_file_op);
} break; } break;
case LNK_Chunk_LeafArray: { case LNK_Chunk_LeafArray: {
LNK_ChunkOp *begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id); #if BUILD_DEBUG
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte); for (U64 i = 0; i < chunk->u.arr->count; ++i) {
lnk_chunk_op_list_push_node(&list, begin_op); Assert(chunk->u.arr->v[i]->type == LNK_Chunk_Leaf);
lnk_chunk_op_list_push_node(&list, align_op); }
#endif
// apply sort
if (chunk->sort_chunk) { if (chunk->sort_chunk) {
lnk_chunk_array_sort(*chunk->u.arr); lnk_chunk_array_sort(*chunk->u.arr);
} }
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1); // recurse into sub chunks
frame->next = 0; struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
frame->chunk_array = *chunk->u.arr; frame->chunk_array = *chunk->u.arr;
frame->ichunk = 0;
SLLStackPush(stack, frame); SLLStackPush(stack, frame);
} goto yeild; } goto _continue;
case LNK_Chunk_List: { case LNK_Chunk_List: {
// balance ops at :end_chunk_series // list -> array
LNK_ChunkOp *begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id);
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
lnk_chunk_op_list_push_node(&list, begin_op);
lnk_chunk_op_list_push_node(&list, align_op);
// chunk list -> chunk array
LNK_ChunkArray chunk_array = {0}; LNK_ChunkArray chunk_array = {0};
chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count); chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count);
for (LNK_ChunkNode *cptr = chunk->u.list->first; cptr != 0; cptr = cptr->next) { for (LNK_ChunkNode *cptr = chunk->u.list->first; cptr != 0; cptr = cptr->next) {
chunk_array.v[chunk_array.count++] = cptr->data; chunk_array.v[chunk_array.count++] = cptr->data;
} }
// apply sort
if (chunk->sort_chunk) { if (chunk->sort_chunk) {
lnk_chunk_array_sort(chunk_array); lnk_chunk_array_sort(chunk_array);
} }
// recurse into list chunk // recurse into sub chunks
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1); struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
frame->next = 0;
frame->chunk_array = chunk_array; frame->chunk_array = chunk_array;
frame->ichunk = 0;
SLLStackPush(stack, frame); SLLStackPush(stack, frame);
} goto yeild; } goto _continue;
case LNK_Chunk_Null: { /* ignore */ } break; case LNK_Chunk_Null: break;
} }
} }
// terminate series // terminate series
if (stack->next) { if (stack->next) {
// pop node chunk from stack
struct Stack *prev = stack->next; struct Stack *prev = stack->next;
Assert(prev->ichunk > 0); Assert(prev->ichunk > 0);
// :end_chunk_series // align chunk end
LNK_ChunkOp *end_virt_op = lnk_push_chunk_op_end_virt(arena); LNK_Chunk *chunk = prev->chunk_array.v[prev->ichunk-1];
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, prev->chunk_array.v[prev->ichunk - 1]->align, align_byte); U64 align_size = AlignPadPow2(cursor, chunk->align);
LNK_ChunkOp *end_op = lnk_push_chunk_op_end_file(arena); lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
lnk_chunk_op_list_push_node(&list, end_virt_op);
lnk_chunk_op_list_push_node(&list, align_op); U64 chunk_start_off = layout.chunk_off_array[chunk->ref.chunk_id];
lnk_chunk_op_list_push_node(&list, end_op); Assert(chunk_start_off != max_U64);
Assert(chunk_start_off <= cursor);
// store id -> virt size
Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
U64 virt_chunk_size = cursor - chunk_start_off;
layout.chunk_virt_size_array[chunk->ref.chunk_id] = virt_chunk_size;
// advance cursor
cursor += align_size;
// store id -> file size
Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
U64 file_chunk_size = cursor - chunk_start_off;
layout.chunk_file_size_array[chunk->ref.chunk_id] = file_chunk_size;
} }
// move to next frame // move to next frame
SLLStackPop(stack); SLLStackPop(stack);
yeild:; _continue:;
} }
ProfEnd();
ProfBegin("Build Aligns Array");
layout.align_array_count = 0;
layout.align_array = push_array(arena, LNK_ChunkAlignArray, align_list.count);
for (LNK_ChunkAlignArrayNode *node = align_list.first; node != 0; node = node->next) {
layout.align_array[layout.align_array_count++] = node->data;
}
ProfEnd();
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return list; return layout;
} }
internal LNK_ChunkLayout internal LNK_ChunkLayout
lnk_chunk_layout_from_op_list(Arena *arena, LNK_ChunkOpList op_list, B32 is_data_inited) lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1); LNK_ChunkLayout layout = lnk_layout_from_chunk(arena, cman->root, cman->total_chunk_count);
ProfEnd();
// setup stack return layout;
struct Stack { }
struct Stack *next;
U64 chunk_id; internal
U64 cursor; THREAD_POOL_TASK_FUNC(lnk_fill_chunks_task)
} *stack = 0; {
ProfBeginFunction();
// setup state
U64 cursor = 0; LNK_ChunkLayoutSerializer *task = raw_task;
String8List data_list = {0}; Rng1U64 range = task->ranges[task_id];
LNK_ChunkLayout layout = task->layout;
// setup output String8 buffer = task->buffer;
U64 *chunk_off_array = push_array_no_zero(arena, U64, op_list.total_chunk_count);
U64 *chunk_file_size_array = push_array_no_zero(arena, U64, op_list.total_chunk_count); for (U64 chunk_idx = range.min; chunk_idx < range.max; ++chunk_idx) {
U64 *chunk_virt_size_array = push_array_no_zero(arena, U64, op_list.total_chunk_count); LNK_Chunk *chunk = layout.chunk_ptr_array[chunk_idx];
// debug stomp so discarded chunks map to invalid offset if (lnk_chunk_is_discarded(chunk)) {
#if LNK_PARANOID continue;
MemorySet(chunk_off_array, 0xFF, sizeof(*chunk_off_array) * op_list.total_chunk_count); }
MemorySet(chunk_file_size_array, 0xFF, sizeof(*chunk_file_size_array) * op_list.total_chunk_count);
MemorySet(chunk_virt_size_array, 0xFF, sizeof(*chunk_virt_size_array) * op_list.total_chunk_count); if (chunk->type == LNK_Chunk_Leaf) {
#endif U64 off = layout.chunk_off_array[chunk->ref.chunk_id];
Assert(off + chunk->u.leaf.size <= buffer.size);
// execute opcodes U8 *buffer_ptr = buffer.str + off;
for (LNK_ChunkOp *op = op_list.first; op != NULL; op = op->next) {
switch (op->type) { if (chunk->u.leaf.str == 0) {
case LNK_ChunkOp_Null: break; // zero out chunk bytes
case LNK_ChunkOp_Begin: { MemorySet(buffer_ptr, 0, chunk->u.leaf.size);
struct Stack *frame = push_array(scratch.arena, struct Stack, 1); } else {
frame->chunk_id = op->u.chunk_id; // copy chunk bytes
frame->cursor = cursor; MemoryCopy(buffer_ptr, chunk->u.leaf.str, chunk->u.leaf.size);
SLLStackPush(stack, frame);
chunk_off_array[stack->chunk_id] = stack->cursor;
} break;
case LNK_ChunkOp_End: {
chunk_file_size_array[stack->chunk_id] = cursor - stack->cursor;
SLLStackPop(stack);
} break;
case LNK_ChunkOp_EndVirt: {
chunk_virt_size_array[stack->chunk_id] = cursor - stack->cursor;
} break;
case LNK_ChunkOp_Align: {
Assert(IsPow2(op->u.align.x));
U64 size = AlignPow2(cursor, op->u.align.x) - cursor;
String8 string;
string.size = size;
string.str = push_array_no_zero(arena, U8, string.size);
MemorySet(string.str, op->u.align.val, string.size);
op->type = LNK_ChunkOp_WriteString;
op->u.string = string;
} // fall-through
case LNK_ChunkOp_WriteString: {
if (is_data_inited) {
// we allow chunks to have null for str for regions in the image that are zeroed out.
if (op->u.string.str == 0) {
op->u.string.str = push_array(arena, U8, op->u.string.size);
}
str8_list_push(scratch.arena, &data_list, op->u.string);
} }
#if LNK_DUMP_CHUNK_LAYOUT
if (op->chunk) {
fprintf(g_layout_file, "[%.*s] %llX %.*s\n", str8_varg(op->chunk->sort_idx), op->chunk->input_idx, str8_varg(op->chunk->debug));
}
#endif
// advance
cursor += op->u.string.size;
} break;
} }
} }
// are begin/end series opcodes balanced?
Assert(stack == 0);
// fill out result
LNK_ChunkLayout layout = {0};
layout.data = str8_list_join(arena, &data_list, 0);
layout.chunk_off_array = chunk_off_array;
layout.chunk_file_size_array = chunk_file_size_array;
layout.chunk_virt_size_array = chunk_virt_size_array;
scratch_end(scratch);
ProfEnd(); ProfEnd();
return layout;
} }
internal LNK_ChunkLayout internal
lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman, COFF_SectionFlags flags, U8 align_byte) THREAD_POOL_TASK_FUNC(lnk_fill_aligns_task)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
LNK_ChunkLayoutSerializer *task = raw_task;
// should we write data for chunks? Rng1U64 range = task->ranges[task_id];
B32 is_data_inited = !!(~flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA); LNK_ChunkLayout layout = task->layout;
String8 buffer = task->buffer;
// build layout U8 fill_byte = task->fill_byte;
LNK_ChunkOpList op_list = lnk_op_list_from_chunk(scratch.arena, cman->root, cman->total_chunk_count, align_byte);
LNK_ChunkLayout layout = lnk_chunk_layout_from_op_list(arena, op_list, is_data_inited); for (U64 align_array_idx = range.min; align_array_idx < range.max; ++align_array_idx) {
LNK_ChunkAlignArray align_array = layout.align_array[align_array_idx];
for (U64 align_idx = 0; align_idx < align_array.count; ++align_idx) {
LNK_ChunkAlign align = align_array.v[align_idx];
Assert(align.off + align.size <= buffer.size);
MemorySet(buffer.str + align.off, fill_byte, align.size);
}
}
ProfEnd();
}
internal void
lnk_serialize_chunk_layout(TP_Context *tp, LNK_ChunkLayout layout, String8 buffer, U8 fill_byte)
{
ProfBeginFunction();
Temp scratch = scratch_begin(0,0);
LNK_ChunkLayoutSerializer task;
task.layout = layout;
task.buffer = buffer;
task.fill_byte = fill_byte;
ProfBeginV("Fill Chunks [Chunk Count %llu]", layout.total_count);
task.ranges = tp_divide_work(scratch.arena, layout.total_count, tp->worker_count);
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_chunks_task, &task);
ProfEnd();
ProfBeginV("Fill Aligns [Array Count %llu]", layout.align_array_count);
task.ranges = tp_divide_work(scratch.arena, layout.align_array_count, tp->worker_count);
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_aligns_task, &task);
ProfEnd();
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return layout;
} }
internal B32 internal B32
@@ -702,15 +678,10 @@ LNK_CHUNK_VISITOR_SIG(lnk_save_chunk_ptr)
internal LNK_ChunkPtr * internal LNK_ChunkPtr *
lnk_make_chunk_id_map(Arena *arena, LNK_ChunkManager *cman) lnk_make_chunk_id_map(Arena *arena, LNK_ChunkManager *cman)
{ {
LNK_ChunkPtr *chunk_id_map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count + 1); LNK_ChunkPtr *map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count);
lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, chunk_id_map); lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, map);
map[0] = &g_null_chunk;
LNK_Chunk *null_chunk = push_array(arena, LNK_Chunk, 1); return map;
null_chunk->is_discarded = 1;
chunk_id_map[0] = null_chunk;
return chunk_id_map;
} }
internal LNK_ChunkNode * internal LNK_ChunkNode *
+50 -16
View File
@@ -5,8 +5,7 @@
//////////////////////////////// ////////////////////////////////
#define LNK_DEBUG_CHUNKS 0 #define LNK_DEBUG_CHUNKS 0
#define LNK_DUMP_CHUNK_LAYOUT 0
//////////////////////////////// ////////////////////////////////
@@ -79,17 +78,14 @@ typedef struct LNK_ChunkOp
struct LNK_ChunkOp *next; struct LNK_ChunkOp *next;
LNK_ChunkOpType type; LNK_ChunkOpType type;
union { union {
String8 string; String8 string;
U64 chunk_id; LNK_Chunk *chunk;
struct { struct {
U64 val; U64 val;
U64 x; U64 x;
} align; } align;
LNK_Chunk *leaf; LNK_Chunk *leaf;
} u; } u;
#if LNK_DUMP_CHUNK_LAYOUT
LNK_Chunk *chunk;
#endif
} LNK_ChunkOp; } LNK_ChunkOp;
typedef struct LNK_ChunkOpList typedef struct LNK_ChunkOpList
@@ -99,12 +95,39 @@ typedef struct LNK_ChunkOpList
LNK_ChunkOp *last; LNK_ChunkOp *last;
} LNK_ChunkOpList; } LNK_ChunkOpList;
typedef struct LNK_ChunkAlign
{
U64 off;
U64 size;
} LNK_ChunkAlign;
typedef struct LNK_ChunkAlignArray
{
U64 count;
LNK_ChunkAlign *v;
} LNK_ChunkAlignArray;
typedef struct LNK_ChunkAlignArrayNode
{
struct LNK_ChunkAlignArrayNode *next;
U64 cap;
LNK_ChunkAlignArray data;
} LNK_ChunkAlignArrayNode;
typedef struct LNK_ChunkAlignArrayList
{
U64 count;
LNK_ChunkAlignArrayNode *first;
LNK_ChunkAlignArrayNode *last;
} LNK_ChunkAlignArrayList;
typedef struct LNK_ChunkLayout typedef struct LNK_ChunkLayout
{ {
String8 data; U64 total_count;
U64 *chunk_off_array; LNK_Chunk **chunk_ptr_array; // discarded chunks point to g_null_chunk
U64 *chunk_file_size_array; U64 *chunk_off_array; // discarded chunks have offset set to max_U64
U64 *chunk_virt_size_array; U64 *chunk_file_size_array; // discarded chunks have offset set to max_U64
U64 *chunk_virt_size_array; // discarded chunks have offset set to max_U64
U64 align_array_count;
LNK_ChunkAlignArray *align_array;
} LNK_ChunkLayout; } LNK_ChunkLayout;
typedef struct LNK_ChunkManager typedef struct LNK_ChunkManager
@@ -113,8 +136,20 @@ typedef struct LNK_ChunkManager
U64 total_chunk_count; U64 total_chunk_count;
} LNK_ChunkManager; } LNK_ChunkManager;
extern LNK_Chunk g_null_chunk; typedef struct
extern LNK_Chunk *g_null_chunk_ptr; {
LNK_ChunkLayout layout;
String8 buffer;
U8 fill_byte;
Rng1U64 *ranges;
} LNK_ChunkLayoutSerializer;
////////////////////////////////
read_only global LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 };
read_only global LNK_Chunk *g_null_chunk_ptr = &g_null_chunk;
////////////////////////////////
internal LNK_ChunkRef lnk_chunk_ref(U64 sect_id, U64 chunk_id); internal LNK_ChunkRef lnk_chunk_ref(U64 sect_id, U64 chunk_id);
internal B32 lnk_chunk_ref_is_equal(LNK_ChunkRef a, LNK_ChunkRef b); internal B32 lnk_chunk_ref_is_equal(LNK_ChunkRef a, LNK_ChunkRef b);
@@ -144,9 +179,8 @@ internal LNK_ChunkOp * lnk_push_chunk_op_end_file(Arena *arena);
internal LNK_ChunkOp * lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val); internal LNK_ChunkOp * lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val);
internal LNK_ChunkOp * lnk_push_chunk_op_write(Arena *arena, String8 string); internal LNK_ChunkOp * lnk_push_chunk_op_write(Arena *arena, String8 string);
internal LNK_ChunkOpList lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 align_byte); internal LNK_ChunkLayout lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count);
internal LNK_ChunkLayout lnk_chunk_layout_from_op_list(Arena *arena, LNK_ChunkOpList op_list, B32 is_data_inited); internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman);
internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman, COFF_SectionFlags flags, U8 align_byte);
#define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud) #define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud)
typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig); typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig);
+1 -1
View File
@@ -202,7 +202,7 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list)
if (os_file_path_exists(name)) { if (os_file_path_exists(name)) {
// read rsp from disk // read rsp from disk
String8 file = os_data_from_file_path(scratch.arena, name); String8 file = lnk_read_data_from_file_path(scratch.arena, name);
// parse rsp // parse rsp
String8List rsp_args = lnk_arg_list_parse_windows_rules(scratch.arena, file); String8List rsp_args = lnk_arg_list_parse_windows_rules(scratch.arena, file);
+273 -115
View File
@@ -84,15 +84,17 @@ read_only struct
{ LNK_CmdSwitch_Natvis, "NATVIS", ":FILENAME", "" }, { LNK_CmdSwitch_Natvis, "NATVIS", ":FILENAME", "" },
{ LNK_CmdSwitch_NotImplemented, "NOASSEMBLY", "", "" }, { LNK_CmdSwitch_NotImplemented, "NOASSEMBLY", "", "" },
{ LNK_CmdSwitch_NoDefaultLib, "NODEFAULTLIB", ":LIBNAME", "" }, { LNK_CmdSwitch_NoDefaultLib, "NODEFAULTLIB", ":LIBNAME", "" },
{ LNK_CmdSwitch_NoDefaultLib, "NOD", ":LIBNAME", "" },
{ LNK_CmdSwitch_NotImplemented, "NOENTRY", "", "" }, { LNK_CmdSwitch_NotImplemented, "NOENTRY", "", "" },
{ LNK_CmdSwitch_NotImplemented, "NOEXP", "", "" }, { LNK_CmdSwitch_NoExp, "NOEXP", "", ".exp is not supported." },
{ LNK_CmdSwitch_NotImplemented, "NOIMPLIB", "", "" }, { LNK_CmdSwitch_NoImpLib, "NOIMPLIB", "", "" },
{ LNK_CmdSwitch_NoLogo, "NOLOGO", "", "" }, { LNK_CmdSwitch_NoLogo, "NOLOGO", "", "" },
{ LNK_CmdSwitch_NxCompat, "NXCOMPAT", "[:NO]", "" }, { LNK_CmdSwitch_NxCompat, "NXCOMPAT", "[:NO]", "" },
{ LNK_CmdSwitch_Opt, "OPT", "", "" }, { LNK_CmdSwitch_Opt, "OPT", "", "" },
{ LNK_CmdSwitch_NotImplemented, "ORDER", "", "" }, { LNK_CmdSwitch_NotImplemented, "ORDER", "", "" },
{ LNK_CmdSwitch_Out, "OUT", ":FILENAME", "" }, { LNK_CmdSwitch_Out, "OUT", ":FILENAME", "" },
{ LNK_CmdSwitch_Pdb, "PDB", ":FILENAME", "" }, { LNK_CmdSwitch_Pdb, "PDB", ":FILENAME", "" },
{ LNK_CmdSwitch_PdbAltPath, "PDBALTPATH", "", "" },
{ LNK_CmdSwitch_NotImplemented, "PDBSTRIPPED", "", "" }, { LNK_CmdSwitch_NotImplemented, "PDBSTRIPPED", "", "" },
{ LNK_CmdSwitch_PdbPageSize, "PDBPAGESIZE", ":#", "Page size must be power of two" }, { LNK_CmdSwitch_PdbPageSize, "PDBPAGESIZE", ":#", "Page size must be power of two" },
{ LNK_CmdSwitch_NotImplemented, "PROFILE", "", "" }, { LNK_CmdSwitch_NotImplemented, "PROFILE", "", "" },
@@ -119,34 +121,38 @@ read_only struct
{ LNK_CmdSwitch_NotImplemented, "WX", "", "" }, { LNK_CmdSwitch_NotImplemented, "WX", "", "" },
//- internal switches //- internal switches
{ LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, { LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
{ LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." }, { LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." },
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, { LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
{ LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, { LNK_CmdSwitch_Rad_DebugAltPath, "RAD_DEBUGALTPATH", "", "" },
{ LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" }, { LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
{ LNK_CmdSwitch_Rad_DeleteManifest, "RAD_DELETE_MANIFEST", "[:NO]", "" }, { LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" }, { LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" }, { LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" }, { LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" }, { LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" },
{ LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." }, { LNK_CmdSwitch_Rad_IdleWorkers, "RAD_IDLE_WORKERS", ":#", "Number of workers to leave idle." },
{ LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" }, { LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." },
{ LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" }, { LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" },
{ LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Path to manifest tool." }, { LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" },
{ LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" }, { LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Path to manifest tool." },
{ LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." }, { LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" },
{ LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" }, { LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." },
{ LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." }, { LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" },
{ LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" }, { LNK_CmdSwitch_Rad_PdbHashTypeNameLength, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." },
{ LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
{ LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, { LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
{ LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." }, { LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." },
{ LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." }, { LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" },
{ LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, { LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." },
{ LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, { LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." },
{ LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." }, { LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." },
{ LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024." }, { LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." },
{ LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" },
{ LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
{ LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." },
{ LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024." },
{ LNK_CmdSwitch_Help, "HELP", "", "" }, { LNK_CmdSwitch_Help, "HELP", "", "" },
{ LNK_CmdSwitch_Help, "?", "", "" }, { LNK_CmdSwitch_Help, "?", "", "" },
@@ -223,6 +229,27 @@ lnk_debug_mode_from_string(String8 string)
return LNK_DebugMode_Null; return LNK_DebugMode_Null;
} }
read_only struct
{
char *name;
LNK_TypeNameHashMode mode;
} g_type_name_hash_mode_map[] = {
{ "none", LNK_TypeNameHashMode_None },
{ "lenient", LNK_TypeNameHashMode_Lenient },
{ "full", LNK_TypeNameHashMode_Full }
};
internal LNK_TypeNameHashMode
lnk_type_name_hash_mode_from_string(String8 string)
{
for (U64 i = 0; i < ArrayCount(g_type_name_hash_mode_map); ++i) {
if (str8_match(str8_cstring(g_type_name_hash_mode_map[i].name), string, StringMatchFlag_CaseInsensitive)) {
return g_type_name_hash_mode_map[i].mode;
}
}
return LNK_TypeNameHashMode_Null;
}
//////////////////////////////// ////////////////////////////////
internal LNK_CmdOption * internal LNK_CmdOption *
@@ -471,22 +498,17 @@ lnk_get_mt_path(Arena *arena)
#undef OS_WINDOWS #undef OS_WINDOWS
#pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "shlwapi.lib")
#include <shlwapi.h> #include <shlwapi.h>
local_persist wchar_t raw_mt_path[MAX_PATH*2] = L"mt.exe";
PathFindOnPathW(&raw_mt_path[0], 0);
String8 mt_path = str8(0,0); String16 mt_path_16 = str16_cstring_capped(&raw_mt_path[0], raw_mt_path + sizeof(raw_mt_path));
local_persist wchar_t raw_mt_path[MAX_PATH + 1] = L"mt.exe"; String8 mt_path = str8_from_16(arena, mt_path_16);
B32 is_mt_found = PathFindOnPathW(&raw_mt_path[0], 0);
if (is_mt_found) { mt_path = path_convert_slashes(arena, mt_path, PathStyle_WindowsAbsolute);
String16 mt_path_16 = str16_cstring(&raw_mt_path[0]);
mt_path = str8_from_16(arena, mt_path_16);
mt_path = path_convert_slashes(arena, mt_path, PathStyle_WindowsAbsolute);
} else {
lnk_error(LNK_Error_Cmdl, "mt.exe not found, please specify path with /RAD_MT_PATH or run vcvarsall.bat");
}
#undef OS_WINDOWS #undef OS_WINDOWS
#define OS_WINDOWS 1 #define OS_WINDOWS 1
#else #else
#error "TODO: find llvm-mt" String8 mt_path = str8_lit("llvm-mt.exe");
#endif #endif
return mt_path; return mt_path;
} }
@@ -791,7 +813,7 @@ lnk_print_help(void)
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
fprintf(stdout, "--- Help -------------------------------------------------------\n"); fprintf(stdout, "--- Help -------------------------------------------------------\n");
fprintf(stdout, " %s\n", BUILD_VERSION_STRING); fprintf(stdout, " %s\n", BUILD_TITLE);
fprintf(stdout, "\n"); fprintf(stdout, "\n");
fprintf(stdout, " Usage: rad-link.exe [Options] [Files] [@rsp]\n"); fprintf(stdout, " Usage: rad-link.exe [Options] [Files] [@rsp]\n");
fprintf(stdout, "\n"); fprintf(stdout, "\n");
@@ -828,6 +850,39 @@ lnk_print_help(void)
//////////////////////////////// ////////////////////////////////
internal String8
lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
for (U64 i = 0; i < string.size; ) {
U64 open = str8_find_needle(string, i, str8_lit("%"), 0);
U64 close = str8_find_needle(string, open+1, str8_lit("%"), 0);
String8 text = str8_substr(string, rng_1u64(i, open));
str8_list_push(scratch.arena, &list, text);
i += text.size;
if (open < close) {
String8 env_var_name = str8_substr(string, rng_1u64(open+1, close));
KeyValuePair *match = hash_table_search_path(env_vars, env_var_name);
if (match) {
str8_list_push(scratch.arena, &list, match->value_string);
i = close+1;
} else {
str8_list_pushf(scratch.arena, &list, "%%%S", env_var_name);
i = close;
}
}
}
String8 result = str8_list_join(arena, &list, 0);
scratch_end(scratch);
return result;
}
internal LNK_Config * internal LNK_Config *
lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
{ {
@@ -836,25 +891,21 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
// parse command line // parse command line
String8List unwrapped_cmd_line = lnk_unwrap_rsp(scratch.arena, raw_cmd_line); String8List unwrapped_cmd_line = lnk_unwrap_rsp(scratch.arena, raw_cmd_line);
LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line); LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line);
// setup default flags // setup default flags
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4));
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FileAlign, "%u", 512); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FileAlign, "%u", 512);
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Fixed)) {
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_DynamicBase, "");
}
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) {
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI)); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI));
} }
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Heap, "%u,%u", MB(1), KB(4));
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, "");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\"");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, "");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, "");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4)); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4));
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Stack, "%u,%u", MB(1), KB(1));
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix()); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix());
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1);
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "");
@@ -870,17 +921,18 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SectVirtOff, "0x1000"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SectVirtOff, "0x1000");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count);
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Manifest, "embed");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows");
//lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapDefined, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapDefined, "0x3ffff");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapInternal, "0x1000"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapInternal, "0x1000");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DeleteManifest, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%");
#if !BUILD_DEBUG #if BUILD_DEBUG
//lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "37"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug");
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write");
#else
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "%u", LNK_Error_InvalidTypeIndex);
#endif #endif
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_MtPath)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_MtPath)) {
@@ -888,9 +940,17 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MtPath, "%S", mt_path); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MtPath, "%S", mt_path);
} }
LNK_Config *config = push_array(arena, LNK_Config, 1); LNK_Config *config = push_array(arena, LNK_Config, 1);
config->raw_cmd_line = raw_cmd_line; config->raw_cmd_line = raw_cmd_line;
config->work_dir = os_get_current_path(scratch.arena); config->work_dir = os_get_current_path(arena);
config->build_imp_lib = 1;
config->build_exp = 1;
config->heap_reserve = MB(1);
config->heap_commit = KB(1);
config->stack_reserve = MB(1);
config->stack_commit = KB(1);
config->pdb_hash_type_names = LNK_TypeNameHashMode_None;
config->pdb_hash_type_name_length = 8;
// process command line switches // process command line switches
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) {
@@ -967,6 +1027,9 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
if (debug_mode == LNK_DebugMode_GHash) { if (debug_mode == LNK_DebugMode_GHash) {
config->debug_mode = LNK_DebugMode_Full; config->debug_mode = LNK_DebugMode_Full;
lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "GHASH is not supported, switching to FULL"); lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "GHASH is not supported, switching to FULL");
} else if (debug_mode == LNK_DebugMode_FastLink) {
config->debug_mode = LNK_DebugMode_Full;
lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "FASTLINK is not supported, switching to FULL");
} else if (debug_mode != LNK_DebugMode_Null) { } else if (debug_mode != LNK_DebugMode_Null) {
config->debug_mode = debug_mode; config->debug_mode = debug_mode;
} else { } else {
@@ -1135,30 +1198,23 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
if (param_arr.count > 0) { if (param_arr.count > 0) {
if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) { if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) {
config->manifest_opt = LNK_ManifestOpt_Embed; config->manifest_opt = LNK_ManifestOpt_Embed;
if (config->delete_manifest == LNK_SwitchState_Null) {
config->delete_manifest = 1;
}
if (param_arr.count == 1) { if (param_arr.count == 1) {
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { config->manifest_resource_id = 0;
config->manifest_resource_id = 2;
} else {
config->manifest_resource_id = 1;
}
} else if (param_arr.count > 1) { } else if (param_arr.count > 1) {
// parse resource id // parse resource id
if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) {
String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0);
String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list);
if (res_id_arr.count == 2) { if (res_id_arr.count == 2) {
U64 resource_id; U64 resource_id;
if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) { if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) {
config->manifest_resource_id = resource_id; config->manifest_resource_id = push_u64(arena, resource_id);
} else { } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]); lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]);
} }
} else { } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=resource_id but got \"%S\"", param_arr.v[1]); lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=# but got \"%S\"", param_arr.v[1]);
} }
} else { } else {
lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]);
@@ -1175,13 +1231,19 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch);
} }
} else if (cmd->value_strings.node_count == 0) { } else if (cmd->value_strings.node_count == 0) {
config->manifest_opt = LNK_ManifestOpt_Embed; config->manifest_opt = LNK_ManifestOpt_WriteToFile;
} else {
lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch);
} }
} break; } break;
case LNK_CmdSwitch_ManifestDependency: { case LNK_CmdSwitch_ManifestDependency: {
String8List manifest_dependency_list = str8_list_copy(arena, &cmd->value_strings); String8List manifest_dependency_list = str8_list_copy(arena, &cmd->value_strings);
str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list); str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list);
if (config->manifest_opt == LNK_ManifestOpt_Null) {
config->manifest_opt = LNK_ManifestOpt_WriteToFile;
}
} break; } break;
case LNK_CmdSwitch_ManifestFile: { case LNK_CmdSwitch_ManifestFile: {
@@ -1262,8 +1324,20 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
} break; } break;
case LNK_CmdSwitch_NoDefaultLib: { case LNK_CmdSwitch_NoDefaultLib: {
String8List no_default_lib_list = str8_list_copy(arena, &cmd->value_strings); if (cmd->value_strings.node_count == 0) {
str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list); config->no_default_libs = 1;
} else {
String8List no_default_lib_list = str8_list_copy(arena, &cmd->value_strings);
str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list);
}
} break;
case LNK_CmdSwitch_NoExp: {
config->build_exp = 0;
} break;
case LNK_CmdSwitch_NoImpLib: {
config->build_imp_lib = 0;
} break; } break;
case LNK_CmdSwitch_NoLogo: { case LNK_CmdSwitch_NoLogo: {
@@ -1316,6 +1390,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_name); lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_name);
} break; } break;
case LNK_CmdSwitch_PdbAltPath: {
// see :PdbAltPath
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_alt_path);
} break;
case LNK_CmdSwitch_PdbPageSize: { case LNK_CmdSwitch_PdbPageSize: {
U64 page_size; U64 page_size;
if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &page_size, LNK_ParseU64Flag_CheckPow2)) { if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &page_size, LNK_ParseU64Flag_CheckPow2)) {
@@ -1412,17 +1491,18 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->rad_debug); lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->rad_debug);
} break; } break;
case LNK_CmdSwitch_Rad_DebugName: { case LNK_CmdSwitch_Rad_DebugName: {
// :Rad_DebugAltPath
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_name); lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_name);
} break; } break;
case LNK_CmdSwitch_Rad_DebugAltPath: {
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_alt_path);
} break;
case LNK_CmdSwitch_Rad_DelayBind: { case LNK_CmdSwitch_Rad_DelayBind: {
lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_DelayBind); lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_DelayBind);
} break; } break;
case LNK_CmdSwitch_Rad_DeleteManifest: {
lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->delete_manifest);
} break;
case LNK_CmdSwitch_Rad_DoMerge: { case LNK_CmdSwitch_Rad_DoMerge: {
lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Merge); lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Merge);
} break; } break;
@@ -1442,8 +1522,8 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
} else if (str8_match(cmd->value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) { } else if (str8_match(cmd->value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) {
config->guid = os_make_guid(); config->guid = os_make_guid();
} else { } else {
OS_Guid guid; Guid guid;
if (os_try_guid_from_string(cmd->value_strings.first->string, &guid)) { if (try_guid_from_string(cmd->value_strings.first->string, &guid)) {
config->guid = guid; config->guid = guid;
} else { } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse \"%S\"", cmd->value_strings.first->string); lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse \"%S\"", cmd->value_strings.first->string);
@@ -1454,6 +1534,10 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
} }
} break; } break;
case LNK_CmdSwitch_Rad_IdleWorkers: {
lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->idle_worker_count, 0);
} break;
case LNK_CmdSwitch_Rad_LargePages: { case LNK_CmdSwitch_Rad_LargePages: {
if (cmd->value_strings.node_count == 0) { if (cmd->value_strings.node_count == 0) {
OS_ProcessInfo *process_info = os_get_process_info(); OS_ProcessInfo *process_info = os_get_process_info();
@@ -1497,6 +1581,9 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) { for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) {
lnk_set_log_status((LNK_LogType)ilog, 1); lnk_set_log_status((LNK_LogType)ilog, 1);
} }
} else if (str8_match(cmd->value_strings.first->string, str8_lit("io"), StringMatchFlag_CaseInsensitive)) {
lnk_set_log_status(LNK_Log_IO_Read, 1);
lnk_set_log_status(LNK_Log_IO_Write, 1);
} else { } else {
LNK_LogType log_type = lnk_log_type_from_string(cmd->value_strings.first->string); LNK_LogType log_type = lnk_log_type_from_string(cmd->value_strings.first->string);
if (log_type == LNK_Log_Null) { if (log_type == LNK_Log_Null) {
@@ -1535,6 +1622,30 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
} }
} break; } break;
case LNK_CmdSwitch_Rad_PdbHashTypeNames: {
String8 mode_string = str8_list_first(&cmd->value_strings);
LNK_TypeNameHashMode mode;
if (mode_string.size == 0) {
config->pdb_hash_type_names = LNK_TypeNameHashMode_Lenient;
} else {
mode = lnk_type_name_hash_mode_from_string(mode_string);
if (mode == LNK_TypeNameHashMode_Null) {
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter: \"%S\"", mode_string);
} else {
config->pdb_hash_type_names = mode;
}
}
} break;
case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: {
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_map);
} break;
case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: {
lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_length, 0);
} break;
case LNK_CmdSwitch_Rad_SectVirtOff: { case LNK_CmdSwitch_Rad_SectVirtOff: {
U64 sect_virt_off; U64 sect_virt_off;
if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &sect_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) { if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &sect_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) {
@@ -1609,16 +1720,19 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
} }
} }
// apply idle workers switch
if (config->idle_worker_count > 0) {
if (config->idle_worker_count < config->worker_count) {
U64 final_worker_count = config->worker_count - config->idle_worker_count;
config->worker_count = final_worker_count;
} else {
lnk_error_cmd_switch(LNK_Warning_Cmdl, LNK_CmdSwitch_Rad_IdleWorkers, "idle worker count %u exceeds total worker count %u", config->idle_worker_count, config->worker_count);
}
}
// :manifest_input // :manifest_input
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestInput)) { if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestInput)) {
switch (config->manifest_opt) { if (config->manifest_opt == LNK_ManifestOpt_Embed) {
case LNK_ManifestOpt_Null: {
lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED");
} break;
case LNK_ManifestOpt_No: {
lnk_error_cmd_switch(LNK_Warning_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED, ignoring inputs");
} break;
case LNK_ManifestOpt_Embed: {
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) {
LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd->string); LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd->string);
if (cmd_switch == LNK_CmdSwitch_ManifestInput) { if (cmd_switch == LNK_CmdSwitch_ManifestInput) {
@@ -1626,7 +1740,17 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
str8_list_concat_in_place(&config->input_list[LNK_Input_Manifest], &manifest_list); str8_list_concat_in_place(&config->input_list[LNK_Input_Manifest], &manifest_list);
} }
} }
} break; } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED");
}
}
// set default manifest resource id
if (config->manifest_resource_id == 0) {
if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
config->manifest_resource_id = push_u64(arena, 2);
} else {
config->manifest_resource_id = push_u64(arena, 1);
} }
} }
@@ -1658,27 +1782,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
config->flags &= ~LNK_ConfigFlag_DelayBind; config->flags &= ~LNK_ConfigFlag_DelayBind;
} }
// gather lib paths from enviroment string
if (config->flags & LNK_ConfigFlag_EnvLib) {
#if OS_WINDOWS
OS_ProcessInfo *process_info = os_get_process_info();
for (String8Node *node = process_info->environment.first; node != 0; node = node->next) {
String8List var_list = str8_split_by_string_chars(scratch.arena, node->string, str8_lit("="), 0);
if (var_list.node_count != 2) {
continue;
}
String8 key = var_list.first->string;
String8 val = var_list.last->string;
if (str8_match(key, str8_lit("Lib"), StringMatchFlag_CaseInsensitive) ||
str8_match(key, str8_lit("LibPath"), StringMatchFlag_CaseInsensitive)) {
String8List val_list = str8_split_by_string_chars(scratch.arena, val, str8_lit(";"), 0);
String8List val_list_copy = str8_list_copy(arena, &val_list);
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy);
}
}
#endif
}
// set flags for /OPT // set flags for /OPT
{ {
// these flags remove and merge inline functions and methods defined in class, // these flags remove and merge inline functions and methods defined in class,
@@ -1720,6 +1823,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
config->file_characteristics |= PE_ImageFileCharacteristic_STRIPPED; config->file_characteristics |= PE_ImageFileCharacteristic_STRIPPED;
config->dll_characteristics &= ~PE_DllCharacteristic_DYNAMIC_BASE; config->dll_characteristics &= ~PE_DllCharacteristic_DYNAMIC_BASE;
} }
// if we don't have a fixed image and dynamic base switch
// was omitted we make image with dynamic base
else if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_DynamicBase)) {
config->dll_characteristics |= PE_DllCharacteristic_DYNAMIC_BASE;
}
// set flag for /guard // set flag for /guard
if (config->guard_flags != LNK_Guard_None) { if (config->guard_flags != LNK_Guard_None) {
@@ -1732,31 +1840,83 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe"); String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe");
config->image_name = make_file_path_with_ext(scratch.arena, name, ext); config->image_name = make_file_path_with_ext(scratch.arena, name, ext);
} }
config->image_name = os_make_full_path(arena, config->image_name); config->image_name = os_full_path_from_path(arena, config->image_name);
// handle empty /PDB // handle empty /PDB
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) {
config->pdb_name = make_file_path_with_ext(arena, config->image_name, str8_lit("pdb")); config->pdb_name = make_file_path_with_ext(arena, config->image_name, str8_lit("pdb"));
} }
config->pdb_name = os_make_full_path(arena, config->pdb_name); config->pdb_name = os_full_path_from_path(arena, config->pdb_name);
// handle empty /RAD_DEBUG_NAME // handle empty /RAD_DEBUG_NAME
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) {
config->rad_debug_name = make_file_name_with_ext(arena, config->image_name, str8_lit("rdi")); config->rad_debug_name = make_file_name_with_ext(arena, config->image_name, str8_lit("rdi"));
} }
config->rad_debug_name = os_make_full_path(arena, config->rad_debug_name); config->rad_debug_name = os_full_path_from_path(arena, config->rad_debug_name);
// handle empty /IMPLIB // handle empty /IMPLIB
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) {
config->imp_lib_name = make_file_name_with_ext(arena, config->image_name, str8_lit("lib")); config->imp_lib_name = make_file_name_with_ext(arena, config->image_name, str8_lit("lib"));
} }
config->imp_lib_name = os_make_full_path(arena, config->imp_lib_name); config->imp_lib_name = os_full_path_from_path(arena, config->imp_lib_name);
// handle empty /MANIFESTFILE // handle empty /MANIFESTFILE
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestFile)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestFile)) {
config->manifest_name = make_file_path_with_ext(arena, config->image_name, str8_lit("manifest")); config->manifest_name = push_str8f(arena, "%S.manifest", config->image_name);
} }
// collect env vars
HashTable *env_vars = hash_table_init(scratch.arena, 512);
{
#if OS_WINDOWS
OS_ProcessInfo *process_info = os_get_process_info();
for (String8Node *node = process_info->environment.first; node != 0; node = node->next) {
String8List list = str8_split_by_string_chars(scratch.arena, node->string, str8_lit("="), 0);
String8 key = list.first->string;
String8 val = str8_zero();
if (list.node_count == 2) {
val = list.last->string;
} else if (list.node_count > 2) {
U64 sep_idx = str8_find_needle(node->string, node->string.size, str8_lit("="), 0);
val = str8_skip(node->string, sep_idx+1);
}
hash_table_push_path_string(scratch.arena, env_vars, key, val);
}
#endif
}
// define linker env vars
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_pdb"), str8_skip_last_slash(config->pdb_name));
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_ext"), str8_skip_last_dot(config->image_name));
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_pdb_path"), config->pdb_name);
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi"), str8_skip_last_slash(config->rad_debug_name));
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi_path"), config->rad_debug_name);
// collect LIB and LIBPATH
if (config->flags & LNK_ConfigFlag_EnvLib) {
KeyValuePair *lib = hash_table_search_path(env_vars, str8_lit("lib"));
if (lib) {
String8List val_list = str8_split_by_string_chars(scratch.arena, lib->value_string, str8_lit(";"), 0);
String8List val_list_copy = str8_list_copy(arena, &val_list);
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy);
}
KeyValuePair *lib_path = hash_table_search_path(env_vars, str8_lit("libpath"));
if (lib_path) {
String8List val_list = str8_split_by_string_chars(scratch.arena, lib->value_string, str8_lit(";"), 0);
String8List val_list_copy = str8_list_copy(arena, &val_list);
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy);
}
}
// :PdbAltPath
config->pdb_alt_path = lnk_expand_env_vars_windows(arena, env_vars, config->pdb_alt_path);
// :Rad_DebugAltPath
config->rad_debug_alt_path = lnk_expand_env_vars_windows(arena, env_vars, config->rad_debug_alt_path);
if (lnk_get_log_status(LNK_Log_Debug)) { if (lnk_get_log_status(LNK_Log_Debug)) {
String8 full_cmd_line = str8_list_join(scratch.arena, &raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") }); String8 full_cmd_line = str8_list_join(scratch.arena, &raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") });
lnk_log(LNK_Log_Debug, "--------------------------------------------------------------------------------"); lnk_log(LNK_Log_Debug, "--------------------------------------------------------------------------------");
@@ -1777,10 +1937,8 @@ lnk_build_config(Arena *arena, int argc, char **argv)
String8List raw_cmd_line = os_string_list_from_argcv(arena, argc, argv); String8List raw_cmd_line = os_string_list_from_argcv(arena, argc, argv);
#if OS_WINDOWS
// remove exe name first argument // remove exe name first argument
str8_list_pop_front(&raw_cmd_line); str8_list_pop_front(&raw_cmd_line);
#endif
// init config // init config
LNK_Config *config = lnk_config_from_cmd_line(arena, raw_cmd_line); LNK_Config *config = lnk_config_from_cmd_line(arena, raw_cmd_line);
+34 -11
View File
@@ -42,11 +42,14 @@ typedef enum
LNK_CmdSwitch_ManifestUac, LNK_CmdSwitch_ManifestUac,
LNK_CmdSwitch_Natvis, LNK_CmdSwitch_Natvis,
LNK_CmdSwitch_NoDefaultLib, LNK_CmdSwitch_NoDefaultLib,
LNK_CmdSwitch_NoExp,
LNK_CmdSwitch_NoImpLib,
LNK_CmdSwitch_NoLogo, LNK_CmdSwitch_NoLogo,
LNK_CmdSwitch_NxCompat, LNK_CmdSwitch_NxCompat,
LNK_CmdSwitch_Opt, LNK_CmdSwitch_Opt,
LNK_CmdSwitch_Out, LNK_CmdSwitch_Out,
LNK_CmdSwitch_Pdb, LNK_CmdSwitch_Pdb,
LNK_CmdSwitch_PdbAltPath,
LNK_CmdSwitch_PdbPageSize, LNK_CmdSwitch_PdbPageSize,
LNK_CmdSwitch_Stack, LNK_CmdSwitch_Stack,
LNK_CmdSwitch_SubSystem, LNK_CmdSwitch_SubSystem,
@@ -95,8 +98,6 @@ typedef enum
LNK_CmdSwitch_Midl, LNK_CmdSwitch_Midl,
LNK_CmdSwitch_NoAssembly, LNK_CmdSwitch_NoAssembly,
LNK_CmdSwitch_NoEntry, LNK_CmdSwitch_NoEntry,
LNK_CmdSwitch_NoExp,
LNK_CmdSwitch_NoImpLib,
LNK_CmdSwitch_Order, LNK_CmdSwitch_Order,
LNK_CmdSwitch_PdbStripped, LNK_CmdSwitch_PdbStripped,
LNK_CmdSwitch_Profile, LNK_CmdSwitch_Profile,
@@ -122,12 +123,13 @@ typedef enum
LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll,
LNK_CmdSwitch_Rad_Debug, LNK_CmdSwitch_Rad_Debug,
LNK_CmdSwitch_Rad_DebugName, LNK_CmdSwitch_Rad_DebugName,
LNK_CmdSwitch_Rad_DebugAltPath,
LNK_CmdSwitch_Rad_DelayBind, LNK_CmdSwitch_Rad_DelayBind,
LNK_CmdSwitch_Rad_DeleteManifest,
LNK_CmdSwitch_Rad_DoMerge, LNK_CmdSwitch_Rad_DoMerge,
LNK_CmdSwitch_Rad_EnvLib, LNK_CmdSwitch_Rad_EnvLib,
LNK_CmdSwitch_Rad_Exe, LNK_CmdSwitch_Rad_Exe,
LNK_CmdSwitch_Rad_Guid, LNK_CmdSwitch_Rad_Guid,
LNK_CmdSwitch_Rad_IdleWorkers,
LNK_CmdSwitch_Rad_LargePages, LNK_CmdSwitch_Rad_LargePages,
LNK_CmdSwitch_Rad_LinkVer, LNK_CmdSwitch_Rad_LinkVer,
LNK_CmdSwitch_Rad_Log, LNK_CmdSwitch_Rad_Log,
@@ -136,6 +138,9 @@ typedef enum
LNK_CmdSwitch_Rad_OsVer, LNK_CmdSwitch_Rad_OsVer,
LNK_CmdSwitch_Rad_PageSize, LNK_CmdSwitch_Rad_PageSize,
LNK_CmdSwitch_Rad_PathStyle, LNK_CmdSwitch_Rad_PathStyle,
LNK_CmdSwitch_Rad_PdbHashTypeNames,
LNK_CmdSwitch_Rad_PdbHashTypeNameMap,
LNK_CmdSwitch_Rad_PdbHashTypeNameLength,
LNK_CmdSwitch_Rad_SectVirtOff, LNK_CmdSwitch_Rad_SectVirtOff,
LNK_CmdSwitch_Rad_SuppressError, LNK_CmdSwitch_Rad_SuppressError,
LNK_CmdSwitch_Rad_SymbolTableCapDefined, LNK_CmdSwitch_Rad_SymbolTableCapDefined,
@@ -205,8 +210,9 @@ typedef U32 LNK_GuardFlags;
typedef enum typedef enum
{ {
LNK_ManifestOpt_Null, LNK_ManifestOpt_Null,
LNK_ManifestOpt_WriteToFile,
LNK_ManifestOpt_Embed, LNK_ManifestOpt_Embed,
LNK_ManifestOpt_No LNK_ManifestOpt_No,
} LNK_ManifestOpt; } LNK_ManifestOpt;
typedef struct LNK_AltNameList typedef struct LNK_AltNameList
@@ -221,6 +227,14 @@ typedef enum
Lnk_DebugInfoGuid_ImageBlake3, Lnk_DebugInfoGuid_ImageBlake3,
} LNK_DebugInfoGuidType; } LNK_DebugInfoGuidType;
typedef enum
{
LNK_TypeNameHashMode_Null,
LNK_TypeNameHashMode_None,
LNK_TypeNameHashMode_Lenient,
LNK_TypeNameHashMode_Full,
} LNK_TypeNameHashMode;
typedef struct LNK_Config typedef struct LNK_Config
{ {
LNK_ConfigFlags flags; LNK_ConfigFlags flags;
@@ -231,7 +245,7 @@ typedef struct LNK_Config
U64 opt_iter_count; U64 opt_iter_count;
LNK_GuardFlags guard_flags; LNK_GuardFlags guard_flags;
LNK_DebugInfoGuidType guid_type; LNK_DebugInfoGuidType guid_type;
OS_Guid guid; Guid guid;
COFF_TimeStamp time_stamp; COFF_TimeStamp time_stamp;
U32 age; U32 age;
U64 section_virt_off; U64 section_virt_off;
@@ -246,8 +260,10 @@ typedef struct LNK_Config
U64 page_size; U64 page_size;
U64 pdb_page_size; U64 pdb_page_size;
U64 worker_count; U64 worker_count;
U64 idle_worker_count;
U64 function_pad_min; U64 function_pad_min;
U64 manifest_resource_id; U64 *manifest_resource_id;
B32 no_default_libs;
Version link_ver; Version link_ver;
Version os_ver; Version os_ver;
Version image_ver; Version image_ver;
@@ -267,13 +283,16 @@ typedef struct LNK_Config
String8 imp_lib_name; String8 imp_lib_name;
String8List raw_cmd_line; String8List raw_cmd_line;
String8 pdb_name; String8 pdb_name;
String8 pdb_alt_path;
String8 mt_path; String8 mt_path;
LNK_TypeNameHashMode pdb_hash_type_names;
String8 pdb_hash_type_name_map;
U64 pdb_hash_type_name_length;
String8List input_list[LNK_Input_Count]; String8List input_list[LNK_Input_Count];
String8List input_default_lib_list; String8List input_default_lib_list;
String8List disallow_lib_list; String8List disallow_lib_list;
String8List delay_load_dll_list; String8List delay_load_dll_list;
String8List natvis_list; String8List natvis_list;
LNK_SwitchState delete_manifest;
String8 manifest_name; String8 manifest_name;
B32 manifest_uac; B32 manifest_uac;
String8 manifest_level; String8 manifest_level;
@@ -281,12 +300,15 @@ typedef struct LNK_Config
String8List manifest_dependency_list; String8List manifest_dependency_list;
LNK_SwitchState rad_debug; LNK_SwitchState rad_debug;
String8 rad_debug_name; String8 rad_debug_name;
String8 rad_debug_alt_path;
String8List include_symbol_list; String8List include_symbol_list;
LNK_AltNameList alt_name_list; LNK_AltNameList alt_name_list;
U64 symbol_table_cap_defined; U64 symbol_table_cap_defined;
U64 symbol_table_cap_internal; U64 symbol_table_cap_internal;
U64 symbol_table_cap_weak; U64 symbol_table_cap_weak;
U64 symbol_table_cap_lib; U64 symbol_table_cap_lib;
B32 build_imp_lib;
B32 build_exp;
} LNK_Config; } LNK_Config;
typedef enum typedef enum
@@ -425,10 +447,11 @@ typedef enum
//////////////////////////////// ////////////////////////////////
// Enum <-> String // Enum <-> String
internal String8 lnk_string_cmd_switch_type(LNK_CmdSwitchType type); internal String8 lnk_string_cmd_switch_type(LNK_CmdSwitchType type);
internal LNK_CmdSwitchType lnk_cmd_switch_from_string(String8 string); internal LNK_CmdSwitchType lnk_cmd_switch_from_string(String8 string);
internal LNK_InputType lnk_input_type_from_string(String8 string); internal LNK_InputType lnk_input_type_from_string(String8 string);
internal LNK_DebugMode lnk_debug_mode_from_string(String8 string); internal LNK_DebugMode lnk_debug_mode_from_string(String8 string);
internal LNK_TypeNameHashMode lnk_type_name_hash_mode_from_string(String8 string);
//////////////////////////////// ////////////////////////////////
// Command Line Helpers // Command Line Helpers
+257 -49
View File
@@ -382,9 +382,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
ProfEnd(); ProfEnd();
if (lnk_get_log_status(LNK_Log_Debug) || PROFILE_TELEMETRY) { if (lnk_get_log_status(LNK_Log_Debug) || PROFILE_TELEMETRY) {
U64 total_debug_s_size = 0; U64 total_debug_s_size = 0, total_debug_t_size = 0, total_debug_p_size = 0;
U64 total_debug_t_size = 0;
U64 total_debug_p_size = 0;
for (U64 obj_idx = 0; obj_idx < obj_count; ++obj_idx) { for (U64 obj_idx = 0; obj_idx < obj_count; ++obj_idx) {
for (LNK_ChunkNode *chunk = debug_s_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) { for (LNK_ChunkNode *chunk = debug_s_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
total_debug_s_size += chunk->data->u.leaf.size; total_debug_s_size += chunk->data->u.leaf.size;
@@ -396,19 +394,16 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
total_debug_p_size += chunk->data->u.leaf.size; total_debug_p_size += chunk->data->u.leaf.size;
} }
} }
String8 total_debug_s_size_string = str8_from_memory_size2(scratch.arena, total_debug_s_size);
String8 total_debug_t_size_string = str8_from_memory_size2(scratch.arena, total_debug_t_size); ProfNoteV("Total .debug$S Input Size: %M", total_debug_s_size);
String8 total_debug_p_size_string = str8_from_memory_size2(scratch.arena, total_debug_p_size); ProfNoteV("Total .debug$T Input Size: %M", total_debug_t_size);
ProfNoteV("Total .debug$P Input Size: %M", total_debug_p_size);
if (lnk_get_log_status(LNK_Log_Debug)) { if (lnk_get_log_status(LNK_Log_Debug)) {
lnk_log(LNK_Log_Debug, "[Total .debug$S Input Size %S]", total_debug_s_size_string); lnk_log(LNK_Log_Debug, "[Total .debug$S Input Size %M]", total_debug_s_size);
lnk_log(LNK_Log_Debug, "[Total .debug$T Input Size %S]", total_debug_t_size_string); lnk_log(LNK_Log_Debug, "[Total .debug$T Input Size %M]", total_debug_t_size);
lnk_log(LNK_Log_Debug, "[Total .debug$P Input Size %S]", total_debug_p_size_string); lnk_log(LNK_Log_Debug, "[Total .debug$P Input Size %M]", total_debug_p_size);
} }
#if PROFILE_TELEMETRY
tmMessage(0, TMMF_ICON_NOTE, "Total .debug$S Input Size: %.*s", str8_varg(total_debug_s_size_string));
tmMessage(0, TMMF_ICON_NOTE, "Total .debug$T Input Size: %.*s", str8_varg(total_debug_t_size_string));
tmMessage(0, TMMF_ICON_NOTE, "Total .debug$P Input Size: %.*s", str8_varg(total_debug_p_size_string));
#endif
} }
// TODO: temp hack, remove when we have null obj with .debug$T // TODO: temp hack, remove when we have null obj with .debug$T
@@ -579,14 +574,14 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
CV_TypeServerInfo ts = cv_type_server_info_from_leaf(leaf); CV_TypeServerInfo ts = cv_type_server_info_from_leaf(leaf);
// search disk for type server // search disk for type server
String8List match_list = os_file_search(scratch.arena, lib_dir_list, ts.name); String8List match_list = lnk_file_search(scratch.arena, lib_dir_list, ts.name);
// chop file name from path and search on it // chop file name from path and search on it
// //
// TODO: check if ts.name is a path and in that case do file search // TODO: check if ts.name is a path and in that case do file search
if (match_list.node_count == 0) { if (match_list.node_count == 0) {
String8 file_name = str8_skip_last_slash(ts.name); String8 file_name = str8_skip_last_slash(ts.name);
match_list = os_file_search(scratch.arena, lib_dir_list, file_name); match_list = lnk_file_search(scratch.arena, lib_dir_list, file_name);
} }
B32 do_debug_info_discard = 0; B32 do_debug_info_discard = 0;
@@ -690,7 +685,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
// read type servers from disk in parallel // read type servers from disk in parallel
{ {
ProfBegin("Read External Type Servers"); ProfBegin("Read External Type Servers");
String8Array msf_data_arr = os_data_from_file_path_parallel(tp, scratch.arena, ts_path_arr); String8Array msf_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, ts_path_arr);
ProfEnd(); ProfEnd();
MSF_Parsed **msf_parse_arr = lnk_msf_parsed_from_data_parallel(tp_arena, tp, msf_data_arr); MSF_Parsed **msf_parse_arr = lnk_msf_parsed_from_data_parallel(tp_arena, tp, msf_data_arr);
@@ -708,8 +703,8 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
pdb_info_parse_from_data(msf_parse->streams[PDB_FixedStream_Info], &info_parse); pdb_info_parse_from_data(msf_parse->streams[PDB_FixedStream_Info], &info_parse);
if (!MemoryMatchStruct(&info_parse.guid, &ts_info_arr[ts_idx].sig)) { if (!MemoryMatchStruct(&info_parse.guid, &ts_info_arr[ts_idx].sig)) {
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
String8 expected_sig_str = os_string_from_guid(scratch.arena, ts_info_arr[ts_idx].sig); String8 expected_sig_str = string_from_guid(scratch.arena, ts_info_arr[ts_idx].sig);
String8 on_disk_sig_str = os_string_from_guid(scratch.arena, info_parse.guid); String8 on_disk_sig_str = string_from_guid(scratch.arena, info_parse.guid);
lnk_error(LNK_Warning_MismatchedTypeServerSignature, "%S: signature mismatch in type server read from disk, expected %S, got %S", lnk_error(LNK_Warning_MismatchedTypeServerSignature, "%S: signature mismatch in type server read from disk, expected %S, got %S",
ts_info_arr[ts_idx].name, expected_sig_str, on_disk_sig_str); ts_info_arr[ts_idx].name, expected_sig_str, on_disk_sig_str);
scratch_end(scratch); scratch_end(scratch);
@@ -2476,6 +2471,211 @@ lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input)
return types; return types;
} }
internal U64
lnk_format_u128(U8 *buf, U64 buf_max, U64 length, U128 v)
{
U64 size = 0;
if (length > 0 && buf_max > 0) {
if (length <= 8) {
U64 mask = length == 8 ? max_U64 : (1ull << (length*8)) - 1;
size = raddbg_snprintf((char*)buf, buf_max - 1, "%llX", (long long)(v.u64[0] & mask));
} else {
U64 mask1 = length == 16 ? max_U64 : (1ull << ((length-8)*8)) - 1;
size = raddbg_snprintf((char*)buf, buf_max, "%llX%llX", (long long)(v.u64[1] & mask1), (long long)v.u64[0]);
}
}
return size;
}
internal
THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task)
{
ProfBeginFunction();
LNK_TypeNameReplacer *task = raw_task;
Rng1U64 range = task->ranges[task_id];
CV_DebugT debug_t = task->debug_t;
U64 hash_length = task->hash_length;
B32 make_map = task->make_map;
Arena *map_arena = 0;
String8List *map = 0;
if (make_map) {
map_arena = task->map_arena->v[task_id];
map = &task->maps[task_id];
}
U64 hash_max_chars = hash_length;
U8 temp[128];
for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) {
CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx);
if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) {
CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data);
if (udt_info.props & CV_TypeProp_HasUniqueName && udt_info.unique_name.size > hash_max_chars) {
// hash unique name
U128 name_hash;
blake3_hasher hasher; blake3_hasher_init(&hasher);
blake3_hasher_update(&hasher, udt_info.unique_name.str, udt_info.unique_name.size);
blake3_hasher_finalize(&hasher, (U8*)&name_hash, sizeof(name_hash));
// emit hash -> unique name map
if (make_map) {
lnk_format_u128(temp, sizeof(temp), hash_length, name_hash);
str8_list_pushf(map_arena, map, "%s %.*s\n", temp, str8_varg(udt_info.unique_name));
}
// parse leaf size
CV_NumericParsed dummy;
U64 numeric_size = cv_read_numeric(leaf.data, sizeof(CV_LeafStruct), &dummy);
U64 colon_pos = str8_find_needle_reverse(udt_info.name, 0, str8_lit("<lambda_"), 0);
B32 is_lambda = colon_pos != 0;
if (is_lambda) {
// replace display type string with unique type name hash
udt_info.name.size = lnk_format_u128(udt_info.name.str, udt_info.name.size, hash_length, name_hash);
// update leaf header
CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx);
header->size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1;
// discard unique name
CV_LeafStruct *lf = (CV_LeafStruct *)(header + 1);
lf->props &= ~CV_TypeProp_HasUniqueName;
} else {
// replace uniuqe type name with hash
udt_info.unique_name.str = udt_info.name.str + udt_info.name.size + 1;
udt_info.unique_name.size = lnk_format_u128(udt_info.unique_name.str, udt_info.unique_name.size, hash_length, name_hash);
// update leaf header
CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx);
header->size = sizeof(CV_LeafKind) +
sizeof(CV_LeafStruct) +
numeric_size +
udt_info.name.size + 1 +
udt_info.unique_name.size + 1;
}
}
}
}
ProfEnd();
}
internal
THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_full_task)
{
ProfBeginFunction();
LNK_TypeNameReplacer *task = raw_task;
Rng1U64 range = task->ranges[task_id];
CV_DebugT debug_t = task->debug_t;
U64 hash_length = task->hash_length;
B32 make_map = task->make_map;
Arena *map_arena = 0;
String8List *map = 0;
if (make_map) {
map_arena = task->map_arena->v[task_id];
map = &task->maps[task_id];
}
U64 hash_max_chars = hash_length*2;
U8 temp[128];
for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) {
CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx);
if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) {
CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data);
if (udt_info.name.size > hash_max_chars) {
// pick name to hash
String8 name;
if (udt_info.props & CV_TypeProp_HasUniqueName) {
name = udt_info.unique_name;
} else {
name = udt_info.name;
}
// hash name
U128 name_hash;
blake3_hasher hasher; blake3_hasher_init(&hasher);
blake3_hasher_update(&hasher, udt_info.name.str, udt_info.name.size);
blake3_hasher_finalize(&hasher, (U8*)&name_hash, sizeof(name_hash));
// emit hash -> name map
if (make_map) {
lnk_format_u128(temp, sizeof(temp), hash_length, name_hash);
str8_list_pushf(map_arena, map, "%s %.*s\n", temp, str8_varg(name));
}
// replace name with hash
udt_info.name.size = lnk_format_u128(udt_info.name.str, udt_info.name.size, hash_length, name_hash);
// parse struct size
CV_NumericParsed dummy;
U64 numeric_size = cv_read_numeric(leaf.data, sizeof(CV_LeafStruct), &dummy);
// update header
CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx);
header->size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1;
// discard unique name
CV_LeafStruct *lf = (CV_LeafStruct *)(header + 1);
lf->props &= ~CV_TypeProp_HasUniqueName;
}
}
}
ProfEnd();
}
internal void
lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name)
{
ProfBeginFunction();
Temp scratch = scratch_begin(arena->v, arena->count);
// init task context
LNK_TypeNameReplacer task = {0};
task.debug_t = debug_t;
task.ranges = tp_divide_work(scratch.arena, debug_t.count, tp->worker_count);
task.hash_length = Clamp(1, hash_length, 16);
if (map_name.size > 0) {
task.make_map = 1;
task.map_arena = tp_arena_alloc(tp);
task.maps = push_array(scratch.arena, String8List, tp->worker_count);
}
// pick task function
TP_TaskFunc *func = 0;
switch (mode) {
case LNK_TypeNameHashMode_Null:
case LNK_TypeNameHashMode_None:
break;
case LNK_TypeNameHashMode_Lenient: func = lnk_replace_type_names_with_hashes_lenient_task; break;
case LNK_TypeNameHashMode_Full: func = lnk_replace_type_names_with_hashes_full_task; break;
}
// run task
tp_for_parallel(tp, arena, tp->worker_count, func, &task);
// optionally write out map file
if (task.make_map) {
String8List map = {0};
str8_list_concat_in_place_array(&map, task.maps, tp->worker_count);
lnk_write_data_list_to_file_path(map_name, map);
tp_arena_release(&task.map_arena);
}
scratch_end(scratch);
ProfEnd();
}
//////////////////////////////// ////////////////////////////////
// PDB Builder // PDB Builder
@@ -2769,6 +2969,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
PDB_DbiModule *mod = task->mod_arr[obj_idx]; PDB_DbiModule *mod = task->mod_arr[obj_idx];
LNK_Obj *obj = &task->obj_arr[obj_idx]; LNK_Obj *obj = &task->obj_arr[obj_idx];
PDB_DbiSectionContribList *dst_list = &task->sc_list[obj_idx]; PDB_DbiSectionContribList *dst_list = &task->sc_list[obj_idx];
String8 image_data = task->image_data;
// TODO: use chunked lists for SC // TODO: use chunked lists for SC
@@ -2790,7 +2991,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
// query chunk info // query chunk info
ISectOff chunk_sc = lnk_sc_from_chunk_ref (sect_id_map, chunk->ref); ISectOff chunk_sc = lnk_sc_from_chunk_ref (sect_id_map, chunk->ref);
String8 chunk_data = lnk_data_from_chunk_ref (sect_id_map, chunk->ref); String8 chunk_data = lnk_data_from_chunk_ref (sect_id_map, image_data, chunk->ref);
LNK_Section *chunk_sect = lnk_sect_from_chunk_ref (sect_id_map, chunk->ref); LNK_Section *chunk_sect = lnk_sect_from_chunk_ref (sect_id_map, chunk->ref);
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref); U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref);
@@ -2827,20 +3028,23 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
//////////////////////////////// ////////////////////////////////
internal internal
THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_task) THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task)
{ {
U64 bucket_idx = task_id; ProfBeginFunction();
LNK_BuildPublicSymbolsTaskData *task = raw_task;
LNK_Section **sect_id_map = task->sect_id_map; LNK_BuildPublicSymbolsTask *task = raw_task;
LNK_SymbolScopeIndex scope_idx = task->scope_idx; LNK_Section **sect_id_map = task->sect_id_map;
LNK_SymbolList bucket = task->bucket_arr[scope_idx][bucket_idx]; CV_SymbolList *pub_list = &task->pub_list_arr[task_id];
CV_SymbolList *pub_list = &task->pub_list_arr[bucket_idx]; LNK_SymbolHashTrieChunkList chunk_list = task->chunk_lists[task_id];
for (LNK_SymbolNode *symbol_node = bucket.first; symbol_node != 0; symbol_node = symbol_node->next) { for (LNK_SymbolHashTrieChunk *chunk = chunk_list.first; chunk != 0; chunk = chunk->next) {
LNK_Symbol *symbol = symbol_node->data; CV_SymbolNode *nodes = push_array_no_zero(arena, CV_SymbolNode, chunk->count);
for (U64 i = 0, node_idx = 0; i < chunk->count; ++i) {
LNK_Symbol *symbol = chunk->v[i].symbol;
Assert(LNK_Symbol_IsDefined(symbol->type));
if (LNK_Symbol_IsDefined(symbol->type)) {
LNK_DefinedSymbol *defined_symbol = &symbol->u.defined; LNK_DefinedSymbol *defined_symbol = &symbol->u.defined;
if (defined_symbol->value_type == LNK_DefinedSymbolValue_Chunk) { if (defined_symbol->value_type == LNK_DefinedSymbolValue_Chunk) {
CV_Pub32Flags flags = 0; CV_Pub32Flags flags = 0;
@@ -2854,11 +3058,15 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_task)
U32 symbol_off32 = safe_cast_u32(symbol_off); U32 symbol_off32 = safe_cast_u32(symbol_off);
U16 symbol_isect16 = safe_cast_u16(symbol_isect); U16 symbol_isect16 = safe_cast_u16(symbol_isect);
CV_SymbolNode *pub_node = cv_symbol_list_push(arena, pub_list); nodes[node_idx].data = cv_make_pub32(arena, flags, symbol_off32, symbol_isect16, symbol->name);
pub_node->data = cv_make_pub32(arena, flags, symbol_off32, symbol_isect16, symbol->name); cv_symbol_list_push_node(pub_list, &nodes[node_idx]);
++node_idx;
} }
} }
} }
ProfEnd();
} }
internal internal
@@ -2866,8 +3074,8 @@ THREAD_POOL_TASK_FUNC(lnk_gsi_hash_cv_list_task)
{ {
ProfBeginFunction(); ProfBeginFunction();
LNK_BuildPublicSymbolsTaskData *task = raw_task; LNK_BuildPublicSymbolsTask *task = raw_task;
Rng1U64 range = task->symbol_ranges[task_id]; Rng1U64 range = task->symbol_ranges[task_id];
for (U64 symbol_idx = range.min; symbol_idx < range.max; ++symbol_idx) { for (U64 symbol_idx = range.min; symbol_idx < range.max; ++symbol_idx) {
CV_Symbol *symbol = &task->symbols.v[symbol_idx]->data; CV_Symbol *symbol = &task->symbols.v[symbol_idx]->data;
@@ -2883,22 +3091,20 @@ lnk_build_pdb_public_symbols(TP_Context *tp,
TP_Arena *arena, TP_Arena *arena,
LNK_SymbolTable *symtab, LNK_SymbolTable *symtab,
LNK_Section **sect_id_map, LNK_Section **sect_id_map,
PDB_PsiContext *psi, PDB_PsiContext *psi)
LNK_SymbolScopeIndex scope_idx)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(arena->v, arena->count); Temp scratch = scratch_begin(arena->v, arena->count);
ProfBegin("Make Public Symbols"); ProfBegin("Defined");
LNK_BuildPublicSymbolsTaskData task = {0}; LNK_BuildPublicSymbolsTask task = {0};
task.sect_id_map = sect_id_map; task.sect_id_map = sect_id_map;
task.scope_idx = scope_idx; task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count);
task.bucket_arr = symtab->buckets; task.chunk_lists = symtab->chunk_lists[LNK_SymbolScopeIndex_Defined];
task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, symtab->bucket_count[scope_idx]); tp_for_parallel(tp, arena, tp->worker_count, lnk_build_pdb_public_symbols_defined_task, &task);
tp_for_parallel(tp, arena, symtab->bucket_count[scope_idx], lnk_build_pdb_public_symbols_task, &task);
ProfEnd(); ProfEnd();
CV_SymbolPtrArray symbols = cv_symbol_ptr_array_from_list(scratch.arena, tp, symtab->bucket_count[scope_idx], task.pub_list_arr); CV_SymbolPtrArray symbols = cv_symbol_ptr_array_from_list(scratch.arena, tp, tp->worker_count, task.pub_list_arr);
ProfBegin("GSI Push"); ProfBegin("GSI Push");
gsi_push_many_arr(tp, psi->gsi, symbols.count, symbols.v); gsi_push_many_arr(tp, psi->gsi, symbols.count, symbols.v);
@@ -2911,7 +3117,8 @@ lnk_build_pdb_public_symbols(TP_Context *tp,
internal String8List internal String8List
lnk_build_pdb(TP_Context *tp, lnk_build_pdb(TP_Context *tp,
TP_Arena *tp_arena, TP_Arena *tp_arena,
OS_Guid guid, String8 image_data,
Guid guid,
COFF_MachineType machine, COFF_MachineType machine,
COFF_TimeStamp time_stamp, COFF_TimeStamp time_stamp,
U32 age, U32 age,
@@ -3070,8 +3277,8 @@ lnk_build_pdb(TP_Context *tp,
ProfBegin("Build DBI Section Headers"); ProfBegin("Build DBI Section Headers");
{ {
LNK_Symbol *coff_sect_array_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); LNK_Symbol *coff_sect_array_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME);
LNK_Chunk *coff_sect_chunk = lnk_defined_symbol_get_chunk(&coff_sect_array_symbol->u.defined); LNK_Chunk *coff_sect_chunk = lnk_chunk_from_symbol(coff_sect_array_symbol);
String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, coff_sect_chunk->ref); String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, coff_sect_chunk->ref);
U64 coff_sect_count = coff_sect_chunk_data.size / sizeof(COFF_SectionHeader); U64 coff_sect_count = coff_sect_chunk_data.size / sizeof(COFF_SectionHeader);
COFF_SectionHeader *coff_sect_ptr = (COFF_SectionHeader*)coff_sect_chunk_data.str; COFF_SectionHeader *coff_sect_ptr = (COFF_SectionHeader*)coff_sect_chunk_data.str;
for (COFF_SectionHeader *hdr_ptr = &coff_sect_ptr[0], *opl = hdr_ptr + coff_sect_count; for (COFF_SectionHeader *hdr_ptr = &coff_sect_ptr[0], *opl = hdr_ptr + coff_sect_count;
@@ -3089,6 +3296,7 @@ lnk_build_pdb(TP_Context *tp,
task.sect_id_map = sect_id_map; task.sect_id_map = sect_id_map;
task.mod_arr = mod_arr; task.mod_arr = mod_arr;
task.sc_list = push_array(scratch.arena, PDB_DbiSectionContribList, obj_count); task.sc_list = push_array(scratch.arena, PDB_DbiSectionContribList, obj_count);
task.image_data = image_data;
tp_for_parallel(tp, tp_arena, obj_count, lnk_push_dbi_sec_contrib_task, &task); tp_for_parallel(tp, tp_arena, obj_count, lnk_push_dbi_sec_contrib_task, &task);
dbi_sec_list_concat_arr(&pdb->dbi->sec_contrib_list, obj_count, task.sc_list); dbi_sec_list_concat_arr(&pdb->dbi->sec_contrib_list, obj_count, task.sc_list);
@@ -3098,7 +3306,7 @@ lnk_build_pdb(TP_Context *tp,
ProfBegin("Build NatVis"); ProfBegin("Build NatVis");
{ {
String8Array natvis_file_path_arr = str8_array_from_list(scratch.arena, &natvis_list); String8Array natvis_file_path_arr = str8_array_from_list(scratch.arena, &natvis_list);
String8Array natvis_file_data_arr = os_data_from_file_path_parallel(tp, scratch.arena, natvis_file_path_arr); String8Array natvis_file_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, natvis_file_path_arr);
for (U64 i = 0; i < natvis_file_data_arr.count; ++i) { for (U64 i = 0; i < natvis_file_data_arr.count; ++i) {
String8 natvis_file_path = natvis_file_path_arr.v[i]; String8 natvis_file_path = natvis_file_path_arr.v[i];
@@ -3125,7 +3333,7 @@ lnk_build_pdb(TP_Context *tp,
} }
ProfEnd(); ProfEnd();
lnk_build_pdb_public_symbols(tp, tp_arena, symtab, sect_id_map, pdb->psi, LNK_SymbolScopeIndex_Defined); lnk_build_pdb_public_symbols(tp, tp_arena, symtab, sect_id_map, pdb->psi);
pdb_build(tp, tp_arena, pdb, string_ht); pdb_build(tp, tp_arena, pdb, string_ht);
+20 -8
View File
@@ -316,6 +316,7 @@ typedef struct
LNK_Section **sect_id_map; LNK_Section **sect_id_map;
PDB_DbiModule **mod_arr; PDB_DbiModule **mod_arr;
PDB_DbiSectionContribList *sc_list; PDB_DbiSectionContribList *sc_list;
String8 image_data;
} LNK_PushDbiSecContribTaskData; } LNK_PushDbiSecContribTaskData;
typedef struct typedef struct
@@ -333,16 +334,15 @@ typedef struct
typedef struct typedef struct
{ {
LNK_Section **sect_id_map; LNK_Section **sect_id_map;
LNK_SymbolScopeIndex scope_idx; LNK_SymbolHashTrieChunkList *chunk_lists;
LNK_SymbolList **bucket_arr; CV_SymbolList *pub_list_arr;
CV_SymbolList *pub_list_arr;
Rng1U64 *symbol_ranges; Rng1U64 *symbol_ranges;
PDB_GsiContext *gsi; PDB_GsiContext *gsi;
CV_SymbolPtrArray symbols; CV_SymbolPtrArray symbols;
U32 *hashes; U32 *hashes;
} LNK_BuildPublicSymbolsTaskData; } LNK_BuildPublicSymbolsTask;
typedef struct typedef struct
{ {
@@ -368,6 +368,16 @@ typedef struct
CV_SymbolNode **symbol_arr; CV_SymbolNode **symbol_arr;
} LNK_GsiUnbucket; } LNK_GsiUnbucket;
typedef struct
{
CV_DebugT debug_t;
Rng1U64 *ranges;
U64 hash_length;
B32 make_map;
TP_Arena *map_arena;
String8List *maps;
} LNK_TypeNameReplacer;
//////////////////////////////// ////////////////////////////////
// RAD Debug Info // RAD Debug Info
@@ -525,6 +535,8 @@ internal void lnk_patch_leaves(TP_Context *tp, LNK_CodeViewInput
internal String8Node * lnk_copy_raw_leaf_arr_to_type_server(TP_Context *tp, CV_DebugT types, PDB_TypeServer *type_server); internal String8Node * lnk_copy_raw_leaf_arr_to_type_server(TP_Context *tp, CV_DebugT types, PDB_TypeServer *type_server);
internal CV_DebugT * lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input); internal CV_DebugT * lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input);
internal void lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name);
//////////////////////////////// ////////////////////////////////
// RAD Debug info // RAD Debug info
@@ -566,12 +578,12 @@ internal void lnk_build_pdb_public_symbols(TP_Context *tp,
TP_Arena *arena, TP_Arena *arena,
LNK_SymbolTable *symtab, LNK_SymbolTable *symtab,
LNK_Section **sect_id_map, LNK_Section **sect_id_map,
PDB_PsiContext *psi, PDB_PsiContext *psi);
LNK_SymbolScopeIndex scope_idx);
internal String8List lnk_build_pdb(TP_Context *tp, internal String8List lnk_build_pdb(TP_Context *tp,
TP_Arena *tp_arena, TP_Arena *tp_arena,
OS_Guid guid, String8 image_data,
Guid guid,
COFF_MachineType machine, COFF_MachineType machine,
COFF_TimeStamp time_stamp, COFF_TimeStamp time_stamp,
U32 age, U32 age,
+3
View File
@@ -70,6 +70,9 @@ lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 bu
for (U64 i = 0; i < ArrayCount(directive_table); ++i) { for (U64 i = 0; i < ArrayCount(directive_table); ++i) {
if (str8_match(directive_table[i].name, opt->string, StringMatchFlag_CaseInsensitive)) { if (str8_match(directive_table[i].name, opt->string, StringMatchFlag_CaseInsensitive)) {
kind = directive_table[i].kind; kind = directive_table[i].kind;
if (kind == LNK_Directive_Merge) {
String8 v = str8_list_join(scratch.arena, &opt->value_strings, &(StringJoin){ .sep = str8_lit_comp(" ")});
}
break; break;
} }
} }
+6 -3
View File
@@ -28,6 +28,8 @@ typedef enum
LNK_Error_UnsupportedMachine, LNK_Error_UnsupportedMachine,
LNK_Error_Mt, LNK_Error_Mt,
LNK_Error_UnableToSerializeMsf, LNK_Error_UnableToSerializeMsf,
LNK_Error_LoadRes,
LNK_Error_IO,
LNK_Error_StopLast, LNK_Error_StopLast,
LNK_Error_First, LNK_Error_First,
@@ -75,6 +77,7 @@ typedef enum
LNK_Warning_UnusedDelayLoadDll, LNK_Warning_UnusedDelayLoadDll,
LNK_Warning_LongSectionName, LNK_Warning_LongSectionName,
LNK_Warning_UnknownSwitch, LNK_Warning_UnknownSwitch,
LNK_Warning_TLSAlign,
LNK_Warning_Last, LNK_Warning_Last,
LNK_Error_Count LNK_Error_Count
@@ -115,7 +118,7 @@ internal void lnk_suppress_error(LNK_ErrorCode code);
internal LNK_ErrorCodeStatus lnk_get_error_code_status(LNK_ErrorCode code); internal LNK_ErrorCodeStatus lnk_get_error_code_status(LNK_ErrorCode code);
internal void lnk_internal_error(LNK_InternalError code, char *file, int line, char *fmt, ...); internal void lnk_internal_error(LNK_InternalError code, char *file, int line, char *fmt, ...);
#define lnk_invalid_path(fmt, ...) lnk_internal_error(LNK_InternalError_InvalidPath, __FILE__, __LINE__, fmt, __VA_ARGS__) #define lnk_invalid_path(...) lnk_internal_error(LNK_InternalError_InvalidPath, __FILE__, __LINE__, __VA_ARGS__)
#define lnk_not_implemented(fmt, ...) lnk_internal_error(LNK_InternalError_NotImplemented, __FILE__, __LINE__, fmt, __VA_ARGS__) #define lnk_not_implemented(...) lnk_internal_error(LNK_InternalError_NotImplemented, __FILE__, __LINE__, __VA_ARGS__)
#define lnk_incomplete_switch(fmt, ...) lnk_internal_error(LNK_InternalError_IncompleteSwitch, __FILE__, __LINE__, fmt, __VA_ARGS__) #define lnk_incomplete_switch(...) lnk_internal_error(LNK_InternalError_IncompleteSwitch, __FILE__, __LINE__, __VA_ARGS__)
+39 -39
View File
@@ -6,7 +6,7 @@ lnk_export_name_compar(const void *a_, const void *b_)
{ {
const LNK_Export *a = (const LNK_Export *)a_; const LNK_Export *a = (const LNK_Export *)a_;
const LNK_Export *b = (const LNK_Export *)b_; const LNK_Export *b = (const LNK_Export *)b_;
return str8_compar_case_sensetive(&a->name, &b->name); return str8_compar_case_sensitive(&a->name, &b->name);
} }
int int
@@ -23,11 +23,15 @@ lnk_export_table_alloc(void)
{ {
ProfBeginFunction(); ProfBeginFunction();
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
LNK_ExportTable *exptab = push_array(arena, LNK_ExportTable, 1);
exptab->arena = arena; LNK_ExportTable *exptab = push_array(arena, LNK_ExportTable, 1);
exptab->voff_size = sizeof(U32); exptab->arena = arena;
exptab->max_ordinal = max_U16; exptab->voff_size = sizeof(U32);
exptab->is_ordinal_used = push_array(arena, B8, exptab->max_ordinal); exptab->max_ordinal = max_U16;
exptab->is_ordinal_used = push_array(arena, B8, exptab->max_ordinal);
exptab->name_export_ht = hash_table_init(arena, 0x10000);
exptab->noname_export_ht = hash_table_init(arena, 0x100);
ProfEnd(); ProfEnd();
return exptab; return exptab;
} }
@@ -44,12 +48,11 @@ lnk_export_table_release(LNK_ExportTable **exptab_ptr)
internal LNK_Export * internal LNK_Export *
lnk_export_table_search(LNK_ExportTable *exptab, String8 name) lnk_export_table_search(LNK_ExportTable *exptab, String8 name)
{ {
for (LNK_Export *exp = exptab->name_export_list.first; exp != NULL; exp = exp->next) { KeyValuePair *kv = hash_table_search_string(exptab->name_export_ht, name);
if (str8_match(exp->name, name, 0)) { if (kv) {
return exp; return kv->value_raw;
}
} }
return NULL; return 0;
} }
internal LNK_Export * internal LNK_Export *
@@ -69,6 +72,7 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
goto exit; goto exit;
} }
LNK_DefinedSymbol *def = &symbol->u.defined; LNK_DefinedSymbol *def = &symbol->u.defined;
// NOTE: It is possible to export a global variable as CODE // NOTE: It is possible to export a global variable as CODE
// with following snippet: // with following snippet:
@@ -141,14 +145,12 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
exp->next = 0; exp->next = 0;
exp->name = push_str8_copy(exptab->arena, exp_parse->alias.size > 0 ? exp_parse->alias : exp_parse->name); exp->name = push_str8_copy(exptab->arena, exp_parse->alias.size > 0 ? exp_parse->alias : exp_parse->name);
exp->symbol = symbol; exp->symbol = symbol;
exp->id = exptab->name_export_list.count; exp->id = exptab->name_export_ht->count;
exp->ordinal = ordinal; exp->ordinal = ordinal;
exp->type = type; exp->type = type;
exp->is_private = 0; // exports through directives are public exp->is_private = 0; // exports through directives are public
// push node hash_table_push_string_raw(exptab->arena, exptab->name_export_ht, exp->name, exp);
SLLQueuePush(exptab->name_export_list.first, exptab->name_export_list.last, exp);
exptab->name_export_list.count += 1;
exit:; exit:;
return exp; return exp;
@@ -175,7 +177,7 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
// is export table empty? // is export table empty?
if (exptab->name_export_list.count == 0 && exptab->noname_export_list.count == 0) { if (exptab->name_export_ht->count == 0 && exptab->noname_export_ht->count == 0) {
goto exit; goto exit;
} }
@@ -198,8 +200,8 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
// push header // push header
PE_ExportTable *header = push_array(edata->arena, PE_ExportTable, 1); PE_ExportTable *header = push_array(edata->arena, PE_ExportTable, 1);
header->ordinal_base = safe_cast_u16(ordinal_low + 1); header->ordinal_base = safe_cast_u16(ordinal_low + 1);
header->export_address_table_count = safe_cast_u32(exptab->name_export_list.count + exptab->noname_export_list.count); header->export_address_table_count = safe_cast_u32(exptab->name_export_ht->count + exptab->noname_export_ht->count);
header->name_pointer_table_count = safe_cast_u32(exptab->name_export_list.count); header->name_pointer_table_count = safe_cast_u32(exptab->name_export_ht->count);
String8 header_data = str8((U8*)header, sizeof(*header)); String8 header_data = str8((U8*)header, sizeof(*header));
String8 image_name_cstr = push_cstr(edata->arena, str8_skip_last_slash(image_name)); String8 image_name_cstr = push_cstr(edata->arena, str8_skip_last_slash(image_name));
@@ -218,20 +220,16 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
lnk_chunk_set_debugf(edata->arena, string_buffer_chunk, "EXPORT_STRING_BUFFER"); lnk_chunk_set_debugf(edata->arena, string_buffer_chunk, "EXPORT_STRING_BUFFER");
lnk_chunk_set_debugf(edata->arena, image_name_chunk, "EXPORT_IMAGE_NAME"); lnk_chunk_set_debugf(edata->arena, image_name_chunk, "EXPORT_IMAGE_NAME");
LNK_Symbol *image_name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.name_voff"), LNK_DefinedSymbolVisibility_Internal, 0, image_name_chunk, 0, 0, 0); LNK_Symbol *image_name_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_voff"), LNK_DefinedSymbolVisibility_Internal, 0, image_name_chunk, 0, 0, 0);
LNK_Symbol *address_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.export_address_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, voff_table_chunk, 0, 0, 0); LNK_Symbol *address_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.export_address_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, voff_table_chunk, 0, 0, 0);
LNK_Symbol *name_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.name_pointer_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, name_voff_table_chunk, 0, 0, 0); LNK_Symbol *name_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_pointer_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, name_voff_table_chunk, 0, 0, 0);
LNK_Symbol *ordinal_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.ordinal_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, ordinal_table_chunk, 0, 0, 0); LNK_Symbol *ordinal_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.ordinal_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, ordinal_table_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, image_name_symbol);
lnk_symbol_table_push(symtab, address_table_symbol);
lnk_symbol_table_push(symtab, name_table_symbol);
lnk_symbol_table_push(symtab, ordinal_table_symbol);
// patch header fields // patch header fields
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_voff), image_name_symbol); lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_voff), image_name_symbol);
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, export_address_table_voff), address_table_symbol); lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, export_address_table_voff), address_table_symbol);
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_pointer_table_voff), name_table_symbol); lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_pointer_table_voff), name_table_symbol);
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, ordinal_table_voff), ordinal_table_symbol); lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, ordinal_table_voff), ordinal_table_symbol);
// reserve virtual offset chunks // reserve virtual offset chunks
LNK_Chunk **ordinal_voff_map = push_array(scratch.arena, LNK_Chunk *, exptab->max_ordinal); LNK_Chunk **ordinal_voff_map = push_array(scratch.arena, LNK_Chunk *, exptab->max_ordinal);
@@ -242,21 +240,23 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
} }
B8 *is_ordinal_bound = push_array(scratch.arena, B8, exptab->max_ordinal); B8 *is_ordinal_bound = push_array(scratch.arena, B8, exptab->max_ordinal);
LNK_ExportList *exp_list_arr[] = { &exptab->name_export_list, &exptab->noname_export_list }; HashTable *exp_ht_arr[] = { exptab->name_export_ht, exptab->noname_export_ht };
for (LNK_ExportList *list_ptr = exp_list_arr[0], *list_opl = list_ptr + ArrayCount(exp_list_arr); for (HashTable **ht_ptr = &exp_ht_arr[0], **ht_opl = ht_ptr + ArrayCount(exp_ht_arr);
list_ptr < list_opl; ht_ptr < ht_opl;
list_ptr += 1) { ht_ptr += 1) {
for (LNK_Export *exp = list_ptr->first; exp != 0; exp = exp->next) { KeyValuePair *kv_arr = key_value_pairs_from_hash_table(scratch.arena, *ht_ptr);
String8 name_cstr = push_cstr(edata->arena, exp->name);
for (U64 i = 0; i < (*ht_ptr)->count; ++i) {
LNK_Export *exp = kv_arr[i].value_raw;
String8 name_cstr = push_cstr(edata->arena, exp->name);
// push name string // push name string
LNK_Chunk *name_chunk = lnk_section_push_chunk_data(edata, string_buffer_chunk, name_cstr, str8(0,0)); LNK_Chunk *name_chunk = lnk_section_push_chunk_data(edata, string_buffer_chunk, name_cstr, str8(0,0));
lnk_chunk_set_debugf(edata->arena, name_chunk, "export: %S", name_cstr); lnk_chunk_set_debugf(edata->arena, name_chunk, "export: %S", name_cstr);
// push name symbol // push name symbol
String8 name_export_name = push_str8f(symtab->arena, "export.%S", name_cstr); String8 name_export_name = push_str8f(symtab->arena->v[0], "export.%S", name_cstr);
LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, name_export_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_export_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, name_symbol);
// name voff // name voff
LNK_Chunk *voff_chunk = lnk_section_push_chunk_bss(edata, name_voff_table_chunk, exptab->voff_size, /* export table must be sorted lexically: */ name_cstr); LNK_Chunk *voff_chunk = lnk_section_push_chunk_bss(edata, name_voff_table_chunk, exptab->voff_size, /* export table must be sorted lexically: */ name_cstr);
+2 -2
View File
@@ -30,8 +30,8 @@ typedef struct LNK_ExportArray
typedef struct LNK_ExportTable typedef struct LNK_ExportTable
{ {
Arena *arena; Arena *arena;
LNK_ExportList name_export_list; HashTable *name_export_ht;
LNK_ExportList noname_export_list; HashTable *noname_export_ht;
U64 voff_size; U64 voff_size;
U64 max_ordinal; U64 max_ordinal;
B8 *is_ordinal_used; B8 *is_ordinal_used;
+66 -105
View File
@@ -2,7 +2,7 @@
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
internal LNK_ImportTable * internal LNK_ImportTable *
lnk_import_table_alloc_regular(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine) lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine)
{ {
ProfBeginFunction(); ProfBeginFunction();
@@ -18,17 +18,11 @@ lnk_import_table_alloc_regular(LNK_SectionTable *st, LNK_SymbolTable *symtab, CO
LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_ImportEntry)), str8_lit("zzzzz")); LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_ImportEntry)), str8_lit("zzzzz"));
lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR"); lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR");
LNK_Symbol *dll_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0);
LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
LNK_Symbol *code_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
lnk_symbol_table_push(symtab, dll_table_symbol);
lnk_symbol_table_push(symtab, int_symbol);
lnk_symbol_table_push(symtab, iat_symbol);
lnk_symbol_table_push(symtab, ilt_symbol);
lnk_symbol_table_push(symtab, code_symbol);
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1); LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1);
@@ -79,23 +73,14 @@ lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, CO
lnk_chunk_set_debugf(data_sect->arena, null_biat_chunk, "BIAT_TERMINATOR"); lnk_chunk_set_debugf(data_sect->arena, null_biat_chunk, "BIAT_TERMINATOR");
} }
LNK_Symbol *dll_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0);
LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
LNK_Symbol *handle_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0);
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
LNK_Symbol *biat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0);
LNK_Symbol *uiat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0);
LNK_Symbol *code_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
lnk_symbol_table_push(symtab, dll_table_symbol);
lnk_symbol_table_push(symtab, int_symbol);
lnk_symbol_table_push(symtab, handle_table_symbol);
lnk_symbol_table_push(symtab, iat_symbol);
lnk_symbol_table_push(symtab, ilt_symbol);
lnk_symbol_table_push(symtab, biat_symbol);
lnk_symbol_table_push(symtab, uiat_symbol);
lnk_symbol_table_push(symtab, code_symbol);
LNK_ImportTableFlags flags = 0; LNK_ImportTableFlags flags = 0;
if (is_unloadable) { if (is_unloadable) {
@@ -178,7 +163,7 @@ lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name)
} }
internal LNK_ImportDLL * internal LNK_ImportDLL *
lnk_import_table_push_dll_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine) lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine)
{ {
ProfBeginFunction(); ProfBeginFunction();
@@ -193,21 +178,18 @@ lnk_import_table_push_dll_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symt
LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero()); LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero());
LNK_Chunk *code_table_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero()); LNK_Chunk *code_table_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero());
String8 ilt_symbol_name = push_str8f(symtab->arena, "%S.lookup_table_voff", dll_name); String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.lookup_table_voff", dll_name);
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0); LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, ilt_symbol);
String8 iat_symbol_name = push_str8f(symtab->arena, "%S.import_addr_table_voff", dll_name); String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "%S.import_addr_table_voff", dll_name);
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, iat_symbol);
String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name); String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name);
LNK_Chunk *dll_name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, dll_name_cstr, str8_zero()); LNK_Chunk *dll_name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, dll_name_cstr, str8_zero());
lnk_chunk_set_debugf(data_sect->arena, dll_name_chunk, "DLL name chunk (%S)", dll_name); lnk_chunk_set_debugf(data_sect->arena, dll_name_chunk, "DLL name chunk (%S)", dll_name);
String8 dll_name_voff_name = push_str8f(symtab->arena, "%S.name_voff", dll_name); String8 dll_name_voff_name = push_str8f(symtab->arena->v[0], "%S.name_voff", dll_name);
LNK_Symbol *dll_name_voff_symbol = lnk_make_defined_symbol_chunk(symtab->arena, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0); LNK_Symbol *dll_name_voff_symbol = lnk_symbol_table_push_defined_chunk(symtab, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, dll_name_voff_symbol);
// chunk for dll directory entry // chunk for dll directory entry
PE_ImportEntry *dir = push_array(imptab->arena, PE_ImportEntry, 1); PE_ImportEntry *dir = push_array(imptab->arena, PE_ImportEntry, 1);
@@ -272,32 +254,29 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
imp_desc->time_stamp = 0; imp_desc->time_stamp = 0;
// emit entry chunk // emit entry chunk
String8 imp_desc_data = str8_struct(imp_desc); String8 imp_desc_data = str8_struct(imp_desc);
LNK_Chunk *imp_desc_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, imp_desc_data, str8_zero()); LNK_Chunk *imp_desc_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, imp_desc_data, str8_zero());
// emit entry symbol // emit entry symbol
String8 imp_desc_name = push_str8f(symtab->arena, "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name); String8 imp_desc_name = push_str8f(symtab->arena->v[0], "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name);
LNK_Symbol *imp_desc_symbol = lnk_make_defined_symbol_chunk(symtab->arena, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0); LNK_Symbol *imp_desc_symbol = lnk_symbol_table_push_defined_chunk(symtab, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, imp_desc_symbol);
// emit string table chunk // emit string table chunk
String8 int_table_chunk_debug = push_str8f(data_sect->arena, "delayed.%S.int", dll_name); String8 int_table_chunk_debug = push_str8f(data_sect->arena, "delayed.%S.int", dll_name);
LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, int_table_chunk_debug); LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, int_table_chunk_debug);
String8 int_table_symbol_name = push_str8f(symtab->arena, "delayed.%S.int", dll_name); String8 int_table_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.int", dll_name);
LNK_Symbol *int_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0); LNK_Symbol *int_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, int_table_symbol);
LNK_Chunk *null_string_chunk = lnk_section_push_chunk_list(data_sect, int_table_chunk, str8_lit("zzzzz")); LNK_Chunk *null_string_chunk = lnk_section_push_chunk_list(data_sect, int_table_chunk, str8_lit("zzzzz"));
lnk_chunk_set_debugf(data_sect->arena, null_string_chunk, "string table null"); lnk_chunk_set_debugf(data_sect->arena, null_string_chunk, "string table null");
// emit DLL name chunk // emit DLL name chunk
String8 name_chunk_data = push_cstr(data_sect->arena, dll_name); String8 name_chunk_data = push_cstr(data_sect->arena, dll_name);
LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero()); LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero());
String8 name_symbol_name = push_str8f(symtab->arena, "delayed.%S.name", dll_name); String8 name_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.name", dll_name);
LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, name_symbol);
// patch DLL name voff // patch DLL name voff
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_voff), name_symbol); lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_voff), name_symbol);
@@ -305,9 +284,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
// emit DLL handle chunk // emit DLL handle chunk
LNK_Chunk *handle_chunk = lnk_section_push_chunk_bss(data_sect, imptab->handle_table_chunk, handle_size, str8_zero()); LNK_Chunk *handle_chunk = lnk_section_push_chunk_bss(data_sect, imptab->handle_table_chunk, handle_size, str8_zero());
String8 handle_name = push_str8f(symtab->arena, "delayed.%S.handle", dll_name); String8 handle_name = push_str8f(symtab->arena->v[0], "delayed.%S.handle", dll_name);
LNK_Symbol *handle_symbol = lnk_make_defined_symbol_chunk(symtab->arena, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0); LNK_Symbol *handle_symbol = lnk_symbol_table_push_defined_chunk(symtab, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, handle_symbol);
// patch DLL handle voff // patch DLL handle voff
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol); lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol);
@@ -315,9 +293,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
// emit IAT chunk // emit IAT chunk
LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero()); LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero());
String8 iat_table_name = push_str8f(symtab->arena, "delayed.%S.iat", dll_name); String8 iat_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.iat", dll_name);
LNK_Symbol *iat_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); LNK_Symbol *iat_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, iat_table_symbol);
LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, str8_lit("zzzzzz")); LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, str8_lit("zzzzzz"));
lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S: IAT terminator", dll_name); lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S: IAT terminator", dll_name);
@@ -328,9 +305,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, str8_lit("zzzzzz")); LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, str8_lit("zzzzzz"));
lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S: ILT terminator", dll_name); lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S: ILT terminator", dll_name);
String8 ilt_table_name = push_str8f(symtab->arena, "delayed.%S.ilt", dll_name); String8 ilt_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.ilt", dll_name);
LNK_Symbol *ilt_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0); LNK_Symbol *ilt_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, ilt_table_symbol);
// patch import address table voff // patch import address table voff
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_table_symbol); lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_table_symbol);
@@ -343,9 +319,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
if (imptab->flags & LNK_ImportTableFlag_EmitBiat) { if (imptab->flags & LNK_ImportTableFlag_EmitBiat) {
biat_chunk = lnk_section_push_chunk_list(data_sect, imptab->biat_chunk, str8_zero()); biat_chunk = lnk_section_push_chunk_list(data_sect, imptab->biat_chunk, str8_zero());
String8 biat_symbol_name = push_str8f(symtab->arena, "delayed.%S.BIAT", dll_name); String8 biat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.BIAT", dll_name);
LNK_Symbol *biat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0); LNK_Symbol *biat_symbol = lnk_symbol_table_push_defined_chunk(symtab, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, biat_symbol);
// patch BIAT field off // patch BIAT field off
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol); lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol);
@@ -356,9 +331,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
if (imptab->flags & LNK_ImportTableFlag_EmitUiat) { if (imptab->flags & LNK_ImportTableFlag_EmitUiat) {
uiat_chunk = lnk_section_push_chunk_list(data_sect, imptab->uiat_chunk, str8_zero()); uiat_chunk = lnk_section_push_chunk_list(data_sect, imptab->uiat_chunk, str8_zero());
String8 uiat_symbol_name = push_str8f(symtab->arena, "delayed.%S.UIAT", dll_name); String8 uiat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.UIAT", dll_name);
LNK_Symbol *uiat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0); LNK_Symbol *uiat_symbol = lnk_symbol_table_push_defined_chunk(symtab, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, uiat_symbol);
// patch UIAT field voff // patch UIAT field voff
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol); lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol);
@@ -372,7 +346,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
LNK_Chunk *tail_merge_chunk = 0; LNK_Chunk *tail_merge_chunk = 0;
switch (machine) { switch (machine) {
case COFF_MachineType_X64: { case COFF_MachineType_X64: {
LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena, str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main); LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main);
tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol); tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol);
} break; } break;
default: { default: {
@@ -401,7 +375,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
} }
internal LNK_ImportFunc * internal LNK_ImportFunc *
lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header) lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header)
{ {
ProfBeginFunction(); ProfBeginFunction();
@@ -438,9 +412,8 @@ lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *sym
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero()); LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
// create symbol for lookup chunk // create symbol for lookup chunk
String8 int_symbol_name = push_str8f(symtab->arena, "regular.%S.%S.name", dll->name, header->func_name); String8 int_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.name", dll->name, header->func_name);
LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0); LNK_Symbol *int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, int_symbol);
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses. // in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses.
ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index); ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index);
@@ -464,12 +437,10 @@ lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *sym
} break; } break;
} }
String8 ilt_symbol_name = push_str8f(symtab->arena, "regular.%S.%S.ilt", dll->name, header->func_name); String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.ilt", dll->name, header->func_name);
String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name); String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0); LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0); LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, ilt_symbol);
lnk_symbol_table_push(symtab, iat_symbol);
// generate thunks // generate thunks
LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr; LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr;
@@ -481,9 +452,8 @@ lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *sym
lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk); lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk);
// push jump thunk symbol // push jump thunk symbol
String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena, header->func_name); String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena->v[0], header->func_name);
jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, jmp_thunk_symbol_name); jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, jmp_thunk_symbol_name);
lnk_symbol_set_debugf(symtab->arena, jmp_thunk_symbol, "x64 jmp thunk %S.%S", dll->name, header->func_name);
} break; } break;
default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break; default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break;
} }
@@ -538,19 +508,16 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
if (header->type == COFF_ImportHeaderType_CODE) { if (header->type == COFF_ImportHeaderType_CODE) {
switch (dll->machine) { switch (dll->machine) {
case COFF_MachineType_X64: { case COFF_MachineType_X64: {
String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name); String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena, iat_symbol_name, LNK_SymbolScopeFlag_Main); LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScopeFlag_Main);
lnk_symbol_set_debugf(symtab->arena, iat_symbol, "x64 IAT (delayed) %S.%S", dll->name, header->func_name);
// emit jmp thunk chunk // emit jmp thunk chunk
jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol); jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol);
jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, header->func_name); jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, header->func_name);
lnk_symbol_set_debugf(symtab->arena, jmp_thunk_symbol, "x64 jmp thunk (delayed) %S.%S", dll->name, header->func_name);
// emit load thunk // emit load thunk
load_thunk_chunk = lnk_emit_load_thunk_x64(code_sect, code_table_chunk, iat_symbol, dll->tail_merge_symbol); load_thunk_chunk = lnk_emit_load_thunk_x64(code_sect, code_table_chunk, iat_symbol, dll->tail_merge_symbol);
load_thunk_symbol = lnk_emit_load_thunk_symbol(symtab, load_thunk_chunk, header->func_name); load_thunk_symbol = lnk_emit_load_thunk_symbol(symtab, load_thunk_chunk, header->func_name);
lnk_symbol_set_debugf(symtab->arena, load_thunk_symbol, "x64 load thunk (delayed) %S.%S", dll->name, header->func_name);
} break; } break;
default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break; default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break;
} }
@@ -582,9 +549,8 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero()); LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
// create symbol for lookup chunk // create symbol for lookup chunk
String8 int_symbol_name = push_str8f(symtab->arena, "%S.%S.name.delayed", dll->name, header->func_name); String8 int_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.name.delayed", dll->name, header->func_name);
int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0); int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, int_symbol);
// dynamic linker patches this voff on DLL load event // dynamic linker patches this voff on DLL load event
ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index); ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index);
@@ -635,13 +601,11 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
lnk_section_associate_chunks(data_sect, iat_chunk, load_thunk_chunk); lnk_section_associate_chunks(data_sect, iat_chunk, load_thunk_chunk);
} }
String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name); String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0); LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, iat_symbol);
String8 ilt_symbol_name = push_str8f(symtab->arena, "%S.%S.ilt.delayed", dll->name, header->func_name); String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.ilt.delayed", dll->name, header->func_name);
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0); LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, ilt_symbol);
// fill out import // fill out import
LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1); LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1);
@@ -771,9 +735,8 @@ lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu
{ {
ProfBeginFunction(); ProfBeginFunction();
// emit load thunk symbol // emit load thunk symbol
String8 load_thunk_name = push_str8f(symtab->arena, "__imp_load_%S", func_name); String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name);
LNK_Symbol *load_thunk_symbol = lnk_make_defined_symbol_chunk(symtab->arena, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, load_thunk_symbol);
ProfEnd(); ProfEnd();
return load_thunk_symbol; return load_thunk_symbol;
} }
@@ -782,9 +745,8 @@ internal LNK_Symbol *
lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name) lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name)
{ {
ProfBeginFunction(); ProfBeginFunction();
String8 jmp_thunk_name = push_str8f(symtab->arena, "%S", func_name); String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name);
LNK_Symbol *jmp_thunk_symbol = lnk_make_defined_symbol_chunk(symtab->arena, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, jmp_thunk_symbol);
ProfEnd(); ProfEnd();
return jmp_thunk_symbol; return jmp_thunk_symbol;
} }
@@ -793,9 +755,8 @@ internal LNK_Symbol *
lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name) lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name)
{ {
ProfBeginFunction(); ProfBeginFunction();
String8 tail_merge_name = push_str8f(symtab->arena, "__tailMerge_%S", func_name); String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name);
LNK_Symbol *tail_merge_symbol = lnk_make_defined_symbol_chunk(symtab->arena, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, tail_merge_symbol);
ProfEnd(); ProfEnd();
return tail_merge_symbol; return tail_merge_symbol;
} }
+3 -3
View File
@@ -59,12 +59,12 @@ typedef struct LNK_ImportTable
HashTable *dll_ht; HashTable *dll_ht;
} LNK_ImportTable; } LNK_ImportTable;
internal LNK_ImportTable * lnk_import_table_alloc_regular(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine); internal LNK_ImportTable * lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine);
internal LNK_ImportTable * lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable); internal LNK_ImportTable * lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable);
internal void lnk_import_table_release(LNK_ImportTable **imptab); internal void lnk_import_table_release(LNK_ImportTable **imptab);
internal LNK_ImportDLL * lnk_import_table_push_dll_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine); internal LNK_ImportDLL * lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine);
internal LNK_ImportDLL * lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine); internal LNK_ImportDLL * lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine);
internal LNK_ImportFunc * lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header); internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header);
internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header); internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header);
internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name); internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name);
internal LNK_ImportFunc * lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name); internal LNK_ImportFunc * lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name);
+256
View File
@@ -0,0 +1,256 @@
////////////////////////////////
// Shared File API
shared_function int
lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max)
{
OS_Handle handle = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, str8((U8*)path, path_size));
Assert(sizeof(handle) <= handle_buffer_max);
MemoryCopy(handle_buffer, &handle, sizeof(handle));
return !os_handle_match(handle, os_handle_zero());
}
shared_function int
lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max)
{
OS_Handle handle = os_file_open(OS_AccessFlag_Write, str8((U8*)path, path_size));
Assert(sizeof(handle) <= handle_buffer_max);
MemoryCopy(handle_buffer, &handle, sizeof(handle));
return !os_handle_match(handle, os_handle_zero());
}
shared_function void
lnk_close_file(void *raw_handle)
{
OS_Handle handle = *(OS_Handle *)raw_handle;
os_file_close(handle);
}
shared_function uint64_t
lnk_size_from_file(void *raw_handle)
{
OS_Handle handle = *(OS_Handle *)raw_handle;
FileProperties props = os_properties_from_file(handle);
return props.size;
}
shared_function uint64_t
lnk_read_file(void *raw_handle, void *buffer, uint64_t buffer_max)
{
OS_Handle handle = *(OS_Handle *)raw_handle;
U64 read_size = os_file_read(handle, rng_1u64(0, buffer_max), buffer);
Assert(read_size == buffer_max);
return read_size;
}
shared_function uint64_t
lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_size)
{
OS_Handle handle = *(OS_Handle*)raw_handle;
U64 write_size = os_file_write(handle, r1u64(offset, offset + buffer_size), buffer);
return write_size;
}
////////////////////////////////
internal void
lnk_log_read(String8 path, U64 size)
{
lnk_log(LNK_Log_IO_Read, "Read from \"%S\" %M", path, size);
}
internal String8
lnk_read_data_from_file_path(Arena *arena, String8 path)
{
String8 data = str8_zero();
OS_Handle handle = {0};
int is_open = lnk_open_file_read((char*)path.str, path.size, &handle, sizeof(handle));
if (is_open) {
U64 buffer_size = lnk_size_from_file(&handle);
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
U64 read_size = lnk_read_file(&handle, buffer, buffer_size);
data = str8(buffer, read_size);
lnk_close_file(&handle);
if (read_size != buffer_size) {
lnk_error(LNK_Warning_IllData, "incomplete file read occurred, read %u bytes, expected %u bytes, file %S", path);
}
if (lnk_get_log_status(LNK_Log_IO_Read)) {
lnk_log_read(path, data.size);
}
} else {
lnk_error(LNK_Error_FileNotFound, "unable to open file %S", path);
}
return data;
}
internal
THREAD_POOL_TASK_FUNC(lnk_data_size_from_file_path_task)
{
LNK_DiskReader *task = raw_task;
String8 path = task->path_arr.v[task_id];
OS_Handle handle = {0};
U64 size = 0;
int is_open = lnk_open_file_read((char*)path.str, path.size, &handle, sizeof(handle));
if (is_open) {
size = lnk_size_from_file(&handle);
}
task->handle_arr[task_id] = handle;
task->size_arr[task_id] = size;
}
internal
THREAD_POOL_TASK_FUNC(lnk_data_from_file_path_task)
{
LNK_DiskReader *task = raw_task;
OS_Handle handle = task->handle_arr[task_id];
U64 buffer_size = task->size_arr[task_id];
U8 *buffer = task->buffer + task->off_arr[task_id];
U64 read_size = lnk_read_file(&handle, buffer, buffer_size);
Assert(read_size == buffer_size);
task->data_arr.v[task_id] = str8(buffer, read_size);
}
internal String8Array
lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr)
{
Temp scratch = scratch_begin(&arena,1);
LNK_DiskReader reader = {0};
reader.path_arr = path_arr;
reader.handle_arr = push_array_no_zero(scratch.arena, OS_Handle, path_arr.count);
reader.size_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
// open handles and get sizes
tp_for_parallel(tp, 0, path_arr.count, lnk_data_size_from_file_path_task, &reader);
// compute file buffer size
U64 total_data_size = sum_array_u64(path_arr.count, reader.size_arr);
// assign offsets into file buffer
U64 *off_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
MemoryCopyTyped(off_arr, reader.size_arr, path_arr.count);
counts_to_offsets_array_u64(path_arr.count, off_arr);
reader.data_arr = str8_array_reserve(arena, path_arr.count);
reader.off_arr = off_arr;
reader.buffer = push_array_no_zero(arena, U8, total_data_size);
// read files and close handles
tp_for_parallel(tp, 0, path_arr.count, lnk_data_from_file_path_task, &reader);
String8Array result = {0};
result.count = path_arr.count;
result.v = reader.data_arr.v;
if (lnk_get_log_status(LNK_Log_IO_Read)) {
for (U64 i = 0; i < result.count; ++i) {
lnk_log_read(path_arr.v[i], result.v[i].size);
}
}
scratch_end(scratch);
return result;
}
internal void
lnk_write_data_list_to_file_path(String8 path, String8List data)
{
ProfBeginV("Write %M to %S", data.total_size, path);
B32 is_written = 0;
OS_Handle handle;
if (lnk_open_file_write((char*)path.str, path.size, &handle, sizeof(handle))) {
U64 offset = 0;
for (String8Node *data_n = data.first; data_n != 0; data_n = data_n->next) {
if (!lnk_write_file(&handle, offset, data_n->string.str, data_n->string.size)) {
break;
}
offset += data_n->string.size;
}
lnk_close_file(&handle);
is_written = (offset == data.total_size);
if (is_written) {
if (lnk_get_log_status(LNK_Log_IO_Write)) {
lnk_log(LNK_Log_IO_Write, "File \"%S\" %M written", path, data.total_size);
}
} else {
lnk_error(LNK_Error_IO, "incomplete write occurred, %M written, expected %M, file %S",
offset, data.total_size, path);
}
} else {
lnk_error(LNK_Error_NoAccess, "don't have access to write to %S", path);
}
ProfEnd();
}
internal void
lnk_write_data_to_file_path(String8 path, String8 data)
{
Temp scratch = scratch_begin(0,0);
String8List data_list = {0};
str8_list_push(scratch.arena, &data_list, data);
lnk_write_data_list_to_file_path(path, data_list);
scratch_end(scratch);
}
internal String8List
lnk_file_search(Arena *arena, String8List dir_list, String8 file_path)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
String8List match_list; MemoryZeroStruct(&match_list);
if (os_file_path_exists(file_path)) {
String8 str = push_str8_copy(arena, file_path);
str8_list_push(arena, &match_list, str);
}
PathStyle file_path_style = path_style_from_str8(file_path);
B32 is_relative = file_path_style != PathStyle_WindowsAbsolute &&
file_path_style != PathStyle_UnixAbsolute;
if (is_relative) {
for (String8Node *i = dir_list.first; i != 0; i = i->next) {
String8List path_list = {0};
str8_list_push(scratch.arena, &path_list, i->string);
str8_list_push(scratch.arena, &path_list, file_path);
String8 path = str8_path_list_join_by_style(scratch.arena, &path_list, PathStyle_SystemAbsolute);
B32 file_exists = os_file_path_exists(path);
if (file_exists) {
B32 is_unique = 1;
OS_FileID file_id = os_id_from_file_path(path);
for (String8Node *k = match_list.first; k != 0; k = k->next) {
OS_FileID test_id = os_id_from_file_path(k->string);
int cmp = os_file_id_compare(test_id, file_id) != 0;
if (cmp == 0) {
is_unique = 0;
break;
}
}
if (is_unique) {
String8 str = push_str8_copy(arena, path);
str8_list_push(arena, &match_list, str);
}
}
}
}
scratch_end(scratch);
ProfEnd();
return match_list;
}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
////////////////////////////////
typedef struct
{
String8Array path_arr;
String8Array data_arr;
OS_Handle *handle_arr;
U64 *size_arr;
U64 *off_arr;
U8 *buffer;
} LNK_DiskReader;
////////////////////////////////
// Shared File API
shared_function int lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max);
shared_function int lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max);
shared_function void lnk_close_file(void *raw_handle);
shared_function uint64_t lnk_size_from_file(void *raw_handle);
shared_function uint64_t lnk_read_file(void *raw_handle, void *buffer, uint64_t buffer_max);
shared_function uint64_t lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_size);
////////////////////////////////
internal String8 lnk_read_data_from_file_path(Arena *arena, String8 path);
internal String8Array lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr);
internal void lnk_write_data_list_to_file_path(String8 path, String8List list);
internal void lnk_write_data_to_file_path(String8 path, String8 data);
internal String8List lnk_file_search(Arena *arena, String8List dir_list, String8 file_path);
+23 -10
View File
@@ -74,7 +74,7 @@ lnk_lib_symbol_name_compar(const void *raw_a, const void *raw_b)
{ {
const LNK_Symbol *sa = (const LNK_Symbol *)raw_a; const LNK_Symbol *sa = (const LNK_Symbol *)raw_a;
const LNK_Symbol *sb = (const LNK_Symbol *)raw_b; const LNK_Symbol *sb = (const LNK_Symbol *)raw_b;
return str8_compar_case_sensetive(&sa->name, &sb->name); return str8_compar_case_sensitive(&sa->name, &sb->name);
} }
int int
@@ -97,6 +97,8 @@ lnk_lib_symbol_array_sort(LNK_LibSymbol *arr, U64 count)
internal LNK_Lib internal LNK_Lib
lnk_lib_from_data(Arena *arena, String8 data, String8 path) lnk_lib_from_data(Arena *arena, String8 data, String8 path)
{ {
ProfBeginFunction();
U64 symbol_count; U64 symbol_count;
String8 string_table; String8 string_table;
U32 *member_off_arr; U32 *member_off_arr;
@@ -167,9 +169,11 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path)
lib.symbol_name_list = symbol_name_list; lib.symbol_name_list = symbol_name_list;
lib.long_names = parse.long_names; lib.long_names = parse.long_names;
ProfEnd();
return lib; return lib;
} }
internal
THREAD_POOL_TASK_FUNC(lnk_lib_initer) THREAD_POOL_TASK_FUNC(lnk_lib_initer)
{ {
LNK_LibIniter *task = raw_task; LNK_LibIniter *task = raw_task;
@@ -179,6 +183,7 @@ THREAD_POOL_TASK_FUNC(lnk_lib_initer)
String8 path = task->path_arr[task_id]; String8 path = task->path_arr[task_id];
*lib = lnk_lib_from_data(arena, data, path); *lib = lnk_lib_from_data(arena, data, path);
lib->input_idx = task->base_input_idx + task_id;
} }
internal LNK_LibNodeArray internal LNK_LibNodeArray
@@ -187,15 +192,16 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S
Assert(data_arr.count == path_arr.count); Assert(data_arr.count == path_arr.count);
U64 lib_count = data_arr.count; U64 lib_count = data_arr.count;
LNK_LibIniter lib_initer = {0}; LNK_LibIniter task = {0};
lib_initer.node_arr = lnk_lib_list_reserve(arena->v[0], list, lib_count); task.node_arr = lnk_lib_list_reserve(arena->v[0], list, lib_count);
lib_initer.data_arr = data_arr.v; task.data_arr = data_arr.v;
lib_initer.path_arr = path_arr.v; task.path_arr = path_arr.v;
tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &lib_initer); task.base_input_idx = list->count;
tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &task);
LNK_LibNodeArray arr; LNK_LibNodeArray arr = {0};
arr.count = lib_count; arr.count = lib_count;
arr.v = lib_initer.node_arr; arr.v = task.node_arr;
return arr; return arr;
} }
@@ -507,15 +513,22 @@ internal LNK_LibBuild
lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ObjList obj_list, LNK_ExportTable *exptab) lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ObjList obj_list, LNK_ExportTable *exptab)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
LNK_LibWriter *writer = lnk_lib_writer_alloc(); LNK_LibWriter *writer = lnk_lib_writer_alloc();
for (LNK_ObjNode *obj_node = obj_list.first; obj_node != 0; obj_node = obj_node->next) { for (LNK_ObjNode *obj_node = obj_list.first; obj_node != 0; obj_node = obj_node->next) {
lnk_lib_writer_push_obj(writer, &obj_node->data); lnk_lib_writer_push_obj(writer, &obj_node->data);
} }
for (LNK_Export *exp = exptab->name_export_list.first; exp != 0; exp = exp->next) {
KeyValuePair *raw_export_arr = key_value_pairs_from_hash_table(scratch.arena, exptab->name_export_ht);
for (U64 i = 0; i < exptab->name_export_ht->count; ++i) {
LNK_Export *exp = raw_export_arr[i].value_raw;
lnk_lib_writer_push_export(writer, machine, time_stamp, dll_name, exp); lnk_lib_writer_push_export(writer, machine, time_stamp, dll_name, exp);
} }
LNK_LibBuild lib = lnk_lib_build_from_writer(arena, writer); LNK_LibBuild lib = lnk_lib_build_from_writer(arena, writer);
lnk_lib_writer_release(&writer); lnk_lib_writer_release(&writer);
scratch_end(scratch);
ProfEnd(); ProfEnd();
return lib; return lib;
} }
+5 -3
View File
@@ -12,6 +12,7 @@ typedef struct LNK_Lib
U32 * member_off_arr; U32 * member_off_arr;
String8List symbol_name_list; String8List symbol_name_list;
String8 long_names; String8 long_names;
U64 input_idx;
} LNK_Lib; } LNK_Lib;
typedef struct LNK_LibNode typedef struct LNK_LibNode
@@ -92,9 +93,10 @@ typedef struct LNK_LibBuild
typedef struct typedef struct
{ {
LNK_LibNode *node_arr; LNK_LibNode *node_arr;
String8 *data_arr; String8 *data_arr;
String8 *path_arr; String8 *path_arr;
U64 base_input_idx;
} LNK_LibIniter; } LNK_LibIniter;
//////////////////////////////// ////////////////////////////////
+2 -1
View File
@@ -40,7 +40,8 @@ lnk_log_type_from_string(String8 string)
"Debug", LNK_Log_Debug, "Debug", LNK_Log_Debug,
"InputObj", LNK_Log_InputObj, "InputObj", LNK_Log_InputObj,
"InputLib", LNK_Log_InputLib, "InputLib", LNK_Log_InputLib,
"IO", LNK_Log_IO, "IO_Read", LNK_Log_IO_Read,
"IO_Write", LNK_Log_IO_Write,
"SizeBreakdown", LNK_Log_SizeBreakdown, "SizeBreakdown", LNK_Log_SizeBreakdown,
"LinkStats", LNK_Log_LinkStats, "LinkStats", LNK_Log_LinkStats,
"Timers", LNK_Log_Timers, "Timers", LNK_Log_Timers,
+2 -1
View File
@@ -9,7 +9,8 @@ typedef enum
LNK_Log_Debug, LNK_Log_Debug,
LNK_Log_InputObj, LNK_Log_InputObj,
LNK_Log_InputLib, LNK_Log_InputLib,
LNK_Log_IO, LNK_Log_IO_Read,
LNK_Log_IO_Write,
LNK_Log_SizeBreakdown, LNK_Log_SizeBreakdown,
LNK_Log_LinkStats, LNK_Log_LinkStats,
LNK_Log_Timers, LNK_Log_Timers,
+29 -14
View File
@@ -61,7 +61,7 @@ lnk_input_obj_compar(const void *raw_a, const void *raw_b)
{ {
const LNK_InputObj **a = (const LNK_InputObj **) raw_a; const LNK_InputObj **a = (const LNK_InputObj **) raw_a;
const LNK_InputObj **b = (const LNK_InputObj **) raw_b; const LNK_InputObj **b = (const LNK_InputObj **) raw_b;
int cmp = str8_compar_case_sensetive(&(*a)->path, &(*b)->path); int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path);
return cmp; return cmp;
} }
@@ -70,7 +70,7 @@ lnk_input_obj_compar_is_before(void *raw_a, void *raw_b)
{ {
LNK_InputObj **a = raw_a; LNK_InputObj **a = raw_a;
LNK_InputObj **b = raw_b; LNK_InputObj **b = raw_b;
int cmp = str8_compar_case_sensetive(&(*a)->path, &(*b)->path); int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path);
int is_before = cmp < 0; int is_before = cmp < 0;
return is_before; return is_before;
} }
@@ -259,11 +259,11 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector)
Rng1U64 range = task->range_arr[task_id]; Rng1U64 range = task->range_arr[task_id];
String8List *list = &task->out_arr[task_id]; String8List *list = &task->out_arr[task_id];
LNK_Obj **obj_ptr = &task->in_arr[range.min]; LNK_ObjNode *obj_ptr = &task->in_arr[range.min];
LNK_Obj **obj_opl = &task->in_arr[range.max]; LNK_ObjNode *obj_opl = &task->in_arr[range.max];
for (; obj_ptr < obj_opl; obj_ptr += 1) { for (; obj_ptr < obj_opl; obj_ptr += 1) {
LNK_Obj *obj = *obj_ptr; LNK_Obj *obj = &obj_ptr->data;
LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_Directive_ManifestDependency]; LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_Directive_ManifestDependency];
for (LNK_Directive *dir = dirs->first; dir != 0; dir = dir->next) { for (LNK_Directive *dir = dirs->first; dir != 0; dir = dir->next) {
String8List dep = str8_list_copy(arena, &dir->value_list); String8List dep = str8_list_copy(arena, &dir->value_list);
@@ -273,14 +273,14 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector)
} }
internal String8List internal String8List
lnk_collect_manifest_dependency_list(TP_Context *tp, TP_Arena *arena, LNK_Obj **obj_arr, U64 obj_count) lnk_collect_manifest_dependency_list(TP_Context *tp, TP_Arena *arena, LNK_ObjNodeArray obj_node_arr)
{ {
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(arena->v, arena->count);
LNK_ManifestDependencyCollector task_data = {0}; LNK_ManifestDependencyCollector task_data = {0};
task_data.in_arr = obj_arr; task_data.in_arr = obj_node_arr.v;
task_data.out_arr = push_array(scratch.arena, String8List, tp->worker_count); task_data.out_arr = push_array(scratch.arena, String8List, tp->worker_count);
task_data.range_arr = tp_divide_work(scratch.arena, obj_count, tp->worker_count); task_data.range_arr = tp_divide_work(scratch.arena, obj_node_arr.count, tp->worker_count);
tp_for_parallel(tp, arena, tp->worker_count, lnk_manifest_dependency_collector, &task_data); tp_for_parallel(tp, arena, tp->worker_count, lnk_manifest_dependency_collector, &task_data);
String8List result = str8_list_arr_concat(task_data.out_arr, tp->worker_count); String8List result = str8_list_arr_concat(task_data.out_arr, tp->worker_count);
@@ -399,7 +399,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
chunk->flags = coff_sect->flags; chunk->flags = coff_sect->flags;
chunk->associate = 0; chunk->associate = 0;
chunk->u.leaf = data; chunk->u.leaf = data;
lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, isect: 0x%llX", path, sect_name_arr[sect_idx], sect_idx); lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, obj_idx: 0x%llX isect: 0x%llX", cached_path, sect_name_arr[sect_idx], obj_idx, sect_idx);
} }
// :common_block // :common_block
@@ -414,10 +414,11 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
master_common_block->flags = LNK_BSS_SECTION_FLAGS; master_common_block->flags = LNK_BSS_SECTION_FLAGS;
master_common_block->associate = 0; master_common_block->associate = 0;
master_common_block->u.list = push_array(arena, LNK_ChunkList, 1); master_common_block->u.list = push_array(arena, LNK_ChunkList, 1);
lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", path); lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", cached_path);
// convert from coff // convert from coff
LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, cached_path, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_arr, master_common_block); B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ;
LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_arr, master_common_block);
LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr);
LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_arr, symbol_arr); LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_arr, symbol_arr);
@@ -425,6 +426,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
obj->data = input->data; obj->data = input->data;
obj->path = cached_path; obj->path = cached_path;
obj->lib_path = cached_lib_path; obj->lib_path = cached_lib_path;
obj->input_idx = obj_idx;
obj->machine = coff_info.machine; obj->machine = coff_info.machine;
obj->chunk_count = chunk_count; obj->chunk_count = chunk_count;
obj->sect_count = coff_info.section_count_no_null; obj->sect_count = coff_info.section_count_no_null;
@@ -712,7 +714,9 @@ lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_ObjList *obj_lis
internal LNK_SymbolArray internal LNK_SymbolArray
lnk_symbol_array_from_coff(Arena *arena, lnk_symbol_array_from_coff(Arena *arena,
String8 coff_data, String8 coff_data,
LNK_Obj *obj,
String8 obj_path, String8 obj_path,
B32 is_big_obj,
U64 string_table_off, U64 string_table_off,
U64 sect_count, U64 sect_count,
COFF_SectionHeader *coff_sect_arr, COFF_SectionHeader *coff_sect_arr,
@@ -729,7 +733,8 @@ lnk_symbol_array_from_coff(Arena *arena,
for (U64 symbol_idx = 0; symbol_idx < coff_symbols.count; symbol_idx += 1) { for (U64 symbol_idx = 0; symbol_idx < coff_symbols.count; symbol_idx += 1) {
COFF_Symbol32 *coff_symbol = &coff_symbols.v[symbol_idx]; COFF_Symbol32 *coff_symbol = &coff_symbols.v[symbol_idx];
LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_symbol_set_debug(symbol, obj_path);
symbol->obj = obj;
String8 name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol->name); String8 name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol->name);
@@ -771,7 +776,17 @@ lnk_symbol_array_from_coff(Arena *arena,
check_sum = secdef->check_sum; check_sum = secdef->check_sum;
if (secdef->selection == COFF_ComdatSelectType_ASSOCIATIVE) { if (secdef->selection == COFF_ComdatSelectType_ASSOCIATIVE) {
LNK_Chunk *head_chunk = &chunk_arr[secdef->number - 1]; U32 secdef_number = secdef->number_lo;
if (is_big_obj) {
secdef_number |= (U32)secdef->number_hi << 16;
}
if (secdef_number == 0 || secdef_number > sect_count) {
lnk_error(LNK_Error_IllData, "%S: symbol %u has out of bounds section definition number %u", name, symbol_idx, secdef_number);
break;
}
LNK_Chunk *head_chunk = &chunk_arr[secdef_number - 1];
LNK_Chunk *associate_chunk = &chunk_arr[coff_symbol->section_number - 1]; LNK_Chunk *associate_chunk = &chunk_arr[coff_symbol->section_number - 1];
lnk_chunk_associate(arena, head_chunk, associate_chunk); lnk_chunk_associate(arena, head_chunk, associate_chunk);
} }
+3 -2
View File
@@ -32,6 +32,7 @@ typedef struct LNK_Obj
String8 data; String8 data;
String8 path; String8 path;
String8 lib_path; String8 lib_path;
U64 input_idx;
U64 common_symbol_size; U64 common_symbol_size;
COFF_MachineType machine; COFF_MachineType machine;
U64 chunk_count; U64 chunk_count;
@@ -151,7 +152,7 @@ typedef struct
typedef struct typedef struct
{ {
LNK_Obj **in_arr; LNK_ObjNode *in_arr;
String8List *out_arr; String8List *out_arr;
Rng1U64 *range_arr; Rng1U64 *range_arr;
} LNK_ManifestDependencyCollector; } LNK_ManifestDependencyCollector;
@@ -179,7 +180,7 @@ internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 input_count, LNK_InputObj **inputs); internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 input_count, LNK_InputObj **inputs);
internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr); internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr);
internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, String8 obj_path, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_Chunk *chunk_arr, LNK_Chunk *master_common_block); internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_Chunk *chunk_arr, LNK_Chunk *master_common_block);
internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count); internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count);
internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_Chunk *sect_chunk_arr, LNK_SymbolArray symbol_array); internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_Chunk *sect_chunk_arr, LNK_SymbolArray symbol_array);
internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr); internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr);
+75 -27
View File
@@ -250,16 +250,18 @@ lnk_code_align_byte_from_machine(COFF_MachineType machine)
internal void internal void
lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine) lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine)
{ {
if (sect->is_loose && sect->has_layout) { if (sect->is_loose) {
// get value for align data fill if (sect->has_layout) {
U8 align_byte = 0; sect->layout = lnk_build_chunk_layout(sect->arena, sect->cman);
B32 is_code = !!(sect->flags & COFF_SectionFlag_CNT_CODE); } else {
if (is_code) { sect->layout.total_count = sect->cman->total_chunk_count;
align_byte = lnk_code_align_byte_from_machine(machine); sect->layout.chunk_ptr_array = lnk_make_chunk_id_map(sect->arena, sect->cman);
sect->layout.chunk_off_array = 0;
sect->layout.chunk_file_size_array = 0;
sect->layout.chunk_virt_size_array = 0;
sect->layout.align_array_count = 0;
sect->layout.align_array = 0;
} }
sect->layout = lnk_build_chunk_layout(sect->arena, sect->cman, sect->flags, align_byte);
sect->is_loose = 0; sect->is_loose = 0;
} }
} }
@@ -300,7 +302,7 @@ lnk_section_table_push(LNK_SectionTable *st, String8 name, COFF_SectionFlags fla
B32 found = 0; B32 found = 0;
for (LNK_SectionNode *curr = sect_list->first, *prev = NULL; curr != NULL; prev = curr, curr = curr->next) { for (LNK_SectionNode *curr = sect_list->first, *prev = NULL; curr != NULL; prev = curr, curr = curr->next) {
LNK_Section *sect = &curr->data; LNK_Section *sect = &curr->data;
int cmp = str8_compar_case_sensetive(&sort_index, &sect->sort_index); int cmp = str8_compar_case_sensitive(&sort_index, &sect->sort_index);
if (cmp < 0) { if (cmp < 0) {
if (prev == NULL) { if (prev == NULL) {
SLLQueuePushFront(sect_list->first, sect_list->last, sect_node); SLLQueuePushFront(sect_list->first, sect_list->last, sect_node);
@@ -594,19 +596,48 @@ lnk_section_table_assign_indices(LNK_SectionTable *st)
} }
internal String8 internal String8
lnk_section_table_serialize(Arena *arena, LNK_SectionTable *st) lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
String8List image_list = {0};
for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { U64 image_size = 0;
LNK_Section *sect = &sect_node->data; for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
str8_list_push(scratch.arena, &image_list, sect->layout.data); LNK_Section *sect = &sect_n->data;
if (sect->has_layout) {
U64 root_size = sect->layout.chunk_file_size_array[sect->root->ref.chunk_id];
image_size += root_size;
}
} }
String8 result = str8_list_join(arena, &image_list, NULL);
U8 *image_buffer = push_array_no_zero(arena, U8, image_size);
String8 image = str8(image_buffer, image_size);
U64 image_cursor = 0;
for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
LNK_Section *sect = &sect_n->data;
if (sect->has_layout) {
if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
continue;
}
U64 sect_size = sect->layout.chunk_file_size_array[sect->root->ref.chunk_id];
String8 sect_data = str8_substr(image, rng_1u64(image_cursor, image_cursor + sect_size));
U8 fill_byte = 0;
if (sect->flags & COFF_SectionFlag_CNT_CODE) {
fill_byte = lnk_code_align_byte_from_machine(machine);
}
lnk_serialize_chunk_layout(tp, sect->layout, sect_data, fill_byte);
image_cursor += sect_size;
}
}
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return result; return image;
} }
internal LNK_ChunkPtr ** internal LNK_ChunkPtr **
@@ -736,24 +767,41 @@ lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref)
} }
internal String8 internal String8
lnk_data_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref) lnk_data_from_chunk_ref(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref)
{ {
LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref); LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref);
LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id]; LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id];
U64 chunk_off = lnk_off_from_chunk_ref(sect_id_map, chunk_ref); String8 chunk_data;
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk_ref); if (sect->has_layout) {
String8 chunk_data = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size)); U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk_ref);
U64 chunk_foff = lnk_file_off_from_chunk_ref(sect_id_map, chunk_ref);
chunk_data = str8_substr(image_data, r1u64(chunk_foff, chunk_foff + chunk_size));
} else {
LNK_Chunk *chunk = sect->layout.chunk_ptr_array[final_chunk_ref.chunk_id];
Assert(chunk->type == LNK_Chunk_Leaf);
chunk_data = chunk->u.leaf;
}
return chunk_data; return chunk_data;
} }
internal String8 internal String8
lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref) lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref)
{ {
LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref); LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref);
LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id]; LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id];
U64 chunk_off = lnk_off_from_chunk_ref(sect_id_map, chunk_ref);
U64 chunk_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk_ref); String8 chunk_data;
String8 chunk_data = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size)); if (sect->has_layout) {
U64 chunk_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk_ref);
U64 chunk_foff = lnk_file_off_from_chunk_ref(sect_id_map, chunk_ref);
chunk_data = str8_substr(image_data, r1u64(chunk_foff, chunk_foff + chunk_size));
} else {
LNK_Chunk *chunk = sect->layout.chunk_ptr_array[final_chunk_ref.chunk_id];
Assert(chunk->type == LNK_Chunk_Leaf);
chunk_data = chunk->u.leaf;
}
return chunk_data; return chunk_data;
} }
+3 -3
View File
@@ -121,7 +121,7 @@ internal void lnk_section_table_build_data(TP_Context *tp, LNK_Se
internal void lnk_section_table_assign_virtual_offsets(LNK_SectionTable *st); internal void lnk_section_table_assign_virtual_offsets(LNK_SectionTable *st);
internal void lnk_section_table_assign_file_offsets(LNK_SectionTable *st); internal void lnk_section_table_assign_file_offsets(LNK_SectionTable *st);
internal void lnk_section_table_assign_indices(LNK_SectionTable *st); internal void lnk_section_table_assign_indices(LNK_SectionTable *st);
internal String8 lnk_section_table_serialize(Arena *arena, LNK_SectionTable *st); internal String8 lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine);
internal LNK_ChunkPtr ** lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *st); internal LNK_ChunkPtr ** lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *st);
internal LNK_Section ** lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *st); internal LNK_Section ** lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *st);
@@ -134,8 +134,8 @@ internal U64 lnk_virt_off_from_chunk_ref(LNK_Section **sect_id_map,
internal U64 lnk_file_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal U64 lnk_file_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal U64 lnk_virt_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal U64 lnk_virt_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal U64 lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal U64 lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
internal String8 lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal String8 lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
internal ISectOff lnk_sc_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal ISectOff lnk_sc_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal U64 lnk_virt_off_from_reloc(LNK_Section **sect_id_map, LNK_Reloc *reloc); internal U64 lnk_virt_off_from_reloc(LNK_Section **sect_id_map, LNK_Reloc *reloc);
internal U64 lnk_isect_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol); internal U64 lnk_isect_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
File diff suppressed because it is too large Load Diff
+52 -84
View File
@@ -90,27 +90,22 @@ typedef enum
LNK_Symbol_Undefined, LNK_Symbol_Undefined,
} LNK_SymbolType; } LNK_SymbolType;
#define LNK_DEBUG_SYMBOLS 1
typedef struct LNK_Symbol typedef struct LNK_Symbol
{ {
String8 name; String8 name;
LNK_SymbolType type; LNK_SymbolType type;
struct LNK_Obj *obj;
union { union {
LNK_DefinedSymbol defined; LNK_DefinedSymbol defined;
LNK_WeakSymbol weak; LNK_WeakSymbol weak;
LNK_UndefinedSymbol undefined; LNK_UndefinedSymbol undefined;
LNK_LazySymbol lazy; LNK_LazySymbol lazy;
} u; } u;
#if LNK_DEBUG_SYMBOLS
String8 debug;
#endif
} LNK_Symbol; } LNK_Symbol;
typedef struct LNK_SymbolNode typedef struct LNK_SymbolNode
{ {
struct LNK_SymbolNode *next; struct LNK_SymbolNode *next;
struct LNK_SymbolNode *prev;
U64 hash;
LNK_Symbol *data; LNK_Symbol *data;
} LNK_SymbolNode; } LNK_SymbolNode;
@@ -133,59 +128,51 @@ typedef struct LNK_SymbolArray
LNK_Symbol *v; LNK_Symbol *v;
} LNK_SymbolArray; } LNK_SymbolArray;
typedef struct LNK_SymbolHashTrie
{
String8 *name;
LNK_Symbol *symbol;
struct LNK_SymbolHashTrie *child[4];
} LNK_SymbolHashTrie;
typedef struct LNK_SymbolHashTrieChunk
{
struct LNK_SymbolHashTrieChunk *next;
U64 count;
U64 cap;
LNK_SymbolHashTrie *v;
} LNK_SymbolHashTrieChunk;
typedef struct LNK_SymbolHashTrieChunkList
{
U64 count;
LNK_SymbolHashTrieChunk *first;
LNK_SymbolHashTrieChunk *last;
} LNK_SymbolHashTrieChunkList;
typedef struct LNK_SymbolTable typedef struct LNK_SymbolTable
{ {
Arena *arena; TP_Arena *arena;
U64 bucket_count[LNK_SymbolScopeIndex_Count]; LNK_SymbolHashTrie *scopes[LNK_SymbolScopeIndex_Count];
LNK_SymbolList *buckets[LNK_SymbolScopeIndex_Count]; LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScopeIndex_Count];
} LNK_SymbolTable; } LNK_SymbolTable;
//////////////////////////////// ////////////////////////////////
// parallel for wrappers // parallel for wrappers
typedef struct
{
LNK_Symbol *symbol_arr;
Rng1U64 *range_arr;
U64 *hash_arr;
} LNK_SymbolNameHasher;
typedef struct
{
LNK_SymbolNode **input_arr;
Rng1U64 *range_arr;
} LNK_SymbolNodePtrHasher;
typedef struct
{
LNK_SymbolNode *input_arr;
Rng1U64 *range_arr;
} LNK_SymbolNodeHasher;
typedef struct typedef struct
{ {
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_SymbolList *bucket_arr; Rng1U64 *ranges;
Rng1U64 *range_arr; LNK_Symbol *arr;
} LNK_DefinedSymbolInserter;
typedef struct
{
LNK_SymbolTable *symtab;
LNK_SymbolList *bucket_arr;
Rng1U64 *range_arr;
} LNK_LazySymbolInserter; } LNK_LazySymbolInserter;
typedef struct
{
LNK_SymbolTable *symtab;
Rng1U64 *range_arr;
} LNK_ComdatFolder;
//////////////////////////////// ////////////////////////////////
extern LNK_Symbol g_null_symbol; global read_only LNK_Symbol g_null_symbol = { str8_lit_comp("NULL"), LNK_Symbol_DefinedStatic };
extern LNK_Symbol *g_null_symbol_ptr; global read_only LNK_Symbol *g_null_symbol_ptr = &g_null_symbol;
////////////////////////////////
internal void lnk_init_symbol(LNK_Symbol *symbol, String8 name, LNK_SymbolType type); internal void lnk_init_symbol(LNK_Symbol *symbol, String8 name, LNK_SymbolType type);
internal void lnk_init_defined_symbol(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags); internal void lnk_init_defined_symbol(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags);
@@ -201,53 +188,34 @@ internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, LNK_
internal LNK_Symbol * lnk_make_weak_symbol(Arena *arena, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback); internal LNK_Symbol * lnk_make_weak_symbol(Arena *arena, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback);
internal LNK_Symbol * lnk_make_lazy_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset); internal LNK_Symbol * lnk_make_lazy_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset);
#if LNK_DEBUG_SYMBOLS internal LNK_Chunk * lnk_chunk_from_symbol(LNK_Symbol *symbol);
#define lnk_symbol_set_debugf(a, s, fmt, ...) do { (s)->debug = push_str8f((a), fmt, __VA_ARGS__); } while (0)
#define lnk_symbol_set_debug(s, str) do { (s)->debug = str; } while (0)
#else
#define lnk_symbol_set_debugf(...)
#define lnk_symbol_set_debug(...)
#endif
internal LNK_Chunk * lnk_defined_symbol_get_chunk(LNK_DefinedSymbol *symbol); ////////////////////////////////
internal void lnk_symbol_update_chunk_ref(LNK_Symbol *symbol, U64 src_sect_id, U64 dst_sect_id, U64 *id_map, U64 id_count);
internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node); internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node);
internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol); internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol);
internal void lnk_symbol_list_push_list(LNK_SymbolList *list, LNK_SymbolList *to_push);
internal void lnk_symbol_list_insert_after(LNK_SymbolList *list, LNK_SymbolNode *node, LNK_SymbolNode *insert);
internal LNK_SymbolNode * lnk_symbol_list_pop_node(LNK_SymbolList *list);
internal LNK_Symbol * lnk_symbol_list_pop(LNK_SymbolList *list);
internal void lnk_symbol_list_remove(LNK_SymbolList *list, LNK_SymbolNode *node);
internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat); internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat);
internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list);
internal LNK_SymbolList lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr); internal LNK_SymbolList lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr);
internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list); internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list);
internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list); internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list);
internal LNK_Symbol * lnk_symbol_array_search(LNK_SymbolArray symarr, String8 name, StringMatchFlags flags);
internal U64 * lnk_symbol_array_hash(TP_Context *tp, Arena *arena, LNK_Symbol *arr, U64 count);
internal LNK_SymbolTable * lnk_symbol_table_alloc(void); ////////////////////////////////
internal LNK_SymbolTable * lnk_symbol_table_alloc_ex(U64 defined_cap, U64 internal_cap, U64 weak_cap, U64 lib_cap);
internal void lnk_symbol_table_release(LNK_SymbolTable **symtab); internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *new_symbol);
internal U64 lnk_symbol_table_hash(String8 string); internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name);
internal LNK_SymbolNode * lnk_symbol_table_search_bucket(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope_idx, U64 bucket_idx, String8 name, U64 hash); internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie);
internal LNK_SymbolNode * lnk_symbol_table_search_node_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name, U64 hash);
internal LNK_SymbolNode * lnk_symbol_table_search_node(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name); ////////////////////////////////
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name);
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, char *fmt, ...); internal U64 lnk_symbol_hash(String8 string);
internal void lnk_symbol_table_push_node_hash(LNK_SymbolTable *symtab, LNK_SymbolNode *node, U64 hash);
internal void lnk_symbol_table_push_node(LNK_SymbolTable *symtab, LNK_SymbolNode *node); internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena);
internal LNK_SymbolNode * lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol); internal LNK_Symbol * lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, U64 hash, String8 name);
internal void lnk_symbol_table_push_lazy_arr(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Symbol *arr, U64 count); internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name);
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, char *fmt, ...);
internal void lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol);
internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol);
internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name); internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name);
internal void lnk_symbol_table_replace(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex iscope, LNK_Symbol *symbol);
internal LNK_Symbol * lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol); internal LNK_Symbol * lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol);
internal LNK_SymbolList lnk_pop_comdat_chain(LNK_SymbolList *bucket, LNK_SymbolNode **cursor);
internal LNK_SymbolNode * lnk_fold_comdat_chain(LNK_SymbolList chain_list);
internal void lnk_fold_comdat_chunks(TP_Context *tp, LNK_SymbolTable *symtab);
-188
View File
@@ -1,188 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal
THREAD_POOL_TASK_FUNC(os_data_size_from_file_path_task)
{
OS_DataSizeFromFilePathTask *task = raw_task;
String8 path = task->path_arr.v[task_id];
OS_Handle handle = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
FileProperties props = os_properties_from_file(handle);
task->handle_arr[task_id] = handle;
task->size_arr[task_id] = props.size;
}
internal
THREAD_POOL_TASK_FUNC(os_data_from_file_path_task)
{
OS_DataFromFilePathTask *task = raw_task;
OS_Handle handle = task->handle_arr[task_id];
U64 size = task->size_arr[task_id];
U8 *buffer = task->buffer + task->off_arr[task_id];
U64 read_size = os_file_read(handle, rng_1u64(0, size), buffer);
Assert(read_size == size);
task->data_arr.v[task_id] = str8(buffer, read_size);
os_file_close(handle);
}
internal String8Array
os_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr)
{
Temp scratch = scratch_begin(&arena,1);
OS_Handle *handle_arr = push_array_no_zero(scratch.arena, OS_Handle, path_arr.count);
U64 *size_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
U64 *off_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
// open handles and get sizes
OS_DataSizeFromFilePathTask sizer;
sizer.path_arr = path_arr;
sizer.size_arr = size_arr;
sizer.handle_arr = handle_arr;
tp_for_parallel(tp, 0, path_arr.count, os_data_size_from_file_path_task, &sizer);
// compute file buffer size
U64 total_data_size = sum_array_u64(path_arr.count, sizer.size_arr);
// assign offsets into file buffer
MemoryCopyTyped(off_arr, sizer.size_arr, path_arr.count);
counts_to_offsets_array_u64(path_arr.count, off_arr);
// read files and close handles
OS_DataFromFilePathTask reader;
reader.data_arr = str8_array_reserve(arena, path_arr.count);
reader.handle_arr = handle_arr;
reader.size_arr = size_arr;;
reader.off_arr = off_arr;
reader.buffer = push_array_no_zero(arena, U8, total_data_size);
tp_for_parallel(tp, 0, path_arr.count, os_data_from_file_path_task, &reader);
String8Array result = {0};
result.count = path_arr.count;
result.v = reader.data_arr.v;
scratch_end(scratch);
return result;
}
internal String8List
os_file_search(Arena *arena, String8List dir_list, String8 file_path)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
String8List match_list; MemoryZeroStruct(&match_list);
if (os_file_path_exists(file_path)) {
String8 str = push_str8_copy(arena, file_path);
str8_list_push(arena, &match_list, str);
}
PathStyle file_path_style = path_style_from_str8(file_path);
B32 is_relative = file_path_style != PathStyle_WindowsAbsolute &&
file_path_style != PathStyle_UnixAbsolute;
if (is_relative) {
for (String8Node *i = dir_list.first; i != 0; i = i->next) {
String8List path_list = {0};
str8_list_push(scratch.arena, &path_list, i->string);
str8_list_push(scratch.arena, &path_list, file_path);
String8 path = str8_path_list_join_by_style(scratch.arena, &path_list, PathStyle_SystemAbsolute);
B32 file_exists = os_file_path_exists(path);
if (file_exists) {
B32 is_unique = 1;
OS_FileID file_id = os_id_from_file_path(path);
for (String8Node *k = match_list.first; k != 0; k = k->next) {
OS_FileID test_id = os_id_from_file_path(k->string);
int cmp = os_file_id_compare(test_id, file_id) != 0;
if (cmp == 0) {
is_unique = 0;
break;
}
}
if (is_unique) {
String8 str = push_str8_copy(arena, path);
str8_list_push(arena, &match_list, str);
}
}
}
}
scratch_end(scratch);
ProfEnd();
return match_list;
}
static struct
{
String8 string;
OperatingSystem os;
} g_os_map[] = {
{ str8_lit_comp("windows"), OperatingSystem_Windows, },
{ str8_lit_comp("linux"), OperatingSystem_Linux, },
{ str8_lit_comp("mac"), OperatingSystem_Mac, },
};
internal OperatingSystem
operating_system_from_string(String8 string)
{
for (U64 i = 0; i < ArrayCount(g_os_map); ++i) {
if (str8_match(g_os_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
return g_os_map[i].os;
}
}
return OperatingSystem_Null;
}
internal B32
os_try_guid_from_string(String8 string, OS_Guid *guid_out)
{
Temp scratch = scratch_begin(0,0);
B32 is_parsed = 0;
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("-"), StringSplitFlag_KeepEmpties);
if (list.node_count == 5) {
String8 data1_str = list.first->string;
String8 data2_str = list.first->next->string;
String8 data3_str = list.first->next->next->string;
String8 data4_hi_str = list.first->next->next->next->string;
String8 data4_lo_str = list.first->next->next->next->next->string;
if (str8_is_integer(data1_str, 16) &&
str8_is_integer(data2_str, 16) &&
str8_is_integer(data3_str, 16) &&
str8_is_integer(data4_hi_str, 16) &&
str8_is_integer(data4_lo_str, 16)) {
U64 data1 = u64_from_str8(data1_str, 16);
U64 data2 = u64_from_str8(data2_str, 16);
U64 data3 = u64_from_str8(data3_str, 16);
U64 data4_hi = u64_from_str8(data4_hi_str, 16);
U64 data4_lo = u64_from_str8(data4_lo_str, 16);
if (data1 <= max_U32 &&
data2 <= max_U16 &&
data3 <= max_U16 &&
data4_hi <= max_U16 &&
data4_lo <= 0xffffffffffff) {
guid_out->data1 = (U32)data1;
guid_out->data2 = (U16)data2;
guid_out->data3 = (U16)data3;
U64 data4 = (data4_hi << 48) | data4_lo;
MemoryCopy(&guid_out->data4[0], &data4, sizeof(data4));
is_parsed = 1;
}
}
}
scratch_end(scratch);
return is_parsed;
}
internal OS_Guid
os_guid_from_string(String8 string)
{
OS_Guid guid = {0};
os_try_guid_from_string(string, &guid);
return guid;
}
-39
View File
@@ -1,39 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#pragma once
#if OS_WINDOWS
# include "os_core_win32.c"
#else
# error "undefined OS"
#endif
typedef struct
{
String8Array path_arr;
OS_Handle *handle_arr;
U64 *size_arr;
} OS_DataSizeFromFilePathTask;
typedef struct
{
String8Array data_arr;
OS_Handle *handle_arr;
U64 *size_arr;
U64 *off_arr;
U8 *buffer;
} OS_DataFromFilePathTask;
internal String8Array os_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr);
internal String8List os_file_search(Arena *arena, String8List dir_list, String8 file_path);
internal B32 os_folder_path_exists(String8 path);
internal OperatingSystem operating_system_from_string(String8 string);
internal B32 os_set_large_pages(B32 toggle);
internal U32 os_get_process_start_time_unix(void);
internal B32 os_try_guid_from_string(String8 string, OS_Guid *guid_out);
internal OS_Guid os_guid_from_string(String8 string);
-168
View File
@@ -1,168 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal U32
w32_unix_time_from_file_time(FILETIME file_time)
{
U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime;
U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000);
Assert(unix_time64 <= max_U32);
U32 unix_time32 = (U32)unix_time64;
return unix_time32;
}
internal B32
os_w32_has_path_volume_prefix(String8 path)
{
if (path.size >= 2) {
U8 *ptr = path.str;
U8 *opl = path.str + path.size;
UnicodeDecode a = utf8_decode(ptr, (U64)(opl-ptr));
ptr += a.inc;
UnicodeDecode b = utf8_decode(ptr, (U64)(opl-ptr));
return a.codepoint < max_U8 && char_is_alpha(a.codepoint) && b.codepoint == ':';
}
return 0;
}
internal B32
os_w32_has_device_prefix(String8 path)
{
if (path.size >= 3) {
U8 *ptr = path.str;
U8 *opl = path.str + path.size;
UnicodeDecode a = utf8_decode(ptr, (U64)(opl-ptr));
ptr += a.inc;
UnicodeDecode b = utf8_decode(ptr, (U64)(opl-ptr));
ptr += b.inc;
UnicodeDecode c = utf8_decode(ptr, (U64)(opl-ptr));
return a.codepoint == '\\' && b.codepoint == '\\' && (c.codepoint == '?' || c.codepoint == '.');
}
return 0;
}
internal B32
os_w32_has_unc_prefix(String8 path)
{
if (path.size >= 2) {
U8 *ptr = path.str;
U8 *opl = path.str + path.size;
UnicodeDecode a = utf8_decode(ptr, (U64)(opl-ptr));
ptr += a.inc;
UnicodeDecode b = utf8_decode(ptr, (U64)(opl-ptr));
return a.codepoint == '\\' && b.codepoint == '\\';
}
return 0;
}
internal B32
os_w32_has_root_drive_prefix(String8 path)
{
if (path.size >= 1) {
UnicodeDecode a = utf8_decode(path.str, path.size);
return a.codepoint == '\\';
}
return 0;
}
internal B32
os_w32_is_path_relative_current_directory(String8 path)
{
if (os_w32_has_path_volume_prefix(path)) {
return 0;
}
if (os_w32_has_device_prefix(path)) {
return 0;
}
if (os_w32_has_unc_prefix(path)) {
return 0;
}
if (os_w32_has_root_drive_prefix(path)) {
return 0;
}
return 1;
}
internal String8
os_make_full_path(Arena *arena, String8 path)
{
String8 full_path;
if (os_w32_is_path_relative_current_directory(path)) {
Temp scratch = scratch_begin(&arena, 1);
String8 current_dir = os_get_current_path(scratch.arena);
String8List list = {0};
str8_list_push(scratch.arena, &list, current_dir);
str8_list_push(scratch.arena, &list, path);
String8 temp_full_path = str8_list_join(scratch.arena, &list, &(StringJoin){ .sep = str8_lit_comp("\\") });
String8List split_full_path = str8_split_path(scratch.arena, temp_full_path);
str8_path_list_resolve_dots_in_place(&split_full_path, PathStyle_WindowsAbsolute);
full_path = str8_list_join(arena, &split_full_path, &(StringJoin){ .sep = str8_lit_comp("\\") });
scratch_end(scratch);
} else {
full_path = push_str8_copy(arena, path);
}
return full_path;
}
internal B32
os_folder_path_exists(String8 path)
{
Temp scratch = scratch_begin(0,0);
String8 actual_path = path;
if (os_w32_is_path_relative_current_directory(path)) {
String8 current = os_get_current_path(scratch.arena);
String8List list = {0};
str8_list_push(scratch.arena, &list, current);
str8_list_push(scratch.arena, &list, path);
StringJoin join = { .sep = str8_lit_comp("\\") };
actual_path =str8_list_join(scratch.arena, &list, &join);
}
String16 path16 = str16_from_8(scratch.arena, actual_path);
DWORD attributes = GetFileAttributesW((WCHAR *)path16.str);
B32 exists = (attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY);
scratch_end(scratch);
return exists;
}
internal B32
os_set_large_pages(B32 toggle)
{
B32 is_ok = 0;
HANDLE token;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
{
LUID luid;
if(LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid))
{
TOKEN_PRIVILEGES priv;
priv.PrivilegeCount = 1;
priv.Privileges[0].Luid = luid;
priv.Privileges[0].Attributes = toggle ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED;
if (AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0) == ERROR_SUCCESS) {
is_ok = 1;
}
}
CloseHandle(token);
}
return is_ok;
}
internal U32
os_get_process_start_time_unix(void)
{
HANDLE handle = GetCurrentProcess();
FILETIME start_time = {0};
FILETIME exit_time;
FILETIME kernel_time;
FILETIME user_time;
if (GetProcessTimes(handle, &start_time, &exit_time, &kernel_time, &user_time)) {
return w32_unix_time_from_file_time(start_time);
}
return 0;
}
-14
View File
@@ -1,14 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "core/os_core.c"
#if OS_WINDOWS
//# include "core/win32/os_core_win32.c"
#elif OS_LINUX
//# include "core/linux/os_core_linux.c"
#else
# error no OS layer setup
#endif
-15
View File
@@ -1,15 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#pragma once
#include "core/os_core.h"
#if OS_WINDOWS
//# include "core/win32/os_core_win32.h"
#elif OS_LINUX
//# include "core/linux/os_core_linux.h"
#else
# error no OS layer setup
#endif
+8 -20
View File
@@ -998,12 +998,7 @@ exit:;
internal MSF_UInt internal MSF_UInt
msf_stream_reserve__(MSF_Context *msf, MSF_Stream *stream, MSF_UInt res) msf_stream_reserve__(MSF_Context *msf, MSF_Stream *stream, MSF_UInt res)
{ {
Temp scratch = scratch_begin(0,0); ProfBeginV("MSF Reserve %m", res);
#if PROFILE_TELEMETRY
String8 size_string = str8_from_memory_size2(scratch.arena, res);
ProfBeginDynamic("MSF Reserve %.*s", str8_varg(size_string));
#endif
B32 is_ok = 1; B32 is_ok = 1;
@@ -1019,7 +1014,6 @@ msf_stream_reserve__(MSF_Context *msf, MSF_Stream *stream, MSF_UInt res)
AssertAlways(is_ok); AssertAlways(is_ok);
} }
scratch_end(scratch);
ProfEnd(); ProfEnd();
return is_ok; return is_ok;
} }
@@ -1152,20 +1146,13 @@ THREAD_POOL_TASK_FUNC(msf_write_task)
internal B32 internal B32
msf_stream_write_parallel(TP_Context *tp, MSF_Context *msf, MSF_StreamNumber sn, void *buffer, MSF_UInt buffer_size) msf_stream_write_parallel(TP_Context *tp, MSF_Context *msf, MSF_StreamNumber sn, void *buffer, MSF_UInt buffer_size)
{ {
Temp scratch = scratch_begin(0,0); ProfBeginV("MSF Write Parallel %m", buffer_size);
#if PROFILE_TELEMETRY
String8 buffer_size_string = str8_from_memory_size2(scratch.arena, buffer_size);
ProfBeginDynamic("MSF Write Parallel [%.*s]", str8_varg(buffer_size_string));
#endif
MSF_Stream *stream = msf_find_stream(msf, sn); MSF_Stream *stream = msf_find_stream(msf, sn);
B32 is_write_ok = msf_stream_reserve__(msf, stream, buffer_size); B32 is_write_ok = msf_stream_reserve__(msf, stream, buffer_size);
if (is_write_ok) { if (is_write_ok) {
Temp scratch = scratch_begin(0,0);
U64 expected_pos = stream->pos + buffer_size; U64 expected_pos = stream->pos + buffer_size;
U64 pre_size = Min(AlignPadPow2(stream->pos, msf->page_size), buffer_size); U64 pre_size = Min(AlignPadPow2(stream->pos, msf->page_size), buffer_size);
@@ -1176,13 +1163,15 @@ msf_stream_write_parallel(TP_Context *tp, MSF_Context *msf, MSF_StreamNumber sn,
U8 *mid_ptr = (U8*)buffer + pre_size; U8 *mid_ptr = (U8*)buffer + pre_size;
U8 *end_ptr = (U8*)buffer + pre_size + mid_size; U8 *end_ptr = (U8*)buffer + pre_size + mid_size;
ProfBegin("Write Buffer Pre"); ProfBeginV("Write Buffer Pre %M", pre_size);
B32 is_pre_written = msf_stream_write__(msf, stream, pre_ptr, pre_size); B32 is_pre_written = msf_stream_write__(msf, stream, pre_ptr, pre_size);
AssertAlways(is_pre_written); AssertAlways(is_pre_written);
ProfEnd(); ProfEnd();
// write buffer mid // write buffer mid
if (mid_size > 0) { if (mid_size > 0) {
Temp scratch = scratch_begin(0,0);
Assert(stream->pos % msf->page_size == 0); Assert(stream->pos % msf->page_size == 0);
Assert(mid_size % msf->page_size == 0); Assert(mid_size % msf->page_size == 0);
@@ -1199,20 +1188,19 @@ msf_stream_write_parallel(TP_Context *tp, MSF_Context *msf, MSF_StreamNumber sn,
U64 after_mid = stream->pos + mid_size; U64 after_mid = stream->pos + mid_size;
B32 is_seek_ok = msf_stream_seek__(msf, stream, after_mid); B32 is_seek_ok = msf_stream_seek__(msf, stream, after_mid);
AssertAlways(is_seek_ok); AssertAlways(is_seek_ok);
scratch_end(scratch);
} }
ProfBegin("Write Buffer End"); ProfBeginV("Write Buffer End %M", end_size);
B32 is_end_ok = msf_stream_write__(msf, stream, end_ptr, end_size); B32 is_end_ok = msf_stream_write__(msf, stream, end_ptr, end_size);
AssertAlways(is_end_ok); AssertAlways(is_end_ok);
ProfEnd(); ProfEnd();
// did we write bytes correctly? // did we write bytes correctly?
AssertAlways(stream->pos == expected_pos); AssertAlways(stream->pos == expected_pos);
scratch_end(scratch);
} }
scratch_end(scratch);
ProfEnd(); ProfEnd();
return is_write_ok; return is_write_ok;
} }
+6 -13
View File
@@ -1265,7 +1265,7 @@ pdb_type_server_build(TP_Context *tp, PDB_TypeServer *ts, PDB_StringTable *strta
lf_arr[lf_arr_idx] = lf; lf_arr[lf_arr_idx] = lf;
lf_arr_idx += 1; lf_arr_idx += 1;
} }
lf_buf_size += AlignPow2(lf->string.size, PDB_LEAF_ALIGN); lf_buf_size += lf->string.size;
lf_node_idx += 1; lf_node_idx += 1;
} }
@@ -1274,7 +1274,6 @@ pdb_type_server_build(TP_Context *tp, PDB_TypeServer *ts, PDB_StringTable *strta
ProfBegin("Write Type Data & Hints"); ProfBegin("Write Type Data & Hints");
PDB_WriteTypesTask write_types_task; PDB_WriteTypesTask write_types_task;
write_types_task.align = PDB_LEAF_ALIGN;
write_types_task.ti_lo = ts->ti_lo; write_types_task.ti_lo = ts->ti_lo;
write_types_task.ti_hi = ts->ti_lo + ts->leaf_list.node_count; write_types_task.ti_hi = ts->ti_lo + ts->leaf_list.node_count;
write_types_task.hint_count = hint_count; write_types_task.hint_count = hint_count;
@@ -1472,7 +1471,7 @@ THREAD_POOL_TASK_FUNC(pdb_push_udt_leaf_task)
CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data);
if (~udt_info.props & CV_TypeProp_FwdRef) { if (~udt_info.props & CV_TypeProp_FwdRef) {
// hash udt and compute bucket index // hash udt and compute bucket index
U32 hash = pdb_hash_udt(udt_info, leaf.data); U32 hash = pdb_hash_udt(udt_info, leaf.data);
U32 bucket_idx = hash % type_ht_cap; U32 bucket_idx = hash % type_ht_cap;
// fill out & insert bucket // fill out & insert bucket
@@ -1649,7 +1648,7 @@ pdb_load_types_from_leaf_list(PDB_TypeServer **type_server_arr, CV_LeafList leaf
//////////////////////////////// ////////////////////////////////
internal PDB_InfoContext * internal PDB_InfoContext *
pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, OS_Guid guid) pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, Guid guid)
{ {
ProfBeginFunction(); ProfBeginFunction();
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
@@ -2522,12 +2521,6 @@ gsi_push_many_list(PDB_GsiContext *gsi, U64 count, U32 *hash_arr, CV_SymbolList
MemoryZeroStruct(list); MemoryZeroStruct(list);
} }
internal void
gsi_push_many_and_remove_duplicates(TP_Context *tp, CV_SymbolList *list)
{
}
internal CV_SymbolNode * internal CV_SymbolNode *
gsi_search(PDB_GsiContext *gsi, CV_Symbol *symbol) gsi_search(PDB_GsiContext *gsi, CV_Symbol *symbol)
{ {
@@ -3535,7 +3528,7 @@ pdb_alloc_msf(U64 page_size)
} }
internal PDB_Context * internal PDB_Context *
pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, OS_Guid guid) pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, Guid guid)
{ {
ProfBeginFunction(); ProfBeginFunction();
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
@@ -3613,7 +3606,7 @@ pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine)
} }
internal void internal void
pdb_set_guid(PDB_Context *pdb, OS_Guid guid) pdb_set_guid(PDB_Context *pdb, Guid guid)
{ {
pdb->info->guid = guid; pdb->info->guid = guid;
} }
@@ -3649,7 +3642,7 @@ pdb_get_age(PDB_Context *pdb)
return pdb->info->age; return pdb->info->age;
} }
internal OS_Guid internal Guid
pdb_get_guid(PDB_Context *pdb) pdb_get_guid(PDB_Context *pdb)
{ {
return pdb->info->guid; return pdb->info->guid;
+6 -7
View File
@@ -135,7 +135,6 @@ typedef struct
typedef struct typedef struct
{ {
U64 align;
CV_TypeIndex ti_lo; CV_TypeIndex ti_lo;
CV_TypeIndex ti_hi; CV_TypeIndex ti_hi;
U64 hint_count; U64 hint_count;
@@ -155,7 +154,7 @@ typedef struct PDB_InfoParse
PDB_TpiVersion version; PDB_TpiVersion version;
COFF_TimeStamp time_stamp; COFF_TimeStamp time_stamp;
U32 age; U32 age;
OS_Guid guid; Guid guid;
String8 extra_info; String8 extra_info;
} PDB_InfoParse; } PDB_InfoParse;
@@ -164,7 +163,7 @@ typedef struct PDB_InfoContext
Arena *arena; Arena *arena;
COFF_TimeStamp time_stamp; COFF_TimeStamp time_stamp;
U32 age; U32 age;
OS_Guid guid; Guid guid;
PDB_FeatureFlags flags; PDB_FeatureFlags flags;
PDB_HashTable named_stream_ht; PDB_HashTable named_stream_ht;
PDB_HashTable src_header_block_ht; PDB_HashTable src_header_block_ht;
@@ -348,23 +347,23 @@ typedef struct
//////////////////////////////// ////////////////////////////////
// PDB // PDB
internal PDB_Context * pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, OS_Guid guid); internal PDB_Context * pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, Guid guid);
internal PDB_Context * pdb_open(String8 data); internal PDB_Context * pdb_open(String8 data);
internal void pdb_release(PDB_Context **pdb_ptr); internal void pdb_release(PDB_Context **pdb_ptr);
internal void pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht); internal void pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht);
internal void pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine); internal void pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine);
internal void pdb_set_guid(PDB_Context *pdb, OS_Guid guid); internal void pdb_set_guid(PDB_Context *pdb, Guid guid);
internal void pdb_set_time_stamp(PDB_Context *pdb, COFF_TimeStamp time_stamp); internal void pdb_set_time_stamp(PDB_Context *pdb, COFF_TimeStamp time_stamp);
internal void pdb_set_age(PDB_Context *pdb, U32 age); internal void pdb_set_age(PDB_Context *pdb, U32 age);
internal COFF_MachineType pdb_get_machine(PDB_Context *pdb); internal COFF_MachineType pdb_get_machine(PDB_Context *pdb);
internal COFF_TimeStamp pdb_get_time_stamp(PDB_Context *pdb); internal COFF_TimeStamp pdb_get_time_stamp(PDB_Context *pdb);
internal U32 pdb_get_age(PDB_Context *pdb); internal U32 pdb_get_age(PDB_Context *pdb);
internal OS_Guid pdb_get_guid(PDB_Context *pdb); internal Guid pdb_get_guid(PDB_Context *pdb);
//////////////////////////////// ////////////////////////////////
// Info // Info
internal PDB_InfoContext * pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, OS_Guid guid); internal PDB_InfoContext * pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, Guid guid);
internal void pdb_info_parse_from_data(String8 data, PDB_InfoParse *parse_out); internal void pdb_info_parse_from_data(String8 data, PDB_InfoParse *parse_out);
internal PDB_InfoContext * pdb_info_open(MSF_Context *msf, MSF_StreamNumber sn); internal PDB_InfoContext * pdb_info_open(MSF_Context *msf, MSF_StreamNumber sn);
internal void pdb_info_build(PDB_InfoContext *info, MSF_Context *msf, MSF_StreamNumber sn); internal void pdb_info_build(PDB_InfoContext *info, MSF_Context *msf, MSF_StreamNumber sn);
+17 -20
View File
@@ -1177,29 +1177,26 @@ internal U64
rdib_sizeof_type(RDIB_Type *type) rdib_sizeof_type(RDIB_Type *type)
{ {
U64 size = 0; U64 size = 0;
if (RDI_TypeKind_FirstBuiltIn <= type->kind && type->kind < RDI_TypeKind_LastBuiltIn) {
RDIB_Type *curr = type; size = type->builtin.size;
while (curr->kind == RDI_TypeKind_Modifier) { } else if (type->kind == RDI_TypeKind_Modifier) {
curr = curr->modifier.type_ref; size = rdib_sizeof_type(type->modifier.type_ref);
} } else if (type->kind == RDI_TypeKind_Ptr || type->kind == RDI_TypeKind_LRef || type->kind == RDI_TypeKind_RRef) {
size = type->ptr.size;
if (RDI_TypeKind_FirstBuiltIn <= curr->kind && curr->kind < RDI_TypeKind_LastBuiltIn) { } else if (type->kind == RDI_TypeKind_Struct || type->kind == RDI_TypeKind_Class ||
size = curr->builtin.size; type->kind == RDI_TypeKind_IncompleteStruct || type->kind == RDI_TypeKind_IncompleteClass) {
} else if (curr->kind == RDI_TypeKind_Ptr || curr->kind == RDI_TypeKind_LRef || curr->kind == RDI_TypeKind_RRef) { size = type->udt.struct_type.size;
size = curr->ptr.size; } else if (type->kind == RDI_TypeKind_Union || type->kind == RDI_TypeKind_IncompleteUnion) {
} else if (curr->kind == RDI_TypeKind_Struct || curr->kind == RDI_TypeKind_Class || size = type->udt.union_type.size;
curr->kind == RDI_TypeKind_IncompleteStruct || curr->kind == RDI_TypeKind_IncompleteClass) { } else if (type->kind == RDI_TypeKind_Enum || type->kind == RDI_TypeKind_IncompleteEnum) {
size = curr->udt.struct_type.size; size = rdib_sizeof_type(type->udt.enum_type.base_type);
} else if (curr->kind == RDI_TypeKind_Union || curr->kind == RDI_TypeKind_IncompleteUnion) { } else if (type->kind == RDI_TypeKind_Bitfield) {
size = curr->udt.union_type.size; size = rdib_sizeof_type(type->bitfield.value_type);
} else if (curr->kind == RDI_TypeKind_Enum || curr->kind == RDI_TypeKind_IncompleteEnum) { } else if (type->kind == RDI_TypeKind_Array) {
size = rdib_sizeof_type(curr->udt.enum_type.base_type); size = type->array.size;
} else if (curr->kind == RDI_TypeKind_Bitfield) {
size = rdib_sizeof_type(curr->bitfield.value_type);
} else { } else {
Assert(!"error: type doens't have a size"); Assert(!"error: type doens't have a size");
} }
return size; return size;
} }
+11
View File
@@ -91,6 +91,13 @@ struct TypeWithBitfield
int z : 10; int z : 10;
}; };
typedef struct BitfieldType64 BitfieldType64;
struct BitfieldType64
{
uint64_t size : 63;
uint64_t is_free : 1;
};
void void
c_type_with_bitfield_usage(void) c_type_with_bitfield_usage(void)
{ {
@@ -103,4 +110,8 @@ c_type_with_bitfield_usage(void)
int x = (b.v + b.x); int x = (b.v + b.x);
int y = (b.y - b.z); int y = (b.y - b.z);
int z = (b.w) + 5; int z = (b.w) + 5;
BitfieldType64 b64 = {0};
b64.size = 524288;
b64.is_free = 1;
int abc = 0;
} }
+6 -2
View File
@@ -279,8 +279,8 @@ few_params1(Pair *pairs, int count, Function_No_Params_Type *no_params_type){
} }
static void static void
type_coverage_eval_tests(void){ type_coverage_eval_tests(void)
{
Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
Basics_Stdint basics_stdint = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; Basics_Stdint basics_stdint = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
@@ -432,6 +432,10 @@ type_coverage_eval_tests(void){
OutputDebugStringA("\n"); OutputDebugStringA("\n");
} }
const int32_t x1 = 3;
const int32_t y1 = -10;
const int32_t z1 = x1 + y1;
int x = (int)(Anonymous_D); int x = (int)(Anonymous_D);
} }

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