942 Commits
Author SHA1 Message Date
ed 132cf395b2 Merge remote-tracking branch 'EpicGamesExt/master' 2026-08-07 00:46:42 -04:00
Ryan Fleury 076d41130c fix qualified identifier expression tree buil 2026-07-29 11:40:41 -07:00
Ryan Fleury ba9d36624d lexer fixes; eval2 resolution qualifiers 2026-07-29 11:35:28 -07:00
Ryan Fleury b27585476a fix popup controls 2026-07-28 14:12:27 -07:00
Ryan Fleury 0fe5aa5a43 first pass at watch expr location locks - still some jank around the edges due to eval incompleteness, but works for basic cases 2026-07-28 11:18:00 -07:00
Ryan Fleury ae8960d563 watch lock (ui part, no caching yet) 2026-07-28 07:42:44 -07:00
Ryan Fleury ec520227c5 enforce standalone 'expression' child for watch expressions in cfg tree, adjust eval / ui to work on that child, instead of assuming the first child of a watch expression node is the expression string itself - this will let us tag watch expressions with other info, like project / lock status etc. 2026-07-27 16:02:10 -07:00
Ryan Fleury 0b4c20b165 fix the lack of using contextual cursor info to commit to command parameter registers 2026-07-27 15:50:52 -07:00
Ryan Fleury 81722ebbac fix oob mouse -> line path 2026-07-27 14:47:41 -07:00
Ryan Fleury 41735fbf8b fix mismatched spaces for token/line dragging 2026-07-27 14:47:41 -07:00
Ryan Fleury 0c434583bc eval, local variable resolution -> do not assume offset evaluations. infer evaluation mode from location info 2026-07-27 14:47:40 -07:00
Ryan Fleury 7fbea68613 fix line-terminated tokens causing incorrect token pt parsing - e.g. unmatched quote in a comment 2026-07-27 14:47:40 -07:00
Ryan Fleury 62241f0d55 fix text search fwds/bwds 2026-07-27 14:47:39 -07:00
Ryan Fleury aa94eb6901 fix find-text-forward 2026-07-27 14:47:38 -07:00
Ryan Fleury 65f5b81d49 fix incorrect multiline hotkey mode setting in text view 2026-07-27 14:47:38 -07:00
Ryan Fleury a27dc03ca2 start meta tokens correctly 2026-07-27 14:47:37 -07:00
Ryan Fleury e55fa733fd mostly restore existing read-only functionality, keep existing patching infrastructure but do not use 2026-07-27 14:47:36 -07:00
Ryan Fleury 9ed2e020e8 checkpoint 2026-07-27 14:47:36 -07:00
Ryan Fleury f247d3c52d fix chunk-up/down 2026-07-27 14:47:35 -07:00
Ryan Fleury 150a2247bb fix page-up 2026-07-27 14:47:34 -07:00
Ryan Fleury 604fe35d91 fix navigations when zero-delta-on-select is enabled in multi-line controls; thread line break parsing 2026-07-27 14:47:34 -07:00
Ryan Fleury 36da346590 binary search for off -> line num 2026-07-27 14:47:33 -07:00
Ryan Fleury c8dae72968 cleanup around single vs. multiline text mutation controls 2026-07-27 14:47:32 -07:00
Ryan Fleury 315e0672d3 checkpoint on text patches 2026-07-27 14:47:31 -07:00
Ryan Fleury bb85f6f692 text patches: checkpoint 2026-07-27 14:47:31 -07:00
Nikita SmithandRyan Fleury cd82268a07 polish ICF section color-space picker 2026-07-27 14:47:30 -07:00
Nikita SmithandRyan Fleury 4235fa85b4 search small libraries on the main thread to reduce wait times in barriers 2026-07-27 14:47:29 -07:00
Nikita SmithandRyan Fleury db0151c3e2 parallel radix sort and coalesce adjacent section contribs 2026-07-27 14:47:29 -07:00
Nikita SmithandRyan Fleury bbb136c9ea radix sort pass over section contribs 2026-07-27 14:47:28 -07:00
Nikita SmithandRyan Fleury 2d827ac15d make const data eligible for ICF 2026-07-27 14:47:28 -07:00
Nikita SmithandRyan Fleury c629c5b10e refactor PDB background file output
Add a shared multi-file background writer with lazy worker startup.
Represent PDB output as a file artifact, keep PDB output state internal
to the builder, and overlap deferred PDB writers with the file maps release.
2026-07-27 14:47:27 -07:00
Nikita SmithandRyan Fleury c96c9620d0 WIP PDB Writer Thread 2026-07-27 14:47:26 -07:00
Nikita SmithandRyan Fleury a73e3e0790 use cycle tracking only on weak and undefined symbols
* profile of /OPT:REF shows that early push to seen_hm dominates the pass;
  cost: 74.23ms -> 6.81ms (-90.8%)
2026-07-27 14:47:26 -07:00
Nikita SmithandRyan Fleury fcee35f3e9 rename RAD_TypeHashAlg; extend /RAD_DEBUG_TYPE_HASH with XXHASH option 2026-07-27 14:47:25 -07:00
Nikita SmithandRyan Fleury 97a1fe6006 radix sort PSI address map 2026-07-27 14:47:24 -07:00
Nikita SmithandRyan Fleury 134cfce799 merge debug info and llvm_addrsig finders into lnk_obj_initer to reduce
time spent in barrier_wait
2026-07-27 14:47:24 -07:00
Nikita SmithandRyan Fleury 4cc0f4813b WIP cache COFF symbol interp 2026-07-27 14:47:23 -07:00
Nikita SmithandRyan Fleury a779d3f1a5 WIP assigned symbols 2026-07-27 14:47:22 -07:00
Nikita SmithandRyan Fleury 493241c1da WIP light COFF symbol table parse 2026-07-27 14:47:22 -07:00
Nikita SmithandRyan Fleury bd2cbfc127 gate for page pre-faulting on windows 2026-07-27 14:47:21 -07:00
Nikita SmithandRyan Fleury cb6443ce4e release file maps before exit in parallel before exit 2026-07-27 14:47:20 -07:00
Nikita SmithandRyan Fleury 58b5b3d92d search chunks only grow while resolving libraries, so revisit only symbols appended since this library's last search 2026-07-27 14:47:20 -07:00
Nikita SmithandRyan Fleury b84d32d9fb optimize ICF refinement and COMDAT handling
Cache immutable section and relocation metadata before color refinement,
then reuse generated-tagged concurrent tables.

Parallelize grouping and fold marking.

Include associative COMDAT descendants in contribution hashes and
canonicalize relocation targets to selected COMDAT leaders.
2026-07-27 14:47:19 -07:00
Nikita SmithandRyan Fleury abfea7c33a update CHANGELOG.md 2026-07-27 14:47:18 -07:00
Nikita SmithandRyan Fleury d1b0bc0af7 refine COMDAT symlink handling
Stop treating COMDAT section-definition symbols as symlink anchors.
Keep zero-sized COMDAT sections only when they have an owned symlink,
so referenced empty COMDAT symbols still resolve while marker sections
like .gsspr/.gssep are skipped.

Update COMDAT/ICF tests to cover zero-sized COMDAT relocation behavior
and the adjusted removed-COMDAT handling.
2026-07-27 14:47:18 -07:00
Nikita SmithandRyan Fleury 8ec931d724 fix import data directory bounds
Include the null import descriptor in the import directory size and derive
the IAT directory RVA from the first import descriptor of the start of
the .idata contribution.
2026-07-27 14:47:17 -07:00
Nikita SmithandRyan Fleury 048b93b166 remove empty sections if it does not have any section contributions too 2026-07-27 14:47:17 -07:00
Nikita SmithandRyan Fleury f3d2792fb8 simplify COMDAT leader symbol patching
Collapse COMDAT leader symbol patching to a single raw-symbol write path
and make the same-object versus cross-object symlink handling explicit.
Preserve public symbol offsets for ICF folds while avoiding cross-object
section number rewrites.
2026-07-27 14:47:16 -07:00
Nikita SmithandRyan Fleury 7197398f31 split external-symbol handling from section-definition fallbacks 2026-07-27 14:47:15 -07:00
Nikita SmithandRyan Fleury d790412219 refactor radlink section gathering
Fold section definition and contributions collection into a worker-count
task with barriers around the serial merge. Share section filtering
between both phases and keep zero-size COMDATs so offset-zero symbols
still map to a section.
2026-07-27 14:47:15 -07:00
Nikita SmithandRyan Fleury b77c958b5f add DEF, GUARD, and SECTION config support
Parse /DEF, /GUARD, and /SECTION switches, including DEF
handling for NAME/LIBRARY, BASE, VERSION, HEAPSIZE, STACKSIZE, EXPORTS,
and SECTIONS.

Store section directives in linker config and apply them consistently
when gathering object sections when pushing/searching image sections.

Pull load-config symbols for /GUARD without setting GUARD_CF until guard
tables are emitted.

Add coverage for DEF file parity, section directives, and guard
load-config handling.
2026-07-27 14:47:14 -07:00
Nikita SmithandRyan Fleury 35722f2a01 handle BOMs in linker response files
Decode UTF-16LE response files with a BOM and strip UTF-8 BOMs before
parsing arguments. Add coverage for UTF-16 response-file input.
2026-07-27 14:47:13 -07:00
Nikita SmithandRyan Fleury 25430ea522 assign COMDAT symlinks after weak symbol replacement
Previously, COMDAT symlinks were assigned as each object batch was loaded.
Weak symbol replacement could later change the selected leader, leaving
objects from earlier passes with stale COMDAT leader refs. Library search
does not need symlinks to be valid, so solve this by doing a single sweep
assignment of COMDAT leaders after a fixed point is found.
2026-07-27 14:47:13 -07:00
Nikita SmithandRyan Fleury 65541eaf91 LLVM BC magic sniffer 2026-07-27 14:47:12 -07:00
Nikita SmithandRyan Fleury afd454b41f fix DBI SC image-section range mapping
Log and skip section contributions that fail to map into the linked image.
Keep a file-range-to-section-number map so compact file ranges produce the
correct DBI section numbers.
2026-07-27 14:47:12 -07:00
Nikita SmithandRyan Fleury 541727b819 debug log unresolved symbols specified in .llvm_addrsig 2026-07-27 14:47:11 -07:00
Nikita SmithandRyan Fleury 3eeae8d365 enable binary for stdout and stderr to bypass CRLF mangling issues in
captured output under build systems
2026-07-27 14:47:10 -07:00
Nikita SmithandRyan Fleury 83c55aebdc check that __imp_* archive symbols are import members before applying
import queue flags to the member
2026-07-27 14:47:09 -07:00
Nikita SmithandRyan Fleury 941b8a011e duplicate identical search aliases are not an error case 2026-07-27 14:47:09 -07:00
Nikita SmithandRyan Fleury d34e1a7802 implement /OPT:ICF
Add identical COMDAT folding using a color-refinement over foldable
read-only sections. Hash section contents, relocation targets, and target
colors until partitions stabilize, then redirect folded COMDAT symlinks
and discard duplicate sections.

Honor .llvm_addrsig via /LLVM_ADDRSIG so address-significant sections
are not folded, keep separate color space for code, unwind info, and
MSVC vftables, and update COMDAT symbol/section mapping after folding.

Add linker tests covering function folding, relocation-sensitive folds,
alignment, color-space separation, symlink chains, .llvm_addrsig,
pdata/xdata, and C++ ICF cases.
2026-07-27 14:47:08 -07:00
Nikita SmithandRyan Fleury 1ea9fae835 debug report live stats after /OPT:REF pass 2026-07-27 14:47:08 -07:00
Ryan Fleury 62328cea3f checkpoint on text patches 2026-07-27 14:47:07 -07:00
Ryan Fleury 20cd955cc9 eval2: first pass at type_key -> string path 2026-07-27 14:47:06 -07:00
Ryan Fleury 0963f4a6de const/volatile/unsigned/signed type operators 2026-07-27 14:47:06 -07:00
Ryan Fleury 78d12eb914 custom module loads -> support manually specifying pdb path 2026-07-23 20:28:52 -07:00
Ryan Fleury b0841ff2da first pass at custom load-module exception (long term for JIT) 2026-07-23 20:22:54 -07:00
Ryan Fleury 16c447bb79 eval2: leaf bytecode in ir tree 2026-06-28 07:36:24 -07:00
Ryan Fleury 96cfb441fd correctly use command titles in native file explorer 2026-06-27 12:07:24 -07:00
Ryan Fleury 0e2b4ac5e7 ui discoverability adjustments 2026-06-27 06:21:31 -07:00
Ryan Fleury 969851b6f0 flip NO_ASYNC; turn on as needed, if a layer requiring it is included 2026-06-27 04:54:30 -07:00
Ryan Fleury 410a8e3afa eval2: function pointer type parsing/compiling 2026-06-27 04:43:58 -07:00
Ryan Fleury cae9754099 eval2: fix parsing task popping rules, still give chance to rhs when popping tasks in all cases 2026-06-27 04:25:05 -07:00
Ryan Fleury b704e797e2 notes 2026-06-27 03:50:17 -07:00
Ryan Fleury 773e6554dc cycle detection in fully qualified string generation 2026-06-26 20:35:50 -07:00
Ryan Fleury fdbcf7ccdc eval2: first pass at c recursive type expression parsing 2026-06-26 16:19:19 -07:00
Ryan Fleury f1f654ecfd eval2: simplify expression parsing info, allow child reversal (for parsing non-canonical expression orders into canonical shapes, e.g. Rust-style casts like 123 as float32 -> cast(float32, 123); ptr/array type operators, etc./ 2026-06-26 13:20:38 -07:00
Ryan Fleury 60b266a1cc support size_of and type_of in clike expressions 2026-06-26 11:28:01 -06:00
Ryan Fleury 9491fdf5c2 eval2: split out expression kinds from parse styles of expressions - lets us separate semantic expression tree from frontend, so that we can easily switch frontend 2026-06-26 11:22:43 -06:00
Ryan Fleury bcbc5e4a2a eval2: macro argument expression tree parsing 2026-06-26 10:07:02 -06:00
Ryan Fleury d7393b2f65 eval2: split string -> expr compilation path into frontend / middle end - string -> expr, where expr is a loose structural syntax tree (where we can get macros and stuff without doing typechecking etc.), and expr -> irtree, where irtree is the usual typed / typechecked / ir structured representation - preserve minimal identifier resolution path for parser, but move most resolution things to the middle-end 2026-06-25 15:48:14 -07:00
Ryan Fleury c2b74260ef eval2: opkind -> exprkind, prepare for exprs being looser 2026-06-25 13:58:03 -07:00
Ryan Fleury 6b52d68c62 eval2 checkpoint: type operations, constructed types, checkpoint before splitting back to frontend / compiler split - we need to do things with the parse tree that we can't with an ir tree 2026-06-25 13:50:16 -07:00
Ryan Fleury c1b3461709 eval2: switch to extrusive lists for expression lists - this lets us reuse expression trees. also solve strange isolated unload module events in win32 demon as well 2026-06-25 11:36:18 -06:00
Ryan Fleury 6c309038ce dbg_engine: ctrl thread - be robust to strange duplicate module unload events 2026-06-25 09:51:13 -06:00
Ryan Fleury 9d651f4bd5 EpicGamesExt -> EpicGames 2026-06-25 09:08:52 -06:00
Ryan Fleury 38c1e2a414 eval2: ptr arithmetic & comparisons 2026-06-25 09:07:34 -06:00
Ryan Fleury c817d1f136 eval2: type keys checkpoint 2026-06-24 20:39:53 -07:00
Ryan Fleury 296c851272 eval2 checkpoint: casts, function calls, expression-embedded identifier definitions, ternaries, compile-time ternaries 2026-06-24 16:29:57 -07:00
Ryan Fleury 6b841d9959 rdi_make: allow duplicates in bake name map insertions - they become extremely costly to check for, and we don't produce them anyways... 2026-06-24 07:20:06 -06:00
Ryan Fleury 1901e67f39 use synchronous reads for call stack computation, but extend artifact cache with the ability to say that a non-retryable failure occurred, so that we can fall back to stale call stacks 2026-06-23 20:00:57 -06:00
ed 3de96443a5 Merge remote-tracking branch 'EpicGamesExt/master'
# Conflicts:
#	.gitignore
2026-06-23 20:12:24 -04:00
Ryan Fleury 3d6851c57a rdi_from_Dwarf: count dependency counts correctly when using cached type content hashes 2026-06-23 16:07:53 -07:00
Nikita SmithandRyan Fleury 4daefad31e map GNU lib extension 2026-06-23 12:32:52 -07:00
Nikita SmithandRyan Fleury 765b61152d sort import library member refs by input index 2026-06-23 12:32:52 -07:00
Nikita SmithandRyan Fleury ad20900fc0 import hash table -> hash map 2026-06-23 12:32:51 -07:00
Nikita SmithandRyan Fleury 8dbced6995 set flag on import member from the originally linked library, otherwise
on subsequent passes linker may queue same import
2026-06-23 12:32:50 -07:00
Nikita SmithandRyan Fleury 84d025e940 force inline string compars 2026-06-23 12:32:50 -07:00
Ryan Fleury 98b7b5859c rdi_from_dwarf: stub out pointers for now, cache as we go, merge type dependency count calculation with hash computation 2026-06-23 12:32:11 -07:00
Ryan Fleury 28009ec01e rdi_from_dwarf type dedup hashing experiments checkpoint 2026-06-23 10:05:28 -07:00
Ryan Fleury a425936f56 run_tests test data download -> fail if curl fails, follow http redirects 2026-06-22 14:42:50 -07:00
Ryan Fleury fef78609d8 turn off d2r tests for now while new deduper is in progress; better tag skipping in dedup hashing 2026-06-22 14:25:25 -07:00
Martins MozeikoandRyan Fleury 401383bbd8 reorganize intrinsic includes to make clang happy 2026-06-22 14:21:01 -07:00
Ryan Fleury 76fa2be5a9 correct arch flags to clang 2026-06-22 13:45:53 -07:00
Ryan Fleury c8c8e02ab0 Revert "use CL driver when compiling with clang on windows to simplify compile and link lines"
This reverts commit ba32d7fdec.

This causes tons of compatibility issues, some of which were preventing
Clang builds on specific Clang versions due to command line
incompatibility between lld-link and link.
2026-06-22 13:44:18 -07:00
Ryan Fleury e2430fa23e remove redundant incs of xxhash - undef cpuid macro before xxhash is
included, so that we don't have conflicting definitions due to memfun
2026-06-22 13:43:19 -07:00
Ryan Fleury 28d037a924 checkpoint on faster rdi_from_dwarf type/namespace deduping 2026-06-22 13:31:08 -07:00
Ryan Fleury 73e9f3c9da rdi_from_dwarf: determinism / regression tests 2026-06-21 20:56:46 -07:00
Ryan Fleury dac63d6bef fix linux build 2026-06-21 20:47:09 -07:00
Ryan Fleury 286589f4de rdi_from_pdb: exemplar tests 2026-06-21 20:37:52 -07:00
Ryan Fleury c890b806d5 pull out test input/exemplar path formation helpers to base; fix torture crash 2026-06-21 20:13:44 -07:00
Ryan Fleury bc324a9041 remove exemplars from repo; switch to storing on test data server 2026-06-21 19:54:37 -07:00
Ryan Fleury fa4c003f79 run_tests.bat -> download test data if stale 2026-06-21 16:20:37 -07:00
Ryan Fleury ed6afcb180 checkpoint on rdi_from_dwarf pass, start addressing O(N lg N) hashing problem for type content, use sibling tags, etc.; remove test inputs from data/, just rely on local folder (filled via data server) 2026-06-21 15:53:38 -07:00
Ryan Fleury d3d35e40d7 rdi_from_dwarf: use sibling tags to advance in hash path too - set up for deduplicating hash work 2026-06-19 20:53:01 -07:00
Nikita SmithandRyan Fleury 4f899ac678 update memfun 2026-06-19 20:12:27 -07:00
Nikita SmithandRyan Fleury 05a024ddb3 remove /RAD_ALT_PCH_DIR
* Instead of matching on file path in LF_PRECOMP, loop over the objects
  with .debug$P and probe leaves at the index specified in LF_PRECOMP.
  If signatures match, use the PCH.
* Demote LNK_Error_PrecompObjNotFound to a recoverable error.
2026-06-19 20:12:27 -07:00
Nikita SmithandRyan Fleury 9b63131f37 ditch semaphores in thread pool in favor of barriers 2026-06-19 20:12:26 -07:00
Nikita SmithandRyan Fleury 6ea9bfc5a3 fix tail comparisons 2026-06-19 20:12:25 -07:00
Nikita SmithandRyan Fleury c81c072018 includes for rdi_from_codeview 2026-06-19 20:12:25 -07:00
Nikita SmithandRyan Fleury 3534100e8d lazy touch obj string tables 2026-06-19 20:12:24 -07:00
Nikita SmithandRyan Fleury 9616307503 add extra node to the symbol ref for better insertion per 2026-06-19 20:12:24 -07:00
Nikita SmithandRyan Fleury 871f94a202 use vectorized memory functions in the base strings 2026-06-19 20:12:23 -07:00
Nikita SmithandRyan Fleury ba32d7fdec use CL driver when compiling with clang on windows to simplify compile and link lines 2026-06-19 20:12:22 -07:00
Nikita SmithandRyan Fleury 8ef58def99 update torture
* factor test registration logic out of the macro to improve debuggability
* expand the test registration logic
* rename group -> layer for consistency
* fix indentation in the slow tests summary
2026-06-19 20:12:22 -07:00
Ryan Fleury 0d62c49c52 only rewrite stdout/stderr/etc. if passed cli specifically 2026-06-19 20:12:21 -07:00
Ryan Fleury fe2aa4d14c com shim for launching raddbg in cli mode, for proper console subsystem style usage of packaged bin utilities; checkpoint on eval2 2026-06-19 20:12:20 -07:00
Ryan Fleury 3fd7b40f4d remove 'global stream' specialities in codeview -> rdi conversion; just have the caller pass all units, and in the case of pdb conversion, we simply make a global unit at that layer. 2026-06-19 20:12:20 -07:00
Ryan Fleury 15601d48d4 rdi_from_dwarf: use sibling tag attributes to gather root-level tag offsets when present - 15x speedup in the gather on webkit DWARFs... 2026-06-19 20:11:50 -07:00
Ryan Fleury 9f82a6fe91 fix flipped interpretation of scope address ranges in dwarf - address class implies opl, not size 2026-06-19 12:41:17 -07:00
Ryan Fleury 3b22b1f13e fix incorrect work happening w/ subsets turned off for psym generation 2026-06-19 12:37:43 -07:00
Ryan Fleury 66bca76edd delete non-codeview-backed pdb conversion path, switch over to codeview conversion totally 2026-06-18 08:59:51 -07:00
Ryan Fleury a441a5eef3 plug in codeview-conversion-backed pdb converison 2026-06-18 08:54:41 -07:00
Ryan Fleury d56cd83cac sketch out revised pdb conversion path which just uses the codeview conversion pass 2026-06-18 08:24:02 -07:00
Ryan Fleury c411895db5 sketch out & get building rdi_from_codeview, extract ~90% of pdb conversion into only working given codeview info *or* something the linker could produce 2026-06-18 08:04:32 -07:00
Ryan Fleury 3aad389174 notes 2026-06-17 19:30:08 -07:00
Ryan Fleury cc75260946 checkpoint on eval2; type graph operations, parsing, etc. 2026-06-17 17:38:09 -07:00
Ryan Fleury 11b3f25842 checkpoint on eval2 2026-06-16 17:56:48 -07:00
Nikita Smith b8bad9a82e range helper that computes max part from min+size 2026-06-16 17:22:53 -07:00
Nikita Smith 267b8fc519 missing count in the range list concat 2026-06-16 17:22:52 -07:00
Nikita Smith 956df5527a switch type server from PDB to a custom file format (RRT) 2026-06-16 17:22:50 -07:00
Ryan Fleury 00da627293 checkpoint on eval2 compiler; setting to disable update checking; cache version check to once per day so that we do not send a lot of extra GH requests every time the debugger starts 2026-06-16 14:30:13 -07:00
Ryan Fleury bcdc6acd0e checkpoint on eval2 parse 2026-06-16 12:29:03 -06:00
Ryan Fleury eb87cb053e fix bad sub register block address calculation!!! 2026-06-14 20:20:52 -07:00
Ryan Fleury 7f985b35f3 only do session-start logic once per tick! 2026-06-13 20:22:37 -07:00
Ryan Fleury d9efc61b66 just dump file name in raddbg state dump; commit to exemplars; keep exemplars more context-free 2026-06-13 11:21:42 -07:00
Ryan Fleury 6a2aa95ea3 okay, *now* bump to 28 2026-06-13 06:38:03 -07:00
Nikita SmithandRyan Fleury c030488814 fallback on PCH signature when file path match fails 2026-06-13 06:20:40 -07:00
Ryan Fleury 6ca7f162aa shift temporarily to 27 2026-06-13 06:17:55 -07:00
Nikita SmithandRyan Fleury c6a4e4c02b skip broken tests 2026-06-12 15:34:30 -07:00
Nikita SmithandRyan Fleury 41e6470d28 fix radbin launch in p2r determinism test 2026-06-12 15:34:29 -07:00
Ryan Fleury 58c17c2bc3 fix bad rdi opcode tables! 2026-06-12 15:30:30 -07:00
Ryan Fleury 083a843bf7 bump to 28 2026-06-12 14:10:20 -07:00
Ryan Fleury d83f1fad1a turn off eval2 for now 2026-06-12 14:10:20 -07:00
Nikita Smith 7d8aa18e4d make debug hash section tests error number agnostic 2026-06-12 13:54:29 -07:00
Ryan Fleury 2b20760386 checkpoint on revised eval system; first pass on interpretation; eliminating all callbacks / eval involvement in contexts/spaces/identifier-resolution/etc. 2026-06-12 13:50:28 -07:00
Nikita Smith ac0c7d9441 on checkout do git LFS in github actions 2026-06-12 13:35:10 -07:00
Nikita Smith 7ad422f8ad make run_tests.sh executable 2026-06-12 13:21:31 -07:00
Nikita Smith 2a5070bb87 update change log 2026-06-12 13:17:21 -07:00
Nikita Smith ac8c3e7a2d do not emit relocation for empty resource entry 2026-06-12 12:05:45 -07:00
Nikita Smith 3f6d5df899 apply merge fixes 2026-06-12 11:53:15 -07:00
Nikita Smith 9ce6b9504b centralize section header reads and writes 2026-06-12 11:40:03 -07:00
Nikita Smith 42cf820972 cache for section flags
modifying the section flags is expensive with COW file mappings, Windows
maps are set to 64k granularity
2026-06-12 11:40:02 -07:00
Nikita Smith 3452f23839 add a new boot mode to RADLINK for launching as a type server
checkpoint
2026-06-12 11:40:01 -07:00
Ryan Fleury 2c4882595c eval system notes 2026-06-11 11:10:28 -07:00
Ryan Fleury d45401e8cd pass over default light 2026-06-11 10:28:39 -07:00
Ryan Fleury f1dfe5f6c0 changelog notes 2026-06-11 09:40:39 -07:00
Ryan Fleury 90b650354a eliminate redundant/unused info from command tables in dbg engine / raddbg 2026-06-11 09:08:34 -07:00
Ryan Fleury 82fd06c8e4 specialize text right-click menus by disasm vs. source 2026-06-11 08:51:47 -07:00
Ryan Fleury a980be7664 notes 2026-06-10 12:51:52 -07:00
Ryan Fleury 645cf46e55 explicit process address space evaluation 2026-06-10 11:57:53 -07:00
Ryan Fleury f7ba4b2ebe move from fixed flags to list of tags (matching command list evaluation names) for context menu command filtering; pull out code for filling command regs from contextual expressions; add mechanism for contextualizing a whole query, so that we can spawn command listers within the context of some other evaluation, which we'd like to fill registers with (e.g. right-clicking a module -> spawn a module command list, contextualized by the module evaluation itself 2026-06-10 09:54:57 -07:00
Ryan Fleury 1577ea5693 fix rdi folder writability test to account for possibly-uncreated directories, so that we don't unnecessarily write into the user-local rdi cache 2026-06-10 08:39:40 -07:00
Ryan Fleury 40d9e5839f fix torture; adjust raddbg test exemplar dumping to avoid dumping info for anything other than the main module, so that we don't get non-deterministic dumps (for e.g. system PDBs) 2026-06-10 07:57:18 -07:00
Ryan Fleury 9af4c3d614 W over A win32 window functions; wakeup on WM_CLOSE (manual merge of
cbf3fd5587)
2026-06-10 04:43:01 -07:00
Ryan Fleury 19cb0331b0 fix implicit expr parameterization in add-breakpoint margin click path 2026-06-10 04:29:32 -07:00
Ryan Fleury 5ddad36380 zero undefined registers in eh unwind 2026-06-09 16:18:47 -07:00
Ryan Fleury ffb79a67ef be robust to missing symbol server support 2026-06-09 16:07:16 -07:00
Ryan Fleury 8a098c5d45 adjust rules for text view loading; handle non-evaluations / empty evaluations correctly 2026-06-09 16:02:33 -07:00
Ryan Fleury f57137288b check if rdi path is writable before deciding to convert to it; if it isn't writable, then redirect to a rdi cache directory 2026-06-09 16:02:33 -07:00
Ryan Fleury 2faa9211eb cleanup 2026-06-09 16:02:32 -07:00
Малов Андрей ВладимировичandRyan Fleury 220b288690 render/opengl/linux/egl: unwrap R_OGL_Window when extracting EGL surface 2026-06-09 16:02:31 -07:00
Малов Андрей ВладимировичandRyan Fleury 7f3318309b render/opengl/linux/glx: force GL_DRAW_BUFFER=GL_BACK after make-current 2026-06-09 16:02:31 -07:00
Ryan Fleury c05846aef1 fix incorrect impl of RDI_EvalOp_Swap 2026-06-09 16:02:30 -07:00
Малов Андрей ВладимировичandRyan Fleury be8ed940bd eval: implement Swap; soft-fail CallSiteValue; no-op piece markers 2026-06-09 16:02:30 -07:00
Малов Андрей ВладимировичandRyan Fleury 94da046fb6 demon/linux: derive symbol count from GNU_HASH 2026-06-09 16:02:29 -07:00
Малов Андрей ВладимировичandRyan Fleury d64912be7e render/opengl/linux/egl: pick config in init; pass to context; bind pbuffer 2026-06-09 16:02:28 -07:00
Малов Андрей ВладимировичandRyan Fleury eee1a64d14 render/opengl/linux/glx: publish chosen visual + colormap to os layer 2026-06-09 16:02:28 -07:00
Малов Андрей ВладимировичandRyan Fleury 2e5a97ebf9 os/gfx/linux: create x11 window with gl-chosen visual / colormap 2026-06-09 16:02:27 -07:00
Aiden ShiandRyan Fleury 562c2e3e5f fix: use fp_flags instead of flags 2026-06-09 15:13:10 -07:00
Daniel Ribeiro MacielandRyan Fleury 972df1a467 fix delete button on linux 2026-06-09 15:11:42 -07:00
Ryan Fleury e047e84433 do not assume writable module 2026-06-09 15:01:01 -07:00
Ryan Fleury fde13f52d3 fix nil text visualizations; fix auto-load-recent-project 2026-06-09 14:56:34 -07:00
Ryan Fleury 5ae286d67e setting for auto-downloading missing debug info (off by default); command for manually loading module debug info as-needed 2026-06-09 14:01:09 -07:00
Ryan Fleury 0105b06fef fix conflicting lifetimes in http read - batch of retry-response-body-pieces was conflicting with asynchronous reading state! 2026-06-09 13:14:29 -07:00
Ryan Fleury 27e1e36f5c fix incorrect marking of non-stale results by artifact cache lookup; fix view addr parameterizations when a register value is used 2026-06-09 11:24:54 -07:00
Ryan Fleury 0f02c32c89 pull failed-unwind-step register-block-restore out of each impl, just do it on the caller side; pull out module-less read-the-stack-pointer unwind fallback from pe/x64 unwinder, use in module-less unwinds in all cases; call into from pe/x64 unwinder in fallback case 2026-06-09 10:58:16 -07:00
Ryan Fleury ec4fd23e15 fix incorrect commits in new pe/x64 unwinder; fix bad unwind termination conditions 2026-06-09 10:38:08 -07:00
Ryan Fleury 9955c8c1a7 temporarily turn off symbol server stuff - switch off spoof for step-over 2026-06-09 09:27:23 -07:00
Ryan Fleury 132751777f eliminate unnecessary info in debug engine entity abstraction / demon events; adjust symbol server / debug info loading such that the debug info loader is the one who decides to kick off downloads based on presence in cache path; use cache path as key, unpack info for download requests 2026-06-08 21:06:44 -07:00
Ryan Fleury b22f9f2d8b checkpoint on symbol server 2026-06-08 17:32:07 -07:00
Ryan Fleury 536ca53d18 rdi_from_pdb: sketch out paths for LF_ALIAS 2026-06-08 11:26:17 -07:00
Ryan Fleury 2d6260fc68 remove dummy test file 2026-06-08 11:13:07 -07:00
Ryan Fleury 5c664261a3 symbol server abstraction layer; http layer; fix to 'prefer_disasm' rule when no disassembly tabs are open; small fixes / cleanup 2026-06-08 11:10:14 -07:00
Ryan Fleury 1ef94cb759 fix find-code-location snap rule when src/disasm occupy same panel & they are found by different rules; conflicting panels must be checked across *all* cases 2026-06-06 15:37:24 -07:00
Ryan Fleury dc613f3a08 correctly handle voff evaluations in generalized watch window completion path (offline evaluation in everything palette case) 2026-06-03 14:43:50 -07:00
Ryan Fleury 09f78fdae4 small parameterization to query watches 2026-06-03 14:28:06 -07:00
Ryan Fleury 015ae9c62c set up for memory right clicks 2026-06-03 12:49:39 -07:00
Ryan Fleury d7b59e4a39 break when value changes 2026-06-03 12:37:28 -07:00
Ryan Fleury 3a04a96e03 eval right-click; start with go-to-memory command 2026-06-03 12:16:42 -07:00
Ryan Fleury 6b88ad1ea3 fix incorrect temp pop 2026-06-03 10:34:01 -07:00
Ryan Fleury 0df1b34580 fix spacing 2026-06-03 10:31:45 -07:00
Ryan Fleury 737ceb1313 tweaks / improvements to watch windows & lister ui - display controls, appearance, remove redundant visual info 2026-06-03 10:28:47 -07:00
Ryan Fleury e7153e8910 auto load project only when project is not specified; fix alt menu weirdness on alt+tab 2026-06-03 09:10:53 -07:00
Ryan Fleury 4d1d362ac1 adjust find-code-location path to absolutify relativized paths based on current thread/module; also respect module-relative / debug-info-relative paths in src -> voff & voff -> src mapping 2026-06-03 09:01:51 -07:00
Ryan Fleury fd1ee1c265 radbin: absolutify relative external-file-paths (debug link, pdb-in-exe), to avoid clashing with working-directory files of the same name 2026-06-02 14:41:43 -07:00
Ryan Fleury e958814b07 use fully-qualified names in eval viz address resolved symbol strings, used in call stack / etc. 2026-06-02 12:16:16 -07:00
Ryan Fleury 5a819f8094 setting for auto-loading of recent projects 2026-06-02 12:11:17 -07:00
Ryan Fleury 1673fa5606 enable lfs on github actions 2026-06-02 12:11:16 -07:00
Ryan Fleury 6a2e2eb798 d2r2 -> d2r 2026-06-02 12:11:16 -07:00
Ryan Fleury 6ed6d3f16d rdi_from_dwarf [1] -> obsolete; promote 2 -> 1 2026-06-02 12:11:15 -07:00
Ryan Fleury b75b9b45cc fix radbin 2026-06-02 12:11:15 -07:00
Ryan Fleury a2700de35d dwarf parse/expr/unwind/dump 2 -> 1; move old stuff to obsolete 2026-06-02 12:11:14 -07:00
Ryan Fleury ef5fc82e9c dead code elimination 2026-06-02 12:11:14 -07:00
Ryan Fleury d73ce364b9 major clean-up pass over unwinding/module-info abstraction, + usage in the debug engine. simplified / cleaned up DWARF helpers for unwind info & expressions. decoupling unwinding / DWARF evaluation from memory read callbacks. light module info now prepared by demon layer - debug engine no longer duplicates per-backend parsing. unwind abstraction layer now does thin abstraction over unwinding backends, debug engine only calls abstraction. clean up demon to have fewer ad-hoc 'queries' on handles, and prefer sending info over debug events when possible / when it fits the usage pattern. move DWARF enum specifications to metacode, generate enums/xlists/tables/etc. decouple raddbg/radbin completely from old parsing helpers. replace portion of DWARF dumping; pull out some new parsing helpers from converter / dumper. 2026-06-02 12:11:13 -07:00
Nikita SmithandRyan Fleury 541d3afefa WIP /RAD_TYPE_SERVER
env vars

replace HashTable with HashMap in config
2026-06-02 12:11:12 -07:00
Nikita SmithandRyan Fleury 4c8d66b431 fix accidental removal of debug info sections resulting in non-eligible
sections not getting marked with 'is_live'
2026-06-02 12:11:11 -07:00
Nikita SmithandRyan Fleury 98a281c8a0 hint for installing external libraries 2026-06-02 12:11:11 -07:00
Ryan Fleury 9cc2afc659 eliminate backend-specific module parsing from debug engine ctrl thread; just pass that info back via the demon event 2026-06-02 12:11:10 -07:00
Ryan Fleury d98d6b56d9 check in test input binaries, adjust torture test data path 2026-06-02 12:11:09 -07:00
Ryan Fleury 1c1fef0f97 lfs tracking for exes/pdbs/rdis/elfs 2026-06-02 12:11:08 -07:00
Ryan Fleury 2dee864547 fix fn pointer mismatch on clang builds 2026-06-02 12:11:08 -07:00
Ryan Fleury f72d7bbe61 run -> run_tests 2026-06-02 12:11:07 -07:00
Ryan Fleury c746fadcaa run -> run_tests 2026-06-02 12:11:07 -07:00
Ryan Fleury 4dd22c9e51 re-enable p2r determinism tests 2026-06-02 12:11:06 -07:00
Ryan Fleury d909f187d5 be robust to any line endings in exemplar data 2026-06-02 12:11:06 -07:00
Ryan Fleury 1ea8c48867 raddbg exemplar tests -> use specific hash version, name exemplars by their platform, skip if test data unavailable 2026-06-02 12:11:05 -07:00
Ryan Fleury dc61f20e3b sketch out stepping/eval exemplar testing; step-to-exit first pass 2026-06-02 12:11:04 -07:00
Ryan Fleury a0bf825169 run-to-name, use to 'seed' test binary cases' 2026-06-02 12:11:03 -07:00
Ryan Fleury 8564884d76 raddbg: stepping regression tests 2026-06-02 12:11:02 -07:00
Ryan Fleury 685c408a13 migrate from torture-defined testing markup -> base 2026-06-02 12:11:02 -07:00
Ryan Fleury 4e72553006 promote test-definition concepts from torture to base layer; reorganize tests to be nested in their respective layer; eliminate 't_group', just use containing layer 2026-06-02 12:11:01 -07:00
Nikita SmithandRyan Fleury a151df283f skip tests without directive, and escape * in ubuntu run 2026-06-02 12:11:00 -07:00
Nikita SmithandRyan Fleury 3a109a7343 sketch test for SYSV and GNU style hash tables 2026-06-02 12:11:00 -07:00
Nikita SmithandRyan Fleury 637a0f88b2 add run_to_line command; clean up pass over script parser; changed
harness to always compile and link tests to prevent code rotting
2026-06-02 12:10:59 -07:00
Nikita SmithandRyan Fleury e3fa8e4830 improve error reports in tests 2026-06-02 12:10:58 -07:00
Nikita SmithandRyan Fleury fe2778133f rework file directive handling; remove T_Group; add SKIP to disable
tests that are not passing; change command line syntax for easier
test run/skip/force; updated help; shortened --dbg_graphical -> --gui;
add 'skip' directive to the dbg scripts
2026-06-02 12:10:58 -07:00
Nikita SmithandRyan Fleury a21a256333 .gitattributes 2026-06-02 12:10:57 -07:00
Ryan Fleury 769bda0ed8 restore torture mdesk tests 2026-06-02 12:10:57 -07:00
Ryan Fleury 96c1ca549c Revert "export line and column numbers from MD"
This reverts commit 29becc3bfa6037a1ba5c5657f891a65a819b0997.
2026-06-02 12:10:56 -07:00
Nikita SmithandRyan Fleury 3a7586e84b export line and column numbers from MD 2026-06-02 12:10:56 -07:00
Ryan Fleury 3715021e0e do not assume nonzero namespace table slots 2026-06-02 12:10:55 -07:00
Nikita SmithandRyan Fleury b1d58fb4f9 skip DWARF line table and checksum tests 2026-06-02 12:10:54 -07:00
Nikita SmithandRyan Fleury e06e7f1c9f split voff_range into two fields 2026-06-02 12:10:54 -07:00
Nikita SmithandRyan Fleury c875c912d2 update IPC parser 2026-06-02 12:10:53 -07:00
Ryan Fleury c723584bfa send acks always 2026-06-02 12:10:53 -07:00
Ryan Fleury 5f851ad1b0 simplify testing ipc driving stuff in raddbg layer; put in formal eval/line-from-vaddr commands 2026-06-02 12:10:52 -07:00
Nikita SmithandRyan Fleury ec6f569181 set CLOCK_MONOTONIC on conditional variables 2026-06-02 12:10:51 -07:00
Ryan Fleury 4bbed83eab only send ack on catch-all path for external driver cmds 2026-06-02 12:10:51 -07:00
Nikita SmithandRyan Fleury e3587dcb9f use GetForegroundWindow for foucs detection with parented debuggers 2026-06-02 12:10:50 -07:00
Nikita SmithandRyan Fleury 568a77b73c fix up scratch conflicts 2026-06-02 12:10:50 -07:00
Nikita SmithandRyan Fleury 4ff6d2cc6c use the make library to generate RDI 2026-06-02 12:10:49 -07:00
Ryan Fleury 4e44a3c271 get default symbol path as part of process info; sketch out windows-style path for local symbol server cache 2026-06-02 12:10:48 -07:00
Ryan Fleury e1782d08cf show line info on visualizing function evaluations 2026-06-02 12:10:48 -07:00
Ryan Fleury 1c29112e9c first pass at per-target output log labels 2026-06-02 12:10:47 -07:00
Nikita SmithandRyan Fleury eb90ddc739 remove eval_compiler_basics 2026-06-02 12:10:46 -07:00
Nikita SmithandRyan Fleury b2318803a1 report radbin errors 2026-06-02 12:10:46 -07:00
Nikita SmithandRyan Fleury e637149ae3 broadcasting a stack pointer and then leaving scope in optimized
mode may cause use-after-free
2026-06-02 12:10:45 -07:00
Nikita SmithandRyan Fleury 79cb6c3c5e step into tests 2026-06-02 12:10:45 -07:00
Nikita SmithandRyan Fleury 09afff7957 improve error handling in the debugger harness (source file + line
number for error reports and allow scripts without header)
2026-06-02 12:10:44 -07:00
Ryan Fleury 56ee3bbf7b eval: use resolution qualifiers to express disambiguating debug info, or module, or unit, and use in debug info resolution matching path; automatically prefer selected thread voff's unit 2026-06-02 12:10:43 -07:00
Ryan Fleury a72d284058 more aggressively use scratch & limit temporary allocations in rdi baker 2026-06-02 12:10:43 -07:00
Martins MozeikoandRyan Fleury 5e2ae50214 cleanup atomic wrappers
* use iso_volatile_load for just a load of u64/u32 from memory on msvc
* use intrin.h _interlocked* intrinsics instead of defines from windows.h
* use better suited fetch_xyz instead of xyz_fetch ones on gcc/clang
2026-06-02 12:10:42 -07:00
Nikita SmithandRyan Fleury eb8cee76c0 update .gitattributes to set LF endings on meta files so metagen
files have consistent line endings regardless of the host preference
2026-06-02 12:10:42 -07:00
Ryan Fleury 0b5651eecd project files 2026-06-02 12:10:41 -07:00
Nikita SmithandRyan Fleury 4a57087d81 dump RDI local vars 2026-06-02 12:10:40 -07:00
Nikita SmithandRyan Fleury 8127763fa4 fix linux build 2026-06-02 12:10:40 -07:00
Nikita SmithandRyan Fleury 2e4069b89a debug stats for /OPT:REF 2026-06-02 12:10:39 -07:00
Nikita SmithandRyan Fleury c5677cf5f4 wire DWARF expression eval to the unwinder 2026-06-02 12:10:39 -07:00
Nikita SmithandRyan Fleury 8126f1f18e first popped value off the stack is right-hand-side 2026-06-02 12:10:38 -07:00
Nikita SmithandRyan Fleury 03180247c9 rebase fixes 2026-06-02 12:10:38 -07:00
Nikita SmithandRyan Fleury 1883649e18 debug util for PDB section map 2026-06-02 12:10:37 -07:00
Nikita SmithandRyan Fleury 2f799e0e0e more /OPT:REF tests 2026-06-02 12:10:37 -07:00
Nikita SmithandRyan Fleury 49af8248ef update tests summary 2026-06-02 12:10:36 -07:00
Nikita SmithandRyan Fleury 31662822db rebase 2026-06-02 12:10:36 -07:00
Nikita SmithandRyan Fleury 19cee2d646 todo 2026-06-02 12:10:35 -07:00
Nikita SmithandRyan Fleury cc93bf4439 mismatched type on 'blur_count' 2026-06-02 12:10:34 -07:00
Nikita SmithandRyan Fleury c62afbcf83 normalize line endings in generated files 2026-06-02 12:10:34 -07:00
Nikita SmithandRyan Fleury 9447cce94d open generated files as binary so we have consistent line endings across
Linux and Windows
2026-06-02 12:10:33 -07:00
Nikita SmithandRyan Fleury 5089a01058 change make_directory behavior on Linux to match Windows behavior 2026-06-02 12:10:32 -07:00
Nikita SmithandRyan Fleury a1f0df2d76 run clang build for now 2026-06-02 12:10:32 -07:00
Nikita SmithandRyan Fleury fb48dcf42b update defines for non-graphical debugger build 2026-06-02 12:10:31 -07:00
Nikita SmithandRyan Fleury 612ac8f414 fix regression introduced in aea4a4ff 2026-06-02 12:10:31 -07:00
Nikita SmithandRyan Fleury 1e0f1d026b sanity-check scissor region, fix var shadowing bug in blur GLSL shader,
and remove 'blur_count' that causes linking issues

[OpenGL] GL_INVALID_OPERATION in glGetUniformLocation(program not linked)
[OpenGL] GL_INVALID_OPERATION in glUniform(program not linked)
[OpenGL] GL_INVALID_VALUE in glScissor
2026-06-02 12:10:30 -07:00
Nikita SmithandRyan Fleury 15bf343168 gate for dwarf converter 2026-06-02 12:10:30 -07:00
Nikita SmithandRyan Fleury a3bac20a73 rebase fixes
normalize line endings

sort test pointers

rebase fixes

rebase fixes
2026-06-02 12:10:29 -07:00
Nikita SmithandRyan Fleury 58fc57f6a3 torture_dbg: reuse Windows env-var expander in the harness compile/link/launch steps 2026-06-02 12:10:28 -07:00
Nikita SmithandRyan Fleury 96e20759d5 file endings 2026-06-02 12:10:28 -07:00
Nikita SmithandRyan Fleury 65288208af dbg_engine: extend trap-net range across contiguous same-source-line ranges 2026-06-02 12:10:27 -07:00
Nikita SmithandRyan Fleury d7e5c5a830 dbg_engine: bugfix memory fetch in step_over, step_over_inst, and step_into
and incorrect boolean logic for trap-net
2026-06-02 12:10:27 -07:00
Nikita SmithandRyan Fleury 4acd8a9b86 fill out address 2026-06-02 12:10:26 -07:00
Nikita SmithandRyan Fleury 528b0fde56 replace hard-coded visual studio path with vswhere 2026-06-02 12:10:26 -07:00
Nikita SmithandRyan Fleury 3e9fff93f1 tidy up names in builds.yml 2026-06-02 12:10:25 -07:00
Nikita SmithandRyan Fleury 146ef012c4 on error restore PATH 2026-06-02 12:10:24 -07:00
Nikita SmithandRyan Fleury ec3da44568 minor fix 2026-06-02 12:10:24 -07:00
Nikita SmithandRyan Fleury 266d66250c process join 2026-06-02 12:10:23 -07:00
Nikita SmithandRyan Fleury a60b61cafd run 2026-06-02 12:10:23 -07:00
Nikita SmithandRyan Fleury bf1fd5fbe8 delete debug code 2026-06-02 12:10:22 -07:00
Nikita SmithandRyan Fleury 608c42a261 run_tests -> run 2026-06-02 12:10:22 -07:00
Nikita SmithandRyan Fleury 56c5036593 use run_tests.sh to drive builds.yml 2026-06-02 12:10:21 -07:00
Nikita SmithandRyan Fleury 1de3be3b8b on windows test clang in release without asan 2026-06-02 12:10:21 -07:00
Nikita SmithandRyan Fleury b4cfc61408 add Ubuntu build and torture steps to GH actions 2026-06-02 12:10:20 -07:00
Nikita SmithandRyan Fleury 7b2743a4d6 enable stepping test 2026-06-02 12:10:19 -07:00
Nikita SmithandRyan Fleury 388bbb95a5 update nuke 2026-06-02 12:10:19 -07:00
Nikita SmithandRyan Fleury ffe18834dd run tests on Linux 2026-06-02 12:10:18 -07:00
Nikita SmithandRyan Fleury e92947057d workaround os_get_current_path 2026-06-02 12:10:18 -07:00
Nikita SmithandRyan Fleury bcf248682c guard against relative path nodes 2026-06-02 12:10:17 -07:00
Nikita SmithandRyan Fleury e17bcd3058 switch for launching debugger with window 2026-06-02 12:10:17 -07:00
Nikita SmithandRyan Fleury 857ab15aaa hack-in temp backslash for windows 2026-06-02 12:10:16 -07:00
Nikita SmithandRyan Fleury 2102239b81 make test ignore slashes 2026-06-02 12:10:15 -07:00
Nikita SmithandRyan Fleury f3c631973b various fixes in torture for Linux compatibility 2026-06-02 12:10:15 -07:00
Nikita SmithandRyan Fleury 14dff337d4 disable radlink tests for windows 2026-06-02 12:10:14 -07:00
Nikita SmithandRyan Fleury 2d99f5600c move linker id helper to the main file so we can use it in other torture
layers
2026-06-02 12:10:14 -07:00
Nikita SmithandRyan Fleury 2ded251f7e update stepping test to produce a fixed exe on windows 2026-06-02 12:10:13 -07:00
Nikita SmithandRyan Fleury f59784bba0 headers for Linux OS layer 2026-06-02 12:10:13 -07:00
Nikita SmithandRyan Fleury fc0b0d1586 more targets 2026-06-02 12:10:12 -07:00
Nikita SmithandRyan Fleury d92d2d435d enable 16-byte CAS intrinsic 2026-06-02 12:10:11 -07:00
Nikita SmithandRyan Fleury 3da0b89ac6 null check semaphore otherwise sem_* crashes 2026-06-02 12:10:11 -07:00
Nikita SmithandRyan Fleury 7c6ad4c563 add file reserve Linux OS API for radlink 2026-06-02 12:10:10 -07:00
Nikita SmithandRyan Fleury 22159ac779 delete unnecessary helper 2026-06-02 12:10:10 -07:00
Nikita SmithandRyan Fleury 61724e88ad event shadowing in dbg engine ctrl causes debugger to return incorrect
last event
2026-06-02 12:10:09 -07:00
Nikita SmithandRyan Fleury 1b868928ea infer path style from top node 2026-06-02 12:10:09 -07:00
Nikita SmithandRyan Fleury de03edc69e rename artifact folder so it does not collide with torture program on linux 2026-06-02 12:10:08 -07:00
Nikita SmithandRyan Fleury 60a38247af capture output on linux 2026-06-02 12:10:07 -07:00
Nikita SmithandRyan Fleury 05fc085dc6 new launch target 2026-06-02 12:10:07 -07:00
Nikita SmithandRyan Fleury 61f7d0c43a minor fixes 2026-06-02 12:10:06 -07:00
Nikita SmithandRyan Fleury b7e86b038b add asan to build.sh 2026-06-02 12:10:05 -07:00
Nikita SmithandRyan Fleury 4648b27a06 increase wait time for memory slice in line stepping 2026-06-02 12:10:05 -07:00
Nikita SmithandRyan Fleury a8c167c6ae builds 2026-06-02 12:10:04 -07:00
Nikita SmithandRyan Fleury b23323c03d add switch to override default logs folder 2026-06-02 12:10:04 -07:00
Nikita SmithandRyan Fleury b4dd1f6fd3 implement os wakeup 2026-06-02 12:10:03 -07:00
Nikita SmithandRyan Fleury 559e730986 add non-graphical debugger and torture targets 2026-06-02 12:10:03 -07:00
Nikita SmithandRyan Fleury 6d6acc737a set torture as launch target 2026-06-02 12:10:02 -07:00
Nikita SmithandRyan Fleury 846b2bdf70 fix process reap in the join API 2026-06-02 12:10:01 -07:00
Nikita SmithandRyan Fleury 55172718c9 implement semaphore take with timeout 2026-06-02 12:10:01 -07:00
Nikita SmithandRyan Fleury cb190ff9e3 set work directory for new process 2026-06-02 12:10:00 -07:00
Nikita SmithandRyan Fleury 25d2d12fc9 set executable permission bit on build.sh 2026-06-02 12:10:00 -07:00
Nikita SmithandRyan Fleury 0cd3cc02ab older bash compatibility improvements and use pkg-config library detection
for external libraries
2026-06-02 12:09:59 -07:00
Nikita SmithandRyan Fleury d7161ea6e6 clean up stepping test, and remove switch for overriding crash dump path 2026-06-02 12:09:59 -07:00
Nikita SmithandRyan Fleury fbdfeea8e6 minor fix 2026-06-02 12:09:58 -07:00
Nikita SmithandRyan Fleury 7b01038f05 add error messages in script runner and create a global default timeout 2026-06-02 12:09:58 -07:00
Nikita SmithandRyan Fleury 2643d14e06 extend os info struct with binary file path 2026-06-02 12:09:57 -07:00
Nikita SmithandRyan Fleury 5d8c568d82 use PID to find and kill running debugger after tests, and add automatic
kill on when torture crashes
2026-06-02 12:09:56 -07:00
Nikita SmithandRyan Fleury 7289338d53 simplify timeouts 2026-06-02 12:09:56 -07:00
Nikita SmithandRyan Fleury 8be21e599e zip torture artifacts on run fail 2026-06-02 12:09:55 -07:00
Nikita SmithandRyan Fleury a6da558b44 query binary name in converter command line setup 2026-06-02 12:09:54 -07:00
Nikita SmithandRyan Fleury 5a3741a264 gen crash dumps 2026-06-02 12:09:54 -07:00
Nikita SmithandRyan Fleury 3ec7ae6746 explain failed launch 2026-06-02 12:09:53 -07:00
Nikita SmithandRyan Fleury b60f5ec7cb wire non graphical raddbg build target 2026-06-02 12:09:53 -07:00
Nikita SmithandRyan Fleury b6bc8d89b0 bifurcate output into stderr and stdout 2026-06-02 12:09:52 -07:00
Nikita SmithandRyan Fleury 3878a4cd95 minor fixes to basic stepping test 2026-06-02 12:09:51 -07:00
Nikita SmithandRyan Fleury 8fe39ca2b9 test asan summary print in github actions 2026-06-02 12:09:51 -07:00
Nikita SmithandRyan Fleury 210b6a212a capture stderr and print out when test fails/crashes 2026-06-02 12:09:50 -07:00
Nikita SmithandRyan Fleury f991a80c85 remove safe call so crashes in github actions print out callstack 2026-06-02 12:09:50 -07:00
Nikita SmithandRyan Fleury a6175fecf6 skip debugger tests (there is no way to launch debugger without window) 2026-06-02 12:09:49 -07:00
Nikita SmithandRyan Fleury 22353d3642 build debugger without asan 2026-06-02 12:09:49 -07:00
Nikita SmithandRyan Fleury 887ee21d94 print out last captured output when a test fails or crashes 2026-06-02 12:09:48 -07:00
Nikita SmithandRyan Fleury a645622b10 basic debugger stepping test run to completion 2026-06-02 12:09:47 -07:00
Ryan Fleury 58e6430955 p2r: more carefully choose symbol chunk sizes - we were spending dramatically more memory than needed in cases where there were many translation units, with very few symbols, because of our overly-aggressive chunk sizes (e.g. chrome.dll.pdb). also, since we just parse the msf by forming contiguous streams, let's just always map input files in radbin by default, so that we don't pay twice for the memory. 2026-05-20 14:02:08 -07:00
Ryan Fleury 1912774377 pass over default theme 2026-05-20 11:37:53 -07:00
Ryan Fleury bc22adc440 bump to 27 2026-05-19 14:42:28 -07:00
Ryan Fleury 95f4ade10d lift wait-for-process-memory-cache-update out of d_process_write, since that path runs on control thread now too as the general 'process handle write' abstraction - just move into the rd_eval_space_write path, since that wait was only for UI benefit anyways 2026-05-19 14:35:29 -07:00
Ryan Fleury 7a5ae846e9 annotate changelog notes with issue numbers 2026-05-19 12:34:37 -07:00
Ryan Fleury 17cdf458d3 on ambiguous debug info matches, inside primary debug info -> try building a fully qualified name from context, and replacing initial debug info match if it hits 2026-05-19 12:08:26 -07:00
Ryan Fleury 161663016f project.raddbg 2026-05-19 11:56:08 -07:00
Ryan Fleury 82f47e3436 changelog notes 2026-05-19 11:55:27 -07:00
Ryan Fleury 3360d97e37 fix eval space creation for nil entities 2026-05-19 11:14:19 -07:00
Ryan Fleury 1a48155116 checkpoint on dump file parsing / cache construction; temporarily turn off crash dump command, since still wip 2026-05-19 09:56:01 -07:00
Ryan Fleury fe4de192e4 linux -> prefix user raddbg data with ., so we get ~/.raddbg normally - on windows keep normal style 2026-05-18 20:18:53 -07:00
Ryan Fleury a75cb2c32d display folder in title fstr generation for file evaluations, but only if not inside a folder context 2026-05-18 20:06:05 -07:00
Ryan Fleury 40885a3f59 fix unmapped address visualization when reading is impossible + stop it from terminating rest of useful visualization 2026-05-18 20:01:15 -07:00
Ryan Fleury 80d68b7f95 dbg_engine: minidump memory64 parsing; rename switch -> better thing for what it is 2026-05-18 19:40:47 -07:00
Nikita Smith a73105b296 torture merge build fixes 2026-05-18 18:18:18 -07:00
Nikita Smith 034f2bf0d9 changelog 2026-05-18 18:11:48 -07:00
Nikita Smith 8c58086585 batch relocations to reduce contention on global reference list 2026-05-18 18:11:48 -07:00
Nikita Smith 2683206ba2 changelog 2026-05-18 18:11:48 -07:00
Nikita Smith 0c656563b8 todo 2026-05-18 18:11:48 -07:00
Nikita Smith 488f4eba9a update change log 2026-05-18 18:11:48 -07:00
Nikita Smith 6daf0a5e59 asan is fine 2026-05-18 18:11:48 -07:00
Nikita Smith e1e8ba826d fix duplicate defer import link 2026-05-18 18:11:48 -07:00
Nikita Smith 2f2c975a4a unpoison released memory 2026-05-18 18:11:48 -07:00
Nikita Smith 1dc72b2bcf replace single-hop associative section walk to multi-hop 2026-05-18 18:11:48 -07:00
Nikita Smith 921030c432 hash map 2026-05-18 18:11:47 -07:00
Nikita Smith b8e85ab9ca fix incorrect GSI symbol compars that determ_test exposed 2026-05-18 18:11:47 -07:00
Nikita Smith ffb6cb8987 minidump includes 2026-05-18 18:11:47 -07:00
Ryan Fleury 4840b46b84 dbg_engine: shift thread register reads / process memory reads -> abstraction layer, rather than directly calling into demon; cache crash dump info, like thread info & memory ranges; implement thread reg reads & memory reads for dumps by using this acceleration structure when we have a dump handle, instead of regular demon reads. 2026-05-18 14:51:17 -07:00
Ryan Fleury 463a4f8565 eliminate redundant focus tab automatic commands 2026-05-17 20:24:27 -07:00
Ryan Fleury 6d6cd7033d minidumps: initial gather / events for process/modules/threads 2026-05-16 20:53:46 -07:00
Ryan Fleury fddf353ea0 minidump format types; open crash dump command, stub out opening path in control thread; expand d_handles to support machine id, entity id, *and* 'controller kind', which can be either a dump file or a demon - this properly separates the true process control abstraction (demon) from opening a regular dump file on any machine, which will let us trivially support any kind of dump file on any platform; also fix bad cfg tree state leak 2026-05-16 18:26:23 -07:00
Ryan Fleury c90cbb80aa fix label rendering in cfg title fstr build 2026-05-14 15:00:07 -07:00
Ryan Fleury cb8f2749d9 source/disassembly inline auto expressions 2026-05-14 14:34:17 -07:00
Ryan Fleury a60502d765 sketch out first pass of autos evaluation 2026-05-14 13:50:34 -07:00
Ryan Fleury 54fc7deafa fix incorrect per-unit line table data offset doubly adding base offset of unit - was breaking non-zero-offset line tables 2026-05-14 08:54:38 -07:00
Ryan Fleury 14390c01f7 respect path style in picking file replacements 2026-05-13 18:54:23 -07:00
Ryan Fleury 5977cb400d only do pointer value visualization with valid pointer spaces; otherwise it is just a value 2026-05-13 18:41:43 -07:00
Ryan Fleury ab4a084c9c fix filtered-tab selection adjustments on project load 2026-05-13 16:01:00 -07:00
Ryan Fleury d207398934 display project names in recent project list; fix 0s for address-disabled string viz 2026-05-13 15:50:59 -07:00
Ryan Fleury fbe7b20aee finish addresses-before-content single-line eval visualization path 2026-05-13 15:22:56 -07:00
Ryan Fleury 58caf0d3d5 upgrade eval space reads with staleness/bad/change info, to expand process memory cache reading abilities to all evaluation spaces; unmapped address visualization (both memory view & single line eval) 2026-05-13 14:48:00 -07:00
Ryan Fleury e6d83f7450 visualize unmapped addresses in memory view more correctly (not as 0s) - annotate explicitly with unmapped address annotation 2026-05-13 14:09:21 -07:00
Ryan Fleury 16b1e728ba breakpoints -> project-tagged user config 2026-05-13 13:38:04 -07:00
Ryan Fleury cfbda8bc4d clear last-focused-external-window on new session 2026-05-13 11:57:03 -07:00
Ryan Fleury 9eecffad78 fix mouse-hover-in-source-evaluation (off -> range) rules, to correctly enclose more expressions 2026-05-13 11:55:52 -07:00
Ryan Fleury a1778421c9 eval extended opcode for setting base offset - used for correct cross-module evaluations, fixes go-to-definition when thread is not in module of resolved identifier's symbol 2026-05-13 11:23:48 -07:00
Ryan Fleury 0563cd3b80 fix incorrect lifetime of calculated implicit user/project arguments 2026-05-13 10:43:43 -07:00
Ryan Fleury 1e0bcf0504 treat relative implicit project args correctly 2026-05-13 10:30:54 -07:00
Ryan Fleury 2231228ffb store loaded debug infos as user config, but project-tagged; eliminate 'recent files' from project file (they are almost entirely duplicative of debug info source files); adjust 'last_user' remembering semantics - do not automatically change last_user when setting user explicitly from command line 2026-05-13 10:18:06 -07:00
Ryan Fleury 1774a76cdb scope ending annotations 2026-05-13 08:58:46 -07:00
Ryan Fleury 264abe57aa allow missing debug info in case of 'step out' - we still want to support traditional behavior especially in e.g. disassembly and so on 2026-05-13 08:40:14 -07:00
Ryan Fleury b198f0b421 just move metagen onto regular base layer - in theory this causes cycles (metagen w/ bug -> generates busted base layer code -> can't build metagen!) but we do not currently generate anything in base, and we also can just revert in that case. 2026-05-12 20:02:35 -07:00
Ryan Fleury a0ace3561f eliminate d2r usage (1) from radbin 2026-05-12 19:58:15 -07:00
Ryan Fleury fa5af4fa9f notes 2026-05-12 19:57:01 -07:00
Ryan Fleury b4f15d3111 adjust project/user saving/loading rules to be less idiosyncratic with other applications. user settings persist, to keep the user from needing to specify things like windows/colors/bindings every time, but projects must always be manually specified, e.g. like usual files in other programs. you can do this either via the ui, or via command line still. also, new user/project no longer require a path - they just clear the existing path, then to set the path you just explicitly save. this makes things much more natural & familiar. 2026-05-12 19:34:42 -07:00
Ryan Fleury dcc78314ab fix dbg_info loader treatment of nil keys, avoid bad usage of blank '.rdi' files; os_lnx_* -> lnx_* 2026-05-12 14:42:29 -07:00
Ryan Fleury 50a68b9d8c adjust internal definition of sync barrier type to match windows 2026-05-12 13:52:25 -07:00
Ryan Fleury d4623a7ddf slow & highly contentious implementation of barriers using more basic sync primitives; fall back if sync barriers not present in win32 version 2026-05-12 13:48:57 -07:00
Ryan Fleury 641a7c8b30 on new debug session: close all loaded debug infos, assume none need to stick around 2026-05-12 09:38:06 -07:00
Ryan Fleury 15a2d5658f fix auto-thread-selection rules 2026-05-11 20:04:36 -07:00
Ryan Fleury d45090a8cc adjust kerning to be rounded, rather than floor'd; adjust step-out desc 2026-05-11 19:53:54 -07:00
Ryan Fleury 9eaff99bbb fix build 2026-05-11 19:44:26 -07:00
Ryan Fleury cbbacf0b5f sketch out extra disasm instruction outputs for determining read/write locations from instructions (autos) 2026-05-11 14:53:05 -07:00
Ryan Fleury d1536953b0 p2r: eliminate spurious duplicate address vmap entries; upgrade step-out with block stepping functionality 2026-05-11 14:21:43 -07:00
Ryan Fleury cc099f55aa do not call destroy on caches without a destroy hook :( 2026-05-11 13:30:59 -07:00
Ryan Fleury de35a86505 fix artifact cache replaced-value deletion - this CAN NOT run if the new value == the old value 2026-05-11 13:29:29 -07:00
Ryan Fleury 52da228efe artifact_cache: fix leak of old-generation artifacts, when those artifacts are replaced by newer generation computations. artifacts can opaquely hold things like arena pointers, and so when we replace them in the cache, we need to respect the lookup api's provision of create/destroy hooks for the cache, such that the artifacts can be released correctly (using the destroy hook) before being replaced. this is separate from regular eviction. 2026-05-11 11:49:15 -07:00
Ryan Fleury 6a95da35e0 opengl: more coverage/convergence w/ d3d11 2026-05-09 20:25:14 -07:00
Ryan Fleury 0cfc113272 opengl: apply transforms to rendering 2026-05-09 13:30:56 -07:00
Ryan Fleury a16716eff7 d2r2: fix missing function types on functions returning void 2026-05-09 12:38:08 -07:00
Ryan Fleury d59d6a21f0 d2r2: do not duplicate line records, were being generated by columnar changes, but these are not currently supported by the debugger 2026-05-09 12:18:05 -07:00
Ryan Fleury 2f6d0f9aaa os -> wm; *_w32_ -> w32_*_, *_lnx_ -> lnx_*_ 2026-05-08 21:17:21 -07:00
Ryan Fleury 9a7782de47 re-slice linux/win32 backends, top-level folder is backend (demon/win32 -> win32/demon, etc.); os_gfx -> window_manager; fix linux / opengl builds for new apis/types 2026-05-08 15:21:22 -07:00
Ryan Fleury aea4a4ff9d eliminate os_core, move into base; eliminate regs, move into arch abstraction layer, define x64 regs in x64 layer; move win32 backend for os core (now base) functionality to top-level win32 layer 2026-05-08 15:21:21 -07:00
Nikita Smith 24c858171f fix complex and char conversion + note 2026-05-07 21:49:15 -07:00
Ryan Fleury 774e8e1305 notes 2026-05-05 12:57:04 -07:00
Ryan Fleury 738163dcbd demon: gather success status of setting traps, but do not fail on failure 2026-05-05 12:35:20 -07:00
Ryan Fleury 356237418f demon: always gather 'active' traps - do not require success 2026-05-05 12:32:00 -07:00
Ryan Fleury b210afa5ee demon/linux: do not assert on trap write/read success. breakpoints can evaluate to unmapped addresses 2026-05-05 12:30:12 -07:00
Ryan Fleury 44c6b6e4d5 do not duplicate function records for decls 2026-05-05 12:22:20 -07:00
Ryan Fleury d9f7385f81 d2r2: fix file sequence map build to use correct source files 2026-05-05 12:13:07 -07:00
Ryan Fleury 1c8a10e0f7 rdi_make: fix path node lookup to respect root-level ..s 2026-05-05 11:47:26 -07:00
Ryan Fleury 26646299a1 rdi_make: preserve root-level ..s in interned path tree 2026-05-05 11:20:38 -07:00
Ryan Fleury 5f8e0a5aa9 rd: fix possible-overrides-from-file-path path to correctly use path styles 2026-05-05 11:00:08 -07:00
Ryan Fleury 6e376e5615 rd: fix file path mapping to correctly use destination path's style in constructing mapped paths 2026-05-05 10:57:46 -07:00
Ryan Fleury 1301165aeb d2r2: disable llvm-dwarfdump-style line table logging 2026-05-05 10:50:47 -07:00
Ryan Fleury 384cf11eed d2r2: fix line table register reset conditions in line table conversion 2026-05-05 10:49:33 -07:00
Ryan Fleury fb04768002 d2r2: hook up scope containers to contained types / namespaces; fix address table parsing 2026-05-05 09:42:55 -07:00
Ryan Fleury aee299efe7 d2r2: deduper fixes/simplification, first half of structured namespace support 2026-05-04 15:41:23 -07:00
Ryan Fleury 8f65f466f5 d2r2: expand tag deduplication to both namespaces and types; gather/deduplicate/convert namespaces 2026-05-04 13:14:13 -07:00
Ryan Fleury 7157e813a0 d2r2: fix line table build - correct program data size, correct special opcode application 2026-05-03 17:55:53 -07:00
Ryan Fleury f2d80da2de d2r2: remove markup 2026-05-03 11:25:56 -07:00
Ryan Fleury e48c23db20 d2r2: don't descend children for childless subprograms! 2026-05-03 11:24:38 -07:00
Ryan Fleury 4f3d9c96b8 d2r2: when deduplicating types, ensure deterministic (hash -> .debug_info off) mapping, by minimizing the .debug_info off found for a particular type hash - in theory, this step should not be necessary, but there is a mistake / broken part of this theory, which was leading to non-deterministic type graphs in a very small # of cases, due to the same hash mapping to different .debug_info offsets across runs. in theory, the hash itself should take care of this, but there is likely something important missing. in either case, minimizing the .debug_info offset is very cheap, and guarantees we parse from a deterministic place no matter what the run looks like. 2026-05-02 20:25:33 -07:00
Ryan Fleury f9eb25dbcb d2r2: do unique type info gathering on a sub-unit granularity, so we can subdivide a unit across all lanes; sort unique type tag slots for determinism 2026-05-01 14:12:35 -07:00
Ryan Fleury 0b5e827f6c rd: prioritize fastpath for non-unwound register reads; d2r2: prepass to find all top-level tag trees, subdivide unit work on a root-level tag tree basis 2026-05-01 12:34:35 -07:00
Ryan Fleury 0b26b1c83e radbin: only dump eh frame data if found 2026-05-01 08:49:16 -07:00
Ryan Fleury 13fb24f253 fix incorrect function parameter type parsing (was causing quadratic parses of .debug_info, oops) 2026-05-01 08:42:48 -07:00
Ryan Fleury 0054935252 d2r2: fix scope voff miscount; pattern match trivial value-register locations -> simple kind; fix pre-dwarf5 file table parsing 2026-04-30 18:09:30 -07:00
Ryan Fleury 0e2b37ba32 dwarf: do not crash on unsupported codes; text: do not crash on arena releasing w/ zero hash (#766, #771?, #761) 2026-04-30 17:51:11 -07:00
Ryan Fleury c83c1f3cfd udt conversion 2026-04-29 16:27:58 -07:00
Ryan Fleury 230b004742 d2r2: function type info; fix reg+off location info for signed offsets, function type deduplicating / construction / referencing, etc. 2026-04-29 15:50:31 -07:00
Ryan Fleury 9a923e9bf9 d2r2: .debug_loclists parsing, DWARF expression -> RDI location info; first pass at baking frame base into var locations to match simpler PDB behavior; fixes to high-pc address evaluation (based on form kind) 2026-04-29 12:40:43 -07:00
Ryan Fleury 242f4e9cbd d2r2: dwarf 5 .debug_rnglists, .debug_addr parsing / usage 2026-04-28 09:37:31 -07:00
Ryan Fleury f5ec462438 d2r2: .debug_aranges parsing / unit conversion; .debug_ranges parsing 2026-04-28 08:57:59 -07:00
Ryan Fleury f1a9fc5e3a turn off new dwarf converter outputs temporarily 2026-04-27 18:14:29 -07:00
Ryan Fleury c6b733de20 d2r2: finished first pass of type conversion; sketched out structure for symbol/unit conversion; plugged everything in 2026-04-27 16:07:07 -07:00
Ryan Fleury ffa41c0a98 d2r2: adjustments to type deduper; sketch out topologically-sorted type building path 2026-04-27 12:02:27 -07:00
Ryan Fleury be1095eccf d2r2: type dedup content hashing cycle detection / handling; type dependency chain build 2026-04-25 09:40:49 -07:00
Ryan Fleury 9768321d08 fix build 2026-04-24 20:45:18 -07:00
Ryan Fleury ad0d023c93 d2r2 type deduplication: further work on type content hashing; correct .debug_str_offsets handling; sketch out type dependency chain build 2026-04-24 20:34:20 -07:00
Ryan Fleury 35e00de05c d2r2: cross-unit, cross-lane type deduplication 2026-04-24 20:34:20 -07:00
Nikita Smith 1f4c4af598 use compound initializers to define and drive obj generation 2026-04-24 13:11:34 -07:00
Ryan Fleury ccb1cd8f4d d2r2: built-in types, move rdi variadic type -> built-in 2026-04-23 18:54:01 -07:00
Ryan Fleury 44a1c9ca1b d2r2: line sequence production / equipping to src files 2026-04-23 18:12:14 -07:00
Nikita Smith 6348c63cdc make namespace optional for specifying test targets 2026-04-23 17:34:02 -07:00
Nikita Smith 7ed5977d20 improve determinism test speed 2026-04-23 17:18:24 -07:00
Ryan Fleury 467e09178e file -> seq list line seq chunk building 2026-04-23 16:10:26 -07:00
Ryan Fleury 611e46cda5 d2r2: fix missing sync; per-unit seq table 2026-04-23 15:40:31 -07:00
Ryan Fleury 2637f6abde further line info conversion progress; fix missing sync 2026-04-23 15:30:55 -07:00
Ryan Fleury 602cf68980 fix builds 2026-04-23 14:45:13 -07:00
Ryan Fleury 2623141fd4 checkpoint on multi-lane / simplified dwarf parsing/conversion; fix incorrect assumption of relative in radbin 2026-04-23 14:25:50 -07:00
Ryan Fleury 6f624c10ad fix dwarf conversion to account for new rdi changes 2026-04-23 12:30:45 -07:00
Ryan Fleury 684eeda139 setting to turn off transient tab spawns 2026-04-22 20:15:36 -07:00
Ryan Fleury 3c214cfbb5 views autocompletion; view doc coverage 2026-04-22 19:57:08 -07:00
Nikita Smith 05d76b416a update defer imp link test 2026-04-22 18:38:03 -07:00
Nikita Smith 435b5183fb warn only if override subsystem is different 2026-04-22 18:38:03 -07:00
Ryan Fleury a027a0ea16 use fully qualified symbol names when doing dbg info searches & when producing strings in debug info table evals 2026-04-22 16:24:23 -07:00
Ryan Fleury 0d3539d707 highlighting for views; view doc / autocompletion coverage 2026-04-22 16:09:32 -07:00
Ryan Fleury 2eb0b8b233 ctrl -> d 2026-04-22 14:53:37 -07:00
Ryan Fleury 0e3c821e28 collapse ctrl/d bps 2026-04-22 14:31:08 -07:00
Ryan Fleury 0d8a6a4d3a ctrl -> d type pass 2026-04-22 13:37:00 -07:00
Ryan Fleury a90fbc844b merge ctrl_init / d_init 2026-04-22 12:56:15 -07:00
Ryan Fleury 2388db3998 fold ctrl layer into dbg engine - no benefit to disallowing dependence on debug engine types inside of ctrl, and it has been causing unnecessary barriers for eventual eval magic. 2026-04-22 12:44:18 -07:00
Ryan Fleury d2eb9628ba test cases for ambiguous statics across many units; comments in exprs 2026-04-22 12:44:18 -07:00
Nikita Smith 86066018e7 helper for writing COFF objs and libs 2026-04-22 12:27:25 -07:00
Nikita SmithandRyan Fleury 4b7dd960d9 pass args to the torture 2026-04-22 09:30:45 -07:00
Nikita SmithandRyan Fleury ffd6f10b31 wildcard match target tests 2026-04-22 09:30:45 -07:00
Nikita SmithandRyan Fleury 4786dc419a wildcard matcher 2026-04-22 09:30:45 -07:00
Nikita SmithandRyan Fleury ffc6905b06 kind mask should be const value 2026-04-22 09:30:45 -07:00
Nikita SmithandRyan Fleury 60c4518d65 run debug tests first 2026-04-22 09:30:45 -07:00
Nikita SmithandRyan Fleury 48f2a931ce clang build fix 2026-04-22 09:30:45 -07:00
Nikita SmithandRyan Fleury a2aab5967c add support for /DEBUG:GHASH 2026-04-22 09:30:45 -07:00
Ryan Fleury 4815007ac1 use fully qualified type names in unpacked eval types - fixes namespaced type views 2026-04-22 09:09:41 -07:00
Ryan Fleury 21a150a181 turn off symbol-lookup highlighting following dot operators 2026-04-21 20:13:54 -07:00
Ryan Fleury 6f2b8540eb store partially-qualified names in generated RDIs; adjust debugger to do fully-qualified lookups when appropriate 2026-04-21 19:36:38 -07:00
Nikita SmithandRyan Fleury 8cf14b5acb minor fix 2026-04-20 15:28:12 -07:00
Ryan Fleury fda0a9751b equip namespace records with container info 2026-04-20 15:14:01 -07:00
Ryan Fleury 581c102bfd sort deduplicated namespace map before producing namespaces 2026-04-20 14:43:03 -07:00
Ryan Fleury 5fb1ef4df9 fix global vmap baking determinism - eliminate dupes 2026-04-20 14:15:38 -07:00
Ryan Fleury 16ea060382 fix source of vmap baking determinism issue, + fix use-after-free from cross-lane scratch usage 2026-04-20 14:06:34 -07:00
Nikita SmithandRyan Fleury 43c3d5e348 test param flag 2026-04-20 13:55:23 -07:00
Nikita SmithandRyan Fleury 52875a2d93 fix regression in RDI make local 2026-04-20 13:55:23 -07:00
Ryan Fleury e8e9ad204a further pdb namespaces progress; fix compile-only output for /o MSVC deprecation 2026-04-20 13:53:50 -07:00
Ryan Fleury e4bd6d5029 revert commit that deleted container-from-procedure APIs for whatever reason 2026-04-20 11:35:04 -07:00
Ryan Fleury 01682dee07 bump to 26 2026-04-20 11:12:25 -07:00
Nikita Smith d607d6377d build fixes 2026-04-20 11:00:54 -07:00
Nikita Smith d7cc06f5d5 show top five slow tests in the summary 2026-04-20 10:39:50 -07:00
Nikita Smith 0a791e5876 add support for LLVM ghash sections 2026-04-20 10:39:50 -07:00
Nikita Smith cd4f81d473 time tests 2026-04-20 10:39:50 -07:00
Nikita Smith 9e19fe5193 prettify elapsed time formatter 2026-04-20 10:39:50 -07:00
Nikita Smith e6f49aaded test stripped PDB 2026-04-20 10:39:50 -07:00
Nikita Smith aefd73e551 test public symbols 2026-04-20 10:39:50 -07:00
Nikita Smith 4decc0d9f0 test GSI procs and typedefs 2026-04-20 10:39:50 -07:00
Ryan Fleury bc43fe9b31 only enable cursor trails if not click+dragging; redundant animation in that case 2026-04-20 10:22:56 -07:00
Ryan Fleury 897ffc6b69 file path evaluation activation in watch windows -> switch to file 2026-04-20 09:57:34 -07:00
Ryan Fleury ee2dcbee48 fix idx shadowing lookup bug in rdim_bake_name_map_insert 2026-04-20 09:57:34 -07:00
Ryan Fleury 03d1575c85 non-scope, non-type namespace gathering / gathering from pdb & baking & dumping 2026-04-20 09:57:34 -07:00
Ryan Fleury 5e81f124dc debug constant data evaluation spaces -> read from rdi data directly 2026-04-20 09:57:33 -07:00
Ryan Fleury 7a59548d5b remove 'Symbols' from section titles, now that old sections are gone 2026-04-20 09:57:33 -07:00
Ryan Fleury 881e19c842 get debugger onto new location info & symbol format 2026-04-20 09:57:33 -07:00
Ryan Fleury 6764e1281e setting for preferring displaying pointer addresses before contents 2026-04-20 09:57:32 -07:00
Ryan Fleury 2bf57c065a new location info format dumping 2026-04-20 09:57:32 -07:00
Ryan Fleury 7383cdc5ae fix dumper for new symbols/locations format; produce dummy global unit for global stream pdb info - avoid stomping on 0 unit; fix stomping of location info, from missing lane sync 2026-04-20 09:57:32 -07:00
Ryan Fleury bec7e630ba fix duplicate nil local, equip locals with their scopes as symbol containers 2026-04-20 09:57:32 -07:00
Ryan Fleury e281528d57 rdi pass checkpoint: rdi baking; scope-organized locals gathering / sorting / organizing; plug into serialization path 2026-04-20 09:57:32 -07:00
Ryan Fleury 290590b885 extend udts w/ container info 2026-04-20 09:57:32 -07:00
Ryan Fleury e6d28d40e2 start plugging in new rdi symbols to dumper 2026-04-20 09:57:31 -07:00
Ryan Fleury 2218649801 fix busted section codes 2026-04-20 09:57:31 -07:00
Ryan Fleury b1e6948576 rdi: extend per-unit info with symbol ranges; build into baker 2026-04-20 09:57:31 -07:00
Ryan Fleury 57e4b69e64 adjust rdi make to keep per-unit info organization - flatten / join in baker, to ensure unit-sorted order 2026-04-20 09:57:31 -07:00
Ryan Fleury b7644a1d34 notes 2026-04-20 09:57:31 -07:00
Ryan Fleury a1978d9fe9 sketch out more locals baking stuff, + notes for unit-arrangement pass 2026-04-20 09:57:31 -07:00
Ryan Fleury abb0199936 checkpoint on new local baking 2026-04-20 09:57:31 -07:00
Ryan Fleury d68e19db8b finish almost all new baking for new symbols/location-info, just missing locals 2026-04-20 09:57:30 -07:00
Ryan Fleury a190051d61 checkpoint on new symbol serialization 2026-04-20 09:57:30 -07:00
Ryan Fleury cff7a786b3 fold voffs/toffs/constants into location case list, plug into converters 2026-04-20 09:57:30 -07:00
Ryan Fleury 4ea7f86d92 checkpoint on new simplified location info baking. plug in constant data baking, bytecode baking 2026-04-20 09:57:30 -07:00
Ryan Fleury 4db9a47d46 new packed location constructions; namespace container baking; feed procedures/constants into new symbol baking path 2026-04-20 09:57:30 -07:00
Ryan Fleury 131d14907e first pass at new unified & tighter symbol location info baking 2026-04-20 09:57:30 -07:00
Ryan Fleury 911e8c135e new location info baking layout computation - symbol-inlined locations in most cases, + indirected to set elements / bytecode / constant data as needed 2026-04-20 09:57:30 -07:00
Ryan Fleury 424549b562 sketch out new location representation 2026-04-20 09:57:30 -07:00
Ryan Fleury eff693244b sketch out first part of new unified symbol table baking pass, sketch out new simplified sections 2026-04-20 09:57:29 -07:00
Nikita Smith 270d73220f test GSI 2026-04-16 16:46:53 -07:00
Nikita Smith e1ab7f4955 GSI parser discarded last symbol in the chain 2026-04-16 16:46:00 -07:00
Nikita Smith 217b761c9b build GSI and PSI before DBI 2026-04-16 16:43:04 -07:00
Nikita Smith 9bf0f77391 size in symbol header was incorrectly including alignment bytes 2026-04-16 16:42:22 -07:00
Nikita Smith 15ff96f4a1 rename macro for declaring tests 2026-04-16 11:52:59 -07:00
Nikita Smith d0364dc39c minor fixes for handling cyclic and corrupted types 2026-04-15 15:32:51 -07:00
Nikita Smith 18f468bc97 os_process_join closes handle 2026-04-15 15:32:51 -07:00
Nikita Smith ae99355c1d shift upper type index bound 2026-04-15 15:32:51 -07:00
Nikita Smith 437e242260 dial down run count in determ_test 2026-04-15 15:32:51 -07:00
Nikita Smith 7872ba5542 disable ASAN for clang (need to figure out how to locate LLVM DLL) 2026-04-15 15:32:51 -07:00
Nikita Smith 4eee46764e update the change log 2026-04-15 15:32:51 -07:00
Nikita Smith d1d42102dd discard trailing free page maps 2026-04-15 15:32:51 -07:00
Nikita Smith 5f3e7e7175 whoops proc refences were pointing to stale symbols
ideally linker parse module streams for proc references
2026-04-15 15:32:51 -07:00
Ryan Fleury dae90f0053 changelog 2026-04-15 12:54:30 -07:00
Ryan Fleury 3bef72f09f changelog work 2026-04-15 12:43:52 -07:00
Ryan Fleury 471abb99ca fix ood readmeg 2026-04-15 12:30:21 -07:00
Ryan Fleury 8513ef8a4f pdb -> rdi conversion: be robust to zero itypes in function type parameter lists. was causing, in some cases, local variables to be incorrectly interpreted as parameters, because there was a (nonexistent) parameter to the function recorded in the type info. 2026-04-15 12:28:42 -07:00
Ryan Fleury 6a36382690 eval: remove incorrect truncate ops 2026-04-15 12:07:14 -07:00
Ryan Fleury 7106265a14 fix duplicate downstream marks of text artifacts; use cancel signal in text processing 2026-04-14 20:10:14 -07:00
Ryan Fleury 0a10e855a5 memory view fixes, changelog, notes 2026-04-14 19:52:10 -07:00
Ryan Fleury 3161fda982 further memory view work: tighter byte context viz, fix missing callstack frames, fix zooming, struct member annotations 2026-04-14 15:35:12 -07:00
Ryan Fleury ee6d9b3a32 fix bad auto column calculating in min edge case 2026-04-13 14:52:09 -07:00
Ryan Fleury 21eb134f24 formalized addr bar in memory view, complete first pass of memory view peek types, various fixes 2026-04-13 14:39:31 -07:00
Nikita Smith 294ede01a2 skip empty hash table adjuster 2026-04-11 14:16:13 -07:00
Nikita Smith e5664facce delete existing files before running test 2026-04-11 13:46:49 -07:00
Nikita Smith 0299b6922f sort global symbols deterministically within GSI bucket 2026-04-11 13:42:30 -07:00
Nikita Smith 1839187a3c sort records must be rebased 2026-04-11 13:41:44 -07:00
Nikita Smith 36d18e440b delete exes to appease windows defender 2026-04-11 12:51:00 -07:00
Nikita Smith 40763c06cf swap dynamic and static libs 2026-04-11 12:50:41 -07:00
Nikita Smith 89a5acba2c WIP stripped PDB 2026-04-10 17:02:04 -07:00
Nikita Smith b4bbc38ab2 validate info stream 2026-04-10 17:02:04 -07:00
Nikita Smith c5dc7bee3e fix info stream layout 2026-04-10 17:02:04 -07:00
Ryan Fleury 686b64c357 start work on more sophisticated memory type interpretation capabilities in memory view 2026-04-09 16:24:28 -07:00
Nikita Smith 120cc529ef update run_tests.bat to use torture 2026-04-09 15:27:20 -07:00
Nikita Smith 38afd6260d port eval test 2026-04-09 14:06:33 -07:00
Nikita Smith 85bbfa755a port pdb -> rdi determinism test 2026-04-09 13:41:04 -07:00
Ryan Fleury 5f5120144b memory copy/paste 2026-04-09 12:08:35 -07:00
Ryan Fleury 9aa63bc86c checkpoint on memory view improvements; bugfixes, improved visualizations, & mutation controls 2026-04-09 11:07:00 -07:00
Ryan Fleury be270a8f8d fix step over/into line operations when source line maps to multiple (potentially) discontiguous code ranges, or at least line info records; this fixes weird stepping with Clang-generated line info for for loops, function prologues in Odin, amongst other similar issues 2026-04-08 14:42:30 -07:00
Ryan Fleury 5bc791566b go to selected thread in ctx menus 2026-04-08 13:44:55 -07:00
Ryan Fleury e9a142b536 fix eval commit rules for strings; do not treat inputs as textual data when committing to pointers unless contents are quoted - fixes inability to change string pointer values 2026-04-08 13:44:55 -07:00
Nikita Smith 1f5bbb9702 minor cleanup 2026-04-08 12:39:15 -07:00
Nikita Smith 33b121215b remove T_EndTest 2026-04-07 21:21:08 -07:00
Ryan Fleury 77afc94cee correctly apply lens type flags in shorthand chained exprs (fixes foo,x
hex inheriatnce)
2026-04-07 17:37:10 -06:00
Ryan Fleury fee9f9a2c3 when resolving irtrees to values, promote register spaces -> containing process space; fixes pointer casts to register values 2026-04-07 17:16:56 -06:00
Ryan Fleury 960f439a59 notes 2026-04-07 15:26:43 -06:00
Nikita Smith 5a0bddafad test EXE and PDB determinism 2026-04-07 11:27:20 -07:00
Nikita Smith 44d09410eb bugfix global symbol dedup 2026-04-07 10:49:48 -07:00
Nikita Smith e54bef58df implement /INFERASANLIBS 2026-04-06 22:18:26 -07:00
Nikita Smith 3bb8983461 implement /WHOLEARCHIVE 2026-04-06 14:35:46 -07:00
Nikita Smith 890f7afccc take exit code before closing process handle 2026-04-06 12:17:25 -07:00
Nikita Smith 8cc8986197 WIP test PDB determinism 2026-04-06 12:04:33 -07:00
Nikita Smith aad1805124 make GSI and PSI serialization deterministic 2026-04-06 12:04:33 -07:00
Nikita Smith 608a0df058 fix race in the type merger 2026-04-06 12:04:33 -07:00
Nikita Smith 232815dbe6 branchless compact 2026-04-06 12:04:33 -07:00
Nikita Smith 85ec2c6317 remove vestige *open functionality from the MSF and PDB 2026-04-06 12:04:33 -07:00
Nikita Smith f69532e11d tweak thread broadcasting and balance symbol inputs 2026-04-06 12:04:33 -07:00
Nikita Smith 77ece3193e fix clang /O2 2026-04-06 12:04:32 -07:00
Nikita Smith f72d127aaa report unknown directives in debug build 2026-04-06 12:04:32 -07:00
Nikita Smith 129f0326f7 use thread broadcasts to simplify global symbol mover 2026-04-06 12:04:32 -07:00
Nikita Smith e9ac0abdf9 thread broadcast 2026-04-06 12:04:32 -07:00
Nikita Smith ef712a36e7 minor bugfix 2026-04-06 12:04:32 -07:00
Nikita Smith 99335959b0 ignore invalid type index errors in release 2026-04-06 12:04:32 -07:00
Nikita Smith c853082e61 test cyclic type detection 2026-04-06 12:04:32 -07:00
Nikita Smith b5f0862a91 fixup file checksums in the MSF streams 2026-04-06 12:04:32 -07:00
Nikita Smith 6b7cd39ff1 msf and cv tree patcher tests 2026-04-06 12:04:32 -07:00
Nikita Smith 30e21a84ea arena helper for dealing with buffer preallocation for workers 2026-04-06 12:04:32 -07:00
Nikita Smith e89041fd59 helper for reading/writing discontinuous memory 2026-04-06 12:04:32 -07:00
Nikita Smith 46243548f3 fixup symbol tree offsets in module stream 2026-04-06 12:04:32 -07:00
Nikita Smith acce76aa4c string list sub range helper 2026-04-06 12:04:32 -07:00
Nikita Smith d7cfd5f55a WIP rework GSI and PSI symbol writer 2026-04-06 12:04:32 -07:00
Nikita Smith 883935d44e WIP simplifying module stream layout step 2026-04-06 12:04:32 -07:00
Nikita Smith f7ac6767cf WIP symbol plumbing 2026-04-06 12:04:32 -07:00
Nikita Smith 12a1e28fff do not round up commit and reserve sizes on optional buffers 2026-04-06 12:04:32 -07:00
Nikita Smith e0c6df710f WIP change symbol extraction approach 2026-04-06 12:04:31 -07:00
Nikita Smith f57b149939 syntax error
fix yaml
2026-04-06 12:04:31 -07:00
Nikita Smith 3834c9be6f torture build with clang release runs out of memory 2026-04-06 12:04:31 -07:00
Nikita Smith 2331425e20 removed duplicate clang sets; disable ICF with lld-link because it erroneously
merges string literals and makes ASAN panic
2026-04-06 12:04:31 -07:00
Nikita Smith f119e8cffc test torture with clang 2026-04-06 12:04:31 -07:00
Nikita Smith 91b50bab00 no need to validate signature in S_OBJ; discard debug info if PCH
is missing instead of exiting
2026-04-06 12:04:31 -07:00
Nikita Smith f703699a59 for mule build tell clang to write objs with .obj extension 2026-04-06 12:04:31 -07:00
Nikita Smith ec1619f357 ASAN freaks out when threads access foreign stack 2026-04-06 12:04:31 -07:00
Nikita Smith b764a838df build meta for torture run; fix base core in metagen 2026-04-06 12:04:31 -07:00
Nikita Smith 44a0efd207 test mismatched PCH signatures and presence of .debug$P and .debug$T in
same obj
2026-04-06 12:04:31 -07:00
Nikita Smith 8a1203ed35 add mutex around fprintf to linearize log 2026-04-06 12:04:31 -07:00
Nikita Smith 3d805af7df WIP test PCH type merging 2026-04-06 12:04:31 -07:00
Nikita Smith fb0b516aa3 objs use 1 byte alignment for leaf data 2026-04-06 12:04:31 -07:00
Nikita Smith d1594f796d fix type source for PCH type indices 2026-04-06 12:04:31 -07:00
Nikita Smith c0418b736d WIP: internal and external type servers are functioning except for the
PCH indirection
2026-04-06 12:04:31 -07:00
Nikita Smith 401ba47ac2 telemetry mark up 2026-04-06 12:04:31 -07:00
Nikita Smith 8f2ec234dc update .gitignore 2026-04-06 12:04:30 -07:00
Nikita Smith 7cf8c00947 improve test for import_export and fix compile errors in merge_duplicates
due to API changes in debug info
2026-04-06 12:04:30 -07:00
Ryan Fleury 45f0b011aa changelog notes 2026-04-02 13:45:04 -06:00
Ryan Fleury da7e3063ae changelog notes 2026-04-02 13:44:10 -06:00
Ryan Fleury 8d67460fa6 treat errored call stacks as valid call stack results - only reject on stale data. allow 0 rips for the top frames. 2026-04-01 11:06:23 -06:00
Ryan Fleury d986ea6cd9 guard against invalid ctrl entity handle resolutions when applying ctrl events; otherwise some edge cases can cause invalid writes. 2026-03-31 07:05:44 -07:00
Ryan Fleury 7021d6056a use project name in window titles 2026-03-29 12:07:27 -07:00
Ryan Fleury a768f398cf single-press-to-activate in text right-click commands menu 2026-03-29 11:46:24 -07:00
Ryan Fleury a23375a070 re-plug raddbg markup data section into module image info cache; fix detachment signifying 2026-03-29 11:05:45 -07:00
Ryan Fleury 8c7b3d7356 project names, remove loaded user viz from top bar (only project is relevant in 99% of cases), clean up loaded project viz 2026-03-29 09:49:20 -07:00
Ryan Fleury 846f174bbd os_process_join on win32 -> CloseHandle of remaining process handle 2026-03-18 21:20:56 -07:00
Nikita Smith 1a10170485 fix clang build error in mule_main 2026-03-17 23:19:57 -07:00
Nikita Smith adbd5c911e update torture runner 2026-03-17 14:44:07 -07:00
Nikita Smith 70677b85d8 align group names 2026-03-17 14:44:07 -07:00
Ryan Fleury 38f08922e5 rdi: sketch out refined location info sections / types - prereq for RDI_Symbol unification 2026-03-10 16:01:33 -07:00
Ryan Fleury 5badc7f325 sketch out unified RDI_Variable to replace RDI_GlobalVariable, RDI_ThreadVariable, RDI_Local, and RDI_Constant, & plug into new RDI structured namespaces 2026-03-09 15:15:48 -07:00
Ryan Fleury 408b3af27c rdi namespace baking; cv parsing rec iterator, deduplicate oob-safe cv record iterating 2026-03-09 14:36:05 -07:00
Ryan Fleury 8db4a09941 eliminate global rdim_shared; just use scratch data 2026-03-09 11:56:43 -07:00
Ryan Fleury e2b9618101 rdi format - namespaces 2026-03-09 09:37:50 -07:00
Ryan Fleury 953f58fd44 notes for next RDI pass to support namespacing, support scope-based lookups for local-statics, support fully-qualified namespace name resolution, & simplify/merge RDI variable symbol types, & reduce a lot of size in RDIs! 2026-03-04 15:35:57 -08:00
Ryan Fleury f59da0be9c extend eval language w/ identifier disambiguators - used to pick amongst many identically-named things. for instance, local_static#0 will match the first local_static, local_static#1 will match the second, etc. 2026-03-04 11:49:04 -08:00
Nikita Smith 1c6baf18f2 msf_parsed_from_data now always returns non-null result 2026-03-04 11:41:51 -08:00
Nikita Smith 0d166b398c add mule_main to the build list 2026-03-04 11:28:53 -08:00
Nikita Smith e9a2f36b23 switch to internal debug mode detection macro for the element size check in radsort 2026-03-04 11:28:53 -08:00
Nikita Smith 57cbd020a1 debugging extras 2026-03-04 11:28:53 -08:00
Ryan Fleury 4312ee14fd first pass at (rdi -> loose rdim) path, used in (rdi * ... * rdi) -> rdi joining in radbin; plug in regular conversion path before voff -> line & breakpad paths in radbin, such that PDBs, DWARFs, RDIs, etc. can be used as input; fix up voff -> line path to plug into regular output systems; remove String8 union thing - three reasons: (a) it was only ever introduced for convenience in Linux layers, so let's just keep zero-terminated Linux nonsense in Linux land, (b) it was just alternate syntax for a cast, so let's just cast, (c) it was misleading - 'cstr' implies null-termination, which String8 of course doesn't guarantee. this led to some misuses, where .cstr was trusted to be zero-terminated, when that was not necessarily true (semaphore opening). 2026-03-03 16:24:54 -08:00
Ryan Fleury 2af3990971 do not rely on lane 0 scratch ptrs for results in p2r - prone to races 2026-03-02 12:17:03 -08:00
Ryan Fleury 9227e884ac san -> asan / ubsan 2026-03-02 12:03:40 -08:00
Nikita Smith 8007c158fa add API to DWARF writer that defines forward references and fix method
conversion in the converter
2026-02-27 11:07:19 -08:00
Nikita Smith b49c902947 remove vim mode line 2026-02-27 00:55:37 -08:00
Nikita Smith 2fbe45cd47 sync before scratch_end to prevent race in the result fill 2026-02-26 16:41:36 -08:00
Nikita Smith a2336b9991 ASAN false-positives when threads access foreign stack addresses 2026-02-26 16:22:36 -08:00
Nikita Smith 13f189ddcd WIP subprogram conversion tests 2026-02-26 14:34:59 -08:00
Nikita Smith e933df6300 WIP type stringifier 2026-02-26 14:34:21 -08:00
Nikita Smith b67d2fad40 convert procedure when it was declared inline but was not inlined 2026-02-25 22:28:09 -08:00
Nikita Smith fdd2f4e8f5 helper for looping over bits in flags 2026-02-25 22:27:12 -08:00
Nikita Smith 1ee8218b0e format visibility attribute 2026-02-25 14:27:59 -08:00
Nikita Smith 3e7b791e01 WIP subprogram conversion test 2026-02-25 11:22:13 -08:00
Nikita Smith dce1f3f8f7 typo 2026-02-25 01:39:48 -08:00
Nikita Smith 3500b9cab8 test checksums 2026-02-24 20:02:29 -08:00
Nikita Smith 2fc4a3472b finalize DWARF line table conversion test 2026-02-24 19:05:22 -08:00
Nikita Smith 732c73deff fix divide by zero in the baker 2026-02-24 18:57:03 -08:00
Nikita Smith 609cbe7288 return invalid line info index on bad virtual offsets 2026-02-24 18:49:11 -08:00
Nikita Smith 3759c3eae4 string natvis 2026-02-24 18:05:39 -08:00
Nikita Smith c7f7e15434 WIP DWARF line table conversion tester 2026-02-24 18:05:39 -08:00
Nikita Smith 03445022d5 make os file read an atomic operation 2026-02-24 18:05:38 -08:00
Nikita Smith eb8fd11b20 input for hashing external leaves was assuming different array layout 2026-02-23 13:55:04 -08:00
Nikita Smith e942dd0380 checkpoint 2026-02-23 12:04:32 -08:00
Nikita Smith 03ab203fb4 warnings 2026-02-23 11:57:05 -08:00
Nikita Smith 2df9a155c6 build radbin for torture 2026-02-23 11:54:37 -08:00
Nikita Smith 6e1816a01c disable crash handler to diagnose crash in github workflows 2026-02-23 11:42:30 -08:00
Nikita Smith b022492c7b use-after-poison fixes 2026-02-23 11:37:36 -08:00
Nikita Smith f07ea37df7 missed format spot 2026-02-23 10:45:05 -08:00
Nikita Smith 8b7215695b test DWARF32 and DWARF64 unit encodings 2026-02-22 22:34:28 -08:00
Nikita Smith cc00fe7825 minor fixes and improvements for DWARF dumper 2026-02-22 20:18:57 -08:00
Nikita Smith 2a8a1a5741 test all LNCT encoding in the file table,
test line instruction encoder,
test special opcode encoding
2026-02-22 20:17:00 -08:00
Nikita Smith a7e64c3928 more reasonable string pad count 2026-02-20 22:24:39 -08:00
Nikita Smith 20d3fa4ddb normalize paths with inconsistent slashes 2026-02-20 22:08:26 -08:00
Nikita Smith 4b88258a30 emit simple DWARF line table 2026-02-20 18:08:45 -08:00
Nikita Smith 121c211d81 minor changes in DWARF dumper 2026-02-20 18:07:47 -08:00
Nikita Smith fda380c66b flush on end sequence opcode and correctly debase addresses 2026-02-20 18:07:06 -08:00
Nikita Smith 3637fe359a do not create async workers for torture 2026-02-20 18:06:31 -08:00
Nikita Smith 6ece754edd max ops and max size for x64 inst 2026-02-20 18:06:00 -08:00
Nikita Smith cfe3cde396 checkpoint: basic line emission 2026-02-20 11:17:12 -08:00
Nikita Smith a6dd529dd5 explicitly handle null terminator in abbrev parse 2026-02-19 18:11:12 -08:00
Nikita Smith a9d3757dbc fix wonky line table indent 2026-02-19 18:11:12 -08:00
Nikita Smith e7cf2513b7 todo 2026-02-19 18:11:11 -08:00
Nikita Smith a02fa0f4cb tests for int128 and uint128 2026-02-18 23:11:25 -08:00
Nikita Smith e300a8579e bump up RDI version 2026-02-18 21:28:40 -08:00
Nikita Smith 338d2177ff added _Decimal* and __bf16 types to RDI and DWARF converter 2026-02-18 21:25:35 -08:00
Nikita Smith f0c3ea7678 treat implicit values as consts 2026-02-18 20:55:41 -08:00
Nikita Smith 28299bf778 move /Zc:preprocessor to common 2026-02-18 19:18:11 -08:00
Nikita Smith 9cc25d11fb update rdi_parse.h 2026-02-18 19:17:40 -08:00
Nikita Smith d26c890246 test basic types 2026-02-18 19:16:51 -08:00
Nikita Smith 09f02f7d08 use xlist macros for float, signed, and unsigned conversion 2026-02-18 16:19:18 -08:00
Nikita Smith a8833dac02 add 96-bit float type to RDI 2026-02-18 16:17:21 -08:00
Nikita Smith 64d0f9b68b copy new memory functions that are used in stb_sprintf to metagen base 2026-02-18 16:16:48 -08:00
Nikita Smith 0e4c864b22 checkpoint: asan crashes radbin in rdi_section_raw_data_from_kind 2026-02-18 01:21:03 -08:00
Nikita Smith 11d90a34a3 stop tests on first fail or crash 2026-02-18 01:20:42 -08:00
Nikita Smith 59e8389ed9 cleanup invoke 2026-02-18 00:56:30 -08:00
Nikita Smith 86de8fb94c string attrib DWARF writer helper 2026-02-18 00:54:55 -08:00
Nikita Smith f9e36b5517 validate attrib-form encoding 2026-02-18 00:54:18 -08:00
Nikita Smith 516365e97b rename CodeView leaf/symbol/debug_s helpers for consistent naming 2026-02-17 03:04:14 -08:00
Nikita Smith 2083c1ed87 serialize symbols directly into MSF streams 2026-02-16 20:32:44 -08:00
Nikita Smith 442f41b51a inline byte hashing around type indices 2026-02-16 13:39:49 -08:00
Nikita Smith 3e5c8ab9f6 minor test fixes 2026-02-16 13:20:13 -08:00
Nikita Smith c1e670a01c type merging test 2026-02-16 12:18:01 -08:00
Nikita Smith 4e4a806b33 pass over the aligner 2026-02-15 23:17:59 -08:00
Nikita Smith 76213ec5cd switch to using 32-bit offsets for leaf records over the pointers 2026-02-15 23:11:51 -08:00
Nikita Smith 09e37a6a2e report unknown ignore codes only in debug builds 2026-02-13 22:10:42 -08:00
Nikita Smith 6fb055bf6e rename asan -> san 2026-02-13 22:07:41 -08:00
Nikita Smith 1f51c6f25b ubsan cleanup 2026-02-13 20:59:26 -08:00
Nikita Smith fbc3cbd6eb polish help in radlink 2026-02-13 19:17:53 -08:00
Nikita Smith 519bc154ec disable async for radlink 2026-02-13 17:33:18 -08:00
Nikita Smith 0315cce2ea track os_commit and os_decommit 2026-02-13 17:31:27 -08:00
Nikita Smith e14d3b7cdb correctly compute size_to_zero for new blocks 2026-02-13 17:29:48 -08:00
Nikita Smith d7a87b7765 share arena between type deduper and MSF 2026-02-13 16:06:54 -08:00
Nikita Smith f5fc3c66b7 reduce leaf hash table bucket size to 8 bytes 2026-02-13 15:03:51 -08:00
Nikita Smith c4b26184fc type warning fix 2026-02-12 13:12:05 -08:00
Nikita Smith 7720ba096e switch to 64-bit type hashes; 128-bits is unnecessary, CodeView can't
have more than 2^32 types
2026-02-12 13:11:36 -08:00
Nikita Smith 1e6df05d9f sort resource pointers 2026-02-11 17:20:38 -08:00
Nikita Smith aa25570904 improve memory usage when reporting unresolved symbols 2026-02-11 15:28:13 -08:00
Nikita Smith e8ca3e0d5c name tag arenas for the memory plots 2026-02-11 15:27:05 -08:00
Nikita Smith 56b89cc8cb plot arena memory usage 2026-02-11 15:26:22 -08:00
Nikita Smith 2a76188570 allocate a minimum cap hash table for the lib member infos 2026-02-11 13:53:37 -08:00
Nikita Smith 5aea3527c1 use-after-poison fix 2026-02-11 13:52:33 -08:00
Nikita Smith efc5855419 bake a predictable producer string 2026-02-11 13:45:25 -08:00
Nikita Smith 21adae63bf enable spec-conformant preprocessor in MSVC 2026-02-11 00:04:43 -08:00
Nikita Smith ddfeba8ae1 natvis for DWARF writer 2026-02-11 00:01:21 -08:00
Nikita Smith da6fd986f0 do not exit on failed call 2026-02-11 00:00:56 -08:00
Nikita Smith aaa5b0cb59 pass over DWARF dumper 2026-02-11 00:00:43 -08:00
Nikita Smith 031e24e1aa handle zero operand count 2026-02-10 23:59:09 -08:00
Nikita Smith ee8562ed97 fix type for the implicit const 2026-02-10 23:58:45 -08:00
Nikita Smith 69434278bd WIP DWARF writer 2026-02-10 23:57:43 -08:00
Nikita Smith ff82d9843c matcher for DW_Form 2026-02-10 15:27:57 -08:00
Nikita Smith 6e100ad52f make form_kind part of DW_Form 2026-02-10 15:27:27 -08:00
Nikita Smith 12f8f4e078 move DW_Form to the DWARF format header 2026-02-10 15:26:56 -08:00
Nikita Smith 988b0f5541 header guard typo 2026-02-09 23:42:09 -08:00
Nikita Smith 9b1a5ae8f8 minor fix 2026-02-09 23:41:33 -08:00
Nikita Smith 482a61aaf7 obj -> COFF serializer 2026-02-09 23:41:19 -08:00
Nikita Smith 33b1e25295 arch -> COFF machine 2026-02-09 23:40:31 -08:00
Nikita Smith 1579e6eae6 simplify serial pushes for u32 and u64 2026-02-09 23:40:10 -08:00
Nikita Smith d7ffea785f compact print abbrev data 2026-02-06 18:49:52 -08:00
Nikita Smith 71a46985b6 use string table extension for long section names 2026-02-05 19:45:35 -08:00
Nikita Smith 010f54674f test for LEB128 reader and writer 2026-02-05 19:45:35 -08:00
Nikita Smith b0d0b6a2b2 factor out LEB128 writer 2026-02-05 19:45:34 -08:00
Nikita Smith b44f79fe44 test section folding with different alignment 2026-02-05 19:45:34 -08:00
Nikita Smith 0c02e21284 WIP tests for ICF 2026-02-05 19:45:34 -08:00
Nikita Smith b6c74ae9bc update values in import_export test 2026-02-05 19:45:34 -08:00
Nikita Smith 0015e52d3c add /FAILIFMISMATCH 2026-02-05 19:45:34 -08:00
Nikita Smith 8b729d4588 refactored testing utility
- factored out common parts in tests into T_BeginTest and T_EndTest
- separated radlink and DWARF tests
2026-02-05 19:45:34 -08:00
Nikita Smith d363c30e95 copy out generic 2026-02-05 19:43:47 -08:00
Nikita Smith ae236f5ccf assert element size does not overflow the simple buffer in radsort 2026-02-05 19:43:47 -08:00
Nikita Smith 09472fafbd typo in the ordinal export sorter 2026-02-05 19:43:47 -08:00
Nikita Smith 15831c704f lock free hash trie 2026-02-05 17:46:10 -08:00
Nikita Smith edd982852e pass over DWARF converter
- prepare to thread line table conversion
- error handling
- organizational improvements
2026-02-05 17:43:20 -08:00
Nikita Smith 4b893d50ec implement swap and drop opcodes; stub out GNU_UnInit 2026-02-05 17:43:20 -08:00
Nikita Smith 5986e595ce eval type group for F80 and F128 2026-02-05 17:43:20 -08:00
Nikita Smith 7d4a64aae6 change size of immediate on Cond opcode to match Skip immediate size 2026-02-05 17:43:20 -08:00
Nikita Smith 2ccb6f6409 natvis 2026-02-05 17:43:19 -08:00
Nikita Smith 3bc9bacf6f update line table dumper; pipe down verbose switch to the DWARF dumper 2026-02-05 17:43:19 -08:00
Nikita Smith 469fbece3d fix check extension in attrib formatter 2026-02-05 17:43:19 -08:00
Nikita Smith 4f30f64914 switched to TryRead helper macro for parsing abbrev table and compile units 2026-02-05 17:43:19 -08:00
Nikita Smith cd70b7e1ec define default debug macros for third party code 2026-02-05 17:43:19 -08:00
Nikita Smith 3d6ca7d610 indent macros 2026-02-05 17:43:19 -08:00
Nikita Smith 6d8cbe8e60 fix stack reference 2026-02-05 17:43:19 -08:00
Nikita Smith 2ca68c1039 flush output buffer before formatting 2026-02-05 17:43:19 -08:00
Nikita Smith c81eafb656 fix memory poisoning for arenas allocated from an optional buffer 2026-02-05 17:43:19 -08:00
Nikita Smith dec5258c32 piece opcodes do not pop the stack 2026-02-05 17:43:19 -08:00
Nikita Smith 82169462a4 detect variable length array in upper bound and lower bound 2026-02-05 17:43:19 -08:00
Nikita Smith 2071e31f29 refactor bad read handling in DWARF parser 2026-02-05 17:43:19 -08:00
Martins MozeikoandNikita a13afb441e fixes issues with minidump on win32
minidump did not have proper exception record passed in, so it did not
contain actual issue of the unhandled exception. Also stack walking
before was mutating registers in exception CONTEXT, this means that
minidump did not have proper call stack anymore. Now code make a local
copy of CONTEXT for stack walking.
2026-02-03 15:15:13 -08:00
Martins MozeikoandNikita f330bde8aa better callstack for null calls
This improves callstack in win32 unhandled exception handler when
indirect call to NULL happens. Before no call stack was printed at
all, so it was hard to know what happened. Now call stack explicitly
will print out [NULL] stack entry + rest of call stack entries. This
is done by manually looking up return address from call stack when
possible.

Also fixes wine compatibility for os_commit function. Wine does not
support RIO buffer functions.
2026-02-03 15:11:03 -08:00
Nikita Smith 3abfb800a8 group forwarder and named exports and sort them together 2026-01-27 11:26:24 -08:00
Nikita Smith cc43d17496 bugfix export by ordinal 2026-01-27 11:25:54 -08:00
Nikita Smith 3113db2d08 add missing retry wraps around syscalls 2026-01-26 15:34:06 -08:00
Nikita Smith be350c4147 add cstr union field to String8 and remove char* casts from the Linux code 2026-01-22 14:04:40 -08:00
Nikita Smith e724ee8185 use /proc/pid/exe to extract ELF header 2026-01-22 13:59:12 -08:00
Nikita Smith e907d895c6 refactored Linux layer to use static types for the entities 2026-01-22 13:30:39 -08:00
Nikita Smith 1ecd970f31 STAP copy functions 2026-01-22 13:30:03 -08:00
Nikita Smith 7627ccf84e move str8 list pop to the base layer 2026-01-22 13:29:45 -08:00
Nikita Smith 29a7dfedac natvis type 2026-01-20 15:35:02 -08:00
Nikita Smith 4f95819eb0 by default linker creates a bind table 2026-01-20 15:33:00 -08:00
Nikita Smith 85df75c30b defer import link test 2026-01-20 15:27:40 -08:00
Nikita Smith 1c0e9030fa move lib member queue state to the link step and release it after link step is done 2026-01-20 15:27:31 -08:00
Nikita Smith d1b055c62f Ignore S_REGREL32 during conversion of optimized procedures.
In optimized builds, MSVC emits parameters as both S_LOCAL and S_REGREL32.
Most likely because their debugger relies on S_REGREL32 to format
parameters in the call stack window.
2026-01-20 14:47:03 -08:00
Nikita Smith a51d3fb752 fix case where return local without a type was converted to a parameter 2026-01-20 14:47:01 -08:00
Nikita Smith 0c4009c328 bugfix import member queue detection 2026-01-16 18:53:03 -08:00
Nikita Smith 8f47ce7616 filter out duplicate page entries before computing the buffer size 2026-01-16 18:52:55 -08:00
Nikita Smith 4ab89cd120 set default values for unload and nobind 2026-01-16 18:41:15 -08:00
Nikita Smith 0168448924 by default commit a page for heap and stack 2026-01-16 18:40:32 -08:00
Nikita Smith 6e32a1f11c ignore /EXPERIMENTAL 2026-01-15 18:29:37 -08:00
Nikita Smith 0c0b7ac6d3 bugfix import linking 2026-01-15 18:25:46 -08:00
Nikita Smith 2729aae982 natvis for linker types 2026-01-15 16:41:07 -08:00
Nikita Smith de164784d0 fix typos in runtime GNU struct parser 2026-01-12 19:06:29 -08:00
Nikita Smith 70d04ac807 clean up unused process fields 2026-01-12 16:48:31 -08:00
Nikita Smith 12b53f4174 move register layout struct to Linux OS layer; use only GPR portion of
the layout struct for reg r/w; handle orig_rax
2026-01-12 16:48:31 -08:00
Nikita Smith fd6c3ef0e0 move GNU and ELF specific struct readers to appropriate layers 2025-12-28 01:16:55 -08:00
Nikita Smith f150662cc4 update logic for tracking new threads 2025-12-20 14:41:01 -08:00
Nikita Smith 13ce0cf020 fix race condition in artifact cache 2025-12-19 17:34:35 -08:00
Nikita Smith 717781e0a3 adjust cursor by delta read size 2025-12-19 17:34:14 -08:00
Nikita Smith 99fe1bc2f2 typo 2025-12-18 20:06:20 -08:00
Nikita Smith cf849f7875 add missing GNU expr opcodes 2025-12-18 20:06:14 -08:00
Nikita Smith cc01c04b8a use p_vaddr for computing dynamic segment address 2025-12-18 20:05:47 -08:00
Nikita Smith ce4d09d431 WIP DW_OP_piece 2025-12-17 17:32:03 -08:00
Nikita Smith 43cb8b7b1a handle DW_Op_FBReg, DW_ExprOp_Deref, DW_ExprOp_BReg*, and DW_ExprOp_BRegX 2025-12-16 17:32:12 -08:00
Nikita Smith 0aea6c4e8f finish value in register test 2025-12-16 13:49:23 -08:00
Nikita Smith da57259379 move DWARF expressions test to the torture 2025-12-16 11:14:17 -08:00
Nikita Smith 823cbf6a72 missing func decls 2025-12-16 11:13:56 -08:00
Nikita Smith 2b4e0f8b77 WIP DWARF expression eval
- fixup jump offsets after expression is serialized
- use generalized machine ops for register reads
- add option to limit number of executed opcodes
2025-12-16 11:12:43 -08:00
Nikita Smith 44123e9712 extend regs with DWARF registers mappings and read/write machine ops 2025-12-16 10:47:05 -08:00
Nikita Smith 952afd49a7 generalize machine ops 2025-12-16 10:40:48 -08:00
Nikita Smith 782f87e512 WIP DWARF expression encoder 2025-12-12 17:39:56 -08:00
Nikita Smith 7d0e168f8f typoes 2025-12-12 12:16:28 -08:00
Nikita Smith 7947d4dc55 outline DWARF expression evaluator 2025-12-11 16:43:21 -08:00
Nikita Smith 5b6ffd5a49 clean up instrumentation inherited during fork 2025-12-09 16:08:19 -08:00
Nikita Smith 094370c028 bugfix last string query 2025-12-09 14:02:06 -08:00
Nikita Smith 962f0e30ae WIP fork 2025-12-09 09:56:43 -08:00
Nikita Smith c221286ab8 WIP process attaching 2025-12-08 13:29:24 -08:00
Nikita Smith 9659ab4ad2 remove privileged registers 2025-12-05 17:03:05 -08:00
Nikita Smith 8005c31276 remove x86 register code 2025-12-05 16:39:02 -08:00
Nikita Smith ce77442d37 fix x87 register layout 2025-12-05 16:36:46 -08:00
Nikita Smith f4ceaecf75 set flags in xstate_bv for updated registers 2025-12-05 13:35:10 -08:00
Nikita Smith 38dbcde3f4 debug info path entity is needed otherwise unwinder fails to map key to RDI 2025-12-02 17:00:05 -08:00
Nikita Smith 81f08a01bc inline anonymous members 2025-12-02 14:39:36 -08:00
Nikita Smith f8f3f95d33 set trace options in PTRACE_SEIZE and remove unnecessary PTRACE_SETOPTIONS 2025-11-27 15:45:36 -08:00
Nikita Smith 1602a9e6ea runtime target OS handling 2025-11-27 11:17:47 -08:00
Nikita Smith 7f701dd806 minor fix 2025-11-26 20:31:34 -08:00
Nikita Smith f9561cb618 add support for CFA in the eval system
Canonical Frame Address is a DWARF-only concept encoded in the unwind info.
Debugger must store this data for each call frame and provide it to
the eval system based on selected stack frame.

To abstract over format details, we introduce a "Frame Unwind Context".
For DWARF, this context maintains the intermediate unwind state and exposes
the CFA, whereas for PE, it remains empty.
2025-11-26 15:42:40 -08:00
Nikita Smith 2a6d0d737c add CFA op to the bytecode 2025-11-26 15:13:24 -08:00
Nikita Smith a1884aaf5f WIP handle abnormal process initialization 2025-11-25 16:24:57 -08:00
Nikita Smith 0565fdef0a WIP add support for GNU LibC TLS model
Unlike on Windows, TLS index isn't part of the module format. glibc stores
it in the opaque link_map struct. There are many different heuristics
a debugger can use to locate it but most of them are unreliable and
prone to errors, or don't work when debugger attaches to a process.
We adopt the newer approach of looking for special symbols
in glibc that provide TLS index offset. These symbols were added in
2021, so programs linked with older glibc won't have TLS support.
2025-11-21 16:41:35 -08:00
Nikita Smith 7347d2f1bc pipe DW_ExprOp_FormTlsAddress through DW_ExprOp_GNU_PushTlsAddress 2025-11-21 16:11:16 -08:00
Nikita Smith 6fa71607e2 do not emit global vars for decls 2025-11-21 16:10:28 -08:00
Nikita Smith 533e7431e7 WIP switch to special mutex for syncing halts 2025-11-19 13:01:25 -08:00
Nikita Smith b7fb4fe04d WIP improved signal handling in multi-threaded programs 2025-11-19 11:38:22 -08:00
Nikita Smith 597ea44337 handle empty hash table case 2025-11-19 11:25:54 -08:00
Nikita Smith e0d0cf6e29 helper marco for dealing with syscalls that are interrupted 2025-11-19 11:25:16 -08:00
Nikita Smith a82cba0c87 cache env strings on startup 2025-11-19 11:24:11 -08:00
Nikita Smith 08f794527c updated hashing libraries 2025-11-13 11:45:34 -08:00
Nikita Smith 7cafde3376 revert DWARF changes to commit bda3a71379 2025-11-13 10:53:29 -08:00
Ryan Fleury 2a76093e17 form value resolution; line table header parsing 2025-11-11 17:24:12 -08:00
Ryan Fleury faee02f763 simplified dwarf parsing checkpoint: pull out form value reading, line table header parsing 2025-11-11 16:27:16 -08:00
Ryan Fleury b8a8ec31c7 checkpoint on simplified / stripped down dwarf -> rdi, and dwarf parsing helpers 2025-11-11 15:10:16 -08:00
Ryan Fleury 17ec73d752 dwarf cleanup checkpoint 2025-11-10 17:41:01 -08:00
Ryan Fleury 08642d2745 next checkpoint on dwarf cleanup 2025-11-10 16:37:23 -08:00
Ryan Fleury f396b2eaa3 start dwarf -> rdi cleanup; eliminate some assertions-as-validation, remove incorrect assumption that line info addresses are vaddrs (they seem to be voffs) 2025-11-10 15:06:52 -08:00
Ryan Fleury efb4731ace respect leading slashes in bake file path tree lookup 2025-11-07 16:53:30 -08:00
Ryan Fleury ed57428602 flip meta check in build.sh 2025-11-07 16:38:46 -08:00
Nikita SmithandRyan Fleury 1196de6916 move sys/wait.h to os_core_linux 2025-11-07 16:37:45 -08:00
Ryan Fleury 035e72306d o_cloexec; preserve leading slashes in root-level paths 2025-11-07 16:37:30 -08:00
Ryan Fleury d4d2159389 eliminate process array join api, no longer needed 2025-11-07 15:54:41 -08:00
Ryan Fleury 4ea3c5a0e4 artifact cache cancellation mutex -> semaphore (fixes cancellation thread on linux - we cannot take/drop across threads with mutexes); flip no_meta -> meta 2025-11-07 15:47:15 -08:00
Ryan Fleury 85778910c6 radbin build.sh 2025-11-07 15:47:15 -08:00
Nikita SmithandRyan Fleury 32bdd14d8e image base for a dynamic ELF is always zero 2025-11-07 15:47:15 -08:00
Nikita SmithandRyan Fleury ddc57a0ac4 WIP changed backend to use ptrace seize and interrupt 2025-11-07 15:47:15 -08:00
Ryan Fleury 80ccfba3c6 fix metagen build on linux 2025-11-07 14:57:41 -08:00
Ryan Fleury af423b142e gl shear 2025-11-07 14:47:14 -08:00
Nikita SmithandRyan Fleury 920a3ab3b7 discard unknown FDEs 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury b00d3d9041 print out call stacks on crashes 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 69fe51ec94 set permissions on shared memory 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 1cb1522931 minor cleanup 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 90c4e1604e implement semaphore open and clsoe 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 857860fb27 remove unused includes and inline ptrace options define 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 880b8135cc add per-item purging to the hash table 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 66606b0327 use STAP probes to generate load and unload module events 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury c8c993d4e8 filter for threads 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury f832ac191c implement process API under Linux 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury e1a46f7d21 reader for STAP arguments 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury bda3a71379 argument parser for simple STAP arguments 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury c4c9ef5182 WIP: got Linux to the point where single stepping and breakpoint
events are being reported correctly to the debugger
2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 0d5df8f38d ELF includes 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury fdb1ad5ab6 do not unwind with PE when DWARF unwinder exits with stale flag 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 6cc7b5622c ELF note parser 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury b596a6ed8a dumper for SHT_NOTE 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 8bc1e4b21c explicitly update stack pointer 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 3f70cd6d05 handle CFI programs without meaningful instructions 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 7616767ed7 fix CFA_Expr instruction fill 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury f2392284d5 add missing case for the register rule 2025-11-07 14:39:46 -08:00
Nikita SmithandRyan Fleury 793cd90604 zero out IP when reached last frame 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 16232b98d8 SP from arch helper 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 9e965e345f string format expression op when version is below 3 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 1b6e9e9d7b parse "Signal Frame" aug flag and fill out augmentation data size 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 821af9b104 fix FDE binary search for case where PC is not exactly on first instruction 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury d44efc15c8 remove structs that are now in GNU layer and add 32 -> 64 bit struct converters 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury e6a01472c8 layer for x64 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 942c354bd9 fix eh_frame dumping 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury f0bd30c89b layer for interfacing with GNU 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury b091233a33 infer path style from exe type 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 36b22c06b1 moved eh_frame files to dwarf layer 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 78f2e641bc fix program header rebase issue in non-PIE exes, and export program header
info through DEMON event
2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 7f705923e6 parse CIE and FDE out of runtime ELF 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 4e2c983b0f skip leading NOP opcodes, which caused extra CFI rows to be emitted 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury dad92610de dumper for .eh_frame_hdr and .eh_frame 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 327645436a named semaphore impl for Linux 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury c32d85ea2d DWARF helper 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury 3b81e1a0e9 connect DWARF virtual stack unwinder 2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury da38f266d9 parser for .eh_frame versions of CIE and FDE and new helper for
mapping PC -> CFI Row
2025-11-07 14:39:45 -08:00
Nikita SmithandRyan Fleury ecbce1efdf add TR and LDTR registers 2025-11-07 14:39:45 -08:00
Ryan Fleury 88b79b2b6a turn off transient tab creation with explicit open/switch command 2025-11-07 14:15:35 -08:00
Ryan Fleury e4aae5b075 respect cursor trail enabling in single line trail path 2025-11-07 13:40:24 -08:00
Ryan Fleury 0549f670c3 cell cursor trail 2025-11-07 13:20:57 -08:00
Ryan Fleury 0c7630e41c cursor trails 2025-11-07 12:00:40 -08:00
Ryan Fleury bc49b806c1 do not retry artifact computation if cancelled 2025-11-07 10:33:17 -08:00
Ryan Fleury e9e0036122 checkpoint on unified lexer 2025-11-06 12:47:05 -08:00
Ryan Fleury 82bc133ba5 first pass at unified lexer path, not plugged in yet 2025-11-04 15:56:42 -08:00
SpeykiousandRyan Fleury 27d01bcee0 Implement Rust syntax highlighting 2025-11-03 16:21:28 -08:00
Ryan Fleury 1ffd662e4f do case/slash insensitive search for filename references for breakpoint disqualification - we can *not* use the string table hash, since paths may disagree on casing 2025-11-03 15:55:43 -08:00
Ryan Fleury cb657aab14 fix bad line range gathering on non-textual files 2025-11-03 15:21:17 -08:00
Ryan Fleury af7f571932 adjust menu bar 2025-11-03 14:59:15 -08:00
Ryan Fleury 499fe635d6 only enable WS_EX_NOREDIRECTIONBITMAP on non-gl renderers - need either this, or we'll need to switch win32/gl to directcomposition (?) 2025-11-03 11:29:04 -08:00
Ryan Fleury 4c32238b38 bump to 25 2025-10-23 17:57:33 -07:00
512 changed files with 154653 additions and 122465 deletions
+7
View File
@@ -1 +1,8 @@
*.sh text=auto eol=lf
src/lib_rdi/rdi.h text=auto eol=lf
src/lib_rdi/rdi.c text=auto eol=lf
*.meta.* text=auto eol=lf
*.exe filter=lfs diff=lfs merge=lfs -text
*.pdb filter=lfs diff=lfs merge=lfs -text
*.elf filter=lfs diff=lfs merge=lfs -text
*.rdi filter=lfs diff=lfs merge=lfs -text
+117 -18
View File
@@ -8,7 +8,45 @@ on:
paths-ignore:
- '**.md'
env:
TORTURE_FLAGS: "--gen_crash_dump"
jobs:
build-ubuntu-24-04:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
target:
- raddbg
- raddbg_non_graphical
- radlink
- radbin
- torture
compiler:
- clang-22
# TODO: - gcc
mode:
- debug
- release
steps:
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: Install Dependencies
shell: bash
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
sudo apt-get update
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
- name: build
shell: bash
run: |
CC="${{ matrix.compiler }}" ./build.sh "${{ matrix.target }}" "${{ matrix.mode }}"
build-windows-2022:
runs-on: windows-2022
strategy:
@@ -18,6 +56,7 @@ jobs:
- raddbg
- radlink
- radbin
- mule_main
compiler:
- msvc
- clang
@@ -25,28 +64,88 @@ jobs:
- debug
- release
steps:
- name: checkout
uses: actions/checkout@v2
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: build (vs 2022)
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
call build meta "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
run-torture:
runs-on: windows-2022
run-ubuntu-24-04:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
compiler:
- clang-22
# TODO: - gcc
mode:
- debug
# TODO: - release
steps:
# - name: Install ASAN
# shell: cmd
# run: |
# "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" modify --installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" --quiet --force --norestart --add Microsoft.VisualStudio.Component.VC.ASAN
- name: checkout
uses: actions/checkout@v2
- name: run-torture
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: Install Dependencies
shell: bash
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
sudo apt-get update
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
# crash callstack symbolizer depends on LLVM
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
- name: Run
shell: bash
run: |
CC="${{ matrix.compiler }}" ./run_tests.sh clang "${{ matrix.mode }}" -- \* $TORTURE_FLAGS
- name: Upload Artifacts
if: failure()
uses: actions/upload-artifact@v7
with:
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
path: |
build/*.core
build/*.exe
build/*.pdb
build/torture_artifacts/**
if-no-files-found: ignore
run-windows-2022:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
compiler:
- msvc
- clang
mode:
- debug
- release
steps:
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: Run
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build radlink asan debug no_meta || exit /b 1
call build torture debug no_meta || exit /b 1
cd build
torture -l:radlink || exit /b 1
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
call run_tests.bat ${{ matrix.compiler }} ${{ matrix.mode }} -- * %TORTURE_FLAGS% || exit /b 1
- name: Upload Artifacts
if: failure()
uses: actions/upload-artifact@v7
with:
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
path: |
build/*.dmp
build/*.exe
build/*.pdb
build/torture_artifacts/**
if-no-files-found: ignore
+2 -1
View File
@@ -1,4 +1,5 @@
/build/
/local/
*~
.vscode/settings.json
.vs
tags
+262
View File
@@ -1,3 +1,265 @@
# v0.9.28-alpha
## Linker Changes
- Implemented `/OPT:ICF` identical COMDAT folding.
- Added DEF, and SECTION configuration support.
- Improved COMDAT handling for weak symbols, ICF, and zero-sized COMDAT
anchors, and stopped emitting empty marker sections that could produce invalid
PE images.
- Fixed import/export edge cases, including import data-directory bounds and
archive member handling for `__imp_*` symbols.
- Accepted duplicate identical weak search aliases without reporting multiply
defined symbols.
- Add support for UTF-16 encoded response files.
- Fixed DBI section-contribution image-section range mapping.
- Improved debug logging for `/OPT:REF` liveness stats and unresolved symbols
referenced by `.llvm_addrsig`.
# v0.9.27-alpha
## Debugger Changes
- Fixed an issue which would rarely cause steps to take a long time.
- Drastically improved memory usage of PDB -> RDI conversion for some
workloads, notably PDBs with many small compilation units.
- Added the ability to disambiguate symbol names by module name, debug info
name, or compilation unit name in expressions. This can be done using the
usual syntax, e.g. `my_module.dll!foo`, or `my_unit.obj!foo`. `:` can also be
used instead of `!`.
- Added the ability to redirect debug string output to any label on a
per-target basis. Those labels can then be evaluated in any watch window or
text visualizer. By default, all targets write to `output`, which is
automatically visualized by an `Output` tab. But if you want different
targets to route their debug output to different buffers, you can name the
buffers differently, and then view those in separate text views.
- Added a `Run To Name` command.
- Added an `Auto Load Last Project` setting, which will automatically load the
most recently loaded project on startup (the old behavior pre-0.9.26). This
setting is off by default.
- Added right-click menus for watch expressions, to easily find them in a
memory view, or to break when their value changes.
- Added preliminary support for symbol servers. First, the debugger can attempt
to download debug info for any module via the `Download Module Debug Info`
command (also accessible by right-clicking a module). Second, the debugger
can be configured to automatically do this for all modules which don't have
debug info via the `Auto Download Debug Info` setting. The local cache path
and server URLs used by the debugger for downloading symbols are parsed from
the `_NT_SYMBOL_PATH` environment variable. If that environment variable is
not configured, then it falls back to the defaults of `C:/SymbolCache` and
`https://msdl.microsoft.com/download/symbols`.
- Adjusted the default dark theme.
- Made several UI visual improvements.
- Fixed a few issues relating to offline symbol evaluation (evaluation of
symbols in debug info when not debugging); this was sometimes preventing
function listers (e.g. used in `Go To Name`) from working when not debugging.
- Fixed the debugger's snap-to-code-location rule when a `Disassembly` tab is
occupying the same panel as source code tabs. Previously, the debugger would
overly aggressively switch back to source code tabs. Now, it should respect
the preference of disassembly correctly.
- Improved the stability of the step-over-line operation. Our stepping
algorithm would sometimes cause spurious (and rarely, non-spurious)
access violation exceptions when a thread would try to execute at address
`0x38f`. This most regularly surfaced when an exception on one thread (like a
breakpoint being hit) would interrupt stepping on another thread. This has
been resolved, and stepping in such scenarios should be much more reliable.
- Fixed some crashes in the PDB -> RDI converter. (#792, #803)
- Fixed a bug which was sometimes causing a step-over operation to resume the
process without catching the target thread after its step completed. (#804)
- Adjusted evaluation visualizations to include fully qualified symbol names.
(#809)
## Linker Changes
- /OPT:REF Fixed a race in the dead-code-elimination pass where the linker
sometimes erroneously removed live sections.
- Fixed a bug where the linker emitted relocations for empty COFF resource entries,
which lead to "relocating against symbol that is in a removed section" errors.
- Added the /RAD_TYPE_SERVER switch to run the type-dedup pass on object files,
producing RRT files that can be passed back on the next link to improve
linking speed.
# v0.9.26-alpha
## Debugger Changes
- Added scope ending visualizations to the text view, to display the header of
a scope at the closing position of the scope. This can be turned off via the
`Cursor Scope End Annotations` setting.
- Added the ability to evaluate `autos`, which is a collection of expressions
that the debugger determines refer to symbols which are being (or about to
be) changed by the selected thread.
- Added source-inline and disassembly-inline visualization of auto expressions.
This can be turned off via the `Show Auto Watches In Source / Disassembly`
setting.
- Added the ability to evaluate local static variables unambiguously, when the
same name is used for multiple local static variables, even when outside the
function containing the local static. This can be done by namespacing the
variable name with the containing function, either using a `::` or `.`
operator. (#359)
- Added a setting, `Transient Tabs`, to disable transient tabs being opened,
when the debugger automatically snaps to new code locations.
- Added a setting, `Display Pointer Addresses Before Contents`, to always
force the debugger to show pointer addresses before attempting to visualize
to what the pointer points.
- Adjusted the `Step Out` command to perform scope-granularity stepping, rather
than only being function-frame-granularity. This uses scope information found
in debug info to step out of scopes when possible, rather than always exiting
the current function frame. This makes the command much more useful for
stepping through larger functions with several scopes of larger work, or for
stepping out of loops. (#746)
- Adjusted the debugger's user & project configuration file behavior to be less
idiosyncratic with other programs. Project files are no longer auto-loaded
based on the project last loaded during the previous debugger runtime.
Creating a new user or project also does not immediately require choosing a
path for the file; these can later be specified using the respective `Save`
commands. (#743)
- Adjusted the debugger to automatically set the current path when loading a
project file. (#743)
- Added syntax highlighting and tab-completion for view identifiers in
watch expressions.
- Added more in-debugger documentation for views and their arguments, when
written in a watch expression.
- Moved configuration data previously treated as project data to being user
data, tagged with the associated project. This includes loaded debug info and
breakpoints. The effect of this is that project files are much easier to
check into source control (they do not change in spurious ways for other
users on a project), but project-related user configuration will still be
correctly filtered based on whatever project is loaded.
- Improved the debugger's behavior with respect to keeping previously-loaded
debug info around. Now, when the debugger begins a new debugging session, it
will unload all loaded debug info, and it will only reload debug info that is
actively found to be needed by debuggees. This preserves the debugger's
ability to use debug info without debugging for features like
go-to-definition and type evaluation, but it stops the debugger from keeping
old and unneeded debug info loaded indefinitely (until it is manually
unloaded). (#711)
- Adjusted recent project visualization to include the name of the project,
specified with the `Project Name` setting.
- Renamed `Switch` to `Open Source File From Debug Info`, to better represent
the command's functionality.
- Adjusted file path evaluation visualization to include the full path to the
containing folder, when it is not obvious from context (for instance, if the
file evaluation is a child evaluation of a folder evaluation, the containing
folder path is not shown; if the file path is evaluated standalone, as it is
in the lister generated for the `Open Source File From Debug Info` command,
then the containing folder path is shown).
- Improved visualization of unmapped addresses in the memory view. Now, instead
of bytes at these addresses being displayed as `0` with a special background,
they are displayed as `x`, and the annotations for these addresses (displayed
at the bottom of the memory view, for the cursor's cell) explicitly label
them as being unmapped.
- Improved visualization of unmapped addresses in watch expressions. Now,
instead of only being colored differently with evaluations reading as zeroed
memory, the value will explicitly label addresses as unmapped when possible.
- Fixed a leak which most notably manifested during rapid creation/destruction
of new threads. (#780)
- Fixed a leak related to debugger's config state. This was difficult to
reproduce, but it may fix leaks experienced after running the debugger for an
extended period of time.
- Fixed a bug where cross-module evaluations would resolve to incorrect
addresses, due to using the incorrect module's base virtual address. This was
also causing broken behavior sometimes in the `Go To Name` lister, and
other similar UIs.
- Fixed a bug where panels without tabs were unnecessarily keeping the debugger
UI awake in some cases.
- Fixed a bug preventing hover evaluation from working on indexing expressions.
(#707)
- Replaced the DWARF -> RDI converter with a new multithreaded version, which
should execute much faster on larger DWARF debug info, and produce much
smaller RDI output, due to the addition of type deduplication.
- Introduced structured namespaces to RDI, which structurally encode namespace
hierarchies for debug info symbols, instead of this information being
implicitly baked using language-specific conventions into symbol names. This
is used to deduplicate repeated namespace prefixes from symbol names, leading
to a smaller string footprint for generated RDIs. Symbols now only store
their partially-qualified name. For example, for a C++ symbol `A::B::C`, the
symbol itself will store its name as `C`, but it will also record its
container as being `B`. `B`, then, will record its container as being `A`.
This allows users of RDI to dynamically construct the fully-qualified name as
needed, and it allows for more reliable and language-agnostic usage of
partially-qualified symbol names.
- Adjusted the debugger to not rely on `SynchronizationBarrier` functions on
Windows when they're not available (pre-Windows-8). (#739)
## Linker Changes
- Implemented /DEBUG:GHASH
- Fixed an issue where an import thunk or import address could be linked from
the currently searched library instead of the library where the first import
reference was found. For example, if the first pass finds the import thunk in
foo.lib and the second pass resolves symbol to the import address in bar.lib,
the linker now always linkes the import thunk and import address members from
the library where the first reference was found.
- /OPT:REF: Fixed an issue with garbage collection of associated sections and
weak symbols that led linker to remove live sections.
- /OPT:REF Added relocation batching to reduce contention on the global
reference list during garbage collection.
# v0.9.25-alpha
## Debugger Changes
- Added a dedicated cursor address bar to the memory view. This can be focused
with the keyboard with the `Focus Menu` command. By default, this command is
bound to `Alt + D`, but if you have existing configuration, you may need to
bind it yourself manually (this can be done in the palette). This address bar
accepts any expression, and controls the cursor's address. All other
configuration options are still available in the memory view settings.
- Added "Peek Types" to the memory view. These control the set of types which
are used to interpret bytes at the cursor. Options exist for basic cases,
like integers and floats, but the view also supports entering a list of
full type expressions, which can include user-defined types like structures.
- Added annotations for members of structure variables to the memory view.
- Added a dedicated zoom setting for the memory view.
- Added a setting for automatically determining the number of columns in the
memory view based on the available space.
- Fixed many bugs and improved visuals in the memory view. (#690)
- Fixed the debugger incorrectly evaluating pointer casts of registers in
register space, rather than promoting them to process address space
evaluations. This fixes cases where expressions like `(int *)rax` were not
evaluating correctly. (#659)
- Fixed the debugger incorrectly requiring multiple step operations when source
lines mapped to multiple discontiguous ranges of instructions. This most
notably showed up with certain styles of `for`-loops, especially with Clang
and other non-C/C++ languages, and function prologues in non-C/C++ languages.
- Fixed the debugger treating the `foo, x` fastpath for `hex(foo)` differently
than `hex(foo)`, in that the hexadecimal setting was not being inherited.
- Fixed the debugger leaking debug info conversion process handles. This
addresses cases where the debugger was preventing stale debug info from being
updated, after a rebuild. (#736)
- Fixed the debugger not correctly using target-embedded markup data. (#702)
- Fixed the debugger not showing full call stacks when the top instruction
pointer is located at a 0 address.
- Fixed integer casts producing incorrect values. (#754)
- Fixed the PDB -> RDI converter's interpretation of certain empty argument
lists in function types in PDB. This fixes some cases where local variables
were being interpreted as parameters, which resulted in incorrect evaluation
results. (#751)
- Fixed several crashes and instabilities. (#735)
- Added a dedicated settings button to the focused tab. This opens the same
menu as right-clicking the tab, but this makes this menu (and thus all
options for all tabs and views) more discoverable.
- Added optional cursor trails, to visualize cursor motion. Can be turned off
by toggling the `Cursor Trail` setting.
- Added project names. When set, this name is used for displaying the project
instead of the project filename in the UI and window titles.
- Adjusted the rules for explicit file location finding commands (like
`Switch`, or `Switch To Partner File`), such that they prefer creating new
non-transient tabs, even if the target file is found within an existing
transient tab.
- Adjusted the source code context menu to activate commands with a single
press, rather than the usual double click behavior from general palettes.
## Linker Changes
- Optimized debug info generation to reduce memory usage in large links by 25%.
- Fixed a determinism issue that caused linker to write unreliable debug info.
- Fixed over-reservetaion of PDB pages, reducing the PDB size.
- Implemented /INFERASANLIBS
- Implemented /WHOLEARCHIVE
- Implemented /PDBSTRIPPED
- Set correct defaults for unload and bind import tables.
# v0.9.24-alpha
## Debugger Changes
+2 -2
View File
@@ -5,7 +5,7 @@ debugger itself, and is intended as a technical overview of the project. The
debugger's README, which includes usage instructions and tips, can be found
packaged along with debugger releases, or within the `build` folder after a
local copy has been built. You can find pre-built release binaries
[here](https://github.com/EpicGamesExt/raddebugger/releases)._
[here](https://github.com/EpicGames/raddebugger/releases)._
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
currently only supports local-machine Windows x64 debugging with PDBs, with
@@ -14,7 +14,7 @@ support native Linux debugging and DWARF debug info.
The debugger is currently in *ALPHA*. In order to get the debugger
bullet-proof, it'd greatly help out if you submitted the issues you find
[here](https://github.com/EpicGamesExt/raddebugger/issues), along with any
[here](https://github.com/EpicGames/raddebugger/issues), along with any
information you can gather, like dump files (along with the build you used),
instructions to reproduce, test executables, and so on.
+35 -18
View File
@@ -24,6 +24,7 @@ cd /D "%~dp0"
:: Below is a list of all possible non-target command line options:
::
:: - `asan`: enable address sanitizer
:: - `ubsan`: enable undefined-behavior sanitizer
:: - `telemetry`: enable RAD telemetry profiling support
:: - `spall`: enable spall profiling support
@@ -35,14 +36,15 @@ if "%debug%"=="1" set release=0 && echo [debug mode]
if "%release%"=="1" set debug=0 && echo [release mode]
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
if "%clang%"=="1" set msvc=0 && echo [clang compile]
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
:: --- Unpack Command Line Build Arguments ------------------------------------
set auto_compile_flags=
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
if "%ubsan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=undefined && echo [ubsan enabled]
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info]
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
@@ -66,21 +68,22 @@ if "%pgo%"=="1" (
)
:: --- Compile/Link Line Definitions ------------------------------------------
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /Zc:preprocessor
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf
set cl_out= /out:
set cl_obj_out= /Fo:
set cl_linker=
set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 -msha
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf
set clang_common= -mcx16 -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 -D_DEBUG %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 -DNDEBUG %clang_common% %auto_compile_flags%
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:noicf
set clang_out= -o
set clang_obj_out= -o
set clang_linker= -Xlinker
:: --- Per-Build Settings -----------------------------------------------------
set link_dll=-DLL
set link_icon=logo.res
if "%msvc%"=="1" set linker=%cl_linker%
if "%clang%"=="1" set linker=%clang_linker%
@@ -92,16 +95,20 @@ if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
if "%msvc%"=="1" set rc=call rc
if "%clang%"=="1" set rc=call llvm-rc
if "%msvc%"=="1" set link_dll=/link /DLL
if "%clang%"=="1" set link_dll=-Xlinker -DLL
:: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug%
if "%msvc%"=="1" set compile_release=%cl_release%
if "%msvc%"=="1" set compile_link=%cl_link%
if "%msvc%"=="1" set out=%cl_out%
if "%msvc%"=="1" set obj_out=%cl_obj_out%
if "%clang%"=="1" set compile_debug=%clang_debug%
if "%clang%"=="1" set compile_release=%clang_release%
if "%clang%"=="1" set compile_link=%clang_link%
if "%clang%"=="1" set out=%clang_out%
if "%clang%"=="1" set obj_out=%clang_obj_out%
if "%debug%"=="1" set compile=%compile_debug%
if "%release%"=="1" set compile=%compile_release%
@@ -119,32 +126,37 @@ for /f %%i in ('call git describe --always --dirty') do set compile=%compile%
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
:: --- Build & Run Metaprogram ------------------------------------------------
pushd build
if "%meta%"=="1" (
echo [doing metagen]
pushd build
echo [building metagen]
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
metagen.exe || exit /b 1
popd
)
if "%no_meta%"=="" if exist metagen.exe (
echo [running metagen]
metagen.exe || exit /b 1
)
popd
:: --- Build Everything (@build_targets) --------------------------------------
pushd build
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
if "%raddbg_non_graphical%"=="1" set didbuild=1 && %compile% -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg_non_graphical.exe || exit /b 1
if "%com_shim%"=="1" set didbuild=1 && %compile% ..\src\com_shim\com_shim_main.c %compile_link% %out%com_shim.exe || exit /b 1
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
if "%eval_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\eval_scratch.c %compile_link% %out%eval_scratch.exe || exit /b 1
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp %obj_out%mule_inline.obj && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp %obj_out%mule_o2.obj && %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 %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture.c %compile_link% %out%torture.exe || exit /b1
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture_main.c %compile_link% %out%torture.exe || exit /b1
if "%dwarf_expr_test%"=="1" set didbuild=1 && %compile% ..\src\torture\dwarf_expr_test.c %compile_link% %out%dwarf_expr_test.exe || exit /b1
if "%unit_sizes_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\scratch\unit_sizes_from_pdb.c %compile_link% %out%unit_sizes_from_pdb.exe || exit /b1
if "%mule_peb_trample%"=="1" (
set didbuild=1
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
@@ -155,6 +167,11 @@ if "%mule_peb_trample%"=="1" (
)
popd
:: --- Set Up Debugger Com Shim -----------------------------------------------
pushd build
if "%raddbg_com_shim%"=="1" copy /y com_shim.exe raddbg.com
popd
:: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" (
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
@@ -165,7 +182,7 @@ if "%didbuild%"=="" (
if "%pgo_run%"=="1" (
if "%radlink%"=="1" (
pushd local\lyra_pgo
call %~dp0build\radlink @lyra.rsp /rad_alt_pch_dir:%~dp0local\lyra_pgo || exit /b 1
call %~dp0build\radlink @lyra.rsp || exit /b 1
popd
)
goto restart
Regular → Executable
+42 -46
View File
@@ -4,78 +4,74 @@ cd "$(dirname "$0")"
# --- Unpack Arguments --------------------------------------------------------
for arg in "$@"; do declare $arg='1'; done
if [ ! -v gcc ]; then clang=1; fi
if [ ! -v release ]; then debug=1; fi
if [ -v debug ]; then echo "[debug mode]"; fi
if [ -v release ]; then echo "[release mode]"; fi
if [ -v clang ]; then compiler="${CC:-clang}"; echo "[clang compile]"; fi
if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
if [[ "$#" == "0" ]]; then raddbg='1'; fi
# --- Unpack Command Line Build Arguments -------------------------------------
auto_compile_flags=''
cc_sanitize=""
if [[ "${asan:-0}" == "1" ]]; then
echo "[asan enabled]"
cc_sanitize="-fsanitize=address"
fi
# --- Get Current Git Commit Id -----------------------------------------------
git_hash=$(git describe --always --dirty)
git_hash_full=$(git rev-parse HEAD)
# --- Compile/Link Line Definitions -------------------------------------------
clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
clang_link="-lpthread -lm -lrt -ldl"
clang_out="-o"
gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
gcc_link="-lpthread -lm -lrt -ldl"
gcc_out="-o"
cc_cflags_gcc=""
cc_cflags_clang=${cc_sanitize}" -fdiagnostics-absolute-paths -Wno-for-loop-analysis -Wno-incompatible-pointer-types-discards-qualifiers -Wno-initializer-overrides -Wno-compare-distinct-pointer-types -Wno-single-bit-bitfield-constant-conversion -Wno-deprecated-declarations -Wno-writable-strings -Wno-unknown-warning-option -Wno-deprecated-register -Wno-unused-local-typedef -msse2"
cc_common="-mcx16 -I../src/ -I../local/ -D_GNU_SOURCE -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wall -Wno-missing-braces -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-value -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
cc_debug="-g -O0 -DBUILD_DEBUG=1 ${cc_common}"
cc_release="-g -O2 -DBUILD_DEBUG=0 ${cc_common}"
cc_link="-lpthread -lm -lrt -ldl"
# --- Per-Build Settings ------------------------------------------------------
link_dll="-fPIC"
link_os_gfx="-lX11 -lXext"
link_render="-lGL -lEGL"
link_font_provider="-lfreetype"
cc_link_dll="-fPIC"
# --- External Libraries ------------------------------------------------------
# sudo apt install -y pkg-config libfreetype6-dev libx11-dev libxext-dev libgl-dev libegl-dev
if [[ -x "$(command -v pkg-config)" ]]; then
cc_font_provider="$(pkg-config --cflags --libs freetype2)"
cc_os_gfx="$(pkg-config --cflags --libs x11 xext)"
cc_render="$(pkg-config --cflags --libs gl egl)"
else
cc_font_provider="-I/usr/include/freetype2 -lfreetype"
cc_os_gfx="-lX11 -lXext"
cc_render="-lGL -lEGL"
fi
# --- Choose Compile/Link Lines -----------------------------------------------
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
if [ -v gcc ]; then compile_release="$gcc_release"; fi
if [ -v gcc ]; then compile_link="$gcc_link"; fi
if [ -v gcc ]; then out="$gcc_out"; fi
if [ -v clang ]; then compile_debug="$clang_debug"; fi
if [ -v clang ]; then compile_release="$clang_release"; fi
if [ -v clang ]; then compile_link="$clang_link"; fi
if [ -v clang ]; then out="$clang_out"; fi
if [ -v debug ]; then compile="$compile_debug"; fi
if [ -v release ]; then compile="$compile_release"; fi
if [[ "${gcc:-0}" == "1" ]]; then compiler="${CC:-gcc} $cc_cflags_gcc"; echo "[gcc compile]";
elif [[ "${clang:-1}" == "1" ]]; then compiler="${CC:-clang} $cc_cflags_clang"; echo "[clang compile]";
fi
if [[ "${release:-0}" == "1" ]]; then echo "[release mode]"; compile="$compiler $cc_release";
elif [[ "${debug:-1}" == "1" ]]; then echo "[debug mode]"; compile="$compiler $cc_debug";
fi
# --- Prep Directories --------------------------------------------------------
mkdir -p build
mkdir -p local
mkdir -p build local
# --- Build & Run Metaprogram -------------------------------------------------
if [ -v no_meta ]; then echo "[skipping metagen]"; fi
if [ ! -v no_meta ]
if [[ "${no_meta:-0}" == "0" ]]
then
echo "[building metagen]"
cd build
$compile_debug ../src/metagen/metagen_main.c $compile_link $out metagen
$compiler $cc_debug ../src/metagen/metagen_main.c $cc_link -o metagen
./metagen
cd ..
fi
# --- Build Everything (@build_targets) ---------------------------------------
cd build
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $link_font_provider $out raddbg; fi
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
if [ -v rdi_breakpad_from_pdb ]; then didbuild=1 && $compile ../src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c $compile_link $out rdi_breakpad_from_pdb; fi
if [ -v ryan_scratch ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $link_render $link_font_provider $out ryan_scratch; fi
if [[ "${raddbg:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg; fi
if [[ "${raddbg_non_graphical:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg_non_graphical; fi
if [[ "${radbin:-0}" == "1" ]]; then didbuild=1 && $compile ../src/radbin/radbin_main.c $cc_link -o radbin; fi
if [[ "${radlink:-0}" == "1" ]]; then didbuild=1 && $compile ../src/linker/lnk.c $cc_link -o radlink; fi
if [[ "${torture:-0}" == "1" ]]; then didbuild=1 && $compile ../src/torture/torture_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o torture; fi
cd ..
# --- Warn On No Builds -------------------------------------------------------
if [ ! -v didbuild ]
if [[ "${didbuild:-0}" == "0" ]]
then
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh rdi_from_pdb\`."
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh radlink\`."
exit 1
fi
+93
View File
@@ -0,0 +1,93 @@
{
"version": "0.2.1",
"defaults": {},
"configurations": [
{
"type": "cppdbg",
"name": "launch - torture",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "build/",
"program": "torture",
"args": [ "d2r_checksums" ],
"stopAtEntry": false,
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "-gdb-set follow-fork-mode parent" },
{ "text": "-gdb-set detach-on-fork on" },
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
},
{
"type": "cppdbg",
"name": "launch - radbin",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "build/",
"program": "radbin",
"args": [ "-voff2line", "-voff:0x1000", "torture_artifacts/d2r_line_table/a.rdi" ],
"stopAtEntry": false,
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "-gdb-set follow-fork-mode parent" },
{ "text": "-gdb-set detach-on-fork on" },
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
},
{
"type": "cppdbg",
"name": "launch - radlink",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "/mnt/c/devel/raddebugger/build/torture_artifacts/debug_p_sig_mismatch",
"program": "/mnt/c/devel/raddebugger/build/radlink",
"args": [ "/subsystem:console", "/entry:entry", "/out:a.exe", "/debug:full", "a.obj", "b.obj", "entry.obj" ],
"stopAtEntry": false,
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
},
{
"type": "cppdbg",
"name": "launch - raddbg",
"request": "launch",
"project": "c://windows//system32//cmd.exe",
"cwd": "build/",
"program": "/mnt/c/devel/raddebugger/build/raddbg",
//"processId": "65821",
"environment": [],
"externalConsole": false,
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "wsl",
"pipeArgs": [ "${debuggerCommand}" ]
},
"setupCommands": [
{ "text": "handle SIGUSR1 nostop" }
],
"MIMode": "gdb"
}
]
}
File diff suppressed because it is too large Load Diff
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_DUMP_H
#define DWARF_DUMP_H
typedef enum
{
DW_DumperCacheFlag_InfoRanges = (1 << 0),
DW_DumperCacheFlag_CuArr = (1 << 1),
DW_DumperCacheFlag_LineVmMap = (1 << 2),
DW_DumperCacheFlag_TagTrees = (1 << 3),
} DW_DumperCacheFlags;
typedef struct DW_Dumper
{
Arena *arena;
Arch arch;
B32 is_relaxed;
B32 is_verbose;
DW_Raw *input;
DW_DumperCacheFlags cache_flags;
struct {
Rng1U64Array info_ranges;
DW_CompUnit *cu_arr;
HashTable *line_vm_map;
DW_TagTree *tag_trees;
} cache;
} DW_Dumper;
#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper)
typedef DW_PRINTER(DW_Printer);
////////////////////////////////
// cache
internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper);
internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper);
internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper);
internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper);
////////////////////////////////
//~ rjf: Stringification Helpers
internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program);
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa);
internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row);
#if 0
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx);
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch);
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges);
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input);
#endif
////////////////////////////////
//~ rjf: Dump Entry Point
internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose);
#endif // DWARF_DUMP_H
File diff suppressed because it is too large Load Diff
+233
View File
@@ -0,0 +1,233 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_EXPR_H
#define DWARF_EXPR_H
////////////////////////////////
// evaluator
#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512)
#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512)
#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64)
#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr)
typedef enum
{
DW_ExprValueType_Generic,
DW_ExprValueType_U8,
DW_ExprValueType_U16,
DW_ExprValueType_U32,
DW_ExprValueType_U64,
DW_ExprValueType_U128,
DW_ExprValueType_U256,
DW_ExprValueType_U512,
DW_ExprValueType_S8,
DW_ExprValueType_S16,
DW_ExprValueType_S32,
DW_ExprValueType_S64,
DW_ExprValueType_S128,
DW_ExprValueType_S256,
DW_ExprValueType_S512,
DW_ExprValueType_F32,
DW_ExprValueType_F64,
DW_ExprValueType_Addr,
DW_ExprValueType_Implicit,
DW_ExprValueType_Bool,
} DW_ExprValueType;
typedef S8 DW_ExprBool;
typedef struct DW_ExprValue
{
DW_ExprValueType type;
Rng1U64Array ranges;
U64 *offsets;
union {
U8 u8;
U16 u16;
U32 u32;
U64 u64;
U128 u128;
U256 u256;
U512 u512;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
F32 f32;
F64 f64;
U64 addr;
DW_ExprBool boolean;
String8 implicit;
String8 generic;
};
} DW_ExprValue;
typedef struct DW_ExprValueNode
{
DW_ExprValue v;
struct DW_ExprValueNode *next;
} DW_ExprValueNode;
typedef enum
{
DW_PieceKind_Null,
DW_PieceKind_Value,
DW_PieceKind_Undefined,
} DW_PieceKind;
typedef struct DW_Piece
{
DW_PieceKind kind;
U64 bit_size;
U8 *value;
} DW_Piece;
typedef struct DW_PieceNode
{
DW_Piece v;
struct DW_PieceNode *next;
} DW_PieceNode;
typedef struct DW_PieceList
{
U64 count;
DW_PieceNode *first;
DW_PieceNode *last;
} DW_PieceList;
typedef struct DW_ExprStack
{
U64 count;
DW_ExprValueNode *top;
} DW_ExprStack;
typedef enum
{
DW_ExprEvalResult_Fail,
DW_ExprEvalResult_Ok,
DW_ExprEvalResult_Maybe,
DW_ExprEvalResult_ExecOpLimitReached,
} DW_ExprEvalResult;
////////////////////////////////
// encoder
typedef enum
{
DW_ExprEncType_Null,
DW_ExprEncType_Op,
DW_ExprEncType_U8,
DW_ExprEncType_U16,
DW_ExprEncType_U32,
DW_ExprEncType_U64,
DW_ExprEncType_S8,
DW_ExprEncType_S16,
DW_ExprEncType_S32,
DW_ExprEncType_S64,
DW_ExprEncType_ULEB128,
DW_ExprEncType_SLEB128,
DW_ExprEncType_Addr,
DW_ExprEncType_Block,
DW_ExprEncType_DwarfUInt,
DW_ExprEncType_Label,
DW_ExprEncType_DeclLabel,
} DW_ExprEncType;
typedef struct DW_ExprEnc
{
DW_ExprEncType type;
union {
DW_ExprOp op;
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
U64 addr;
String8 block;
String8 label;
};
} DW_ExprEnc;
#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v }
#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v }
#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v }
#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v }
#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v }
#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v }
#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v }
#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v }
#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v }
#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v }
#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v }
#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v }
#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v }
#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v }
#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) }
#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) }
////////////////////////////////
// pieces
internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v);
// size -> type
internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size);
// type -> size
internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k);
// typer
internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type);
// arithmetic operators
internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs);
// comparison operators
internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs);
// bitwise operators
internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs);
// unary operators
internal DW_ExprValue dw_expr_abs(DW_ExprValue value);
internal DW_ExprValue dw_expr_neg(DW_ExprValue value);
internal DW_ExprValue dw_expr_not(DW_ExprValue value);
// stack
internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value);
internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size);
internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack);
internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack);
internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx);
// value helpers
internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v);
// evaluator
internal DW_ExprEvalResult dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls_base, U64 op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out);
#endif //DWARF_EXPR_H
File diff suppressed because it is too large Load Diff
+528
View File
@@ -0,0 +1,528 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_PARSE_H
#define DWARF_PARSE_H
typedef struct DW_Section
{
String8 name;
String8 data;
B32 is_dwo;
} DW_Section;
typedef struct DW_Raw
{
DW_Section sec[DW_Section_COUNT];
DW_Section sup[DW_Section_COUNT];
} DW_Raw;
typedef struct DW_ListUnit
{
DW_Version version;
U64 address_size;
U64 segment_selector_size;
U64 entry_size;
String8 entries;
} DW_ListUnit;
typedef struct DW_ListUnitInput
{
U64 addr_count;
U64 str_offset_count;
U64 rnglist_count;
U64 loclist_count;
Rng1U64Array addr_ranges;
Rng1U64Array str_offset_ranges;
Rng1U64Array rnglist_ranges;
Rng1U64Array loclist_ranges;
DW_ListUnit *addrs;
DW_ListUnit *str_offsets;
DW_ListUnit *rnglists;
DW_ListUnit *loclists;
} DW_ListUnitInput;
typedef struct DW_AbbrevTableEntry
{
U64 id;
U64 off;
} DW_AbbrevTableEntry;
typedef struct DW_AbbrevTable DW_AbbrevTable;
struct DW_AbbrevTable
{
U64 count;
DW_AbbrevTableEntry *entries;
};
typedef enum DW_AbbrevKind
{
DW_Abbrev_Null,
DW_Abbrev_Tag,
DW_Abbrev_Attrib,
DW_Abbrev_AttribSequenceEnd,
DW_Abbrev_DIEBegin,
DW_Abbrev_DIEEnd,
} DW_AbbrevKind;
typedef U32 DW_AbbrevFlags;
enum
{
DW_AbbrevFlag_HasImplicitConst = (1 << 0),
DW_AbbrevFlag_HasChildren = (1 << 1),
};
typedef struct DW_Abbrev
{
DW_AbbrevKind kind;
U64 sub_kind;
U64 id;
S64 implicit_const;
DW_AbbrevFlags flags;
} DW_Abbrev;
typedef struct DW_Attrib
{
U64 info_off;
U64 abbrev_off;
U64 abbrev_id;
DW_AttribKind attrib_kind;
DW_Form form;
} DW_Attrib;
typedef struct DW_AttribNode
{
struct DW_AttribNode *next;
DW_Attrib v;
} DW_AttribNode;
typedef struct DW_AttribList
{
DW_AttribNode *first;
DW_AttribNode *last;
U64 count;
} DW_AttribList;
typedef U8 DW_TagSpare;
typedef struct DW_Tag
{
B32 has_children;
U64 abbrev_id;
DW_TagKind kind;
DW_AttribList attribs;
U64 info_off;
DW_TagSpare v;
} DW_Tag;
typedef struct DW_TagNode
{
DW_Tag tag;
struct DW_TagNode *sibling;
struct DW_TagNode *first_child;
struct DW_TagNode *last_child;
} DW_TagNode;
typedef struct DW_Loc
{
Rng1U64 range;
String8 expr;
} DW_Loc;
typedef struct DW_LocNode
{
DW_Loc v;
struct DW_LocNode *next;
} DW_LocNode;
typedef struct DW_LocList
{
U64 count;
DW_LocNode *first;
DW_LocNode *last;
} DW_LocList;
typedef struct DW_CompUnit
{
B32 relaxed;
DW_Ext ext;
DW_CompUnitKind kind;
DW_Version version;
DW_Format format;
U64 address_size;
U64 abbrev_off;
Rng1U64 info_range;
U64 first_tag_info_off;
DW_AbbrevTable abbrev_table;
DW_ListUnit *addr_lu;
DW_ListUnit *str_offsets_lu;
DW_ListUnit *rnglists_lu;
DW_ListUnit *loclists_lu;
U64 low_pc;
U64 dwo_id;
DW_Tag tag;
HashTable *tag_ht;
} DW_CompUnit;
typedef struct DW_TagTree
{
DW_TagNode *root;
U64 tag_count;
} DW_TagTree;
////////////////////////////////
typedef struct DW_LineFile
{
String8 path;
U64 dir_idx;
U64 time_stamp;
U64 size;
U128 md5;
String8 source;
} DW_LineFile;
typedef struct DW_LineFileNode
{
struct DW_LineFileNode *next;
DW_LineFile file;
} DW_LineFileNode;
typedef struct DW_LineFileList
{
U64 node_count;
DW_LineFileNode *first;
DW_LineFileNode *last;
} DW_LineFileList;
typedef struct DW_LineFileArray
{
U64 count;
DW_LineFile *v;
} DW_LineFileArray;
typedef struct DW_LineVMHeader
{
U64 unit_length;
DW_Version version;
U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str.
U8 segment_selector_size;
U64 header_length;
U8 min_inst_len;
U8 max_ops_for_inst;
U8 default_is_stmt;
S8 line_base;
U8 line_range;
U8 opcode_base;
U64 num_opcode_lens;
U8 *opcode_lens;
U64 line_program_off;
String8Array dir_table;
DW_LineFileArray file_table;
} DW_LineVMHeader;
typedef struct DW_LineVMState
{
U64 address; // Address of a machine instruction.
U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction.
// Line table doesn't contain full path to a file, instead
// DWARF encodes path as two indices. First index will point into a directory
// table, and second points into a file name table.
U64 file_index;
U64 line;
U64 column;
B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint.
B32 basic_block; // Indicates that the "address" is inside a basic block.
// Indicates that "address" points to place where function starts.
// Usually prologue is the place where compiler emits instructions to
// prepare stack for a function.
B32 prologue_end;
B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack.
U64 isa; // Instruction set that is used.
U64 discriminator; // Arbitrary id that indicates to which block these instructions belong.
B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows.
} DW_LineVMState;
typedef struct DW_LineVM
{
Arena *arena;
U64 cursor;
String8 program;
DW_LineVMHeader header;
B32 new_line;
B32 new_seq;
B32 skip_opcode;
DW_LineVMState state;
U64 advance;
U64 opcode_off;
DW_StdOpcode opcode;
DW_ExtOpcode ext_opcode;
U64 ext_length;
U64 line_advance;
U64 addr_advance;
HashTable *ext_file_ht;
struct {
union {
String8 string;
U64 u64;
S64 s64;
};
} operands[4];
String8 error;
} DW_LineVM;
////////////////////////////////
// .debug_pubnames and .debug_pubtypes
typedef struct DW_PubStringsBucket
{
struct DW_PubStringsBucket *next;
String8 string;
U64 info_off;
U64 cu_info_off;
} DW_PubStringsBucket;
typedef struct DW_PubStringsTable
{
U64 size;
DW_PubStringsBucket **buckets;
} DW_PubStringsTable;
typedef struct DW_Reference
{
DW_CompUnit *cu;
U64 info_off; // global .debug_info offset
} DW_Reference;
////////////////////////////////
//~ Expression
typedef union DW_ExprOperand
{
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
String8 block;
} DW_ExprOperand;
typedef struct DW_ExprInst
{
DW_ExprOp opcode;
DW_ExprOperand *operands;
U64 size;
struct DW_ExprInst *next;
struct DW_ExprInst *prev;
} DW_ExprInst;
typedef struct DW_Expr
{
U64 count;
DW_ExprInst *first;
DW_ExprInst *last;
} DW_Expr;
////////////////////////////////
// .debug_frame
typedef struct DW_CIE
{
String8 insts;
String8 aug_string;
String8 aug_data;
U64 code_align_factor;
S64 data_align_factor;
U64 ret_addr_reg;
U64 ext[4];
DW_Format format;
U8 version;
U8 address_size;
U8 segment_selector_size;
} DW_CIE;
typedef struct DW_FDE
{
DW_Format format;
U64 cie_pointer;
Rng1U64 pc_range;
String8 insts;
} DW_FDE;
typedef union DW_CFA_Operand
{
U64 u64;
S64 s64;
String8 block;
} DW_CFA_Operand;
typedef enum
{
DW_CFA_ParseErrorCode_NewInst,
DW_CFA_ParseErrorCode_End,
DW_CFA_ParseErrorCode_OutOfData
} DW_CFA_ParseErrorCode;
typedef struct DW_CFA_Inst
{
DW_CFA_Opcode opcode;
DW_CFA_Operand operands[DW_CFA_OperandMax];
} DW_CFA_Inst;
typedef struct DW_CFA_InstNode
{
DW_CFA_Inst v;
struct DW_CFA_InstNode *next;
} DW_CFA_InstNode;
typedef struct DW_CFA_InstList
{
U64 count;
DW_CFA_InstNode *first;
DW_CFA_InstNode *last;
} DW_CFA_InstList;
#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out)
typedef DW_DECODE_PTR(DW_DecodePtr);
// hasher
internal U64 dw_hash_from_string(String8 string);
// deserial helpers
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out);
internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out);
internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data);
internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data);
// list units
internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out);
internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input);
internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index);
internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index);
// abbrev table
internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base);
internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id);
// form and tag
internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out);
internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out);
internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out);
// attrib interp
internal U64 dw_interp_sec_offset(DW_Form form);
internal String8 dw_interp_exprloc (DW_Form form);
internal U128 dw_interp_const_u128(DW_Form form);
internal U64 dw_interp_const_u64 (DW_Form form);
internal U32 dw_interp_const_u32 (DW_Form form);
internal S64 dw_interp_const_s64 (DW_Form form);
internal S32 dw_interp_const_s32 (DW_Form form);
internal B32 dw_interp_flag (DW_Form form);
internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form);
internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form);
internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form);
internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form);
internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind);
internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
// compile unit
internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed);
internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu);
internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree);
internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off);
// line VM
internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out);
internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu);
internal void dw_line_vm_release(DW_LineVM *vm);
internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance);
internal B32 dw_line_vm_step(DW_LineVM *vm);
internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx);
internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file);
// helper for .debug_pubtypes and .debug_pubnames
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind);
// expression
internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data);
// debug frame
internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n);
internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v);
internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out);
internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out);
internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out);
internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out);
internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out);
internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
#endif // DWARF_PARSE_H
+373
View File
@@ -0,0 +1,373 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal DW_CFI_Row *
dw_make_cfi_row(Arena *arena, U64 reg_count)
{
DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1);
row->regs = push_array(arena, DW_CFI_Register, reg_count);
for EachIndex(reg_idx, reg_count) {
row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue;
}
return row;
}
internal void
dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count)
{
dst->cfa = src->cfa;
MemoryCopyTyped(dst->regs, src->regs, reg_count);
}
internal DW_CFI_Row *
dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count)
{
DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count);
dw_memcpy_cfi_row(new_row, row, reg_count);
return new_row;
}
internal DW_CFI_Unwind *
dw_cfi_unwind_init(Arena *arena,
Arch arch,
DW_CIE *cie,
DW_FDE *fde,
DW_DecodePtr *decode_ptr_func,
void *decode_ptr_ud)
{
Temp scratch = scratch_begin(&arena, 1);
DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1);
uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->cie = cie;
uw->fde = fde;
uw->pc = fde->pc_range.min;
uw->arch = arch;
uw->reg_count = dw_reg_count_from_arch(arch);
// setup initial register rules
DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->row = dw_make_cfi_row(arena, uw->reg_count);
uw->curr_inst = initial_insts.first;
if (!dw_cfi_next_row(arena, uw)) {
AssertAlways(0 && "unable to interpret initial row instructions");
}
// make first row from initial rules
uw->initial_row = uw->row;
uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count);
uw->curr_inst = uw->insts.first;
scratch_end(scratch);
return uw;
}
internal B32
dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw)
{
B32 is_row_valid = 0;
DW_CFA_InstNode *row_inst = uw->curr_inst;
// skip leading nops
while (uw->curr_inst) {
if (uw->curr_inst->v.opcode != DW_CFA_Nop) {
break;
}
uw->curr_inst = uw->curr_inst->next;
}
while (uw->curr_inst) {
DW_CFA_Inst *inst = &uw->curr_inst->v;
// validate register operands
DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode);
U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode);
for EachIndex(operand_idx, operand_count) {
if (operand_types[operand_idx] == DW_CFA_OperandType_Register) {
if (inst->operands[operand_idx].u64 >= uw->reg_count) {
goto exit;
}
}
}
switch (inst->opcode) {
// Row Creation Instructions
case DW_CFA_SetLoc: {
uw->pc = inst->operands[0].u64;
} break;
case DW_CFA_AdvanceLoc:
case DW_CFA_AdvanceLoc1:
case DW_CFA_AdvanceLoc2:
case DW_CFA_AdvanceLoc4: {
uw->pc += inst->operands[0].u64;
} break;
// CFA Definition Instructions
case DW_CFA_DefCfa:
case DW_CFA_DefCfaSf: {
U64 reg = inst->operands[0].u64;
S64 off = inst->operands[1].s64;
uw->row->cfa.rule = DW_CFA_Rule_RegOff;
uw->row->cfa.reg = reg;
uw->row->cfa.off = off;
} break;
case DW_CFA_DefCfaRegister: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
U64 reg = inst->operands[0].u64;
uw->row->cfa.reg = reg;
} break;
case DW_CFA_DefCfaOffset:
case DW_CFA_DefCfaOffsetSf: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
uw->row->cfa.off = inst->operands[0].s64;
} break;
case DW_CFA_DefCfaExpr: {
uw->row->cfa.rule = DW_CFA_Rule_Expression;
uw->row->cfa.expr = inst->operands[0].block;
} break;
// Register Rule Instructions
case DW_CFA_Undefined: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined;
} break;
case DW_CFA_SameValue: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue;
} break;
case DW_CFA_Offset:
case DW_CFA_OffsetExt:
case DW_CFA_OffsetExtSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_ValOffset:
case DW_CFA_ValOffsetSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Register: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Expr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_ValExpr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_Restore:
case DW_CFA_RestoreExt: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg] = uw->initial_row->regs[reg];
} break;
// Row State Instructions
case DW_CFA_RememberState: {
DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count);
SLLStackPush(uw->row, new_row);
} break;
case DW_CFA_RestoreState: {
if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops
DW_CFI_Row *free_row = uw->row;
SLLStackPop(uw->row);
SLLStackPush(uw->free_rows, free_row);
} break;
case DW_CFA_Nop: {} break;
default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode
}
uw->curr_inst = uw->curr_inst->next;
if (uw->curr_inst) {
if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; }
}
}
is_row_valid = row_inst != 0;
exit:;
return is_row_valid;
}
internal DW_CFI_Row *
dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc)
{
Temp scratch = scratch_begin(&arena, 1);
B32 is_row_found = 0;
U64 reg_count = dw_reg_count_from_arch(arch);
DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx);
DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count);
U64 prev_pc = uw->pc;
while (dw_cfi_next_row(scratch.arena, uw)) {
if (prev_pc <= pc && pc < uw->pc) {
is_row_found = 1;
break;
}
dw_memcpy_cfi_row(row, uw->row, uw->reg_count);
prev_pc = uw->pc;
}
// handle last row
if (!is_row_found) {
if (contains_1u64(fde->pc_range, pc)) {
row = uw->row;
is_row_found = 1;
}
}
// copy out final row
DW_CFI_Row *result = 0;
if (is_row_found) {
result = dw_copy_cfi_row(arena, row, reg_count);
}
scratch_end(scratch);
return result;
}
internal MachineOpResult
dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out)
{
MachineOpResult unwind_status = MachineOpResult_Fail;
ARCH_Info *arch_info = arch_info_from_arch(arch);
switch(row->cfa.rule)
{
case DW_CFA_Rule_Null:{}break;
case DW_CFA_Rule_RegOff:
{
// TODO: report error (invalid register read)
U64 cfa_reg_value = 0;
U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg);
AssertAlways(reg_size <= sizeof(cfa_reg_value));
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value))
{
break;
}
*cfa_out = cfa_reg_value + row->cfa.off;
unwind_status = MachineOpResult_Ok;
}break;
case DW_CFA_Rule_Expression:
{
Temp scratch = scratch_begin(0,0);
DW_ExprValue value = {0};
DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr);
DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value);
if (eval_result == DW_ExprEvalResult_Ok) {
if (DW_ExprValueType_IsInt(value.type)) {
*cfa_out = value.u64;
unwind_status = MachineOpResult_Ok;
}
} else if (eval_result == DW_ExprEvalResult_Maybe) {
unwind_status = MachineOpResult_Maybe;
}
scratch_end(scratch);
}break;
}
return unwind_status;
}
internal MachineOpResult
dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud)
{
Temp scratch = scratch_begin(0,0);
MachineOpResult unwind_status = MachineOpResult_Ok;
ARCH_Info *arch_info = arch_info_from_arch(arch);
U64 max_reg_size = dw_reg_max_size_from_arch(arch);
void *reg_buffer = push_array(scratch.arena, U8, max_reg_size);
U64 reg_count = dw_reg_count_from_arch(arch);
for EachIndex(reg_idx, reg_count)
{
DW_CFI_Register *reg = &row->regs[reg_idx];
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
switch(reg->rule)
{
default:{}break;
case DW_CFI_RegisterRule_Undefined: {} break;
case DW_CFI_RegisterRule_SameValue: {} break;
case DW_CFI_RegisterRule_Offset:
{
// read register value from memory
U64 addr = cfa + reg->n;
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud);
if (unwind_status != MachineOpResult_Ok) { goto exit; }
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_ValOffset:
{
// compute register value
U64 reg_value = cfa + reg->n;
// write register value to the thread context
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, &reg_value))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_Register:
{
// read register value from another register
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
if (unwind_status != MachineOpResult_Ok) { goto exit; }
}break;
case DW_CFI_RegisterRule_Expression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_ValExpression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_Architectural:
{
NotImplemented;
}break;
}
}
// update stack pointer
arch_reg_block_write_sp(arch_info, reg_block, cfa);
exit:;
scratch_end(scratch);
return unwind_status;
}
+81
View File
@@ -0,0 +1,81 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_UNWIND_H
#define DWARF_UNWIND_H
typedef enum DW_CFI_RegisterRule
{
DW_CFI_RegisterRule_Undefined,
DW_CFI_RegisterRule_SameValue,
DW_CFI_RegisterRule_Offset,
DW_CFI_RegisterRule_ValOffset,
DW_CFI_RegisterRule_Register,
DW_CFI_RegisterRule_Expression,
DW_CFI_RegisterRule_ValExpression,
DW_CFI_RegisterRule_Architectural
} DW_CFI_RegisterRule;
typedef enum DW_CFA_Rule
{
DW_CFA_Rule_Null,
DW_CFA_Rule_RegOff,
DW_CFA_Rule_Expression
} DW_CFA_Rule;
typedef struct DW_CFA
{
DW_CFA_Rule rule;
union {
struct {
DW_Reg reg;
S64 off;
};
String8 expr;
};
} DW_CFA;
typedef struct DW_CFI_Register
{
DW_CFI_RegisterRule rule;
union {
S64 n;
String8 expr;
};
} DW_CFI_Register;
typedef struct DW_CFI_Row
{
DW_CFA cfa;
DW_CFI_Register *regs;
struct DW_CFI_Row *next;
} DW_CFI_Row;
typedef struct DW_CFI_Unwind
{
DW_CFA_InstList insts;
DW_CIE *cie;
DW_FDE *fde;
DW_CFI_Row *initial_row;
DW_CFI_Row *row;
DW_CFA_InstNode *curr_inst;
DW_CFI_Row *free_rows;
U64 pc;
Arch arch;
U64 reg_count;
} DW_CFI_Unwind;
////////////////////////////////
internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count);
internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count);
internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw);
internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc);
internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out);
internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud);
#endif // DWARF_UNWIND_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,275 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RDI_FROM_DWARF_H
#define RDI_FROM_DWARF_H
////////////////////////////////
//~ Conversion
typedef struct D2R_ConvertParams
{
String8 dbg_name;
String8 dbg_data;
String8 exe_name;
String8 exe_data;
ExecutableImageKind exe_kind;
RDIM_SubsetFlags subset_flags;
B32 deterministic;
B32 is_parse_relaxed;
} D2R_ConvertParams;
#define D2R_UNIT_CHUNK_CAP 512
#define D2R_UDT_CHUNK_CAP 1024
#define D2R_TYPE_CHUNK_CAP 1024
#define D2R_SRC_FILE_CAP 1024
#define D2R_LINE_TABLE_CAP 1024
#define D2R_GVAR_CHUNK_CAP 1024
#define D2R_TVAR_CHUNK_CAP 1024
#define D2R_LOCATIONS_CAP 4096
#define D2R_PROC_CHUNK_CAP 4096
#define D2R_SCOPE_CHUNK_CAP 4096
#define D2R_INLINE_SITE_CHUNK_CAP 4096
typedef struct D2R_Shared
{
RDIM_TopLevelInfo top_level_info;
RDIM_BinarySectionList binary_sections;
RDIM_UnitChunkList units;
RDIM_UDTChunkList udts;
RDIM_TypeChunkList types;
RDIM_SrcFileChunkList src_files;
RDIM_LineTableChunkList line_tables;
} D2R_Shared;
////////////////////////////////
//~ Value Types
typedef enum
{
D2R_ArithmeticType_Null,
D2R_ArithmeticType_Signed,
D2R_ArithmeticType_Unsigned,
D2R_ArithmeticType_Float,
} D2R_ArithmeticType;
#define D2R_ValueType_Signed_XList \
X(S8, Signed, 1 ) \
X(S16, Signed, 2 ) \
X(S32, Signed, 4 ) \
X(S64, Signed, 8 ) \
X(S128, Signed, 16) \
X(S256, Signed, 32) \
X(S512, Signed, 64)
#define D2R_ValueType_Unsigned_XList \
X(U8, Unsigned, 1 ) \
X(U16, Unsigned, 2 ) \
X(U32, Unsigned, 4 ) \
X(U64, Unsigned, 8 ) \
X(U128, Unsigned, 16) \
X(U256, Unsigned, 32) \
X(U512, Unsigned, 64)
#define D2R_ValueType_Float_XList \
X(F16, Float, 2 ) \
X(F32, Float, 4 ) \
X(F48, Float, 6 ) \
X(F64, Float, 8 ) \
X(F80, Float, 10) \
X(F96, Float, 12) \
X(F128, Float, 16)
#define D2R_ValueType_XList \
X(Generic, Null, 0 ) \
X(ImplicitValue, Null, 0 ) \
X(Address, Unsigned, 0 ) \
D2R_ValueType_Signed_XList \
D2R_ValueType_Unsigned_XList \
D2R_ValueType_Float_XList
typedef enum
{
#define X(t, ...) D2R_ValueType_##t,
D2R_ValueType_XList
#undef X
D2R_ValueType_Bool = D2R_ValueType_S8,
} D2R_ValueType;
typedef struct D2R_ValueTypeNode
{
D2R_ValueType type;
struct D2R_ValueTypeNode *next;
} D2R_ValueTypeNode;
typedef struct D2R_ValueTypeStack
{
U64 count;
D2R_ValueTypeNode *top;
D2R_ValueTypeNode *free_list;
} D2R_ValueTypeStack;
////////////////////////////////
//~ Type Table
typedef struct D2R_TypeTable
{
HashTable *ht;
RDIM_TypeChunkList *types;
U64 type_chunk_cap;
RDIM_Type **builtin_types;
} D2R_TypeTable;
////////////////////////////////
//~ Tag Iterator
typedef DW_TagSpare D2R_TagFlags;
enum
{
D2R_TagFlags_TypeConverted = (1 << 0),
D2R_TagFlags_UdtConverted = (1 << 1),
};
typedef struct D2R_TagFrame
{
DW_TagNode *node;
RDIM_Scope *scope;
struct D2R_TagFrame *next;
} D2R_TagFrame;
typedef struct D2R_TagIterator
{
D2R_TagFrame *free_list;
D2R_TagFrame *stack;
DW_TagNode *null_tag_node;
DW_TagNode *tag_node;
B32 visit_children;
} D2R_TagIterator;
////////////////////////////////
//~ Line Table Conversion
typedef struct D2R_SrcFileLookup
{
DW_LineFile *file;
DW_LineVM *vm;
RDIM_SrcFile *src_file;
} D2R_SrcFileLookup;
////////////////////////////////
//~ Contrib Map
typedef struct D2R_CompUnitContribMap
{
U64 count;
U64 *info_off_arr;
RDIM_Rng1U64ChunkList *voff_range_arr;
} D2R_CompUnitContribMap;
////////////////////////////////
//~ RDIM Bytecode Extensions
internal B32 rdim_is_eval_bytecode_static (RDIM_EvalBytecode bc);
internal B32 rdim_static_eval_bytecode_to_voff(RDIM_EvalBytecode bc, U64 image_base, U64 *voff_out);
////////////////////////////////
//~ DWARF -> RDI Enums
internal RDI_Language d2r_rdi_language_from_dw_language(DW_Language v);
internal RDI_RegCodeX64 d2r_rdi_reg_code_from_dw_reg_x64 (DW_RegX64 v);
internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg (Arch arch, DW_Reg v);
////////////////////////////////
//~ Value Type
internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type);
internal D2R_ValueType d2r_value_type_stack_pop (D2R_ValueTypeStack *stack);
internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack);
internal D2R_ValueType d2r_signed_value_type_from_bit_size (U64 bit_size);
internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size);
internal D2R_ValueType d2r_float_type_from_bit_size (U64 bit_size);
internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type);
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
internal B32 d2r_is_value_type_signed (D2R_ValueType v);
internal B32 d2r_is_value_type_integral(D2R_ValueType v);
internal B32 d2r_is_value_type_unsigned(D2R_ValueType v);
internal B32 d2r_is_value_type_float (D2R_ValueType v);
internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs);
internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v);
internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc);
internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
////////////////////////////////
//~ Expression Conversion
internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out);
internal RDIM_Location d2r_transpile_expression (Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr);
internal RDIM_Location d2r_location_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
internal RDIM_LocationCaseList d2r_locset_from_attrib (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
internal RDIM_LocationCaseList d2r_var_locset_from_tag (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag);
////////////////////////////////
//~ Type Table
internal RDIM_Type * d2r_create_type (Arena *arena, D2R_TypeTable *type_table);
internal RDIM_Type * d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off);
internal RDIM_Type * d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off);
internal RDIM_Type * d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
////////////////////////////////
//~ Tag Iterator
internal D2R_TagIterator * d2r_tag_iterator_init(Arena *arena, DW_TagNode *root);
internal void d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter);
internal void d2r_tag_iterator_skip_children (D2R_TagIterator *iter);
internal DW_TagNode * d2r_tag_iterator_parent_tag_node(D2R_TagIterator *iter);
internal DW_Tag d2r_tag_iterator_parent_tag (D2R_TagIterator *iter);
////////////////////////////////
//~ Type Conversion
internal void d2r_flag_converted_tag(DW_TagNode *tag_node);
internal B8 d2r_is_tag_converted (DW_TagNode *tag_node);
internal RDIM_Type * d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_Tag tag, DW_AttribKind kind);
internal void d2r_convert_types(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_TagNode *root);
////////////////////////////////
//~ UDT Conversion
internal B8 d2r_is_udt_tag_converted (DW_TagNode *tag_node);
internal void d2r_flag_converted_udt_tag(DW_TagNode *tag_node);
internal void d2r_inline_anonymous_udt_member(Arena *arena, RDIM_UDT *top_udt, U64 base_off, RDIM_UDT *udt);
internal void d2r_convert_udts(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, DW_TagNode *root);
////////////////////////////////
//~ Symbol Conversion
internal RDIM_Scope * d2r_push_scope (Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges);
internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out);
internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag);
internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, U64 image_base, Arch arch, DW_TagNode *root, RDIM_Unit *unit_rdi);
////////////////////////////////
//~ Line Table Conversion
internal U64 d2r_hash_line_file(String8 dir_path, DW_LineFile *file);
internal void d2r_sort_ptrs(void **ptrs, U64 count, int (* is_before)(void *a, void *b));
////////////////////////////////
//~ Contrib Map
internal D2R_CompUnitContribMap d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Raw *input, U64 image_base);
internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off);
////////////////////////////////
//~ Entry Point
internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params);
#endif // RDI_FROM_DWARF_H
+7 -3
View File
@@ -46,14 +46,17 @@ load_paths =
commands =
{
//- rjf: [raddbg]
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "raddbg_stable --ipc kill_all && build torture && build ryan_scratch && pushd build && torture eval2/* && ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [scratch]
.f2 = { .win = "build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f2 = { .win = "pushd build && for /l %i in (1, 1, 3) do (radbin --rdi raddbg.exe --out:raddbg_%i.rdi && radbin --dump raddbg_%i.rdi --out:raddbg_%i.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f2 = { .win = "pushd build && radbin --rdi raddbg.exe --thread_count=1 --out:1.rdi && radbin --rdi raddbg.exe --thread_count=8 --out:8.rdi && radbin --dump 1.rdi --out:1.dump && radbin --dump 8.rdi --out:8.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [textperf]
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
@@ -66,6 +69,7 @@ commands =
//- rjf: running target
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "build torture", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+75
View File
@@ -0,0 +1,75 @@
// raddbg 0.9.28 project file
name: "The RAD Debugger"
target:
{
executable: "build/raddbg.exe"
working_directory: "../raddebugger"
arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user"
debug_subprocesses: 0
}
target:
{
executable: "build/raddbg.exe"
working_directory: "../raddebugger"
arguments: "--user:test123"
debug_subprocesses: 0
}
target:
{
executable: "build/mule_main.exe"
working_directory: build
output_label: output_a
}
target:
{
executable: "build/torture.exe"
working_directory: build
arguments: "eval2/*"
}
target:
{
executable: "build/metagen.exe"
working_directory: build
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--rdi raddbg"
}
target:
{
executable: "build/release_version/raddbg.exe"
working_directory: "build/release_version"
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--rdi fat.so --capture"
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--rdi fat.debug --capture"
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--rdi raddbg"
}
watch_pin: expression: tag_hash_slots
target:
{
executable: "build/ryan_scratch.exe"
working_directory: build
enabled: 1
}
target:
{
executable: "../../Program Files/SuperTux/bin/supertux2.exe"
working_directory: "../../Program Files/SuperTux/bin"
}
+122 -17
View File
@@ -1,21 +1,126 @@
@echo off
setlocal
cd /D "%~dp0"
setlocal enabledelayedexpansion
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:
set TARGET_VALUES=radlink radbin mule_main mule_module torture
set CC_VALUES=msvc clang
set MODE_VALUES=debug release
set RAW_ARGS=%*
set TORTURE_ARGS=
set RUN_TORTURE=1
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%
:: Make test data directories
if not exist local mkdir local
pushd local
if not exist test_data mkdir test_data
popd
:: Check if we need new test data version
pushd local
set need_test_data=0
curl -sfL -o test_data_version_latest.txt https://data.raddbg.com/public/raddbg_test_data_version.txt || exit /b 1
if exist "test_data_version_current.txt" (
fc /b "test_data_version_latest.txt" "test_data_version_current.txt" > nul
) else (
echo Test data not present.
set need_test_data=1
)
if errorlevel 1 (
echo Test data out-of-date.
set need_test_data=1
)
popd
:: Download test data if stale
if "%need_test_data%"=="1" (
echo Downloading test data...
pushd local
pushd test_data
curl -sfL -o test_data.zip https://data.raddbg.com/public/raddbg_test_data.zip || exit /b 1
tar -xf test_data.zip || exit /b 1
del test_data.zip
popd
copy /y test_data_version_latest.txt test_data_version_current.txt
popd
)
popd
:parse_args
if "%~1" == "" goto parse_done
if "%~1" == "--" goto parse_torture_args
if /i "%~1" == "msvc" set CC_VALUES=msvc && shift /1 && goto parse_args
if /i "%~1" == "clang" set CC_VALUES=clang && shift /1 && goto parse_args
if /i "%~1" == "debug" set MODE_VALUES=debug && shift /1 && goto parse_args
if /i "%~1" == "release" set MODE_VALUES=release && shift /1 && goto parse_args
if /i "%~1" == "no_torture" set RUN_TORTURE=0 && shift /1 && goto parse_args
echo usage: %~nx0 [msvc^|clang] [debug^|release] [no_torture] [-- torture-args]
exit /b 1
:parse_torture_args
shift /1
if "%~1" == "" set "TORTURE_ARGS=" && goto parse_done
set "TORTURE_ARGS=%RAW_ARGS%"
if "%TORTURE_ARGS:~0,3%" == "-- " set "TORTURE_ARGS=%TORTURE_ARGS:~3%" && goto parse_done
set "TORTURE_ARGS=%TORTURE_ARGS:* -- =%"
:parse_done
if not defined TORTURE_ARGS set "TORTURE_ARGS=*
for %%m in (%MODE_VALUES%) do for %%c in (%CC_VALUES%) do (
setlocal
:: nuke artifacts from last run
if exist build/torture_artifacts rmdir /s /q build\torture_artifacts
if exist build\metagen.exe del /q build\metagen.exe
for %%t in (%TARGET_VALUES%) do (
if exist build\%%t.exe del /q build\%%t.exe
if exist build\%%t.pdb del /q build\%%t.pdb
)
if "%%c" == "clang" (
:: Prefer standalone LLVM clang over Visual Studio clang so ASAN runtime files match the compiler.
set "clang_path="
for /f "tokens=*" %%i in ('where clang') do (
set "candidate_clang_path=%%~dpi"
if "!candidate_clang_path:Microsoft Visual Studio=!"=="!candidate_clang_path!" (
if not defined clang_path set "clang_path=!candidate_clang_path!"
)
)
if not defined clang_path (
echo ERROR: standalone LLVM clang not found in PATH
exit /b 1
)
set PATH=!clang_path!;!PATH!
for /f "tokens=3 delims=. " %%v in ('clang -v 2^>^&1 ^| findstr version') do set clang_version=%%v
if not defined clang_version (
echo ERROR: failed to detect clang version
exit /b 1
)
set PATH=!clang_path!..\lib\clang\!clang_version!\lib\windows;!PATH!
)
:: TODO: unblock asan
call build.bat meta %%c %%m raddbg raddbg_non_graphical || (endlocal exit /b 1)
:: clang does not compile with asan in release mode because it runs out of memory
if "%%c" equ "clang" (
if /i "%%m" equ "release" (
call build.bat no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
) else (
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
)
) else (
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
)
if "%RUN_TORTURE%" equ "1" (
pushd build
torture %TORTURE_ARGS%
popd
if errorlevel 1 (
endlocal
exit /b 1
)
)
endlocal
)
Executable
+77
View File
@@ -0,0 +1,77 @@
#!/bin/bash
set -eu
cd "$(dirname "$0")"
target_values=(raddbg raddbg_non_graphical radlink radbin torture)
cc_values=(clang gcc)
mode_values=(debug release)
run_torture=1
torture_args=()
while [[ $# -gt 0 ]]; do
case "$1" in
--)
shift
torture_args=("$@")
break
;;
clang)
cc_values=("$1")
shift
;;
gcc)
cc_values=("$1")
shift
;;
debug|release)
mode_values=("$1")
shift
;;
no_torture)
run_torture=0
shift
;;
*)
echo "usage: $0 [clang|gcc] [debug|release] [no_torture] [-- torture-args]"
exit 1
;;
esac
done
if [[ "${#torture_args[@]}" == "0" ]]; then
torture_args=("*")
fi
for m in "${mode_values[@]}"; do
for c in "${cc_values[@]}"; do
# nuke artifacts from last run
rm -rf build/torture_artifacts
rm -f build/metagen
for t in "${target_values[@]}"; do
rm -f "build/$t"
done
# build targets
./build.sh meta "$c" "$m" "${target_values[@]}"
# run torture from build folder
if [[ "$run_torture" == "1" ]]; then
torture_compiler_args=()
has_clang_arg=0
has_gcc_arg=0
for arg in "${torture_args[@]}"; do
case "$arg" in
-clang:*|--clang:*) has_clang_arg=1 ;;
-gcc:*|--gcc:*) has_gcc_arg=1 ;;
esac
done
if [[ "$c" == clang && "$has_clang_arg" == "0" ]]; then
torture_compiler_args=("-clang:$(command -v "${CC:-clang}")")
elif [[ "$c" == gcc && "$has_gcc_arg" == "0" ]]; then
torture_compiler_args=("-gcc:$(command -v "${CC:-gcc}")")
fi
(cd build && ./torture "${torture_compiler_args[@]}" "${torture_args[@]}")
fi
done
done
+174
View File
@@ -0,0 +1,174 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Abstracted Architecture Functions
internal ARCH_Info *
arch_info_from_arch(Arch arch)
{
ARCH_Info *result = &arch_info_nil;
switch(arch)
{
default:{}break;
#if defined(X64_H)
case Arch_x64:
{
local_persist U8 trap_inst_bytes[] = {0xcc};
local_persist read_only ARCH_Info info =
{
.reg_block_size = sizeof(X64_RegBlock),
.instruction_pointer_reg_code = X64_RegCode_rip,
.stack_pointer_reg_code = X64_RegCode_rsp,
.reg_code_count = X64_RegCode_COUNT,
.trap_instruction = {trap_inst_bytes, sizeof(trap_inst_bytes)},
.reg_code_rng_table = x64_reg_code_rng_table,
.reg_code_name_table = x64_reg_code_name_table,
.reg_code_base_table = x64_reg_code_base_table,
.reg_code_is_vector_table = x64_reg_code_is_vector_table,
};
result = &info;
}break;
#endif
}
return result;
}
internal ARCH_RegCode
arch_reg_code_from_name(ARCH_Info *arch_info, String8 name)
{
ARCH_RegCode result = 0;
for EachIndex(code, arch_info->reg_code_count)
{
if(str8_match(arch_info->reg_code_name_table[code], name, 0))
{
result = code;
break;
}
}
return result;
}
internal B32
arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst)
{
B32 result = 0;
{
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
Rng1U16 try_range = range;
Rng1U16 read_range = intersect_1u16(legal_range, try_range);
U64 read_size = dim_1u16(read_range);
if(read_size != 0)
{
MemoryCopy(dst, (U8 *)block + read_range.min, read_size);
result = 1;
}
}
return result;
}
internal B32
arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src)
{
B32 result = 0;
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
Rng1U16 try_range = range;
Rng1U16 write_range = intersect_1u16(legal_range, try_range);
U64 write_size = dim_1u16(write_range);
if(write_size != 0)
{
MemoryCopy((U8 *)block + write_range.min, src, write_size);
result = 1;
}
return result;
}
internal U64
arch_ip_from_reg_block(ARCH_Info *arch_info, void *block)
{
U64 result = 0;
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
}
return result;
}
internal U64
arch_sp_from_reg_block(ARCH_Info *arch_info, void *block)
{
U64 result = 0;
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
}
return result;
}
internal B32
arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip)
{
B32 result = 0;
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &ip);
}
return result;
}
internal B32
arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp)
{
B32 result = 0;
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
if(reg_code < arch_info->reg_code_count)
{
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &sp);
}
return result;
}
#if defined(RDI_H)
internal ARCH_RegCode
arch_reg_code_from_rdi(Arch arch, RDI_RegCode code)
{
ARCH_RegCode result = 0;
{
ARCH_Info *arch_info = arch_info_from_arch(arch);
U8 *rdi_from_reg_code_table = arch_rdi_from_reg_code_table_from_arch(arch);
for EachIndex(c, arch_info->reg_code_count)
{
if(rdi_from_reg_code_table[c] == code)
{
result = c;
break;
}
}
}
return result;
}
#endif
#if defined(DWARF_H)
internal ARCH_RegCode
arch_reg_code_from_dw(Arch arch, DW_RegCode code)
{
ARCH_RegCode result = 0;
{
ARCH_Info *arch_info = arch_info_from_arch(arch);
U8 *dw_from_reg_code_table = arch_dw_from_reg_code_table_from_arch(arch);
for EachIndex(c, arch_info->reg_code_count)
{
if(dw_from_reg_code_table[c] == code)
{
result = c;
break;
}
}
}
return result;
}
#endif
+54
View File
@@ -0,0 +1,54 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_H
#define ARCH_H
////////////////////////////////
//~ rjf: Abstraction Backend Info
typedef U8 ARCH_RegCode;
typedef struct ARCH_Info ARCH_Info;
struct ARCH_Info
{
U16 reg_block_size;
ARCH_RegCode instruction_pointer_reg_code;
ARCH_RegCode stack_pointer_reg_code;
U16 reg_code_count;
String8 trap_instruction;
Rng1U16 *reg_code_rng_table;
String8 *reg_code_name_table;
U8 *reg_code_base_table;
B8 *reg_code_is_vector_table;
};
////////////////////////////////
//~ rjf: Globals
global read_only Rng1U16 arch_reg_code_rng_nil = {0};
global read_only String8 arch_reg_code_name_nil = {0};
global read_only U8 arch_reg_code_u8_nil = 0;
global read_only B8 arch_reg_code_b8_nil = 0;
global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil};
////////////////////////////////
//~ rjf: Abstracted Architecture Functions
internal ARCH_Info *arch_info_from_arch(Arch arch);
internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name);
internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst);
internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src);
internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block);
internal U64 arch_sp_from_reg_block(ARCH_Info *arch_info, void *block);
internal B32 arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip);
internal B32 arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp);
#if defined(RDI_H)
internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code);
#endif
#if defined(DWARF_H)
internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_RegCode code);
#endif
#endif // REGS_H
+11
View File
@@ -0,0 +1,11 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "arch/arch.c"
#include "arch/os/arch_os.c"
#if defined(DWARF_H)
# include "arch/dwarf/arch_dwarf.c"
#endif
#if defined(RDI_H)
# include "arch/rdi/arch_rdi.c"
#endif
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_INC_H
#define ARCH_INC_H
#include "arch/arch.h"
#include "arch/os/arch_os.h"
#if defined(DWARF_H)
# include "arch/dwarf/arch_dwarf.h"
#endif
#if defined(RDI_H)
# include "arch/rdi/arch_rdi.h"
#endif
#endif // ARCH_INC_H
+19
View File
@@ -0,0 +1,19 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal U8 *
arch_dw_from_reg_code_table_from_arch(Arch arch)
{
U8 *result = &arch_reg_code_u8_nil;
switch(arch)
{
default:{}break;
#if defined(X64_H)
case Arch_x64:
{
result = dw_reg_code_from_x64_table;
}break;
#endif
}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_DWARF_H
#define ARCH_DWARF_H
internal U8 *arch_dw_from_reg_code_table_from_arch(Arch arch);
#endif // ARCH_DWARF_H
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx)
{
B32 result = 0;
if(0){}
#define Case(arch_, os_, impl) else if((arch) == arch_ && (os) == os_) do {result = impl(reg_block, thread_ctx);}while(0)
#if defined(X64_H) && defined(WIN32_X64_H)
Case(Arch_x64, OperatingSystem_Windows, w32_x64_write_reg_block_from_thread_ctx);
#endif
#undef Case
else{}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_OS_H
#define ARCH_OS_H
internal B32 arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx);
#endif // ARCH_OS_H
+19
View File
@@ -0,0 +1,19 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal U8 *
arch_rdi_from_reg_code_table_from_arch(Arch arch)
{
U8 *result = &arch_reg_code_u8_nil;
switch(arch)
{
default:{}break;
#if defined(X64_H)
case Arch_x64:
{
result = rdi_reg_code_from_x64_table;
}break;
#endif
}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef ARCH_RDI_H
#define ARCH_RDI_H
internal U8 *arch_rdi_from_reg_code_table_from_arch(Arch arch);
#endif // ARCH_RDI_H
+103 -22
View File
@@ -18,9 +18,8 @@ ac_init(void)
ac_shared->req_batches[idx].mutex = mutex_alloc();
ac_shared->req_batches[idx].arena = arena_alloc();
}
ac_shared->cancel_thread_semaphore = semaphore_alloc(0, 1, str8_zero());
ac_shared->cancel_thread = thread_launch(ac_cancel_thread_entry_point, 0);
ac_shared->cancel_thread_mutex = mutex_alloc();
mutex_take(ac_shared->cancel_thread_mutex);
}
////////////////////////////////
@@ -59,6 +58,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
cache->slots_count = Max(256, params->slots_count);
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
cache->stripes = stripe_array_alloc(cache_stripe->arena);
cache->stripe_free_node_ptrs = push_array(cache_stripe->arena, AC_NodePtr *, cache->stripes.count);
}
}
if(cache != 0)
@@ -74,6 +74,9 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
//- rjf: unpack thread context
B32 is_node_work_active = (ac_tctx != 0);
//- rjf: cache * key -> existing artifact
B32 artifact_is_stale = 1;
B32 got_artifact = 0;
@@ -93,11 +96,16 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
artifact_is_stale = is_stale;
artifact = n->val;
access_touch(access, &n->access_pt, stripe->cv);
ins_atomic_u64_eval_assign(&n->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
}
if(is_stale)
{
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
need_request = got_task;
if(is_node_work_active)
{
ins_atomic_u32_eval_assign(&n->other_nodes_depend_on_me, 1);
}
}
break;
}
@@ -109,7 +117,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
{
RWMutexScope(stripe->rw_mutex, 1) for(;;)
{
B32 out_of_time = (os_now_microseconds() >= endt_us);
B32 out_of_time = (now_time_us() >= endt_us);
// rjf: find node in cache
AC_Node *node = 0;
@@ -141,8 +149,12 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
node->key = str8_copy(stripe->arena, key);
node->working_count = 1;
node->evict_threshold_us = params->evict_threshold_us;
if(is_node_work_active)
{
node->other_nodes_depend_on_me = 1;
}
node->access_pt.last_time_touched_us = os_now_microseconds();
}
node->access_pt.last_time_touched_us = now_time_us();
node->access_pt.last_update_idx_touched = update_tick_idx();
// rjf: request
@@ -179,9 +191,10 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time))
{
got_artifact = 1;
artifact_is_stale = (node->last_completed_gen == params->gen);
artifact_is_stale = (node->last_completed_gen != params->gen);
artifact = node->val;
access_touch(access, &node->access_pt, stripe->cv);
ins_atomic_u64_eval_assign(&node->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
}
// rjf: abort if needed
@@ -218,7 +231,7 @@ ac_async_tick(void)
//
if(lane_idx() == 0)
{
mutex_drop(ac_shared->cancel_thread_mutex);
semaphore_drop(ac_shared->cancel_thread_semaphore);
}
//////////////////////////////
@@ -244,7 +257,9 @@ ac_async_tick(void)
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
{
next = n->next;
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) == 0)
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) &&
ins_atomic_u64_eval(&n->working_count) == 0 &&
(ins_atomic_u32_eval(&n->other_nodes_depend_on_me) == 0 || ac_shared->request_gen > n->last_touched_ac_request_gen))
{
slot_has_work = 1;
if(!write_mode)
@@ -328,6 +343,11 @@ ac_async_tick(void)
lane_sync_u64(&tasks_count, 0);
lane_sync();
//////////////////////////////
//- rjf: set up artifact cache thread context
//
ac_tctx = push_array(scratch.arena, AC_TCTX, 1);
//////////////////////////////
//- rjf: do all requests
//
@@ -371,12 +391,12 @@ ac_async_tick(void)
}
// rjf: compute val
B32 retry = 0;
AC_Status status = AC_Status_Good;
U64 gen = r->gen;
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
// rjf: retry? -> resubmit request
if(retry && lane_idx() == 0)
if(status == AC_Status_NeedRetry && lane_idx() == 0 && !ins_atomic_u32_eval(r->cancel_signal))
{
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
@@ -392,7 +412,7 @@ ac_async_tick(void)
// rjf: create function -> cache
AC_Cache *cache = 0;
if(!retry && lane_idx() == 0)
if(status != AC_Status_NeedRetry && lane_idx() == 0)
{
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
@@ -411,7 +431,7 @@ ac_async_tick(void)
}
// rjf: write value into cache
if(!retry && lane_idx() == 0)
if(status != AC_Status_NeedRetry && lane_idx() == 0)
{
U64 hash = u64_hash_from_str8(r->key);
U64 slot_idx = hash%cache->slots_count;
@@ -423,8 +443,26 @@ ac_async_tick(void)
{
if(str8_match(n->key, r->key, 0))
{
n->last_completed_gen = gen;
B32 got_new_value = (status == AC_Status_Good);
// rjf: eliminate existing values, if any, if they do not match the current
if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
{
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
{
cache->destroy(n->val);
MemoryZeroStruct(&n->val);
break;
}
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
}
// rjf: write new value
if(got_new_value)
{
n->val = val;
}
n->last_completed_gen = gen;
ins_atomic_u64_dec_eval(&n->working_count);
ins_atomic_u64_inc_eval(&n->completion_count);
}
@@ -477,15 +515,15 @@ ac_async_tick(void)
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
// rjf: compute val
B32 retry = 0;
AC_Status status = AC_Status_Good;
U64 gen = r->gen;
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
// rjf: restore wide lane ctx
lane_ctx(lane_ctx_restore);
// rjf: retry? -> resubmit request
if(retry)
if(status == AC_Status_NeedRetry && !ins_atomic_u32_eval(r->cancel_signal))
{
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex)
@@ -501,7 +539,7 @@ ac_async_tick(void)
// rjf: create function -> cache
AC_Cache *cache = 0;
if(!retry)
if(status != AC_Status_NeedRetry)
{
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
@@ -520,7 +558,7 @@ ac_async_tick(void)
}
// rjf: write value into cache
if(!retry)
if(status != AC_Status_NeedRetry)
{
U64 hash = u64_hash_from_str8(r->key);
U64 slot_idx = hash%cache->slots_count;
@@ -532,8 +570,26 @@ ac_async_tick(void)
{
if(str8_match(n->key, r->key, 0))
{
n->last_completed_gen = gen;
B32 got_new_value = (status == AC_Status_Good);
// rjf: eliminate existing values, if any, if they do not match the current
if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
{
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
{
cache->destroy(n->val);
MemoryZeroStruct(&n->val);
break;
}
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
}
// rjf: store
if(got_new_value)
{
n->val = val;
}
n->last_completed_gen = gen;
ins_atomic_u64_dec_eval(&n->working_count);
ins_atomic_u64_inc_eval(&n->completion_count);
}
@@ -585,12 +641,36 @@ ac_async_tick(void)
}
lane_sync();
//////////////////////////////
//- rjf: increment the request gen, only if all requests are empty
//
if(lane_idx() == 0)
{
B32 have_live_requests = 0;
for EachElement(idx, ac_shared->req_batches)
{
MutexScope(ac_shared->req_batches[idx].mutex)
{
have_live_requests = (ac_shared->req_batches[idx].wide_count != 0 || ac_shared->req_batches[idx].thin_count != 0);
}
}
if(!have_live_requests)
{
ac_shared->request_gen += 1;
}
}
//////////////////////////////
//- rjf: reset thread context
//
ac_tctx = 0;
//////////////////////////////
//- rjf: disable cancellation scanning
//
if(lane_idx() == 0)
{
mutex_take(ac_shared->cancel_thread_mutex);
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
}
scratch_end(scratch);
}
@@ -603,8 +683,8 @@ ac_cancel_thread_entry_point(void *p)
{
for(;;)
{
os_sleep_milliseconds(50);
MutexScope(ac_shared->cancel_thread_mutex)
sleep_ms(50);
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
{
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
{
@@ -650,5 +730,6 @@ ac_cancel_thread_entry_point(void *p)
}
}
}
semaphore_drop(ac_shared->cancel_thread_semaphore);
}
}
+34 -3
View File
@@ -4,6 +4,17 @@
#ifndef ARTIFACT_CACHE_H
#define ARTIFACT_CACHE_H
////////////////////////////////
//~ rjf: Artifact Computation Statuses
typedef enum AC_Status
{
AC_Status_Good,
AC_Status_NeedRetry,
AC_Status_Failed,
}
AC_Status;
////////////////////////////////
//~ rjf: Artifact Handle Type
@@ -16,7 +27,7 @@ struct AC_Artifact
////////////////////////////////
//~ rjf: Artifact Computation Function Types
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
typedef void AC_DestroyFunctionType(AC_Artifact artifact);
typedef U32 AC_Flags;
@@ -59,6 +70,13 @@ struct AC_RequestNode
AC_Request v;
};
typedef struct AC_NodePtr AC_NodePtr;
struct AC_NodePtr
{
AC_NodePtr *next;
struct AC_Node *node;
};
typedef struct AC_Node AC_Node;
struct AC_Node
{
@@ -76,8 +94,9 @@ struct AC_Node
U64 working_count;
U64 completion_count;
U64 evict_threshold_us;
U64 last_touched_ac_request_gen;
B32 cancelled;
U64 _unused_;
B32 other_nodes_depend_on_me;
};
typedef struct AC_Slot AC_Slot;
@@ -99,6 +118,7 @@ struct AC_Cache
U64 slots_count;
AC_Slot *slots;
StripeArray stripes;
AC_NodePtr **stripe_free_node_ptrs;
};
typedef struct AC_RequestBatch AC_RequestBatch;
@@ -114,10 +134,17 @@ struct AC_RequestBatch
U64 thin_count;
};
typedef struct AC_TCTX AC_TCTX;
struct AC_TCTX
{
U64 _unused_;
};
typedef struct AC_Shared AC_Shared;
struct AC_Shared
{
Arena *arena;
U64 request_gen;
// rjf: cache cache
U64 cache_slots_count;
@@ -129,13 +156,14 @@ struct AC_Shared
// rjf: cancel thread
Thread cancel_thread;
Mutex cancel_thread_mutex;
Semaphore cancel_thread_semaphore;
};
////////////////////////////////
//~ rjf: Globals
global AC_Shared *ac_shared = 0;
thread_static AC_TCTX *ac_tctx = 0;
////////////////////////////////
//~ rjf: Layer Initialization
@@ -151,6 +179,9 @@ internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_Artif
////////////////////////////////
//~ rjf: Asynchronous Tick
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void ac_async_tick(void);
////////////////////////////////
+164 -36
View File
@@ -1,6 +1,25 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Global Arena Table
#if ARENA_TABLE_DEBUG
typedef struct ArenaTableNode ArenaTableNode;
struct ArenaTableNode
{
ArenaTableNode *next;
Arena *arena;
};
global U64 arena_table_take_init = 0;
global U64 arena_table_inited = 0;
global U64 arena_table_lock = 0;
global ArenaTableNode *arena_table = 0;
global U64 arena_table_count = 0;
global U64 arena_table_cap = 0;
global ArenaTableNode *free_arena_table_node = 0;
#endif
////////////////////////////////
//~ rjf: Arena Functions
@@ -9,48 +28,58 @@
internal Arena *
arena_alloc_(ArenaParams *params)
{
// rjf: round up reserve/commit sizes
ProfBeginFunction();
U64 reserve_size = params->reserve_size;
U64 commit_size = params->commit_size;
if(params->flags & ArenaFlag_LargePages)
{
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
}
else
{
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
}
// rjf: reserve/commit initial block
void *base = params->optional_backing_buffer;
if(base == 0)
{
// rjf: round up reserve/commit sizes
if(params->flags & ArenaFlag_LargePages)
{
base = os_reserve_large(reserve_size);
os_commit_large(base, commit_size);
reserve_size = AlignPow2(reserve_size, get_system_info()->large_page_size);
commit_size = AlignPow2(commit_size, get_system_info()->large_page_size);
}
else
{
base = os_reserve(reserve_size);
os_commit(base, commit_size);
reserve_size = AlignPow2(reserve_size, get_system_info()->page_size);
commit_size = AlignPow2(commit_size, get_system_info()->page_size);
}
raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
if(params->flags & ArenaFlag_LargePages)
{
base = reserve_memory_large(reserve_size);
commit_memory_large(base, commit_size);
}
else
{
base = reserve_memory(reserve_size);
commit_memory(base, commit_size);
}
AsanPoisonMemoryRegion(base, commit_size);
// TODO(rjf): we need to reintroduce this later when we have the ability to remove annotations...
// raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
}
else
{
AsanPoisonMemoryRegion(base, params->reserve_size);
}
// rjf: panic on arena creation failure
#if OS_FEATURE_GRAPHICAL
if(Unlikely(base == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
abort_self(1);
}
#endif
// rjf: extract arena header & fill
Arena *arena = (Arena *)base;
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
Arena *arena = base;
arena->current = arena;
arena->flags = params->flags;
arena->cmt_size = params->commit_size;
@@ -61,22 +90,94 @@ arena_alloc_(ArenaParams *params)
arena->res = reserve_size;
arena->allocation_site_file = params->allocation_site_file;
arena->allocation_site_line = params->allocation_site_line;
arena->name = params->name;
#if ARENA_FREE_LIST
arena->free_last = 0;
#endif
AsanPoisonMemoryRegion(base, commit_size);
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
// rjf: store in global arena table
#if ARENA_TABLE_DEBUG
if(ins_atomic_u64_eval_cond_assign(&arena_table_take_init, 1, 0) == 0)
{
arena_table = reserve_memory(GB(256));
arena_table_cap = 4096;
commit_memory(arena_table, arena_table_cap * sizeof(arena_table[0]));
ins_atomic_u64_inc_eval(&arena_table_inited);
}
for(;!ins_atomic_u64_eval(&arena_table_inited);) {}
for(;;)
{
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
if(got_lock)
{
ArenaTableNode *node = free_arena_table_node;
if(node != 0)
{
SLLStackPop(free_arena_table_node);
}
else
{
node = &arena_table[arena_table_count];
if(arena_table_count >= arena_table_cap)
{
U64 arena_table_cap__pre_grow = arena_table_cap;
arena_table_cap *= 2;
U64 arena_table_cap__post_grow = arena_table_cap;
commit_memory(arena_table + arena_table_cap__pre_grow, sizeof(arena_table[0]) * (arena_table_cap__post_grow - arena_table_cap__pre_grow));
}
arena_table_count += 1;
}
node->arena = arena;
arena->table_node = node;
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
break;
}
}
#endif
ProfEnd();
return arena;
}
internal void
arena_release(Arena *arena)
{
ProfBeginFunction();
#if PROFILE_TELEMETRY
{
Arena *base_arena = arena;
while (base_arena->prev) base_arena = base_arena->prev;
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, 0, "%s/%p", base_arena->name, base_arena);
}
#endif
#if ARENA_TABLE_DEBUG
for(Arena *n = arena->current; n != 0; n = n->prev)
{
for(;;)
{
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
if(got_lock)
{
ArenaTableNode *table_node = n->table_node;
MemoryZeroStruct(table_node);
SLLStackPush(free_arena_table_node, table_node);
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
break;
}
}
}
#endif
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
{
prev = n->prev;
os_release(n, n->res);
AsanUnpoisonMemoryRegion(n, n->cmt);
release_memory(n, n->res);
}
ProfEnd();
}
//- rjf: arena push/pop core functions
@@ -88,6 +189,16 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
U64 pos_pre = AlignPow2(current->pos, align);
U64 pos_pst = pos_pre + size;
// TODO: Newly allocated arenas already have zeroed commited pages,
// so this unnecessarily zeroes them again.
//
// rjf: compute the size we need to zero
U64 size_to_zero = 0;
if(zero)
{
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
}
// rjf: chain, if needed
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
{
@@ -128,6 +239,12 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
.flags = current->flags,
.allocation_site_file = current->allocation_site_file,
.allocation_site_line = current->allocation_site_line);
size_to_zero = 0;
}
else
{
size_to_zero = size;
}
new_block->base_pos = current->base_pos + current->res;
@@ -138,13 +255,6 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
pos_pst = pos_pre + size;
}
// rjf: compute the size we need to zero
U64 size_to_zero = 0;
if(zero)
{
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
}
// rjf: commit new pages, if needed
if(current->cmt < pos_pst)
{
@@ -155,12 +265,13 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
U8 *cmt_ptr = (U8 *)current + current->cmt;
if(current->flags & ArenaFlag_LargePages)
{
os_commit_large(cmt_ptr, cmt_size);
commit_memory_large(cmt_ptr, cmt_size);
}
else
{
os_commit(cmt_ptr, cmt_size);
commit_memory(cmt_ptr, cmt_size);
}
AsanPoisonMemoryRegion(cmt_ptr, cmt_size);
current->cmt = cmt_pst_clamped;
}
@@ -171,18 +282,24 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero)
result = (U8 *)current+pos_pre;
current->pos = pos_pst;
AsanUnpoisonMemoryRegion(result, size);
if(size_to_zero != 0)
{
MemoryZero(result, size_to_zero);
}
#if PROFILE_TELEMETRY
if(size > KB(1))
{
Arena *base_arena = arena;
while (base_arena->prev) base_arena = base_arena->prev;
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
}
#endif
// rjf: panic on failure
#if OS_FEATURE_GRAPHICAL
if(Unlikely(result == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
abort_self(1);
}
#endif
@@ -215,7 +332,8 @@ arena_pop_to(Arena *arena, U64 pos)
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{
prev = current->prev;
os_release(current, current->res);
AsanUnpoisonMemoryRegion(current, current->cmt);
release_memory(current, current->res);
}
#endif
arena->current = current;
@@ -223,6 +341,16 @@ arena_pop_to(Arena *arena, U64 pos)
AssertAlways(new_pos <= current->pos);
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
current->pos = new_pos;
#if PROFILE_TELEMETRY
if((pos - (new_pos + current->base_pos)) > KB(1))
{
Arena *base_arena = arena;
while (base_arena->prev) base_arena = base_arena->prev;
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
}
#endif
}
//- rjf: arena push/pop helpers
+5
View File
@@ -25,6 +25,7 @@ struct ArenaParams
void *optional_backing_buffer;
char *allocation_site_file;
int allocation_site_line;
char *name;
};
typedef struct Arena Arena;
@@ -41,9 +42,13 @@ struct Arena
U64 res;
char *allocation_site_file;
int allocation_site_line;
char *name;
#if ARENA_FREE_LIST
Arena *free_last;
#endif
#if ARENA_TABLE_DEBUG
struct ArenaTableNode *table_node;
#endif
};
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
+50 -2
View File
@@ -138,6 +138,10 @@
# define BUILD_DEBUG 1
#endif
#if !defined(BUILD_TESTS)
# define BUILD_TESTS 0
#endif
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
# define BUILD_SUPPLEMENTARY_UNIT 0
#endif
@@ -159,7 +163,7 @@
#endif
#if !defined(BUILD_VERSION_PATCH)
# define BUILD_VERSION_PATCH 24
# define BUILD_VERSION_PATCH 28
#endif
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
@@ -183,7 +187,7 @@
#endif
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGamesExt/raddebugger/issues"
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGames/raddebugger/issues"
#endif
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
@@ -244,4 +248,48 @@
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
#endif
////////////////////////////////
// extra intrinisc includes, so older clang versions are happy
// when optiona intrinsics like avx2 & avx512 are used later
// these must come first before any other intrinsic includes
// otherwise compiler will define macros that prevent declarations
// of intrinsics when included next time
#if ARCH_X64 && COMPILER_CLANG
# if defined(__IMMINTRIN_H)
# error "include this header before immintrin.h / x86intrin.h / intrin.h"
# endif
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wreserved-macro-identifier"
# pragma push_macro("__SHA__")
# pragma push_macro("__AVX__")
# pragma push_macro("__AVX2__")
# pragma push_macro("__BMI2__")
# pragma push_macro("__SSE4_1__")
# pragma push_macro("__AVX512F__")
# pragma push_macro("__AVX512VL__")
# pragma push_macro("__AVX512BW__")
# pragma push_macro("__AVX512VBMI__")
# define __SHA__ 1
# define __AVX__ 1
# define __AVX2__ 1
# define __BMI2__ 1
# define __SSE4_1__ 1
# define __AVX512F__ 1
# define __AVX512VL__ 1
# define __AVX512BW__ 1
# define __AVX512VBMI__ 1
# include <immintrin.h>
# pragma pop_macro("__AVX512VBMI__")
# pragma pop_macro("__AVX512BW__")
# pragma pop_macro("__AVX512VL__")
# pragma pop_macro("__AVX512F__")
# pragma pop_macro("__SSE4_1__")
# pragma pop_macro("__BMI2__")
# pragma pop_macro("__AVX2__")
# pragma pop_macro("__AVX__")
# pragma pop_macro("__SHA__")
# pragma clang diagnostic pop
#endif
#endif // BASE_CONTEXT_CRACKING_H
+126 -13
View File
@@ -79,19 +79,21 @@ u64_up_to_pow2(U64 x){
}
internal S32
extend_sign32(U32 x, U32 size){
U32 high_bit = size * 8;
U32 shift = 32 - high_bit;
S32 result = ((S32)x << shift) >> shift;
return result;
extend_sign32(U32 x, U32 size)
{
U32 n = size * 8;
U32 m = (U32)1 << (n - 1);
S32 r = (S32)((x ^ m) - m);
return r;
}
internal S64
extend_sign64(U64 x, U64 size){
U64 high_bit = size * 8;
U64 shift = 64 - high_bit;
S64 result = ((S64)x << shift) >> shift;
return result;
extend_sign64(U64 x, U64 size)
{
U64 n = size * 8;
U64 m = (U64)1 << (n - 1);
S64 r = (S64)((x ^ m) - m);
return r;
}
internal F32
@@ -286,6 +288,56 @@ memory_is_zero(void *ptr, U64 size)
return result;
}
internal void UBSAN_NO_ALIGN
memory_write16(void *ptr, U16 v)
{
MemoryCopy(ptr, &v, sizeof(v));
}
internal void UBSAN_NO_ALIGN
memory_write32(void *ptr, U32 v)
{
MemoryCopy(ptr, &v, sizeof(v));
}
internal void UBSAN_NO_ALIGN
memory_write64(void *ptr, U64 v)
{
MemoryCopy(ptr, &v, sizeof(v));
}
internal U8 UBSAN_NO_ALIGN
memory_read8(void *ptr)
{
U8 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
internal U16 UBSAN_NO_ALIGN
memory_read16(void *ptr)
{
U16 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
internal U32 UBSAN_NO_ALIGN
memory_read32(void *ptr)
{
U32 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
internal U64 UBSAN_NO_ALIGN
memory_read64(void *ptr)
{
U64 result;
MemoryCopy(&result, ptr, sizeof(result));
return result;
}
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
@@ -413,6 +465,38 @@ byte_size_from_arch(Arch arch)
return bit_size_from_arch(arch) / 8;
}
internal U64
max_ops_per_instruction_from_arch(Arch arch)
{
U64 max_ops = 0;
switch (arch)
{
case Arch_Null: break;
case Arch_x64: max_ops = 1; break;
case Arch_x86:
case Arch_arm32:
case Arch_arm64: NotImplemented; break;
default: InvalidPath;
}
return max_ops;
}
internal U64
min_instruction_size_from_arch(Arch arch)
{
U64 min_instruction_size = 0;
switch(arch)
{
case Arch_Null: break;
case Arch_x64: min_instruction_size = 1; break;
case Arch_x86:
case Arch_arm32:
case Arch_arm64: NotImplemented; break;
default: InvalidPath;
}
return min_instruction_size;
}
internal U64
max_instruction_size_from_arch(Arch arch)
{
@@ -539,10 +623,10 @@ date_time_from_unix_time(U64 unix_time)
}
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
//~ rjf: Wrapped Ring Buffer Reads/Writes
internal U64
ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
{
Assert(src_data_size <= ring_size);
{
@@ -559,7 +643,7 @@ ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_d
}
internal U64
ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
{
Assert(read_size <= ring_size);
{
@@ -608,6 +692,26 @@ u64_array_bsearch(U64 *arr, U64 count, U64 value)
////////////////////////////////
internal U32
idx_of_zero_byte64(U8 *ptr, U64 size)
{
Assert(size == 8);
#if ARCH_X64
__m128i v = _mm_loadl_epi64((__m128i*)ptr);
__m128i m = _mm_cmpeq_epi8(v, _mm_setzero_si128());
U32 bits = _mm_movemask_epi8(m);
return ctz32(bits);
#else
U64 x;
MemoryCopyStruct(&x, ptr);
U64 splat = ~0ULL / 255;
U64 mask_lsb = 0x01 * splat;
U64 mask_msb = 0x80 * splat;
U64 t = (x - mask_lsb) & (~x & mask_msb);
return ctz64(t) / 8;
#endif
}
internal U64
index_of_zero_u32(U32 *ptr, U64 count)
{
@@ -630,6 +734,15 @@ index_of_zero_u64(U64 *ptr, U64 count)
return max_U64;
}
internal U64
count_digits_u64(U64 v, U64 radix)
{
if (v == 0) { return 1; }
U64 count = 0;
for (U64 x = v; x > 0; x /= radix) { count += 1; }
return count;
}
////////////////////////////////
//~ rjf: Third Party Includes
+172 -63
View File
@@ -7,11 +7,13 @@
////////////////////////////////
//~ rjf: Foreign Includes
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
////////////////////////////////
//~ rjf: Third Party Includes
@@ -180,8 +182,9 @@
//~ rjf: Member Offsets
#define Member(T,m) (((T*)0)->m)
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
#define OffsetOf(T,m) offsetof(T, m)
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
#define MemberFromPtr(T,ptr,m) (void*)((((U8 *)ptr)+OffsetOf(T,m)))
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
////////////////////////////////
@@ -196,6 +199,7 @@
#define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1))
#define EachInRange(it, range) (U64 it = (range).min; it < (range).max; it += 1)
#define EachNode(it, T, first) (T *it = first; it != 0; it = it->next)
#define EachBit(it, flags) (U64 (_i_) = (flags), it = (flags) & -(flags); (_i_) != 0; (_i_) &= ((_i_) - 1), it = (flags) & -(flags))
////////////////////////////////
//~ rjf: Memory Operation Macros
@@ -203,7 +207,6 @@
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
#define MemoryStrlen(ptr) strlen(ptr)
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
@@ -221,9 +224,6 @@
#define MemoryIsZeroStruct(ptr) memory_is_zero((ptr), sizeof(*(ptr)))
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
#define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
////////////////////////////////
//~ rjf: Asserts
@@ -252,38 +252,44 @@
#if COMPILER_MSVC
# include <intrin.h>
# if ARCH_X64
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)InterlockedCompareExchange128((__int64 *)(x), ((__int64 *)&(k))[1], ((__int64 *)&(k))[0], (__int64 *)c)
# define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((__int64 *)(x))
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((__int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((__int64 *)(x),(c))
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((__int64 *)(x), c)
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((__int64 *)(x),(k),(c))
# define ins_atomic_u32_eval(x) *((volatile U32 *)(x))
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((LONG *)(x))
# define ins_atomic_u32_dec_eval(x) InterlockedDecrement((LONG *)(x))
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((LONG *)(x),(c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((LONG *)(x),(k),(c))
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((LONG *)(x), (c))
# define ins_atomic_u8_eval_assign(x,c) InterlockedExchange8((CHAR *)(x), (c))
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)_InterlockedCompareExchange128((__int64 *)(x), ((__int64 *)&(k))[1], ((__int64 *)&(k))[0], (__int64 *)(c))
# define ins_atomic_u64_eval(x) (U64)__iso_volatile_load64((__int64*)(x))
# define ins_atomic_u64_inc_eval(x) _InterlockedIncrement64((__int64 *)(x))
# define ins_atomic_u64_dec_eval(x) _InterlockedDecrement64((__int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) _InterlockedExchange64((__int64 *)(x), (c))
# define ins_atomic_u64_add_eval(x,c) _interlockedadd64((__int64 *)(x), (c))
# define ins_atomic_u64_eval_cond_assign(x,k,c) _InterlockedCompareExchange64((__int64 *)(x), (k), (c))
# define ins_atomic_u32_eval(x) (U32)__iso_volatile_load32((__int32*)(x))
# define ins_atomic_u32_inc_eval(x) _InterlockedIncrement((long *)(x))
# define ins_atomic_u32_dec_eval(x) _InterlockedDecrement((long *)(x))
# define ins_atomic_u32_eval_assign(x,c) _InterlockedExchange((long *)(x), (c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) _InterlockedCompareExchange((long *)(x), (k), (c))
# define ins_atomic_u32_add_eval(x,c) _interlockedadd((long *)(x), (c))
# define ins_atomic_u8_eval_assign(x,c) _InterlockedExchange8((char *)(x), (char)(c))
# define ins_atomic_u8_or(x,c) _InterlockedOr8((char *)(x), (char)(c))
# define ins_atomic_u32_or(x,c) _InterlockedOr((long *)(x), (long)(c))
# else
# error Atomic intrinsics not defined for this compiler / architecture combination.
# endif
#elif COMPILER_CLANG || COMPILER_GCC
# include <immintrin.h>
# include <emmintrin.h>
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)__atomic_compare_exchange_n((__int128 *)(x),(__int128 *)(c),*(__int128 *)(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST)
# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
# define ins_atomic_u64_eval(x) __atomic_load_n((U64 *)(x), __ATOMIC_SEQ_CST)
# define ins_atomic_u64_inc_eval(x) __atomic_add_fetch((U64 *)(x), 1, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_dec_eval(x) __atomic_sub_fetch((U64 *)(x), 1, __ATOMIC_SEQ_CST)
# 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((U64 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u64_add_eval(x,c) __atomic_add_fetch((U64 *)(x), c, __ATOMIC_SEQ_CST)
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((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((U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
# define ins_atomic_u32_dec_eval(x) (__atomic_fetch_sub((U32 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
# define ins_atomic_u32_inc_eval(x) __atomic_add_fetch((U32 *)(x), 1, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_dec_eval(x) __atomic_sub_fetch((U32 *)(x), 1, __ATOMIC_SEQ_CST)
# define ins_atomic_u32_add_eval(x,c) __atomic_add_fetch((U32 *)(x), c, __ATOMIC_SEQ_CST)
# 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((U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST)
# define ins_atomic_u8_or(x,c) __atomic_fetch_or((U8 *)(x), (U8)(c), __ATOMIC_SEQ_CST)
# define ins_atomic_u32_or(x,c) __atomic_fetch_or((U32 *)(x), (U32)(c), __ATOMIC_SEQ_CST)
#else
# error Atomic intrinsics not defined for this compiler / architecture.
#endif
@@ -363,9 +369,7 @@ CheckNil(nil,p) ? \
#if COMPILER_MSVC
# if defined(__SANITIZE_ADDRESS__)
# define ASAN_ENABLED 1
# define NO_ASAN __declspec(no_sanitize_address)
# else
# define NO_ASAN
# define ASAN_NO_ADDR __declspec(no_sanitize_address)
# endif
#elif COMPILER_CLANG
# if defined(__has_feature)
@@ -373,9 +377,15 @@ CheckNil(nil,p) ? \
# define ASAN_ENABLED 1
# endif
# endif
# define NO_ASAN __attribute__((no_sanitize("address")))
#else
# define NO_ASAN
# define ASAN_NO_ADDR __attribute__((no_sanitize("address")))
# define UBSAN_NO_ALIGN __attribute__((no_sanitize("alignment")))
#endif
#ifndef ASAN_NO_ADDR
# define ASAN_NO_ADDR
#endif
#ifndef UBSAN_NO_ALIGN
# define UBSAN_NO_ALIGN
#endif
#if ASAN_ENABLED
@@ -437,6 +447,9 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s
# define this_function_name __func__
#endif
#define TryRead(func__, cursor__, label__) do { U64 size__ = (func__); if (size__ == 0) { goto label__; } cursor__ += size__; } while (0)
#define TryReadBreak(func__, cursor__) { U64 size__ = (func__); if (size__ == 0) { break; } cursor__ += size__; }
////////////////////////////////
//~ rjf: Base Types
@@ -462,6 +475,8 @@ union U128
U16 u16[8];
U32 u32[4];
U64 u64[2];
F32 f32[4];
F64 f64[2];
};
typedef union U256 U256;
union U256
@@ -471,6 +486,8 @@ union U256
U32 u32[8];
U64 u64[4];
U128 u128[2];
F32 f32[8];
F64 f64[4];
};
typedef union U512 U512;
union U512
@@ -481,37 +498,48 @@ union U512
U64 u64[8];
U128 u128[4];
U256 u256[2];
F32 f32[16];
F64 f64[8];
};
#pragma pack(push, 1)
typedef struct U80 U80;
struct U80
{
U64 int1_frac63;
U16 sign1_exp15;
};
#pragma pack(pop)
////////////////////////////////
//~ rjf: Basic Type Structures
typedef struct U16Array U16Array;
struct U16Array
{
U64 count;
U16 *v;
U64 count;
};
typedef struct U32Array U32Array;
struct U32Array
{
U64 count;
U32 *v;
U64 count;
};
typedef struct U64Array U64Array;
struct U64Array
{
U64 count;
U64 *v;
U64 count;
};
typedef struct U128Array U128Array;
struct U128Array
{
U64 count;
U128 *v;
U64 count;
};
////////////////////////////////
@@ -611,19 +639,19 @@ typedef enum Arch
Arch_arm64,
Arch_arm32,
Arch_COUNT,
#if ARCH_X64
Arch_CURRENT = Arch_x64,
#elif ARCH_X86
Arch_CURRENT = Arch_x86,
#elif ARCH_ARM64
Arch_CURRENT = Arch_arm64,
#elif ARCH_ARM32
Arch_CURRENT = Arch_arm32,
#else
Arch_CURRENT = Arch_Null,
#endif
}
Arch;
#if ARCH_X64
# define Arch_CURRENT Arch_x64
#elif ARCH_X86
# define Arch_CURRENT Arch_x86
#elif ARCH_ARM64
# define Arch_CURRENT Arch_arm64
#elif ARCH_ARM32
# define Arch_CURRENT Arch_arm32
#else
# define Arch_CURRENT Arch_Null
#endif
typedef enum Compiler
{
@@ -632,17 +660,42 @@ typedef enum Compiler
Compiler_gcc,
Compiler_clang,
Compiler_COUNT,
#if COMPILER_MSVC
Compiler_CURRENT = Compiler_msvc,
#elif COMPILER_GCC
Compiler_CURRENT = Compiler_gcc,
#elif COMPILER_CLANG
Compiler_CURRENT = Compiler_clang,
#else
Compiler_CURRENT = Compiler_Null,
#endif
}
Compiler;
#if COMPILER_MSVC
# define Compiler_CURRENT Compiler_msvc
#elif COMPILER_GCC
# define Compiler_CURRENT Compiler_gcc
#elif COMPILER_CLANG
# define Compiler_CURRENT Compiler_clang
#else
# define Compiler_CURRENT Compiler_Null
#endif
typedef enum Linker
{
Linker_Null,
Linker_radlink,
Linker_msvc,
Linker_lld,
Linker_COUNT
}
Linker;
////////////////////////////////
//~ rjf: Access Flags
typedef U32 AccessFlags;
enum
{
AccessFlag_Read = (1<<0),
AccessFlag_Write = (1<<1),
AccessFlag_Execute = (1<<2),
AccessFlag_Append = (1<<3),
AccessFlag_ShareRead = (1<<4),
AccessFlag_ShareWrite = (1<<5),
AccessFlag_Inherited = (1<<6),
};
////////////////////////////////
//~ rjf: Text 2D Coordinates & Ranges
@@ -678,6 +731,29 @@ union Guid
};
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
////////////////////////////////
//~ Machine Ops
typedef enum MachineOpResult
{
MachineOpResult_Null,
MachineOpResult_Ok,
MachineOpResult_Fail,
MachineOpResult_Maybe,
} MachineOpResult;
#define MACHINE_OP_REG_READ(name) MachineOpResult name(U64 reg_id, void *buffer, U64 buffer_max, void *ud)
typedef MACHINE_OP_REG_READ(MachineOp_RegRead);
#define MACHINE_OP_REG_WRITE(name) MachineOpResult name(U64 reg_id, void *value, U64 value_size, void *ud)
typedef MACHINE_OP_REG_WRITE(MachineOp_RegWrite);
#define MACHINE_OP_MEM_READ(name) MachineOpResult name(U64 addr, void *buffer, U64 buffer_size, void *ud)
typedef MACHINE_OP_MEM_READ(MachineOp_MemRead);
#define MACHINE_OP_MEM_WRITE(name) MachineOpResult name(U64 addr, void *value, U64 value_size, void *ud)
typedef MACHINE_OP_MEM_WRITE(MachineOp_MemWrite);
////////////////////////////////
//~ rjf: Basic Constants
@@ -973,6 +1049,15 @@ internal F32 sign_from_side_F32(Side side);
internal B32 memory_is_zero(void *ptr, U64 size);
internal void memory_write16(void *ptr, U16 v);
internal void memory_write32(void *ptr, U32 v);
internal void memory_write64(void *ptr, U64 v);
internal U8 memory_read8(void *ptr);
internal U16 memory_read16(void *ptr);
internal U32 memory_read32(void *ptr);
internal U64 memory_read64(void *ptr);
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
@@ -991,6 +1076,8 @@ internal B32 txt_rng_contains(TxtRng r, TxtPt pt);
internal U64 bit_size_from_arch(Arch arch);
internal U64 byte_size_from_arch(Arch arch);
internal U64 max_ops_per_instruction_from_arch(Arch arch);
internal U64 min_instruction_size_from_arch(Arch arch);
internal U64 max_instruction_size_from_arch(Arch arch);
////////////////////////////////
@@ -1002,12 +1089,32 @@ internal DateTime date_time_from_micro_seconds(U64 time);
internal DateTime date_time_from_unix_time(U64 unix_time);
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
//~ rjf: @per_os_impl Debugger Attachment Checking
internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
internal B32 debugger_is_attached(void);
////////////////////////////////
//~ rjf: @per_os_impl Platform Time Functions
internal U64 now_time_us(void);
internal U32 now_time_unix(void);
internal DateTime now_time_universal(void);
internal DateTime universal_from_local_time(DateTime *dt);
internal DateTime local_from_universal_time(DateTime *dt);
internal void sleep_ms(U32 ms);
////////////////////////////////
//~ rjf: @per_os_impl Platform GUID Functions
internal Guid make_guid(void);
////////////////////////////////
//~ rjf: Wrapped Ring Buffer Reads/Writes
internal U64 wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
internal U64 wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
#define wrapped_write_struct(ring_base, ring_size, ring_pos, ptr) wrapped_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
#define wrapped_read_struct(ring_base, ring_size, ring_pos, ptr) wrapped_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
////////////////////////////////
//~ rjf: Sorts
@@ -1020,7 +1127,9 @@ internal U64 u64_array_bsearch(U64 *arr, U64 count, U64 value);
////////////////////////////////
internal U32 idx_of_zero_byte64(U8 *ptr, U64 size); // size must be exactly 8 bytes
internal U64 index_of_zero_u32(U32 *ptr, U64 count);
internal U64 index_of_zero_u64(U64 *ptr, U64 count);
internal U64 count_digits_u64(U64 v, U64 radix);
#endif // BASE_CORE_H
@@ -1,2 +1,2 @@
// Copyright (c) 2024 Epic Games Tools
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+20
View File
@@ -0,0 +1,20 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_DYNAMIC_LIBARIES_H
#define BASE_DYNAMIC_LIBARIES_H
typedef struct Library Library;
struct Library
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: @per_os_impl Dynamically-Loaded Libraries
internal Library library_open(String8 path);
internal void library_close(Library lib);
internal VoidProc *library_load_proc(Library lib, String8 name);
#endif // BASE_DYNAMIC_LIBARIES_H
+28 -13
View File
@@ -11,6 +11,10 @@ global B32 async_loop_again_high_priority = 0;
global B32 global_async_exit = 0;
thread_static B32 is_async_thread = 0;
// NOTE(rjf): defined by target
raddbg_entry_point(entry_point);
internal void entry_point(CmdLine *cmdline);
internal void
main_thread_base_entry_point(int arguments_count, char **arguments)
{
@@ -54,12 +58,15 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
}
//- rjf: initialize all included layers
#if defined(HTTP_H) && !defined(HTTP_INIT_MANUAL)
http_init();
#endif
#if defined(SYMBOL_SERVER_H) && !defined(SMSV_INIT_MANUAL)
smsv_init();
#endif
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
ac_init();
#endif
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
async_init(&cmdline);
#endif
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
c_init();
#endif
@@ -75,11 +82,11 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
dmn_init();
#endif
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
ctrl_init();
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
d_init();
#endif
#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL)
os_gfx_init();
#if defined(WINDOW_MANAGER_H) && !defined(WM_INIT_MANUAL)
wm_init();
#endif
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
fp_init();
@@ -90,22 +97,20 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
fnt_init();
#endif
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
d_init();
#endif
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
rd_init(&cmdline);
#endif
//- rjf: launch async threads
#if NEED_ASYNC
Thread *async_threads = 0;
U64 lane_broadcast_val = 0;
{
U64 num_main_threads = 1;
#if defined(CTRL_CORE_H)
#if defined(DBG_ENGINE_CORE_H)
num_main_threads += 1;
#endif
U64 num_async_threads = os_get_system_info()->logical_processor_count;
U64 num_async_threads = get_system_info()->logical_processor_count;
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
num_async_threads -= num_main_threads_clamped;
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
@@ -127,17 +132,21 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
}
}
#endif
//- rjf: call into entry point
entry_point(&cmdline);
//- rjf: join async threads
#if NEED_ASYNC
ins_atomic_u32_inc_eval(&global_async_exit);
ins_atomic_u32_inc_eval(&async_loop_again);
cond_var_broadcast(async_tick_start_cond_var);
for EachIndex(idx, async_threads_count)
{
thread_join(async_threads[idx], max_U64);
}
#endif
//- rjf: end captures
if(capture)
@@ -194,7 +203,7 @@ async_thread_entry_point(void *params)
{
if(!ins_atomic_u32_eval(&async_loop_again))
{
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+1000000);
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, now_time_us()+1000000);
}
ins_atomic_u32_eval_assign(&async_loop_again, 0);
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
@@ -213,6 +222,12 @@ async_thread_entry_point(void *params)
#if defined(FILE_STREAM_H)
fs_async_tick();
#endif
#if defined(HTTP_H)
http_async_tick();
#endif
#if defined(SYMBOL_SERVER_H)
smsv_async_tick();
#endif
#if defined(DBG_INFO_H)
di_async_tick();
#endif
+169
View File
@@ -0,0 +1,169 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Handle Type Functions
internal File
file_zero(void)
{
File f = {0};
return f;
}
internal B32
file_match(File a, File b)
{
B32 result = MemoryMatchStruct(&a, &b);
return result;
}
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
internal String8
data_from_file_path(Arena *arena, String8 path)
{
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
FileProperties props = properties_from_file(file);
String8 data = string_from_file_range(arena, file, r1u64(0, props.size));
file_close(file);
return data;
}
internal B32
write_data_to_file_path(String8 path, String8 data)
{
B32 good = 0;
File file = file_open(AccessFlag_Write, path);
if(!file_match(file, file_zero()))
{
U64 bytes_written = file_write(file, r1u64(0, data.size), data.str);
good = (bytes_written == data.size);
file_close(file);
}
return good;
}
internal B32
write_data_list_to_file_path(String8 path, String8List list)
{
B32 good = 0;
File file = file_open(AccessFlag_Write, path);
if(!file_match(file, file_zero()))
{
Temp scratch = scratch_begin(0, 0);
U64 write_buffer_size = KB(64);
U8 *write_buffer = push_array_no_zero(scratch.arena, U8, write_buffer_size);
U64 write_buffer_write_pos = 0;
U64 write_buffer_read_pos = 0;
U64 file_off = 0;
{
for(String8Node *n = list.first; n != 0; n = n->next)
{
for(U64 n_off = 0; n_off < n->string.size;)
{
U64 write_buffer_unconsumed_size = (write_buffer_write_pos - write_buffer_read_pos);
U64 write_buffer_available_size = (write_buffer_size - write_buffer_unconsumed_size);
if(write_buffer_available_size == 0)
{
U64 file_write_size = file_write(file, r1u64(file_off, file_off+write_buffer_size), write_buffer);
if(file_write_size != write_buffer_size)
{
goto dbl_break;
}
file_off += write_buffer_size;
write_buffer_read_pos += write_buffer_size;
}
else
{
U64 bytes_to_copy = Min(write_buffer_available_size, n->string.size - n_off);
write_buffer_write_pos += wrapped_write(write_buffer, write_buffer_size, write_buffer_write_pos, n->string.str + n_off, bytes_to_copy);
n_off += bytes_to_copy;
}
}
}
if(write_buffer_write_pos > write_buffer_read_pos)
{
U64 file_write_size = file_write(file, r1u64(file_off, file_off + (write_buffer_write_pos-write_buffer_read_pos)), write_buffer);
file_off += file_write_size;
}
}
dbl_break:;
good = (file_off == list.total_size);
file_close(file);
scratch_end(scratch);
}
return good;
}
internal B32
append_data_to_file_path(String8 path, String8 data)
{
B32 good = 0;
if(data.size != 0)
{
File file = file_open(AccessFlag_Write|AccessFlag_Append, path);
if(!file_match(file, file_zero()))
{
U64 pos = properties_from_file(file).size;
U64 bytes_written = file_write(file, r1u64(pos, pos+data.size), data.str);
good = (bytes_written == data.size);
file_close(file);
}
}
return good;
}
internal FileID
id_from_file_path(String8 path)
{
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
FileID id = id_from_file(file);
file_close(file);
return id;
}
internal S64
file_id_compare(FileID a, FileID b)
{
S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v));
return cmp;
}
internal String8
string_from_file_range(Arena *arena, File file, Rng1U64 range)
{
U64 pre_pos = arena_pos(arena);
String8 result;
result.size = dim_1u64(range);
result.str = push_array_no_zero(arena, U8, result.size);
U64 actual_read_size = file_read(file, range, result.str);
if(actual_read_size < result.size)
{
arena_pop_to(arena, pre_pos + actual_read_size);
result.size = actual_read_size;
}
return result;
}
internal String8
file_read_cstring(Arena *arena, File file, U64 off)
{
Temp scratch = scratch_begin(&arena, 1);
String8List block_list = {0};
for(U64 cursor = off, stride = 256;; cursor += stride)
{
U8 *raw_block = push_array_no_zero(scratch.arena, U8, stride);
U64 read_size = file_read(file, r1u64(cursor, cursor + stride), raw_block);
String8 block = str8_cstring_capped(raw_block, raw_block+read_size);
str8_list_push(scratch.arena, &block_list, block);
if(read_size != stride || (block.size+1 <= read_size && block.str[block.size] == 0))
{
break;
}
}
String8 result = str8_list_join(arena, &block_list, 0);
scratch_end(scratch);
return result;
}
+102
View File
@@ -0,0 +1,102 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_FILES_H
#define BASE_FILES_H
typedef U32 FileIterFlags;
enum
{
FileIterFlag_SkipFolders = (1 << 0),
FileIterFlag_SkipFiles = (1 << 1),
FileIterFlag_SkipHiddenFiles = (1 << 2),
FileIterFlag_Done = (1 << 31),
};
typedef struct FileIter FileIter;
struct FileIter
{
FileIterFlags flags;
U8 memory[800];
};
typedef struct FileInfo FileInfo;
struct FileInfo
{
String8 name;
FileProperties props;
};
// nick: on-disk file identifier
typedef struct FileID FileID;
struct FileID
{
U64 v[3];
};
typedef struct File File;
struct File
{
U64 u64[1];
};
typedef struct FileMap FileMap;
struct FileMap
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: Handle Type Functions
internal File file_zero(void);
internal B32 file_match(File a, File b);
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
internal String8 data_from_file_path(Arena *arena, String8 path);
internal B32 write_data_to_file_path(String8 path, String8 data);
internal B32 write_data_list_to_file_path(String8 path, String8List list);
internal B32 append_data_to_file_path(String8 path, String8 data);
internal FileID id_from_file_path(String8 path);
internal S64 file_id_compare(FileID a, FileID b);
internal String8 string_from_file_range(Arena *arena, File file, Rng1U64 range);
internal String8 file_read_cstring(Arena *arena, File file, U64 off);
////////////////////////////////
//~ rjf: @per_os_impl File System (Implemented Per-OS)
//- rjf: files
internal File file_open(AccessFlags flags, String8 path);
internal void file_close(File file);
internal U64 file_read(File file, Rng1U64 rng, void *out_data);
#define file_read_struct(f, off, ptr) file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr))
internal U64 file_write(File file, Rng1U64 rng, void *data);
internal B32 file_set_times(File file, DateTime time);
internal FileProperties properties_from_file(File file);
internal FileID id_from_file(File file);
internal B32 file_reserve_size(File file, U64 size);
internal B32 delete_file_at_path(String8 path);
internal B32 copy_file_path(String8 dst, String8 src);
internal B32 move_file_path(String8 dst, String8 src);
internal String8 full_path_from_path(Arena *arena, String8 path);
internal B32 file_path_exists(String8 path);
internal B32 folder_path_exists(String8 path);
internal FileProperties properties_from_file_path(String8 path);
//- rjf: file maps
internal FileMap file_map_open(AccessFlags flags, File file);
internal void file_map_close(FileMap map);
internal void * file_map_view_open(FileMap map, AccessFlags flags, Rng1U64 range);
internal void file_map_view_close(FileMap map, void *ptr, Rng1U64 range);
//- rjf: directory iteration
internal FileIter *file_iter_begin(Arena *arena, String8 path, FileIterFlags flags);
internal B32 file_iter_next(Arena *arena, FileIter *iter, FileInfo *info_out);
internal void file_iter_end(FileIter *iter);
//- rjf: directory creation
internal B32 make_directory(String8 path);
#endif // BASE_FILES_H
+17
View File
@@ -9,14 +9,31 @@
#include "base_core.c"
#include "base_profile.c"
#include "base_memory.c"
#include "base_arena.c"
#include "base_math.c"
#include "base_strings.c"
#include "base_memory_map.c"
#include "base_hash.c"
#include "base_system.c"
#include "base_threads.c"
#include "base_ring.c"
#include "base_thread_context.c"
#include "base_files.c"
#include "base_shared_memory.c"
#include "base_processes.c"
#include "base_dynamic_libraries.c"
#include "base_command_line.c"
#include "base_markup.c"
#include "base_meta.c"
#include "base_log.c"
#include "base_test.c"
#include "base_entry_point.c"
#if OS_WINDOWS
# include "win32/base/win32_base.c"
#elif OS_LINUX
# include "linux/base/linux_base.c"
#else
# error Operating system backend not found for base layer.
#endif
+17
View File
@@ -11,16 +11,33 @@
#include "base_core.h"
#include "base_profile.h"
#include "base_memory.h"
#include "base_arena.h"
#include "base_math.h"
#include "base_strings.h"
#include "base_memory_map.h"
#include "base_hash.h"
#include "base_system.h"
#include "base_threads.h"
#include "base_ring.h"
#include "base_thread_context.h"
#include "base_files.h"
#include "base_shared_memory.h"
#include "base_processes.h"
#include "base_dynamic_libraries.h"
#include "base_command_line.h"
#include "base_markup.h"
#include "base_meta.h"
#include "base_log.h"
#include "base_test.h"
#include "base_entry_point.h"
#if OS_WINDOWS
# include "win32/base/win32_base.h"
#elif OS_LINUX
# include "linux/base/linux_base.h"
#else
# error Operating system backend not found for base layer.
#endif
#endif // BASE_INC_H
+2
View File
@@ -9,6 +9,8 @@ C_LINKAGE thread_static Log *log_active;
C_LINKAGE thread_static Log *log_active = 0;
#endif
String8 g_logs_folder;
////////////////////////////////
//~ rjf: Log Creation/Selection
+5
View File
@@ -36,6 +36,11 @@ struct Log
LogScope *top_scope;
};
////////////////////////////////
// Globals
extern String8 g_logs_folder;
////////////////////////////////
//~ rjf: Log Creation/Selection
-19
View File
@@ -1,21 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
set_thread_name(String8 string)
{
ProfThreadName("%.*s", str8_varg(string));
os_set_thread_name(string);
}
internal void
set_thread_namef(char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
set_thread_name(string);
va_end(args);
scratch_end(scratch);
}
-2
View File
@@ -15,8 +15,6 @@
# define LAYER_COLOR 0x404040ff
#endif
internal void set_thread_name(String8 string);
internal void set_thread_namef(char *fmt, ...);
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
#endif // BASE_MARKUP_H
+35 -16
View File
@@ -407,6 +407,26 @@ transpose_4x4f32(Mat4x4F32 mat)
////////////////////////////////
//~ rjf: Range Ops
internal Rng1U8 rng_1u8(U8 min, U8 max) {Rng1U8 r = {min, max}; if(r.min > r.max) { Swap(U8, r.min, r.max); } return r;}
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x) {r.min += x; r.max += x; return r;}
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x) {r.min -= x; r.max += x; return r;}
internal U8 center_1u8(Rng1U8 r) {U8 c = (r.min+r.max)/2; return c;}
internal B32 contains_1u8(Rng1U8 r, U8 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal U8 dim_1u8(Rng1U8 r) {U8 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal U8 clamp_1u8(Rng1U8 r, U8 v) {v = Clamp(r.min, v, r.max); return v;}
internal Rng1U16 rng_1u16(U16 min, U16 max) {Rng1U16 r = {min, max}; if(r.min > r.max) { Swap(U16, r.min, r.max); } return r;}
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x) {r.min += x; r.max += x; return r;}
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x) {r.min -= x; r.max += x; return r;}
internal U16 center_1u16(Rng1U16 r) {U16 c = (r.min+r.max)/2; return c;}
internal B32 contains_1u16(Rng1U16 r, U16 x) {B32 c = (r.min <= x && x < r.max); return c;}
internal U16 dim_1u16(Rng1U16 r) {U16 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
internal U16 clamp_1u16(Rng1U16 r, U16 v) {v = Clamp(r.min, v, r.max); return v;}
internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;}
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;}
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
@@ -738,6 +758,7 @@ rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat)
list->first = to_concat->first;
list->last = to_concat->last;
}
list->count += to_concat->count;
MemoryZeroStruct(to_concat);
}
}
@@ -758,34 +779,32 @@ rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
}
internal U64
rng_1u64_array_bsearch(Rng1U64Array arr, U64 value)
rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value)
{
if(arr.count > 0 && arr.v[0].min < value && value < arr.v[arr.count-1].max)
U64 result = 0;
if(array->count > 0 && array->v[0].min <= value && value < array->v[array->count-1].max)
{
U64 l = 0;
U64 r = arr.count - 1;
for(; l <= r; )
U64 min_idx = 0;
U64 max_idx = array->count - 1;
for(;min_idx <= max_idx;)
{
U64 m = l + (r - l) / 2;
if(contains_1u64(arr.v[m], value))
U64 mid_idx = min_idx + (max_idx - min_idx) / 2;
if(contains_1u64(array->v[mid_idx], value))
{
return m;
result = mid_idx+1;
break;
}
else if(arr.v[m].min < value)
else if(array->v[mid_idx].min < value)
{
l = m + 1;
min_idx = mid_idx + 1;
}
else
{
r = m - 1;
max_idx = mid_idx - 1;
}
}
}
else if(arr.count == 1 && contains_1u64(arr.v[0], value))
{
return 0;
}
return max_U64;
return result;
}
internal void
+57 -2
View File
@@ -177,6 +177,28 @@ struct Mat4x4F32
//- rjf: 1-range
typedef union Rng1U8 Rng1U8;
union Rng1U8
{
struct
{
U8 min;
U8 max;
};
U8 v[2];
};
typedef union Rng1U16 Rng1U16;
union Rng1U16
{
struct
{
U16 min;
U16 max;
};
U16 v[2];
};
typedef union Rng1U32 Rng1U32;
union Rng1U32
{
@@ -339,9 +361,9 @@ struct Rng1U64Node
typedef struct Rng1U64List Rng1U64List;
struct Rng1U64List
{
U64 count;
Rng1U64Node *first;
Rng1U64Node *last;
U64 count;
};
typedef struct Rng1U64Array Rng1U64Array;
@@ -546,7 +568,32 @@ internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
////////////////////////////////
//~ rjf: Range Ops
#define r1u8(min, max) rng_1u8((min), (max))
#define r1u8s(min, size) rng_1u8((min), (min)+(size))
internal Rng1U8 rng_1u8(U8 min, U8 max);
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x);
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x);
internal U8 center_1u8(Rng1U8 r);
internal B32 contains_1u8(Rng1U8 r, U8 x);
internal U8 dim_1u8(Rng1U8 r);
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b);
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b);
internal U8 clamp_1u8(Rng1U8 r, U8 v);
#define r1u16(min, max) rng_1u16((min), (max))
#define r1u16s(min, size) rng_1u16((min), (min)+(size))
internal Rng1U16 rng_1u16(U16 min, U16 max);
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x);
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x);
internal U16 center_1u16(Rng1U16 r);
internal B32 contains_1u16(Rng1U16 r, U16 x);
internal U16 dim_1u16(Rng1U16 r);
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b);
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b);
internal U16 clamp_1u16(Rng1U16 r, U16 v);
#define r1u32(min, max) rng_1u32((min), (max))
#define r1u32s(min, size) rng_1u32((min), (min)+(size))
internal Rng1U32 rng_1u32(U32 min, U32 max);
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x);
@@ -558,6 +605,7 @@ internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b);
internal U32 clamp_1u32(Rng1U32 r, U32 v);
#define r1s32(min, max) rng_1s32((min), (max))
#define r1s32s(min,size) rng_1s32((min), (min)+(size))
internal Rng1S32 rng_1s32(S32 min, S32 max);
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x);
@@ -569,6 +617,7 @@ internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b);
internal S32 clamp_1s32(Rng1S32 r, S32 v);
#define r1u64(min, max) rng_1u64((min), (max))
#define r1u64s(min, size) rng_1u64((min), (min)+(size))
internal Rng1U64 rng_1u64(U64 min, U64 max);
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x);
@@ -580,6 +629,7 @@ internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b);
internal U64 clamp_1u64(Rng1U64 r, U64 v);
#define r1s64(min, max) rng_1s64((min), (max))
#define r1s64s(min, size) rng_1s64((min), (min)+(size))
internal Rng1S64 rng_1s64(S64 min, S64 max);
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x);
@@ -591,6 +641,7 @@ internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b);
internal S64 clamp_1s64(Rng1S64 r, S64 v);
#define r1f32(min, max) rng_1f32((min), (max))
#define r1f32s(min, size) rng_1f32((min), (min)+(size))
internal Rng1F32 rng_1f32(F32 min, F32 max);
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x);
@@ -602,6 +653,7 @@ internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b);
internal F32 clamp_1f32(Rng1F32 r, F32 v);
#define r2s16(min, max) rng_2s16((min), (max))
#define r2s16s(min, size) r2s16((min), (min)+(size))
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
@@ -614,6 +666,7 @@ internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b);
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
#define r2s32(min, max) rng_2s32((min), (max))
#define r2s32s(min, size) r2s32((min), (min)+(size))
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
@@ -626,6 +679,7 @@ internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b);
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
#define r2s64(min, max) rng_2s64((min), (max))
#define r2s64s(min, size) r2s64((min), (min)+(size))
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
@@ -638,6 +692,7 @@ internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b);
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
#define r2f32(min, max) rng_2f32((min), (max))
#define r2f32s(min, size) r2f32((min), (min)+(size))
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
@@ -682,7 +737,7 @@ internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value);
internal U64 rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value);
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
+2
View File
@@ -0,0 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+20
View File
@@ -0,0 +1,20 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_MEMORY_H
#define BASE_MEMORY_H
////////////////////////////////
//~ rjf: @per_os_impl Platform Memory Allocation
//- rjf: basic
internal void *reserve_memory(U64 size);
internal B32 commit_memory(void *ptr, U64 size);
internal void decommit_memory(void *ptr, U64 size);
internal void release_memory(void *ptr, U64 size);
//- rjf: large pages
internal void *reserve_memory_large(U64 size);
internal B32 commit_memory_large(void *ptr, U64 size);
#endif // BASE_MEMORY_H
+56
View File
@@ -0,0 +1,56 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Memory Map Functions
internal void
memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data)
{
MemoryMapRangeNode *n = push_array(arena, MemoryMapRangeNode, 1);
n->v.vaddr_range = vaddr_range;
n->v.base = data;
SLLQueuePush(map->first_range, map->last_range, n);
}
internal U64
memory_map_read(MemoryMap *map, Rng1U64 range, void *dst)
{
U64 dst_vaddr = range.min;
{
for(;;)
{
U64 start_dst_vaddr = dst_vaddr;
B32 found = 0;
for(MemoryMapRangeNode *n = map->first_range; n != 0; n = n->next)
{
if(contains_1u64(n->v.vaddr_range, dst_vaddr))
{
U64 src_off = dst_vaddr - n->v.vaddr_range.min;
U64 num_bytes_possible = n->v.vaddr_range.max - dst_vaddr;
U64 num_bytes_needed = range.max - dst_vaddr;
U64 num_bytes_to_read = Min(num_bytes_needed, num_bytes_possible);
MemoryCopy((U8 *)dst + (dst_vaddr - range.min), (U8 *)n->v.base + src_off, num_bytes_to_read);
dst_vaddr += num_bytes_to_read;
found = 1;
}
}
if(!found || start_dst_vaddr == dst_vaddr)
{
break;
}
}
}
U64 bytes_read = (dst_vaddr - range.min);
return bytes_read;
}
internal String8
memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range)
{
String8 result = {0};
result.size = dim_1u64(range);
result.str = push_array(arena, U8, result.size);
memory_map_read(map, range, result.str);
return result;
}
+39
View File
@@ -0,0 +1,39 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_MEMORY_MAP_H
#define BASE_MEMORY_MAP_H
////////////////////////////////
//~ rjf: Memory Map Types
typedef struct MemoryMapRange MemoryMapRange;
struct MemoryMapRange
{
Rng1U64 vaddr_range;
void *base;
};
typedef struct MemoryMapRangeNode MemoryMapRangeNode;
struct MemoryMapRangeNode
{
MemoryMapRangeNode *next;
MemoryMapRange v;
};
typedef struct MemoryMap MemoryMap;
struct MemoryMap
{
MemoryMapRangeNode *first_range;
MemoryMapRangeNode *last_range;
};
////////////////////////////////
//~ rjf: Memory Map Functions
internal void memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data);
internal U64 memory_map_read(MemoryMap *map, Rng1U64 range, void *dst);
#define memory_map_read_struct(map, vaddr, ptr) memory_map_read((map), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
internal String8 memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range);
#endif // BASE_MEMORY_MAP_H
+115
View File
@@ -0,0 +1,115 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Handle Type Functions
internal Process
process_zero(void)
{
Process p = {0};
return p;
}
internal B32
process_match(Process a, Process b)
{
B32 result = MemoryMatchStruct(&a, &b);
return result;
}
internal void
process_list_push(Arena *arena, ProcessList *list, Process p)
{
ProcessNode *n = push_array(arena, ProcessNode, 1);
SLLQueuePush(list->first, list->last, n);
n->v = p;
list->count += 1;
}
////////////////////////////////
//~ rjf: Process Launcher Helpers
internal Process
launch_cmd_line(String8 string)
{
Temp scratch = scratch_begin(0, 0);
U8 split_chars[] = {' '};
String8List parts = str8_split(scratch.arena, string, split_chars, ArrayCount(split_chars), 0);
Process process = {0};
if(parts.node_count != 0)
{
// rjf: unpack exe part
String8 exe = parts.first->string;
String8 exe_folder = str8_chop_last_slash(exe);
if(exe_folder.size == 0)
{
exe_folder = get_current_path(scratch.arena);
}
// rjf: find stdout delimiter
String8Node *stdout_delimiter_n = 0;
for(String8Node *n = parts.first; n != 0; n = n->next)
{
if(str8_match(n->string, str8_lit(">"), 0))
{
stdout_delimiter_n = n;
break;
}
}
// rjf: read stdout path
String8 stdout_path = {0};
if(stdout_delimiter_n && stdout_delimiter_n->next)
{
stdout_path = stdout_delimiter_n->next->string;
}
// rjf: open stdout handle
File stdout_handle = {0};
if(stdout_path.size != 0)
{
File file = file_open(AccessFlag_Write|AccessFlag_Read, stdout_path);
file_close(file);
stdout_handle = file_open(AccessFlag_Write|AccessFlag_Append|AccessFlag_ShareRead|AccessFlag_ShareWrite|AccessFlag_Inherited, stdout_path);
}
// rjf: form command line
String8List cmdline = {0};
for(String8Node *n = parts.first; n != stdout_delimiter_n && n != 0; n = n->next)
{
str8_list_push(scratch.arena, &cmdline, n->string);
}
// rjf: launch
ProcessLaunchParams params = {0};
params.cmd_line = cmdline;
params.path = exe_folder;
params.inherit_env = 1;
params.stdout_file = stdout_handle;
process = process_launch(&params);
// rjf: close stdout handle
{
if(stdout_path.size != 0)
{
file_close(stdout_handle);
}
}
}
scratch_end(scratch);
return process;
}
internal Process
launch_cmd_linef(char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = str8fv(scratch.arena, fmt, args);
Process result = launch_cmd_line(string);
va_end(args);
scratch_end(scratch);
return result;
}
+91
View File
@@ -0,0 +1,91 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_PROCESSES_H
#define BASE_PROCESSES_H
typedef struct ProcessInfo ProcessInfo;
struct ProcessInfo
{
U32 pid;
B32 large_pages_allowed;
String8 binary_file_path;
String8 binary_path;
String8 initial_path;
String8 user_program_config_data_path;
String8 user_program_cache_data_path;
String8 user_program_logs_data_path;
String8List module_load_paths;
String8List environment;
};
typedef struct Process Process;
struct Process
{
U64 u64[1];
};
typedef struct ProcessNode ProcessNode;
struct ProcessNode
{
ProcessNode *next;
Process v;
};
typedef struct ProcessList ProcessList;
struct ProcessList
{
ProcessNode *first;
ProcessNode *last;
U64 count;
};
typedef struct ProcessLaunchParams ProcessLaunchParams;
struct ProcessLaunchParams
{
String8List cmd_line;
String8 path;
String8List env;
B32 inherit_env;
B32 debug_subprocesses;
B32 consoleless;
File stdout_file;
File stderr_file;
File stdin_file;
};
////////////////////////////////
//~ rjf: Handle Type Functions
internal Process process_zero(void);
internal B32 process_match(Process a, Process b);
internal void process_list_push(Arena *arena, ProcessList *list, Process p);
////////////////////////////////
//~ rjf: Process Launcher Helpers
internal Process launch_cmd_line(String8 string);
internal Process launch_cmd_linef(char *fmt, ...);
////////////////////////////////
//~ rjf: @per_os_impl Aborting
internal void abort_self(U64 exit_code);
////////////////////////////////
//~ rjf: @per_os_impl Process Info
internal ProcessInfo *get_process_info(void);
internal String8 get_current_path(Arena *arena);
internal U32 get_process_start_time_unix(void);
////////////////////////////////
//~ rjf: @per_os_impl Child Processes
internal Process process_launch(ProcessLaunchParams *params);
internal U64 pid_from_process(Process process);
internal B32 process_join(Process process, U64 endt_us, U64 *exit_code_out);
internal void process_detach(Process process);
internal B32 process_kill(Process process);
#endif // BASE_PROCESSES_H
+1 -1
View File
@@ -24,7 +24,7 @@ spall_begin(char *fmt, ...)
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, os_now_microseconds(), spall_tid, spall_pid);
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, now_time_us(), spall_tid, spall_pid);
va_end(args);
scratch_end(scratch);
}
+1 -1
View File
@@ -79,7 +79,7 @@ thread_static U32 spall_pid = 0;
internal inline void spall_begin(char *fmt, ...);
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
# define ProfBeginDynamic(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, os_now_microseconds(), spall_tid, spall_pid)), 0 : 0)
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, now_time_us(), spall_tid, spall_pid)), 0 : 0)
# define ProfTick(...)
# define ProfIsCapturing(...) (!!spall_capturing)
# define ProfBeginCapture(...) (spall_capturing = 1)
+139
View File
@@ -0,0 +1,139 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Ring Functions
internal Ring *
make_ring(Arena *arena, U64 size)
{
Ring *ring = push_array(arena, Ring, 1);
ring->size = size;
ring->base = push_array(arena, U8, ring->size);
return ring;
}
internal B32
ring_try_write(Ring *ring, U64 size, void *ptr)
{
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
U64 bytes_available = ring->size - bytes_unconsumed;
B32 result = 0;
if(bytes_available >= size)
{
result = 1;
ring->write_pos += wrapped_write(ring->base, ring->size, ring->write_pos, ptr, size);
}
return result;
}
internal B32
ring_try_read(Ring *ring, U64 size, void *ptr)
{
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
B32 result = 0;
if(bytes_unconsumed >= size)
{
result = 1;
ring->read_pos += wrapped_read(ring->base, ring->size, ring->read_pos, ptr, size);
}
return result;
}
////////////////////////////////
//~ rjf: Guarded Ring Functions
internal GuardedRing *
guarded_ring_alloc(Arena *arena, U64 size)
{
ProfBeginFunction();
GuardedRing *gr = push_array(arena, GuardedRing, 1);
gr->ring = make_ring(arena, size);
gr->mutex = mutex_alloc();
gr->cv = cond_var_alloc();
ProfEnd();
return gr;
}
internal void
guarded_ring_release(GuardedRing *ring)
{
ProfBeginFunction();
mutex_release(ring->mutex);
cond_var_release(ring->cv);
ProfEnd();
}
internal RingGuard
guarded_ring_open(GuardedRing *ring)
{
RingGuard guard = {ring};
mutex_take(ring->mutex);
return guard;
}
internal void
guarded_ring_close(RingGuard *guard)
{
mutex_drop(guard->r->mutex);
}
internal B32
guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr)
{
B32 result = ring_try_write(guard->r->ring, size, ptr);
if(result)
{
cond_var_broadcast(guard->r->cv);
}
return result;
}
internal B32
guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr)
{
B32 result = ring_try_read(guard->r->ring, size, ptr);
if(result)
{
cond_var_broadcast(guard->r->cv);
}
return result;
}
internal B32
guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
{
B32 write_good = 0;
for(;!write_good;)
{
write_good = guarded_ring_try_write(guard, size, ptr);
if(now_time_us() >= endt_us)
{
break;
}
if(!write_good)
{
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
}
}
return write_good;
}
internal B32
guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
{
B32 read_good = 0;
for(;!read_good;)
{
read_good = guarded_ring_try_read(guard, size, ptr);
if(now_time_us() >= endt_us)
{
break;
}
if(!read_good)
{
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
}
}
return read_good;
}
+56
View File
@@ -0,0 +1,56 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_RING_H
#define BASE_RING_H
typedef struct Ring Ring;
struct Ring
{
U8 *base;
U64 size;
U64 write_pos;
U64 read_pos;
};
typedef struct GuardedRing GuardedRing;
struct GuardedRing
{
Ring *ring;
Mutex mutex;
CondVar cv;
};
typedef struct RingGuard RingGuard;
struct RingGuard
{
GuardedRing *r;
};
////////////////////////////////
//~ rjf: Ring Functions
internal Ring *make_ring(Arena *arena, U64 size);
internal B32 ring_try_write(Ring *ring, U64 size, void *ptr);
internal B32 ring_try_read(Ring *ring, U64 size, void *ptr);
#define ring_try_write_struct(ring, ptr) ring_try_write((ring), sizeof(*(ptr)), (ptr))
#define ring_try_read_struct(ring, ptr) ring_try_read((ring), sizeof(*(ptr)), (ptr))
////////////////////////////////
//~ rjf: Guarded Ring Functions
internal GuardedRing *guarded_ring_alloc(Arena *arena, U64 size);
internal void guarded_ring_release(GuardedRing *ring);
internal RingGuard guarded_ring_open(GuardedRing *ring);
internal void guarded_ring_close(RingGuard *guard);
internal B32 guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr);
internal B32 guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr);
#define guarded_ring_try_write_struct(ring, ptr) guarded_ring_try_write((ring), sizeof(*(ptr)), (ptr))
#define guarded_ring_try_read_struct(ring, ptr) guarded_ring_try_read((ring), sizeof(*(ptr)), (ptr))
internal B32 guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
internal B32 guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
#define guarded_ring_write_struct_or_wait(ring, ptr, endt_us) guarded_ring_write_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
#define guarded_ring_read_struct_or_wait(ring, ptr, endt_us) guarded_ring_read_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
#define guarded_ring_write_string_or_wait(ring, string, endt_us) guarded_ring_write_or_wait((ring), (string).size, (string).str, (endt_us))
#endif // BASE_RING_H
+2
View File
@@ -0,0 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_SHARED_MEMORY_H
#define BASE_SHARED_MEMORY_H
typedef struct SharedMemory SharedMemory;
struct SharedMemory
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: @per_os_impl Shared Memory
internal SharedMemory shared_memory_alloc(U64 size, String8 name);
internal SharedMemory shared_memory_open(String8 name);
internal void shared_memory_close(SharedMemory handle);
internal void * shared_memory_view_open(SharedMemory handle, Rng1U64 range);
internal void shared_memory_view_close(SharedMemory handle, void *ptr, Rng1U64 range);
#endif // BASE_SHARED_MEMORY_H
+498 -146
View File
@@ -1,6 +1,14 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
#ifndef MEM_STATIC
# define MEM_STATIC
# define MEM_API ASAN_NO_ADDR static inline
# include "third_party/martins_memfun/memfun.h"
#endif
////////////////////////////////
//~ rjf: Character Classification & Conversion Functions
@@ -211,12 +219,9 @@ str32_cstring(U32 *c)
internal String8
str8_cstring_capped(void *cstr, void *cap)
{
char *ptr = (char *)cstr;
char *opl = (char *)cap;
for (;ptr < opl && *ptr != 0; ptr += 1);
U64 size = (U64)(ptr - (char *)cstr);
String8 result = str8((U8*)cstr, size);
return result;
U64 cap_size = (U64)((U8 *)cap - (U8 *)cstr);
U64 size = MemFind(cstr, cap_size, 0);
return str8(cstr, size);
}
internal String16
@@ -230,24 +235,6 @@ str16_cstring_capped(void *cstr, void *cap)
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;
}
////////////////////////////////
//~ rjf: String Stylization
@@ -293,7 +280,11 @@ str8_match(String8 a, String8 b, StringMatchFlags flags)
B32 result = 0;
if(a.size == b.size && flags == 0)
{
result = MemoryMatch(a.str, b.str, b.size);
result = MemIsEqual(a.str, b.str, b.size);
}
else if (a.size == b.size && flags == StringMatchFlag_CaseInsensitive)
{
result = MemCompareI(a.str, b.str, a.size) == 0;
}
else if(a.size == b.size || (flags & StringMatchFlag_RightSideSloppy))
{
@@ -325,6 +316,88 @@ str8_match(String8 a, String8 b, StringMatchFlags flags)
return result;
}
internal B32
str8_char_match(U8 a, U8 b, StringMatchFlags flags)
{
U8 at = a;
U8 bt = b;
if (flags & StringMatchFlag_CaseInsensitive) {
at = upper_from_char(at);
bt = upper_from_char(bt);
}
if (flags & StringMatchFlag_SlashInsensitive) {
if (at == '\\') { at = '/'; }
if (bt == '\\') { bt = '/'; }
}
return (at == bt);
}
internal B32
str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags)
{
B32 matched = 0;
U64 pattern_cursor = 0;
U64 string_cursor = 0;
U64 pattern_start = max_U64;
U64 string_start = 0;
for (;;) {
if (pattern_cursor == pattern.size) {
if (string_cursor == string.size || (flags & StringMatchFlag_RightSideSloppy)) {
matched = 1;
break;
}
}
if (string_cursor == string.size) {
while (pattern_cursor < pattern.size && pattern.str[pattern_cursor] == '*') {
pattern_cursor += 1;
}
matched = (pattern_cursor == pattern.size);
break;
}
if (pattern_cursor < pattern.size && pattern.str[pattern_cursor] == '*') {
pattern_start = pattern_cursor;
string_start = string_cursor;
pattern_cursor += 1;
continue;
}
if (pattern_cursor < pattern.size && (pattern.str[pattern_cursor] == '?' || str8_char_match(string.str[string_cursor], pattern.str[pattern_cursor], flags))) {
string_cursor += 1;
pattern_cursor += 1;
continue;
}
if (pattern_start != max_U64) {
pattern_cursor = pattern_start + 1;
string_start += 1;
string_cursor = string_start;
continue;
}
break;
}
return matched;
}
internal B32
str8_starts_with(String8 string, String8 expected_prefix)
{
return str8_match(str8_prefix(string, expected_prefix.size), expected_prefix, 0);
}
internal B32
str8_starts_withi(String8 string, String8 expected_prefix)
{
return str8_match(str8_prefix(string, expected_prefix.size), expected_prefix, StringMatchFlag_CaseInsensitive);
}
internal U64
str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
{
@@ -341,6 +414,10 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
{
needle_first_char_adjusted = upper_from_char(needle_first_char_adjusted);
}
if(adjusted_flags & StringMatchFlag_SlashInsensitive)
{
needle_first_char_adjusted = correct_slash_from_char(needle_first_char_adjusted);
}
for(;p < stop_p; p += 1)
{
U8 haystack_char_adjusted = *p;
@@ -348,6 +425,10 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
{
haystack_char_adjusted = upper_from_char(haystack_char_adjusted);
}
if(adjusted_flags & StringMatchFlag_SlashInsensitive)
{
haystack_char_adjusted = correct_slash_from_char(haystack_char_adjusted);
}
if(haystack_char_adjusted == needle_first_char_adjusted)
{
if(str8_match(str8_range(p + 1, string_opl), needle_tail, adjusted_flags))
@@ -454,6 +535,18 @@ str8_chop(String8 str, U64 amt)
return str;
}
internal String8
str8_chop_line(String8 *str)
{
U64 new_line_pos = str8_find_needle(*str, 0, str8_lit("\n"), 0);
String8 line = str8_prefix(*str, new_line_pos);
if (str8_ends_with(line, str8_lit("\r"), 0)) {
line = str8_chop(line, 1);
}
*str = str8_skip(*str, new_line_pos + 1);
return line;
}
internal String8
str8_skip_chop_whitespace(String8 string)
{
@@ -616,6 +709,22 @@ str8_is_integer(String8 string, U32 radix)
return result;
}
internal B32
str8_is_integer_signed(String8 string, U32 radix)
{
B32 result = 0;
String8 sign = str8_prefix(string, 1);
if(str8_match(sign, str8_lit("-"), 0))
{
result = str8_is_integer(str8_skip(string, 1), radix);
}
else
{
result = str8_is_integer(string, radix);
}
return result;
}
internal U64
u64_from_str8(String8 string, U32 radix)
{
@@ -715,7 +824,7 @@ str8_from_memory_size(Arena *arena, U64 size)
{
if(size < KB(1))
{
result = push_str8f(arena, "%llu Bytes", size);
result = push_str8f(arena, "%llu byte%s", size, size == 1 ? "" : "s");
}
else if(size < MB(1))
{
@@ -1062,26 +1171,19 @@ str8_list_concat_in_place(String8List *list, String8List *to_push)
}
internal String8Node*
str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){
String8Node *node = push_array_no_zero(arena, String8Node, 1);
U64 new_size = list->total_size + min;
U64 increase_size = 0;
if (align > 1){
// NOTE(allen): assert is power of 2
Assert(((align - 1) & align) == 0);
U64 mask = align - 1;
new_size += mask;
new_size &= (~mask);
increase_size = new_size - list->total_size;
str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align)
{
read_only local_persist U8 zeroes[64] = {0};
Assert(IsPow2OrZero(align));
U64 pad = Max(min, AlignPadPow2(list->total_size, align));
if(pad < sizeof(zeroes))
{
return str8_list_push(arena, list, str8(zeroes, pad));
}
else
{
return str8_list_push(arena, list, str8(push_array(arena, U8, pad), pad));
}
local_persist const U8 zeroes_buffer[64] = {0};
Assert(increase_size <= ArrayCount(zeroes_buffer));
SLLQueuePush(list->first, list->last, node);
list->node_count += 1;
list->total_size = new_size;
node->string.str = (U8*)zeroes_buffer;
node->string.size = increase_size;
return(node);
}
internal String8Node*
@@ -1106,6 +1208,21 @@ str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...)
return result;
}
internal String8Node*
str8_list_pop_front(String8List *list)
{
String8Node *node = 0;
if(list->node_count)
{
node = list->first;
Assert(list->total_size >= list->first->string.size);
list->node_count -= 1;
list->total_size -= list->first->string.size;
SLLQueuePop(list->first, list->last);
}
return node;
}
internal String8List
str8_list_copy(Arena *arena, String8List *list)
{
@@ -1119,6 +1236,42 @@ str8_list_copy(Arena *arena, String8List *list)
return result;
}
internal String8List
str8_list_substr(Arena *arena, String8List list, Rng1U64 range)
{
String8List result = {0};
String8Node *n = list.first;
U64 front_min = 0;
{
U64 cursor = 0;
for (; n != 0; cursor += n->string.size, n = n->next) {
if (cursor + n->string.size > range.min) {
front_min = range.min - cursor;
break;
}
}
}
if (front_min > 0) {
U64 front_max = front_min + Min(dim_1u64(range), n->string.size);
str8_list_push(arena, &result, str8_substr(n->string, r1u64(front_min, front_max)));
n = n->next;
}
for (; n != 0; n = n->next) {
if (result.total_size >= dim_1u64(range)) {
break;
}
U64 copy_max = dim_1u64(range) - result.total_size;
U64 copy_size = Min(copy_max, n->string.size);
str8_list_push(arena, &result, str8_substr(n->string, r1u64(0, copy_size)));
}
return result;
}
////////////////////////////////
//~ rjf: String Splitting & Joining
@@ -1313,6 +1466,31 @@ str8_from_version(Arena *arena, U64 version)
////////////////////////////////
//~ rjf: String Path Helpers
internal String8
program_ext_postfix_from_os(OperatingSystem os, B32 require_ext)
{
String8 result = {0};
switch(os)
{
default:{}break;
case OperatingSystem_Windows:
{
result = s(".exe");
}break;
case OperatingSystem_Linux:
if(require_ext)
{
result = s(".elf");
}break;
case OperatingSystem_Mac:
if(require_ext)
{
result = s(".macho");
}break;
}
return result;
}
internal String8
str8_chop_last_slash(String8 string)
{
@@ -2222,24 +2400,35 @@ string_from_elapsed_time(Arena *arena, DateTime dt)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if(dt.year)
{
if (dt.year) {
str8_list_pushf(scratch.arena, &list, "%dy", dt.year);
str8_list_pushf(scratch.arena, &list, "%um", dt.mon);
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
}
else if(dt.mon)
{
} else if (dt.mon) {
str8_list_pushf(scratch.arena, &list, "%um", dt.mon);
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
}
else if (dt.day)
{
} else if (dt.day) {
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
}
str8_list_pushf(scratch.arena, &list, "%u:%u:%u:%u ms", dt.hour, dt.min, dt.sec, dt.msec);
StringJoin join = { str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") };
String8 result = str8_list_join(arena, &list, &join);
if (dt.hour) {
str8_list_pushf(scratch.arena, &list, "%uh %um %u.%us", dt.hour, dt.min, dt.sec, dt.msec);
} else if (dt.min) {
str8_list_pushf(scratch.arena, &list, "%um %u.%us", dt.min, dt.sec, dt.msec);
} else if (dt.sec) {
str8_list_pushf(scratch.arena, &list, "%u.%us", dt.sec, dt.msec);
} else if (dt.msec) {
str8_list_pushf(scratch.arena, &list, "%ums", dt.msec);
} else if (dt.micro_sec) {
str8_list_pushf(scratch.arena, &list, "%uus", dt.micro_sec);
}
if (list.node_count == 0) {
str8_list_pushf(scratch.arena, &list, "0");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") });
scratch_end(scratch);
return result;
}
@@ -2606,7 +2795,8 @@ fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src)
//~ NOTE(allen): Serialization Helpers
internal void
str8_serial_begin(Arena *arena, String8List *srl){
str8_serial_begin(Arena *arena, String8List *srl)
{
String8Node *node = push_array(arena, String8Node, 1);
node->string.str = push_array_no_zero(arena, U8, 0);
srl->first = srl->last = node;
@@ -2615,7 +2805,8 @@ str8_serial_begin(Arena *arena, String8List *srl){
}
internal String8
str8_serial_end(Arena *arena, String8List *srl){
str8_serial_end(Arena *arena, String8List *srl)
{
U64 size = srl->total_size;
U8 *out = push_array_no_zero(arena, U8, size);
str8_serial_write_to_dst(srl, out);
@@ -2624,19 +2815,20 @@ str8_serial_end(Arena *arena, String8List *srl){
}
internal void
str8_serial_write_to_dst(String8List *srl, void *out){
str8_serial_write_to_dst(String8List *srl, void *out)
{
U8 *ptr = (U8*)out;
for (String8Node *node = srl->first;
node != 0;
node = node->next){
U64 size = node->string.size;
MemoryCopy(ptr, node->string.str, size);
for EachNode(n, String8Node, srl->first)
{
U64 size = n->string.size;
MemoryCopy(ptr, n->string.str, size);
ptr += size;
}
}
internal U64
str8_serial_push_align(Arena *arena, String8List *srl, U64 align){
str8_serial_push_align(Arena *arena, String8List *srl, U64 align)
{
Assert(IsPow2(align));
U64 pos = srl->total_size;
@@ -2648,11 +2840,13 @@ str8_serial_push_align(Arena *arena, String8List *srl, U64 align){
U8 *buf = push_array(arena, U8, size);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
if(str->str + str->size == buf)
{
srl->last->string.size += size;
srl->total_size += size;
}
else{
else
{
str8_list_push(arena, srl, str8(buf, size));
}
}
@@ -2665,13 +2859,15 @@ str8_serial_push_size(Arena *arena, String8List *srl, U64 size)
void *result = 0;
if(size != 0)
{
U8 *buf = push_array_no_zero(arena, U8, size);
U8 *buf = push_array(arena, U8, size);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
if(str->str + str->size == buf)
{
srl->last->string.size += size;
srl->total_size += size;
}
else{
else
{
str8_list_push(arena, srl, str8(buf, size));
}
result = buf;
@@ -2680,7 +2876,8 @@ str8_serial_push_size(Arena *arena, String8List *srl, U64 size)
}
internal void *
str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size){
str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size)
{
void *result = str8_serial_push_size(arena, srl, size);
if(result != 0)
{
@@ -2690,61 +2887,50 @@ str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size){
}
internal void
str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first){
for (String8Node *node = first;
node != 0;
node = node->next){
str8_serial_push_data(arena, srl, node->string.str, node->string.size);
str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first)
{
for EachNode(n, String8Node, first)
{
str8_serial_push_data(arena, srl, n->string.str, n->string.size);
}
}
internal void
str8_serial_push_u64(Arena *arena, String8List *srl, U64 x){
U8 *buf = push_array_no_zero(arena, U8, 8);
MemoryCopy(buf, &x, 8);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
srl->last->string.size += 8;
srl->total_size += 8;
}
else{
str8_list_push(arena, srl, str8(buf, 8));
}
internal void *
str8_serial_push_u64(Arena *arena, String8List *srl, U64 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_u32(Arena *arena, String8List *srl, U32 x){
U8 *buf = push_array_no_zero(arena, U8, 4);
MemoryCopy(buf, &x, 4);
String8 *str = &srl->last->string;
if (str->str + str->size == buf){
srl->last->string.size += 4;
srl->total_size += 4;
}
else{
str8_list_push(arena, srl, str8(buf, 4));
}
internal void *
str8_serial_push_u32(Arena *arena, String8List *srl, U32 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_u16(Arena *arena, String8List *srl, U16 x){
str8_serial_push_data(arena, srl, &x, sizeof(x));
internal void *
str8_serial_push_u16(Arena *arena, String8List *srl, U16 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_u8(Arena *arena, String8List *srl, U8 x){
str8_serial_push_data(arena, srl, &x, sizeof(x));
internal void *
str8_serial_push_u8(Arena *arena, String8List *srl, U8 x)
{
return str8_serial_push_data(arena, srl, &x, sizeof(x));
}
internal void
str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str){
str8_serial_push_data(arena, srl, str.str, str.size);
internal void *
str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str)
{
void *ptr = str8_serial_push_data(arena, srl, str.str, str.size);
str8_serial_push_u8(arena, srl, 0);
return ptr;
}
internal void
str8_serial_push_string(Arena *arena, String8List *srl, String8 str){
str8_serial_push_data(arena, srl, str.str, str.size);
internal void *
str8_serial_push_string(Arena *arena, String8List *srl, String8 str)
{
return str8_serial_push_data(arena, srl, str.str, str.size);
}
////////////////////////////////
@@ -2822,76 +3008,242 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out)
return block_out->size;
}
internal U64
str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte = 0;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
internal U64
str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
{
value |= -(S64)(1ull << shift);
}
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
////////////////////////////////
internal int
force_inline int
str8_compar(String8 a, String8 b, B32 ignore_case)
{
int cmp = 0;
U64 size = Min(a.size, b.size);
if (ignore_case) {
for (U64 i = 0; i < size; ++i) {
U8 la = lower_from_char(a.str[i]);
U8 lb = lower_from_char(b.str[i]);
if (la < lb) {
cmp = -1;
break;
} else if (la > lb) {
cmp = +1;
break;
}
}
} else {
for (U64 i = 0; i < size; ++i) {
if (a.str[i] < b.str[i]) {
cmp = -1;
break;
} else if (a.str[i] > b.str[i]) {
cmp = +1;
break;
}
}
}
int cmp = ignore_case ? MemCompareI(a.str, b.str, size) : MemCompare(a.str, b.str, size);
// normalize compar result
cmp = cmp > 0 ? 1 : cmp < 0 ? -1 : 0;
if (cmp == 0) {
// shorter prefix must precede longer prefixes
if (a.size > b.size) {
cmp = +1;
} else if (b.size > a.size) {
cmp = -1;
}
if (cmp == 0)
{
cmp = a.size < b.size ? -1 :
a.size > b.size ? +1 : 0;
}
return cmp;
}
internal int str8_compar_ignore_case(const void *a, const void *b)
force_inline int
str8_compar_ignore_case(const void *a, const void *b)
{
return str8_compar(*(String8*)a, *(String8*)b, 1);
}
internal int
force_inline int
str8_compar_case_sensitive(const void *a, const void *b)
{
return str8_compar(*(String8*)a, *(String8*)b, 0);
}
internal int
force_inline int
str8_is_before_case_sensitive(const void *a, const void *b)
{
int cmp = str8_compar_case_sensitive(a, b);
return cmp < 0;
}
////////////////////////////////
// string buffer
internal B32
str8_buffer_skip(String8Node *buf, U64 *pos, U64 skip)
{
S64 to_skip;
for (to_skip = skip; to_skip > 0;) {
if (buf == 0) { break; }
U64 left = Min(to_skip, buf->string.size - *pos);
*pos += left;
if (*pos == buf->string.size) {
if (buf->next) { *buf = *buf->next; }
else { *buf = (String8Node){0}; buf = 0; }
*pos = 0;
}
to_skip -= (S64)left;
}
Assert(to_skip == 0);
return (to_skip == 0);
}
internal U64
str8_buffer_read(String8Node *buf, U64 *pos, U64 read_size, void *out)
{
U64 cursor = 0;
for (; cursor < read_size ;) {
if (buf == 0) { break; }
U64 copy_size = Min(read_size - cursor, (buf->string.size - *pos));
void *dst = (U8 *)out + cursor;
void *src = buf->string.str + *pos;
MemoryCopy(dst, src, copy_size);
*pos += copy_size;
cursor += copy_size;
if (*pos >= buf->string.size) {
if (buf->next) { *buf = *buf->next; }
else { *buf = (String8Node){0}; buf = 0; }
*pos = 0;
}
}
return cursor;
}
internal U64
str8_buffer_peek(String8Node *buf, U64 *pos, U64 read_size, void *out)
{
String8Node buf_copy = *buf;
U64 pos_copy = *pos;
return str8_buffer_read(&buf_copy, &pos_copy, read_size, out);
}
internal U64
str8_buffer_write(String8Node *buf, U64 *pos, String8 data)
{
U64 copy_size = 0;
if (buf) {
for (copy_size = 0; copy_size < data.size; ) {
U64 data_size = data.size - copy_size;
U64 available_size = buf->string.size - *pos;
U64 to_copy = Min(available_size, data_size);
if (data.str == 0) {
MemorySet(buf->string.str + *pos, 0, to_copy);
} else {
U8 *data_ptr = data.str + copy_size;
MemoryCopy(buf->string.str + *pos, data_ptr, to_copy);
}
*pos += to_copy;
copy_size += to_copy;
if (*pos >= buf->string.size) {
if (buf->next) {
*buf = *buf->next;
*pos = 0;
} else {
break;
}
}
}
Assert(copy_size == data.size);
} else {
copy_size = data.size;
}
return copy_size;
}
internal U64
str8_buffer_write_u16(String8Node *buf, U64 *pos, U16 v)
{
return str8_buffer_write(buf, pos, str8_struct(&v));
}
internal U64
str8_buffer_write_u32(String8Node *buf, U64 *pos, U32 v)
{
return str8_buffer_write(buf, pos, str8_struct(&v));
}
internal U64
str8_buffer_write_zeroes(String8Node *buf, U64 *pos, U64 size)
{
return str8_buffer_write(buf, pos, str8(0, size));
}
internal U64
str8_buffer_write_string_list(String8Node *buf, U64 *pos, String8List list)
{
U64 copy_size = 0;
for EachNode(n, String8Node, list.first) { copy_size += str8_buffer_write(buf, pos, n->string); }
return copy_size;
}
////////////////////////////////
//~ rjf: Basic String Hashes
#pragma push_macro("__cpuid")
#undef __cpuid
#if !defined(XXH_IMPLEMENTATION)
# define XXH_INLINE_ALL
# define XXH_IMPLEMENTATION
# define XXH_STATIC_LINKING_ONLY
# include "third_party/xxHash/xxhash.h"
#endif
#pragma pop_macro("__cpuid")
internal U64
u64_hash_from_seed_str8(U64 seed, String8 string)
+33 -8
View File
@@ -160,8 +160,11 @@ internal U64 cstring32_length(U32 *c);
////////////////////////////////
//~ rjf: String Constructors
#define s(S) str8_lit(S)
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
#define str8_lit_cstr(S) str8((U8*)(S), sizeof(S))
#define str8_varg(S) (int)((S).size), ((S).str)
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
@@ -182,7 +185,6 @@ internal String16 str16_cstring(U16 *c);
internal String32 str32_cstring(U32 *c);
internal String8 str8_cstring_capped(void *cstr, void *cap);
internal String16 str16_cstring_capped(void *cstr, void *cap);
internal String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
////////////////////////////////
//~ rjf: String Stylization
@@ -197,6 +199,10 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
#define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags))
#define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags))
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
#define str8_matchi(a, b) str8_match(a, b, StringMatchFlag_CaseInsensitive)
internal B32 str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags);
internal B32 str8_starts_with(String8 string, String8 expected_prefix);
internal B32 str8_starts_withi(String8 string, String8 expected_prefix);
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_is_before(String8 a, String8 b);
@@ -210,6 +216,7 @@ internal String8 str8_prefix(String8 str, U64 size);
internal String8 str8_skip(String8 str, U64 amt);
internal String8 str8_postfix(String8 str, U64 size);
internal String8 str8_chop(String8 str, U64 amt);
internal String8 str8_chop_line(String8 *str);
internal String8 str8_skip_chop_whitespace(String8 string);
internal String8 str8_skip_chop_slashes(String8 string);
@@ -233,6 +240,7 @@ internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unn
//- rjf: string -> integer
internal S64 sign_from_str8(String8 string, String8 *string_tail);
internal B32 str8_is_integer(String8 string, U32 radix);
internal B32 str8_is_integer_signed(String8 string, U32 radix);
internal U64 u64_from_str8(String8 string, U32 radix);
internal S64 s64_from_str8(String8 string, U32 radix);
internal U32 u32_from_str8(String8 string, U32 radix);
@@ -266,7 +274,9 @@ internal void str8_list_concat_in_place(String8List *list, String8List *
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
internal String8Node* str8_list_pop_front(String8List *list);
internal String8List str8_list_copy(Arena *arena, String8List *list);
internal String8List str8_list_substr(Arena *arena, String8List list, Rng1U64 range);
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
////////////////////////////////
@@ -312,6 +322,8 @@ g_path_style_map[] =
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
};
internal String8 program_ext_postfix_from_os(OperatingSystem os, B32 require_ext);
internal String8 str8_chop_last_slash(String8 string);
internal String8 str8_skip_last_slash(String8 string);
internal String8 str8_chop_last_dot(String8 string);
@@ -422,13 +434,12 @@ internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 alig
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
internal void * str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
internal void * str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
internal void * str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
internal void * str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
internal void * str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
internal void * str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
@@ -443,6 +454,20 @@ internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 of
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
////////////////////////////////
//~ string buffer
internal B32 str8_buffer_skip(String8Node *buf, U64 *pos, U64 skip);
internal U64 str8_buffer_read(String8Node *buf, U64 *pos, U64 read_size, void *out);
internal U64 str8_buffer_peek(String8Node *buf, U64 *pos, U64 read_size, void *out);
internal U64 str8_buffer_write(String8Node *buf, U64 *pos, String8 data);
internal U64 str8_buffer_write_u16(String8Node *buf, U64 *pos, U16 v);
internal U64 str8_buffer_write_u32(String8Node *buf, U64 *pos, U32 v);
internal U64 str8_buffer_write_zeroes(String8Node *buf, U64 *pos, U64 size);
internal U64 str8_buffer_write_string_list(String8Node *buf, U64 *pos, String8List list);
////////////////////////////////
//~ rjf: Basic String Hashes
+2
View File
@@ -0,0 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_SYSTEM_H
#define BASE_SYSTEM_H
typedef struct SystemInfo SystemInfo;
struct SystemInfo
{
U32 logical_processor_count;
U64 page_size;
U64 large_page_size;
U64 allocation_granularity;
String8 machine_name;
};
////////////////////////////////
//~ rjf: @per_os_impl System Info
internal SystemInfo *get_system_info(void);
#endif // BASE_SYSTEM_H
+51
View File
@@ -0,0 +1,51 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if BUILD_TESTS
internal String8
test_build_exe_path(Arena *arena, String8 name)
{
String8 folder = get_process_info()->binary_path;
String8 path = str8f(arena, "%S/%S%S", folder, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 0));
return path;
}
internal String8
test_input_path(Arena *arena, TestCtx *ctx, String8 name)
{
String8 path = str8f(arena, "%S/%S", ctx->input_data_path, name);
return path;
}
internal String8
test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name)
{
String8 path = str8f(arena, "%S/%S%S", ctx->input_data_path, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 1));
return path;
}
internal String8
test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name)
{
String8 path = str8f(arena, "%S/%S", ctx->exemplars_path, name);
return path;
}
internal void
base_register_test(char *func_name_cstr, TestFunctionType *fn, char *file_path_cstr, int line, int skip)
{
String8 file_path = str8_cstring(file_path_cstr);
U64 src_min = str8_find_needle(file_path, 0, s("src/"), StringMatchFlag_SlashInsensitive);
U64 src_max = src_min + str8_lit("src/").size;
U64 layer_slash_max = str8_find_needle(file_path, src_max, s("/"), StringMatchFlag_SlashInsensitive);
TestInfo *t = &test_infos[test_infos_count++];
t->layer = str8_substr(file_path, r1u64(src_max, layer_slash_max));
t->label = str8_cstring(func_name_cstr);
t->decl_line = line;
t->skip = skip;
t->test_fn = fn;
}
#endif
+101
View File
@@ -0,0 +1,101 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_TEST_H
#define BASE_TEST_H
typedef enum TestStatus
{
TestStatus_Fail,
TestStatus_Crash,
TestStatus_Pass,
TestStatus_Skip,
TestStatus_COUNT
}
TestStatus;
typedef struct TestResult TestResult;
struct TestResult
{
TestStatus status;
char *fail_file;
int fail_line;
char *fail_cond;
};
typedef struct TestCtx TestCtx;
struct TestCtx
{
CmdLine *cmdline;
String8 exemplars_path;
String8 artifacts_path;
String8 input_data_path;
TestResult *result_out;
String8List *test_out;
};
#define TEST_FUNCTION_SIG(name) void name(Arena *arena, TestCtx *ctx)
#define TEST_FUNCTION_DEF(name) TEST_FUNCTION_SIG(test__##name)
typedef TEST_FUNCTION_SIG(TestFunctionType);
typedef struct TestInfo TestInfo;
struct TestInfo
{
String8 layer;
String8 label;
S64 decl_line;
B32 skip;
TestFunctionType *test_fn;
};
#if BUILD_TESTS
// alloc storage for the tests
global U16 test_infos_count = 0;
global TestInfo test_infos[0xffff] = {0};
internal String8 test_build_exe_path(Arena *arena, String8 name);
internal String8 test_input_path(Arena *arena, TestCtx *ctx, String8 name);
internal String8 test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name);
internal String8 test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name);
internal void base_register_test(char *func_name, TestFunctionType *fn, char *file_path, int line, int skip);
#define AddTest(name, file_path, line, skip_, ...) \
TEST_FUNCTION_DEF(name); \
__VA_ARGS__ void add_test__##name(void) { base_register_test(Stringify(name), test__##name, file_path, line, skip_); }
# if COMPILER_MSVC
# pragma section(".CRT$XCU", read)
# define DeclareTest(name, skip) \
/* register test */ AddTest(name, __FILE__, __LINE__, (skip)) \
/* alloc function pointer */ __declspec(allocate(".CRT$XCU")) void (*add_test_ptr__##name)(void) = add_test__##name; \
/* do not GC test caller */ __pragma(comment(linker, "/include:" Stringify(add_test_ptr__##name)))
# elif COMPILER_GCC || COMPILER_CLANG
// clang and gcc allocate memory for the function pointer automatically
# define DeclareTest(name, skip) AddTest(name, __FILE__, __LINE__, (skip), __attribute__((constructor)))
# else
# error DeclareTest not defined for this compiler.
# endif
#else
# define DeclareTest(name, skip)
#endif
#define Test(name) DeclareTest(name, 0) TEST_FUNCTION_DEF(name)
#define SkippedTest(name) DeclareTest(name, 1) TEST_FUNCTION_DEF(name)
#define TestCheck(c) do { if (!(c)) { \
/* record failed check */ ctx->result_out[0] = (TestResult){ .fail_file = __FILE__, .fail_line = __LINE__, .fail_cond = Stringify(c) }; \
/* under debugger? -> trap */ if(debugger_is_attached()) { Trap(); } \
/* exit test */ return; \
} } while(0)
#define TestSkip() do { \
ctx->result_out[0] = (TestResult){ .status = TestStatus_Skip }; \
return; \
} while(0)
// test log
#define test_out(string) str8_list_push(arena, ctx->test_out, (string))
#define test_outf(...) str8_list_pushf(arena, ctx->test_out, __VA_ARGS__)
#endif // BASE_TEST_H
+17 -8
View File
@@ -17,10 +17,19 @@ C_LINKAGE thread_static TCTX *tctx_thread_local = 0;
internal TCTX *
tctx_alloc(void)
{
Arena *arena = arena_alloc();
TCTX *tctx = push_array(arena, TCTX, 1);
tctx->arenas[0] = arena;
tctx->arenas[1] = arena_alloc();
#if PROFILE_TELEMETRY
thread_static static char name[2][1024];
raddbg_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", tid());
raddbg_snprintf(name[1], sizeof(name[1]), "Scratch/1[TID:%u]", tid());
Arena *arena_0 = arena_alloc(.name = name[0]);
Arena *arena_1 = arena_alloc(.name = name[1]);
#else
Arena *arena_0 = arena_alloc();
Arena *arena_1 = arena_alloc();
#endif
TCTX *tctx = push_array(arena_0, TCTX, 1);
tctx->arenas[0] = arena_0;
tctx->arenas[1] = arena_1;
tctx->lane_ctx.lane_count = 1;
return tctx;
}
@@ -99,7 +108,7 @@ tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_sr
}
// rjf: all cases: barrier
os_barrier_wait(tctx->lane_ctx.barrier);
barrier_wait(tctx->lane_ctx.barrier);
// rjf: doing broadcast -> copy from broadcast memory on destination lanes
if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx)
@@ -110,7 +119,7 @@ tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_sr
// rjf: doing broadcast -> barrier on all lanes
if(broadcast_ptr != 0)
{
os_barrier_wait(tctx->lane_ctx.barrier);
barrier_wait(tctx->lane_ctx.barrier);
}
ProfEnd();
@@ -193,7 +202,7 @@ internal void
access_touch(Access *access, AccessPt *pt, CondVar cv)
{
ins_atomic_u64_inc_eval(&pt->access_refcount);
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, os_now_microseconds());
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, now_time_us());
ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx());
Touch *touch = tctx_thread_local->free_touch;
if(touch != 0)
@@ -219,7 +228,7 @@ access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params)
U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us);
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
B32 result = (access_refcount == 0 &&
last_time_touched_us + params->time <= os_now_microseconds() &&
last_time_touched_us + params->time <= now_time_us() &&
last_update_idx_touched + params->update_idxs <= update_tick_idx());
return result;
}
+167 -65
View File
@@ -1,70 +1,6 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Thread Functions
internal Thread
thread_launch(ThreadEntryPointFunctionType *f, void *p)
{
Thread thread = os_thread_launch(f, p);
return thread;
}
internal B32
thread_join(Thread thread, U64 endt_us)
{
B32 result = os_thread_join(thread, endt_us);
return result;
}
internal void
thread_detach(Thread thread)
{
os_thread_detach(thread);
}
////////////////////////////////
//~ rjf: Synchronization Primitive Functions
//- rjf: recursive mutexes
internal Mutex mutex_alloc(void) {return os_mutex_alloc();}
internal void mutex_release(Mutex mutex) {os_mutex_release(mutex);}
internal void mutex_take(Mutex mutex) {os_mutex_take(mutex);}
internal void mutex_drop(Mutex mutex) {os_mutex_drop(mutex);}
//- rjf: reader/writer mutexes
internal RWMutex rw_mutex_alloc(void) {return os_rw_mutex_alloc();}
internal void rw_mutex_release(RWMutex mutex) {os_rw_mutex_release(mutex);}
internal void rw_mutex_take(RWMutex mutex, B32 write_mode) {os_rw_mutex_take(mutex, write_mode);}
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode) {os_rw_mutex_drop(mutex, write_mode);}
//- rjf: condition variables
internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();}
internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);}
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);}
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) {return os_cond_var_wait_rw(cv, mutex_rw, write_mode, endt_us);}
internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);}
internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);}
//- rjf: cross-process semaphores
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name) {return os_semaphore_alloc(initial_count, max_count, name);}
internal void semaphore_release(Semaphore semaphore) {os_semaphore_release(semaphore);}
internal Semaphore semaphore_open(String8 name) {return os_semaphore_open(name);}
internal void semaphore_close(Semaphore semaphore) {os_semaphore_close(semaphore);}
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us) {return os_semaphore_take(semaphore, endt_us);}
internal void semaphore_drop(Semaphore semaphore) {os_semaphore_drop(semaphore);}
//- rjf: barriers
internal Barrier barrier_alloc(U64 count) {return os_barrier_alloc(count);}
internal void barrier_release(Barrier barrier) {os_barrier_release(barrier);}
internal void barrier_wait(Barrier barrier) {os_barrier_wait(barrier);}
////////////////////////////////
//~ rjf: Table Stripe Functions
@@ -72,7 +8,7 @@ internal StripeArray
stripe_array_alloc(Arena *arena)
{
StripeArray array = {0};
array.count = os_get_system_info()->logical_processor_count;
array.count = get_system_info()->logical_processor_count;
array.v = push_array(arena, Stripe, array.count);
for EachIndex(idx, array.count)
{
@@ -100,3 +36,169 @@ stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx)
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
return stripe;
}
////////////////////////////////
//~ rjf: Thread Info Helpers
internal void
set_thread_name(String8 string)
{
ProfThreadName("%.*s", str8_varg(string));
set_platform_thread_name(string);
}
internal void
set_thread_namef(char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
set_thread_name(string);
va_end(args);
scratch_end(scratch);
}
////////////////////////////////
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
//- rjf: slow barriers
typedef struct BarrierNode BarrierNode;
struct BarrierNode
{
BarrierNode *next;
U64 count;
U64 threads_left_to_enter;
U64 threads_left_to_leave;
RWMutex rw_mutex;
CondVar cv;
};
typedef struct BarrierTCTX BarrierTCTX;
struct BarrierTCTX
{
Arena *arena;
BarrierNode *free_barrier_node;
};
thread_static BarrierTCTX *barrier_tctx = 0;
internal Barrier
slow_barrier_alloc(U64 count)
{
if(barrier_tctx == 0)
{
Arena *arena = arena_alloc();
barrier_tctx = push_array(arena, BarrierTCTX, 1);
barrier_tctx->arena = arena;
}
BarrierNode *n = barrier_tctx->free_barrier_node;
if(n != 0)
{
SLLStackPop(barrier_tctx->free_barrier_node);
}
else
{
n = push_array_no_zero(barrier_tctx->arena, BarrierNode, 1);
}
MemoryZeroStruct(n);
n->count = count;
n->threads_left_to_enter = count;
n->rw_mutex = rw_mutex_alloc();
n->cv = cond_var_alloc();
Barrier result = {(U64)n};
return result;
}
internal void
slow_barrier_release(Barrier barrier)
{
if(barrier_tctx == 0)
{
Arena *arena = arena_alloc();
barrier_tctx = push_array(arena, BarrierTCTX, 1);
barrier_tctx->arena = arena;
}
BarrierNode *n = (BarrierNode *)barrier.u64[0];
rw_mutex_release(n->rw_mutex);
cond_var_release(n->cv);
SLLStackPush(barrier_tctx->free_barrier_node, n);
}
internal void
slow_barrier_wait(Barrier barrier)
{
ProfBeginFunction();
BarrierNode *n = (BarrierNode *)barrier.u64[0];
U64 threads_left_to_enter = ins_atomic_u64_dec_eval(&n->threads_left_to_enter);
//- rjf: threads left to enter > 0 => wait
if(threads_left_to_enter > 0)
{
// rjf: first try a spin loop
B32 done_waiting = 0;
ProfScope("spin loop wait") for(U64 spin_count = 0; spin_count < 10000; spin_count += 1)
{
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
{
done_waiting = 1;
break;
}
}
// rjf: not done waiting -> need to do slow wait on condition variable
if(!done_waiting) ProfScope("slow wait")
{
RWMutexScope(n->rw_mutex, 0) for(;;)
{
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
{
break;
}
cond_var_wait_rw(n->cv, n->rw_mutex, 0, max_U64);
}
}
// rjf: decrement leave counter
if(ins_atomic_u64_dec_eval(&n->threads_left_to_leave) > 0)
{
ProfScope("signal") cond_var_signal(n->cv);
}
}
//- rjf: threads left to enter == 0 -> last thread, wakeup
else
{
ins_atomic_u64_eval_assign(&n->threads_left_to_enter, n->count);
ProfScope("wake up") RWMutexScope(n->rw_mutex, 1)
{
ins_atomic_u64_eval_assign(&n->threads_left_to_leave, n->count-1);
}
ProfScope("signal") cond_var_signal(n->cv);
}
//- rjf: wait for threads left to leave == 0
ProfScope("wait for threads to leave")
{
for(U64 spin_count = 0;; spin_count += 1)
{
if(ins_atomic_u64_eval(&n->threads_left_to_leave) == 0)
{
break;
}
}
}
ProfEnd();
}
////////////////////////////////
///~ Semaphore
internal void
semaphore_drop(Semaphore semaphore)
{
semaphore_drop_count(semaphore, 1);
}
+32 -6
View File
@@ -67,14 +67,33 @@ struct StripeArray
};
////////////////////////////////
//~ rjf: Thread Functions
//~ rjf: Table Stripe Functions
internal StripeArray stripe_array_alloc(Arena *arena);
internal void stripe_array_release(StripeArray *stripes);
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
////////////////////////////////
//~ rjf: Thread Info Helpers
internal void set_thread_name(String8 string);
internal void set_thread_namef(char *fmt, ...);
////////////////////////////////
//~ rjf: @per_os_impl Current Thread Info
internal U32 tid(void);
internal void set_platform_thread_name(String8 name);
////////////////////////////////
//~ rjf: @per_os_impl Thread Functions
internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
internal B32 thread_join(Thread thread, U64 endt_us);
internal void thread_detach(Thread thread);
////////////////////////////////
//~ rjf: Synchronization Primitive Functions
//~ rjf: @per_os_impl Synchronization Primitive Functions
//- rjf: recursive mutexes
internal Mutex mutex_alloc(void);
@@ -110,6 +129,7 @@ internal Semaphore semaphore_open(String8 name);
internal void semaphore_close(Semaphore semaphore);
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
internal void semaphore_drop(Semaphore semaphore);
internal void semaphore_drop_count(Semaphore semaphore, U64 drop_count);
//- rjf: barriers
internal Barrier barrier_alloc(U64 count);
@@ -124,10 +144,16 @@ internal void barrier_wait(Barrier barrier);
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
////////////////////////////////
//~ rjf: Table Stripe Functions
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
internal StripeArray stripe_array_alloc(Arena *arena);
internal void stripe_array_release(StripeArray *stripes);
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
//- rjf: slow barriers
internal Barrier slow_barrier_alloc(U64 count);
internal void slow_barrier_release(Barrier barrier);
internal void slow_barrier_wait(Barrier barrier);
////////////////////////////////
//~ rjf: @per_os_impl Safe Calls
internal void safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr);
#endif // BASE_THREADS_H
+340
View File
@@ -0,0 +1,340 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
Test(str8_list_substr)
{
String8List zero_list = {0};
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "b");
str8_list_pushf(arena, &list, "c");
String8List sub = str8_list_substr(arena, list, r1u64(0, 3));
String8 result = str8_list_join(arena, &list, 0);
T_Ok(str8_match(result, str8_lit("abc"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "b");
str8_list_pushf(arena, &list, "c");
String8List sub = str8_list_substr(arena, list, r1u64(0, max_U64));
String8 result = str8_list_join(arena, &list, 0);
T_Ok(str8_match(result, str8_lit("abc"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "bcd");
String8List sub = str8_list_substr(arena, list, r1u64(2, 3));
String8 result = str8_list_join(arena, &sub, 0);
T_Ok(str8_match(result, str8_lit("c"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "a");
str8_list_pushf(arena, &list, "bcd");
String8List sub = str8_list_substr(arena, list, r1u64(1, 2));
String8 result = str8_list_join(arena, &sub, 0);
T_Ok(str8_match(result, str8_lit("b"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "ab");
str8_list_pushf(arena, &list, "cd");
str8_list_pushf(arena, &list, "ef");
String8List sub = str8_list_substr(arena, list, r1u64(1, 5));
String8 result = str8_list_join(arena, &sub, 0);
T_Ok(str8_match(result, str8_lit("bcde"), 0));
}
{
String8List list = {0};
str8_list_pushf(arena, &list, "abc");
String8List zero = str8_list_substr(arena, list, r1u64(0, 0));
T_Ok(MemoryMatchStruct(&zero, &zero_list));
String8List out_of_bounds_range = str8_list_substr(arena, list, r1u64(max_U64/2, max_U64));
T_Ok(MemoryMatchStruct(&out_of_bounds_range, &zero_list));
}
}
TEST(bit_array)
{
for (U64 start=0; start<32*3; start++) {
for (U64 end=start; end<32*3; end++) {
U32 v[3] = { 0 };
for (U64 i=start; i<end; i++) {
v[i/32] |= 1 << (i%32);
}
for (U64 lo=0; lo<32*3; lo++) {
for (U64 hi=0; hi<32*3; hi++) {
U64 expected_idx = Min(hi, end) - 1;
B32 expected_r = hi <= start || lo >= end || lo >= hi || start >= end ? 0 : 1;
U64 idx = bit_array_scan_right_to_left32((U32Array){.v=v, .count=ArrayCount(v)}, lo, hi, 1);
B32 r = idx < hi;
T_Ok(r == expected_r);
if (r) {
T_Ok(idx == expected_idx);
}
}
}
}
}
}
TEST(count_digits)
{
T_Ok(count_digits_u64(0, 10) == 1);
T_Ok(count_digits_u64(99, 10) == 2);
T_Ok(count_digits_u64(999, 10) == 3);
T_Ok(count_digits_u64(9999, 10) == 4);
T_Ok(count_digits_u64(99999, 10) == 5);
T_Ok(count_digits_u64(999999, 10) == 6);
}
TEST(match_wildcard)
{
// empty strings
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit(""), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("**"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit(""), 0) == 0);
// exact
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("a"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), 0) == 0);
// ?
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("a?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?b"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("??"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a?c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("???"), 0) == 0);
// *
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("b*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("**"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a**c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*b*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*a*d*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abcd"), str8_lit("a*d"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abefcdgiescdfimde"), str8_lit("ab*cd?i*de"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("mississippi"), str8_lit("m*iss*ppi"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("aa"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("aa"), str8_lit("a"), 0) == 0);
// case insensitive
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), StringMatchFlag_CaseInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("FooBar"), str8_lit("foobar"), StringMatchFlag_CaseInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("Foobar"), str8_lit("foo*"), StringMatchFlag_CaseInsensitive) == 1);
// right side sloppy
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("ab"), StringMatchFlag_RightSideSloppy) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit(""), StringMatchFlag_RightSideSloppy) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("a"), StringMatchFlag_RightSideSloppy) == 0);
// slash insensitive
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), StringMatchFlag_SlashInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("a/b/c"), str8_lit("a\\*\\c"), StringMatchFlag_SlashInsensitive) == 1);
// combined
T_Ok(str8_match_wildcard(str8_lit("Ab\\Cde"), str8_lit("ab/*e"), StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*?*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*?*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("?*?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?*?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?*?"), 0) == 0);
}
TEST(hash_map)
{
{
HashMap hm = {0};
U64 test_count = 256;
for EachIndex(i, test_count) { hash_map_push_u64_u64(arena, &hm, i, i*2); }
// test tombstone reuse
for (U64 i = 10; i < test_count; ++i) {
HashMapNode *test_node = hash_map_search(&hm, hash_map_hasher(str8_struct(&i)), (HashMapKey){ .key_u64 = i }, hash_map_match_u64);
T_Ok(hash_map_purge_u64(&hm, i) == 1);
T_Ok(hash_map_push_u64_u64(arena, &hm, i, 10) == test_node);
}
// delete some items and after search them
for (U64 i = 0; i < 10; ++i) {
T_Ok(hash_map_purge_u64(&hm, i));
}
T_Ok(hm.tombstone_count == 10);
for (U64 i = 0; i < 10; ++i) {
T_Ok(hash_map_search_u64_raw(&hm, i) == 0);
}
// extract pairs and test sorting
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
sort_hash_map_key_value_u64(pairs, hm.count);
for (U64 i = 1; i < hm.count; ++i) {
T_Ok(pairs[i-1].key.key_u64 < pairs[i].key.key_u64);
}
// did purge put all the nodes on free list?
hash_map_purge(&hm);
U64 free_list_count = 0;
for (HashMapNode *n = hm.free_list; n != 0; n = n->next) { free_list_count += 1; }
T_Ok(free_list_count == test_count);
}
// test search through tombstones
{
HashMap hm = {0};
U64 hash = 12345;
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 1 }, .value = { .value_u64 = 10 } }, hash_map_match_u64);
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 2 }, .value = { .value_u64 = 20 } }, hash_map_match_u64);
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 3 }, .value = { .value_u64 = 30 } }, hash_map_match_u64);
T_Ok(hash_map_purge_u64(&hm, 1));
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 2 }, hash_map_match_u64)->v.value.value_u64 == 20);
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 3 }, hash_map_match_u64)->v.value.value_u64 == 30);
}
// interleaved purges
{
HashMap hm = {0};
for EachIndex(round, 100) {
for EachIndex(i, 256) { hash_map_push_u64_u64(arena, &hm, i, round); }
for (U64 i = 0; i < 256; i += 2) { hash_map_purge_u64(&hm, i); }
for (U64 i = 0; i < 256; i += 2) { hash_map_push_u64_u64(arena, &hm, i, round + 1); }
T_Ok(hm.count == 256);
T_Ok(hm.tombstone_count == 0);
}
for EachIndex(i, 100) {
T_Ok(hash_map_purge_u64(&hm, 123123123 + i) == 0);
}
}
// empty hash map test
{
HashMap hm = {0};
T_Ok(hash_map_search_u64_raw(&hm, 123) == 0);
T_Ok(hash_map_purge_u64(&hm, 123) == 0);
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
T_Ok(pairs == 0 || hm.count == 0);
hash_map_purge(&hm);
T_Ok(hm.count == 0);
T_Ok(hm.tombstone_count == 0);
}
// heavy collision
{
HashMap hm = {0};
U64 hash = 12345;
U64 count = 1024;
for EachIndex(i, count) {
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = i }, .value = { .value_u64 = i*3 } }, hash_map_match_u64);
}
for EachIndex(i, count) {
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = i }, hash_map_match_u64)->v.value.value_u64 == i*3);
}
}
// duplicate key test
{
HashMap hm = {0};
U64 a = 1;
U64 b = 2;
HashMapNode *n0 = hash_map_push_u64_u64(arena, &hm, 1, a);
HashMapNode *n1 = hash_map_push_u64_u64(arena, &hm, 1, b);
T_Ok(hm.count == 1);
T_Ok(n0 == n1);
U64 test = *hash_map_search_u64_u64(&hm, 1);
T_Ok(test != b);
}
// test paths
{
HashMap hm = {0};
U64 foo = 0;
U64 bar = 1;
hash_map_push_path_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
hash_map_push_path_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
hash_map_push_path_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
hash_map_push_path_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
hash_map_push_path_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
T_Ok(hm.count == 2);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:/devel/test")) == &foo);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:\\devel\\TEST")) == &foo);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/mnt/devel")) == &bar);
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/MNT/DEVEL")) == &bar);
}
// test strings
{
HashMap hm = {0};
U64 foo = 0;
U64 bar = 1;
hash_map_push_string_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
hash_map_push_string_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
hash_map_push_string_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
hash_map_push_string_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
hash_map_push_string_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
T_Ok(hm.count == 5);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/DEVEL/test")) == &foo);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:\\DEVEL\\test")) == &foo);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/devel\\test")) == &foo);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/mnt/devel")) == &bar);
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/MNT/devel")) == &bar);
}
}
-41
View File
@@ -47,7 +47,6 @@ cv_size_from_reg(CV_Arch arch, CV_Reg reg)
{
switch(arch)
{
case CV_Arch_8086: return cv_size_from_reg_x86(reg);
case CV_Arch_X64 : return cv_size_from_reg_x64(reg);
default: NotImplemented;
}
@@ -59,25 +58,12 @@ cv_is_reg_sp(CV_Arch arch, CV_Reg reg)
{
switch(arch)
{
case CV_Arch_8086: return reg == CV_Regx86_ESP;
case CV_Arch_X64: return reg == CV_Regx64_RSP;
default: NotImplemented;
}
return 0;
}
internal U64
cv_size_from_reg_x86(CV_Reg reg)
{
switch(reg)
{
#define X(NAME, CODE, RDI_NAME, BYTE_POS, BYTE_SIZE) case CV_Regx86_##NAME: return BYTE_SIZE;
CV_Reg_X86_XList(X)
#undef X
}
return 0;
}
internal U64
cv_size_from_reg_x64(CV_Reg reg)
{
@@ -111,18 +97,6 @@ cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg)
CV_Reg fp_reg = 0;
switch (arch)
{
case CV_Arch_8086:
{
switch (encoded_reg)
{
case CV_EncodedFramePtrReg_None : break;
case CV_EncodedFramePtrReg_StackPtr: AssertAlways(!"TODO: not tested, this is a guess");
fp_reg = CV_Regx86_ESP; break;
case CV_EncodedFramePtrReg_FramePtr: fp_reg = CV_Regx86_EBP; break;
case CV_EncodedFramePtrReg_BasePtr : fp_reg = CV_Regx86_EBX; break;
default: InvalidPath;
}
} break;
case CV_Arch_X64:
{
switch (encoded_reg)
@@ -144,14 +118,6 @@ cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg)
{
U32 r = 0;
switch (arch) {
case CV_Arch_8086: {
switch (encoded_frame_reg) {
case 0: r = 0; break;
case 1: r = CV_AllReg_VFRAME; break;
case 2: r = CV_Regx86_EBP; break;
case 3: r = CV_Regx86_EBX; break;
}
} break;
case CV_Arch_X64: {
switch (encoded_frame_reg) {
case 0: r = 0; break;
@@ -207,13 +173,6 @@ cv_string_from_reg_id(Arena *arena, CV_Arch arch, U32 id)
{
String8 result = str8_zero();
switch (arch) {
case CV_Arch_8086: {
switch (id) {
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
CV_Reg_X86_XList(X)
#undef X
}
} break;
case CV_Arch_X64: {
switch (id) {
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
+29 -282
View File
@@ -33,7 +33,7 @@ read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF;
////////////////////////////////
//~ Aligns
#define CV_LeafAlign 4
#define CV_LeafAlign 1
#define CV_SymbolAlign 1
#define CV_C13SubSectionAlign 4
#define CV_FileCheckSumsAlign 4
@@ -41,261 +41,6 @@ read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF;
////////////////////////////////
//~ rjf: Registers
// X(NAME, CODE, (RDI_RegCode_X86) NAME, BYTE_POS, BYTE_SIZE)
#define CV_Reg_X86_XList(X) \
X(NONE, 0, nil, 0, 0) \
X(AL, 1, eax, 0, 1) \
X(CL, 2, ecx, 0, 1) \
X(DL, 3, edx, 0, 1) \
X(BL, 4, ebx, 0, 1) \
X(AH, 5, eax, 1, 1) \
X(CH, 6, ecx, 1, 1) \
X(DH, 7, edx, 1, 1) \
X(BH, 8, ebx, 1, 1) \
X(AX, 9, eax, 0, 2) \
X(CX, 10, ecx, 0, 2) \
X(DX, 11, edx, 0, 2) \
X(BX, 12, ebx, 0, 2) \
X(SP, 13, esp, 0, 2) \
X(BP, 14, ebp, 0, 2) \
X(SI, 15, esi, 0, 2) \
X(DI, 16, edi, 0, 2) \
X(EAX, 17, eax, 0, 4) \
X(ECX, 18, ecx, 0, 4) \
X(EDX, 19, edx, 0, 4) \
X(EBX, 20, ebx, 0, 4) \
X(ESP, 21, esp, 0, 4) \
X(EBP, 22, ebp, 0, 4) \
X(ESI, 23, esi, 0, 4) \
X(EDI, 24, edi, 0, 4) \
X(ES, 25, es, 0, 2) \
X(CS, 26, cs, 0, 2) \
X(SS, 27, ss, 0, 2) \
X(DS, 28, ds, 0, 2) \
X(FS, 29, fs, 0, 2) \
X(GS, 30, gs, 0, 2) \
X(IP, 31, eip, 0, 2) \
X(FLAGS, 32, eflags, 0, 2) \
X(EIP, 33, eip, 0, 4) \
X(EFLAGS, 34, eflags, 0, 4) \
X(MM0, 146, fpr0, 0, 8) \
X(MM1, 147, fpr1, 0, 8) \
X(MM2, 148, fpr2, 0, 8) \
X(MM3, 149, fpr3, 0, 8) \
X(MM4, 150, fpr4, 0, 8) \
X(MM5, 151, fpr5, 0, 8) \
X(MM6, 152, fpr6, 0, 8) \
X(MM7, 153, fpr7, 0, 8) \
X(XMM0, 154, ymm0, 0, 16) \
X(XMM1, 155, ymm1, 0, 16) \
X(XMM2, 156, ymm2, 0, 16) \
X(XMM3, 157, ymm3, 0, 16) \
X(XMM4, 158, ymm4, 0, 16) \
X(XMM5, 159, ymm5, 0, 16) \
X(XMM6, 160, ymm6, 0, 16) \
X(XMM7, 161, ymm7, 0, 16) \
X(XMM00, 162, ymm0, 0, 4) \
X(XMM01, 163, ymm0, 4, 4) \
X(XMM02, 164, ymm0, 8, 4) \
X(XMM03, 165, ymm0, 12, 4) \
X(XMM10, 166, ymm1, 0, 4) \
X(XMM11, 167, ymm1, 4, 4) \
X(XMM12, 168, ymm1, 8, 4) \
X(XMM13, 169, ymm1, 12, 4) \
X(XMM20, 170, ymm2, 0, 4) \
X(XMM21, 171, ymm2, 4, 4) \
X(XMM22, 172, ymm2, 8, 4) \
X(XMM23, 173, ymm2, 12, 4) \
X(XMM30, 174, ymm3, 0, 4) \
X(XMM31, 175, ymm3, 4, 4) \
X(XMM32, 176, ymm3, 8, 4) \
X(XMM33, 177, ymm3, 12, 4) \
X(XMM40, 178, ymm4, 0, 4) \
X(XMM41, 179, ymm4, 4, 4) \
X(XMM42, 180, ymm4, 8, 4) \
X(XMM43, 181, ymm4, 12, 4) \
X(XMM50, 182, ymm5, 0, 4) \
X(XMM51, 183, ymm5, 4, 4) \
X(XMM52, 184, ymm5, 8, 4) \
X(XMM53, 185, ymm5, 12, 4) \
X(XMM60, 186, ymm6, 0, 4) \
X(XMM61, 187, ymm6, 4, 4) \
X(XMM62, 188, ymm6, 8, 4) \
X(XMM63, 189, ymm6, 12, 4) \
X(XMM70, 190, ymm7, 0, 4) \
X(XMM71, 191, ymm7, 4, 4) \
X(XMM72, 192, ymm7, 8, 4) \
X(XMM73, 193, ymm7, 12, 4) \
X(XMM0L, 194, ymm0, 0, 8) \
X(XMM1L, 195, ymm1, 0, 8) \
X(XMM2L, 196, ymm2, 0, 8) \
X(XMM3L, 197, ymm3, 0, 8) \
X(XMM4L, 198, ymm4, 0, 8) \
X(XMM5L, 199, ymm5, 0, 8) \
X(XMM6L, 200, ymm6, 0, 8) \
X(XMM7L, 201, ymm7, 0, 8) \
X(XMM0H, 202, ymm0, 8, 8) \
X(XMM1H, 203, ymm1, 8, 8) \
X(XMM2H, 204, ymm2, 8, 8) \
X(XMM3H, 205, ymm3, 8, 8) \
X(XMM4H, 206, ymm4, 8, 8) \
X(XMM5H, 207, ymm5, 8, 8) \
X(XMM6H, 208, ymm6, 8, 8) \
X(XMM7H, 209, ymm7, 8, 8) \
X(YMM0, 252, ymm0, 0, 32) \
X(YMM1, 253, ymm1, 0, 32) \
X(YMM2, 254, ymm2, 0, 32) \
X(YMM3, 255, ymm3, 0, 32) \
X(YMM4, 256, ymm4, 0, 32) \
X(YMM5, 257, ymm5, 0, 32) \
X(YMM6, 258, ymm6, 0, 32) \
X(YMM7, 259, ymm7, 0, 32) \
X(YMM0H, 260, ymm0, 16, 16) \
X(YMM1H, 261, ymm1, 16, 16) \
X(YMM2H, 262, ymm2, 16, 16) \
X(YMM3H, 263, ymm3, 16, 16) \
X(YMM4H, 264, ymm4, 16, 16) \
X(YMM5H, 265, ymm5, 16, 16) \
X(YMM6H, 266, ymm6, 16, 16) \
X(YMM7H, 267, ymm7, 16, 16) \
X(YMM0I0, 268, ymm0, 0, 8) \
X(YMM0I1, 269, ymm0, 8, 8) \
X(YMM0I2, 270, ymm0, 16, 8) \
X(YMM0I3, 271, ymm0, 24, 8) \
X(YMM1I0, 272, ymm1, 0, 8) \
X(YMM1I1, 273, ymm1, 8, 8) \
X(YMM1I2, 274, ymm1, 16, 8) \
X(YMM1I3, 275, ymm1, 24, 8) \
X(YMM2I0, 276, ymm2, 0, 8) \
X(YMM2I1, 277, ymm2, 8, 8) \
X(YMM2I2, 278, ymm2, 16, 8) \
X(YMM2I3, 279, ymm2, 24, 8) \
X(YMM3I0, 280, ymm3, 0, 8) \
X(YMM3I1, 281, ymm3, 8, 8) \
X(YMM3I2, 282, ymm3, 16, 8) \
X(YMM3I3, 283, ymm3, 24, 8) \
X(YMM4I0, 284, ymm4, 0, 8) \
X(YMM4I1, 285, ymm4, 8, 8) \
X(YMM4I2, 286, ymm4, 16, 8) \
X(YMM4I3, 287, ymm4, 24, 8) \
X(YMM5I0, 288, ymm5, 0, 8) \
X(YMM5I1, 289, ymm5, 8, 8) \
X(YMM5I2, 290, ymm5, 16, 8) \
X(YMM5I3, 291, ymm5, 24, 8) \
X(YMM6I0, 292, ymm6, 0, 8) \
X(YMM6I1, 293, ymm6, 8, 8) \
X(YMM6I2, 294, ymm6, 16, 8) \
X(YMM6I3, 295, ymm6, 24, 8) \
X(YMM7I0, 296, ymm7, 0, 8) \
X(YMM7I1, 297, ymm7, 8, 8) \
X(YMM7I2, 298, ymm7, 16, 8) \
X(YMM7I3, 299, ymm7, 24, 8) \
X(YMM0F0, 300, ymm0, 0, 4) \
X(YMM0F1, 301, ymm0, 4, 4) \
X(YMM0F2, 302, ymm0, 8, 4) \
X(YMM0F3, 303, ymm0, 12, 4) \
X(YMM0F4, 304, ymm0, 16, 4) \
X(YMM0F5, 305, ymm0, 20, 4) \
X(YMM0F6, 306, ymm0, 24, 4) \
X(YMM0F7, 307, ymm0, 28, 4) \
X(YMM1F0, 308, ymm1, 0, 4) \
X(YMM1F1, 309, ymm1, 4, 4) \
X(YMM1F2, 310, ymm1, 8, 4) \
X(YMM1F3, 311, ymm1, 12, 4) \
X(YMM1F4, 312, ymm1, 16, 4) \
X(YMM1F5, 313, ymm1, 20, 4) \
X(YMM1F6, 314, ymm1, 24, 4) \
X(YMM1F7, 315, ymm1, 28, 4) \
X(YMM2F0, 316, ymm2, 0, 4) \
X(YMM2F1, 317, ymm2, 4, 4) \
X(YMM2F2, 318, ymm2, 8, 4) \
X(YMM2F3, 319, ymm2, 12, 4) \
X(YMM2F4, 320, ymm2, 16, 4) \
X(YMM2F5, 321, ymm2, 20, 4) \
X(YMM2F6, 322, ymm2, 24, 4) \
X(YMM2F7, 323, ymm2, 28, 4) \
X(YMM3F0, 324, ymm3, 0, 4) \
X(YMM3F1, 325, ymm3, 4, 4) \
X(YMM3F2, 326, ymm3, 8, 4) \
X(YMM3F3, 327, ymm3, 12, 4) \
X(YMM3F4, 328, ymm3, 16, 4) \
X(YMM3F5, 329, ymm3, 20, 4) \
X(YMM3F6, 330, ymm3, 24, 4) \
X(YMM3F7, 331, ymm3, 28, 4) \
X(YMM4F0, 332, ymm4, 0, 4) \
X(YMM4F1, 333, ymm4, 4, 4) \
X(YMM4F2, 334, ymm4, 8, 4) \
X(YMM4F3, 335, ymm4, 12, 4) \
X(YMM4F4, 336, ymm4, 16, 4) \
X(YMM4F5, 337, ymm4, 20, 4) \
X(YMM4F6, 338, ymm4, 24, 4) \
X(YMM4F7, 339, ymm4, 28, 4) \
X(YMM5F0, 340, ymm5, 0, 4) \
X(YMM5F1, 341, ymm5, 4, 4) \
X(YMM5F2, 342, ymm5, 8, 4) \
X(YMM5F3, 343, ymm5, 12, 4) \
X(YMM5F4, 344, ymm5, 16, 4) \
X(YMM5F5, 345, ymm5, 20, 4) \
X(YMM5F6, 346, ymm5, 24, 4) \
X(YMM5F7, 347, ymm5, 28, 4) \
X(YMM6F0, 348, ymm6, 0, 4) \
X(YMM6F1, 349, ymm6, 4, 4) \
X(YMM6F2, 350, ymm6, 8, 4) \
X(YMM6F3, 351, ymm6, 12, 4) \
X(YMM6F4, 352, ymm6, 16, 4) \
X(YMM6F5, 353, ymm6, 20, 4) \
X(YMM6F6, 354, ymm6, 24, 4) \
X(YMM6F7, 355, ymm6, 28, 4) \
X(YMM7F0, 356, ymm7, 0, 4) \
X(YMM7F1, 357, ymm7, 4, 4) \
X(YMM7F2, 358, ymm7, 8, 4) \
X(YMM7F3, 359, ymm7, 12, 4) \
X(YMM7F4, 360, ymm7, 16, 4) \
X(YMM7F5, 361, ymm7, 20, 4) \
X(YMM7F6, 362, ymm7, 24, 4) \
X(YMM7F7, 363, ymm7, 28, 4) \
X(YMM0D0, 364, ymm0, 0, 8) \
X(YMM0D1, 365, ymm0, 8, 8) \
X(YMM0D2, 366, ymm0, 16, 8) \
X(YMM0D3, 367, ymm0, 24, 8) \
X(YMM1D0, 368, ymm1, 0, 8) \
X(YMM1D1, 369, ymm1, 8, 8) \
X(YMM1D2, 370, ymm1, 16, 8) \
X(YMM1D3, 371, ymm1, 24, 8) \
X(YMM2D0, 372, ymm2, 0, 8) \
X(YMM2D1, 373, ymm2, 8, 8) \
X(YMM2D2, 374, ymm2, 16, 8) \
X(YMM2D3, 375, ymm2, 24, 8) \
X(YMM3D0, 376, ymm3, 0, 8) \
X(YMM3D1, 377, ymm3, 8, 8) \
X(YMM3D2, 378, ymm3, 16, 8) \
X(YMM3D3, 379, ymm3, 24, 8) \
X(YMM4D0, 380, ymm4, 0, 8) \
X(YMM4D1, 381, ymm4, 8, 8) \
X(YMM4D2, 382, ymm4, 16, 8) \
X(YMM4D3, 383, ymm4, 24, 8) \
X(YMM5D0, 384, ymm5, 0, 8) \
X(YMM5D1, 385, ymm5, 8, 8) \
X(YMM5D2, 386, ymm5, 16, 8) \
X(YMM5D3, 387, ymm5, 24, 8) \
X(YMM6D0, 388, ymm6, 0, 8) \
X(YMM6D1, 389, ymm6, 8, 8) \
X(YMM6D2, 390, ymm6, 16, 8) \
X(YMM6D3, 391, ymm6, 24, 8) \
X(YMM7D0, 392, ymm7, 0, 8) \
X(YMM7D1, 393, ymm7, 8, 8) \
X(YMM7D2, 394, ymm7, 16, 8) \
X(YMM7D3, 395, ymm7, 24, 8)
typedef U16 CV_Regx86;
typedef enum CV_Regx86Enum
{
#define X(CVN,C,RDN,BP,BZ) CV_Regx86_##CVN = C,
CV_Reg_X86_XList(X)
#undef X
}
CV_Regx86Enum;
// X(NAME, CODE, (RDI_RegisterCode_X64) NAME, BYTE_POS, BYTE_SIZE)
#define CV_Reg_X64_XList(X) \
X(NONE, 0, nil, 0, 0) \
@@ -382,14 +127,14 @@ X(FPDS, 142, nil, 0, 0) \
X(ISEM, 143, nil, 0, 0) \
X(FPEIP, 144, nil, 0, 0) \
X(FPEDO, 145, nil, 0, 0) \
X(MM0, 146, fpr0, 0, 8) \
X(MM1, 147, fpr1, 0, 8) \
X(MM2, 148, fpr2, 0, 8) \
X(MM3, 149, fpr3, 0, 8) \
X(MM4, 150, fpr4, 0, 8) \
X(MM5, 151, fpr5, 0, 8) \
X(MM6, 152, fpr6, 0, 8) \
X(MM7, 153, fpr7, 0, 8) \
X(MM0, 146, st0, 0, 8) \
X(MM1, 147, st1, 0, 8) \
X(MM2, 148, st2, 0, 8) \
X(MM3, 149, st3, 0, 8) \
X(MM4, 150, st4, 0, 8) \
X(MM5, 151, st5, 0, 8) \
X(MM6, 152, st6, 0, 8) \
X(MM7, 153, st7, 0, 8) \
X(XMM0, 154, zmm0, 0, 16) \
X(XMM1, 155, zmm1, 0, 16) \
X(XMM2, 156, zmm2, 0, 16) \
@@ -463,22 +208,22 @@ X(EMM4H, 232, zmm4, 8, 8) \
X(EMM5H, 233, zmm5, 8, 8) \
X(EMM6H, 234, zmm6, 8, 8) \
X(EMM7H, 235, zmm7, 8, 8) \
X(MM00, 236, fpr0, 0, 4) \
X(MM01, 237, fpr0, 4, 4) \
X(MM10, 238, fpr1, 0, 4) \
X(MM11, 239, fpr1, 4, 4) \
X(MM20, 240, fpr2, 0, 4) \
X(MM21, 241, fpr2, 4, 4) \
X(MM30, 242, fpr3, 0, 4) \
X(MM31, 243, fpr3, 4, 4) \
X(MM40, 244, fpr4, 0, 4) \
X(MM41, 245, fpr4, 4, 4) \
X(MM50, 246, fpr5, 0, 4) \
X(MM51, 247, fpr5, 4, 4) \
X(MM60, 248, fpr6, 0, 4) \
X(MM61, 249, fpr6, 4, 4) \
X(MM70, 250, fpr7, 0, 4) \
X(MM71, 251, fpr7, 4, 4) \
X(MM00, 236, st0, 0, 4) \
X(MM01, 237, st0, 4, 4) \
X(MM10, 238, st1, 0, 4) \
X(MM11, 239, st1, 4, 4) \
X(MM20, 240, st2, 0, 4) \
X(MM21, 241, st2, 4, 4) \
X(MM30, 242, st3, 0, 4) \
X(MM31, 243, st3, 4, 4) \
X(MM40, 244, st4, 0, 4) \
X(MM41, 245, st4, 4, 4) \
X(MM50, 246, st5, 0, 4) \
X(MM51, 247, st5, 4, 4) \
X(MM60, 248, st6, 0, 4) \
X(MM61, 249, st6, 4, 4) \
X(MM70, 250, st7, 0, 4) \
X(MM71, 251, st7, 4, 4) \
X(XMM8, 252, zmm8, 0, 16) \
X(XMM9, 253, zmm9, 0, 16) \
X(XMM10, 254, zmm10, 0, 16) \
@@ -1416,6 +1161,8 @@ struct CV_SymPub32
//- (SymKind: LPROC32, GPROC32)
#define CV_IsProc32(x) (x == CV_SymKind_LPROC32_ID || x == CV_SymKind_GPROC32_ID || x == CV_SymKind_LPROC32_DPC)
typedef struct CV_SymProc32 CV_SymProc32;
struct CV_SymProc32
{
@@ -2795,7 +2542,8 @@ X(TypeMDTokenMap, 0xFB) \
X(MergedAssemblyInput, 0xFC) \
X(CoffSymbolRVA, 0xFD) \
X(XfgHashType, 0xFF) \
X(XfgHashVirtual, 0x100)
X(XfgHashVirtual, 0x100) \
X(GlobalRefs, 0xCAFE) \
typedef U32 CV_C13SubSectionKind;
typedef enum CV_C13SubSectionKindEnum
@@ -2963,7 +2711,6 @@ struct CV_TypeIndexArray
////////////////////////////////
internal CV_Arch cv_arch_from_coff_machine(COFF_MachineType machine);
internal U64 cv_size_from_reg_x86(CV_Reg reg);
internal U64 cv_size_from_reg_x64(CV_Reg reg);
internal U64 cv_size_from_reg(CV_Arch arch, CV_Reg reg);
internal B32 cv_is_reg_sp(CV_Arch arch, CV_Reg reg);
+75 -33
View File
@@ -29,7 +29,7 @@ cv_numeric_from_data_range(U8 *first, U8 *opl)
CV_NumericParsed result = {0};
if(first + 2 <= opl)
{
U16 x = *(U16*)first;
U16 x = memory_read16(first);
if(x < 0x8000)
{
result.kind = CV_NumericKind_USHORT;
@@ -1025,63 +1025,77 @@ internal U64
cv_name_offset_from_symbol(CV_SymKind kind, String8 data)
{
U64 offset = data.size;
switch (kind) {
case CV_SymKind_COMPILE: break;
case CV_SymKind_OBJNAME: break;
case CV_SymKind_THUNK32: {
switch(kind)
{
case CV_SymKind_COMPILE:{}break;
case CV_SymKind_OBJNAME:{}break;
case CV_SymKind_THUNK32:
{
offset = sizeof(CV_SymThunk32);
} break;
case CV_SymKind_LABEL32: {
}break;
case CV_SymKind_LABEL32:
{
offset = sizeof(CV_SymLabel32);
} break;
case CV_SymKind_REGISTER: {
}break;
case CV_SymKind_REGISTER:
{
offset = sizeof(CV_SymRegister);
} break;
case CV_SymKind_CONSTANT: {
}break;
case CV_SymKind_CONSTANT:
{
offset = sizeof(CV_SymConstant);
CV_NumericParsed size;
offset += cv_read_numeric(data, offset, &size);
} break;
case CV_SymKind_UDT: {
}break;
case CV_SymKind_UDT:
{
offset = sizeof(CV_SymUDT);
} break;
case CV_SymKind_BPREL32: {
}break;
case CV_SymKind_BPREL32:
{
offset = sizeof(CV_SymBPRel32);
} break;
}break;
case CV_SymKind_LDATA32:
case CV_SymKind_GDATA32: {
case CV_SymKind_GDATA32:
{
offset = sizeof(CV_SymData32);
} break;
case CV_SymKind_PUB32: {
}break;
case CV_SymKind_PUB32:
{
offset = sizeof(CV_SymPub32);
} break;
}break;
case CV_SymKind_LPROC32:
case CV_SymKind_GPROC32:
case CV_SymKind_LPROC32_ID:
case CV_SymKind_GPROC32_ID: {
case CV_SymKind_GPROC32_ID:
{
offset = sizeof(CV_SymProc32);
} break;
case CV_SymKind_REGREL32: {
}break;
case CV_SymKind_REGREL32:
{
offset = sizeof(CV_SymRegrel32);
} break;
}break;
case CV_SymKind_LTHREAD32:
case CV_SymKind_GTHREAD32: {
case CV_SymKind_GTHREAD32:
{
offset = sizeof(CV_SymData32);
} break;
}break;
case CV_SymKind_COMPILE2: break;
case CV_SymKind_LOCALSLOT: {
case CV_SymKind_LOCALSLOT:
{
offset = sizeof(CV_SymSlot);
} break;
}break;
case CV_SymKind_PROCREF:
case CV_SymKind_LPROCREF:
case CV_SymKind_DATAREF: {
case CV_SymKind_DATAREF:
{
offset = sizeof(CV_SymRef2);
} break;
}break;
case CV_SymKind_TRAMPOLINE: break;
case CV_SymKind_LOCAL: {
case CV_SymKind_LOCAL:
{
offset = sizeof(CV_SymLocal);
} break;
default: InvalidPath;
}break;
}
return offset;
}
@@ -1606,3 +1620,31 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
return result;
}
//- rjf: record iterator
internal B32
cv_rec_next(String8 data, CV_RecRangeArray *recs, B32 is_leaf, CV_RecIter *iter)
{
B32 result = 0;
{
U64 next_num = iter->num+1;
for(;1 <= next_num && next_num <= recs->count; next_num += 1)
{
CV_RecRange *rec_range = &recs->ranges[next_num-1];
U64 rec_off_first = rec_range->off + 2; // (skip 2 header bytes)
U64 rec_off_opl = rec_range->off + rec_range->hdr.size;
U16 kind = rec_range->hdr.kind;
U64 header_struct_size = (is_leaf ? cv_header_struct_size_from_leaf_kind(kind) : cv_header_struct_size_from_sym_kind(kind));
if(rec_off_opl <= data.size && rec_off_first + header_struct_size <= data.size)
{
result = 1;
iter->num = next_num;
iter->kind = kind;
iter->struct_base = data.str + rec_off_first;
iter->opl = data.str + rec_off_opl;
break;
}
}
}
return result;
}
+15
View File
@@ -236,6 +236,18 @@ struct CV_TypeIdArray
U64 count;
};
////////////////////////////////
//~ Record Iterator
typedef struct CV_RecIter CV_RecIter;
struct CV_RecIter
{
U64 num;
U16 kind;
void *struct_base;
void *opl;
};
////////////////////////////////
//- Hasher
@@ -301,5 +313,8 @@ internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym
internal CV_LeafParsed * cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first);
internal CV_C13Parsed * cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections);
//- rjf: record iterator
internal B32 cv_rec_next(String8 data, CV_RecRangeArray *recs, B32 is_leaf, CV_RecIter *iter);
#endif // CODEVIEW_PARSE_H
+17 -7
View File
@@ -92,13 +92,8 @@ coff_read_symbol_name(String8 string_table, COFF_SymbolName *name)
if (name->long_name.zeroes == 0) {
str8_deserial_read_cstr(string_table, name->long_name.string_table_offset, &name_str);
} else {
U32 i;
for (i = 0; i < sizeof(name->short_name); ++i) {
if (name->short_name[i] == '\0') {
break;
}
}
name_str = str8(name->short_name, i);
U32 name_size = idx_of_zero_byte64(name->short_name, sizeof(name->short_name));
name_str = str8(name->short_name, name_size);
}
return name_str;
}
@@ -455,6 +450,21 @@ arch_from_coff_machine(COFF_MachineType machine)
return result;
}
internal COFF_MachineType
coff_machine_from_arch(Arch arch)
{
COFF_MachineType machine = COFF_MachineType_Unknown;
switch (arch) {
case Arch_Null: machine = COFF_MachineType_Unknown; break;
case Arch_x86: machine = COFF_MachineType_X86; break;
case Arch_x64: machine = COFF_MachineType_X64; break;
case Arch_arm64: machine = COFF_MachineType_Arm64; break;
case Arch_arm32: machine = COFF_MachineType_Arm; break;
default: InvalidPath; break;
}
return machine;
}
internal U64
coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff)
{
+11 -6
View File
@@ -162,8 +162,10 @@ enum
};
#define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask)
#define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl)
#define COFF_SectionFlags_Reserved 3
typedef struct COFF_SectionHeader
typedef struct COFF_SectionHeader COFF_SectionHeader;
struct COFF_SectionHeader
{
U8 name[8];
U32 vsize;
@@ -175,12 +177,12 @@ typedef struct COFF_SectionHeader
U16 reloc_count;
U16 line_count;
COFF_SectionFlags flags;
} COFF_SectionHeader;
};
////////////////////////////////
typedef U8 COFF_SymType;
enum
typedef enum COFF_SymTypeEnum
{
COFF_SymType_Null,
COFF_SymType_Void,
@@ -198,10 +200,11 @@ enum
COFF_SymType_Word,
COFF_SymType_UInt,
COFF_SymType_DWord
};
}
COFF_SymTypeEnum;
typedef U8 COFF_SymStorageClass;
enum
typedef enum COFF_SymStorageClassEnum
{
COFF_SymStorageClass_Null = 0x00,
COFF_SymStorageClass_Automatic = 0x01,
@@ -230,7 +233,8 @@ enum
COFF_SymStorageClass_WeakExternal = 0x69,
COFF_SymStorageClass_CLRToken = 0x6b,
COFF_SymStorageClass_EndOfFunction = 0xff
};
}
COFF_SymStorageClassEnum;
typedef U8 COFF_SymDType;
enum
@@ -629,6 +633,7 @@ internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine);
internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
internal Arch arch_from_coff_machine(COFF_MachineType machine);
internal COFF_MachineType coff_machine_from_arch(Arch arch);
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
////////////////////////////////
+1 -1
View File
@@ -648,7 +648,7 @@ coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data,
}
if (opts & RD_Option_Dwarf) {
DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
DW_Raw dwarf_input = dw_raw_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
dw_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
}
+1 -4
View File
@@ -184,10 +184,7 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta
U64 name_with_slash_size = member->name.size + 1;
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
// have we seen this member name before?
KeyValuePair *is_present = hash_table_search_string(name_ht, member->name);
if (is_present) {
name = is_present->value_string;
} else {
if (!hash_table_search_string_string(name_ht, member->name, &name)) {
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
+111 -1
View File
@@ -1,7 +1,10 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal COFF_ObjWriter*
coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine)
{
Arena *arena = arena_alloc();
Arena *arena = arena_alloc(.name = "COFF OBJ WRITER");
COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1);
obj_writer->arena = arena;
obj_writer->time_stamp = time_stamp;
@@ -440,6 +443,18 @@ coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *
return reloc;
}
internal COFF_ObjReloc *
coff_obj_writer_section_push_reloc_rel32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
{
COFF_RelocType reloc_type = 0;
switch (obj_writer->machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Rel32; break;
default: { NotImplemented; } break;
}
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
}
internal COFF_ObjReloc *
coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
{
@@ -496,5 +511,100 @@ coff_obj_section_is_before(void *raw_a, void *raw_b)
return (*a)->section_number < (*b)->section_number;
}
#ifdef OBJ_H
internal String8
coff_from_obj(Arena *arena, OBJ *obj)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_MachineType machine = coff_machine_from_arch(obj->arch);
COFF_TimeStamp time_stamp = (COFF_TimeStamp)obj->time_stamp;
COFF_ObjWriter *cow = coff_obj_writer_alloc(time_stamp, machine);
// push sections
HashTable *section_remap = hash_table_init(scratch.arena, obj->symbols.count * 2);
for EachNode(section_n, OBJ_SectionNode, obj->sections.first) {
OBJ_Section *section = &section_n->v;
COFF_SectionFlags flags = 0;
if (section->flags & OBJ_SectionFlag_Read) { flags |= COFF_SectionFlag_MemRead; }
if (section->flags & OBJ_SectionFlag_Write) { flags |= COFF_SectionFlag_MemWrite; }
if (section->flags & OBJ_SectionFlag_Exec) { flags |= COFF_SectionFlag_MemExecute|COFF_SectionFlag_CntCode; }
if ( ! (section->flags & OBJ_SectionFlag_Exec)) { flags |= COFF_SectionFlag_CntInitializedData; }
if ( ! (section->flags & OBJ_SectionFlag_Load)) { flags |= COFF_SectionFlag_MemDiscardable; }
COFF_ObjSection *section_coff = coff_obj_writer_push_section(cow, section->name, flags, str8_zero());
section_coff->data = section->data;
// obj -> coff section
hash_table_push_raw_raw(scratch.arena, section_remap, section, section_coff);
}
// push symbols
HashTable *symbol_remap = hash_table_init(scratch.arena, obj->symbols.count * 2);
for EachNode(symbol_n, OBJ_SymbolNode, obj->symbols.first) {
OBJ_Symbol *symbol = &symbol_n->v;
switch (symbol->ref_kind) {
case OBJ_RefKind_Null: break;
case OBJ_RefKind_Section: {
OBJ_Section *section = symbol->ref;
COFF_ObjSection *section_coff = hash_table_search_raw_raw(section_remap, section);
COFF_SymbolLocation location = (COFF_SymbolLocation){ .type = COFF_SymbolLocation_Section, .u.section = section_coff };
COFF_SymStorageClass storage_class = COFF_SymStorageClass_Null;
switch (symbol->scope) {
case OBJ_SymbolScope_Null: break;
case OBJ_SymbolScope_Local: storage_class = COFF_SymStorageClass_Static; break;
case OBJ_SymbolScope_Global: storage_class = COFF_SymStorageClass_External; break;
}
COFF_ObjSymbol *symbol_coff = coff_obj_writer_push_symbol(cow,
symbol->name,
0,
location,
(COFF_SymbolType){0},
storage_class);
hash_table_push_raw_raw(scratch.arena, symbol_remap, symbol, symbol_coff);
} break;
}
}
// push relocations
for EachNode(section_n, OBJ_SectionNode, obj->sections.first) {
OBJ_Section *section = &section_n->v;
COFF_ObjSection *section_coff = hash_table_search_raw_raw(section_remap, section);
for EachNode(reloc_n, OBJ_RelocNode, section->relocs.first) {
OBJ_Reloc *reloc = &reloc_n->v;
// obj -> coff reloc type
COFF_RelocType reloc_type_coff = 0;
switch (cow->machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: {
switch (reloc->kind) {
case OBJ_RelocKind_Null: break;
case OBJ_RelocKind_SecRel: reloc_type_coff = COFF_Reloc_X64_SecRel; break;
default: InvalidPath; break;
}
} break;
default: InvalidPath; break;
}
// push reloc entry
COFF_ObjSymbol *symbol_coff = hash_table_search_raw_raw(symbol_remap, reloc->symbol);
AssertAlways(symbol_coff);
coff_obj_writer_section_push_reloc(cow, section_coff, reloc->offset, symbol_coff, reloc_type_coff);
}
}
String8 raw_obj = coff_obj_writer_serialize(arena, cow);
coff_obj_writer_release(&cow);
scratch_end(scratch);
return raw_obj;
}
#endif
+24 -16
View File
@@ -1,3 +1,6 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_OBJ_WRITER_H
#define COFF_OBJ_WRITER_H
@@ -95,34 +98,39 @@ typedef struct COFF_ObjWriter
////////////////////////////////
internal COFF_ObjWriter * coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
internal COFF_ObjWriter * coff_obj_writer_alloc (COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal void coff_obj_writer_release (COFF_ObjWriter **obj_writer);
internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer);
internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol* coff_obj_writer_push_symbol (COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern (COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static (COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef (COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak (COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs (COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef (COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func (COFF_ObjWriter *obj_writer, String8 name);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect (COFF_ObjWriter *obj_writer, String8 name, U32 value);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect (COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common (COFF_ObjWriter *obj_writer, String8 name, U32 size);
internal void coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_rel32 (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff (COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
internal void coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive);
#ifdef OBJ_H
internal String8 coff_from_obj(Arena *arena, OBJ *obj);
#endif
#endif // COFF_OBJ_WRITER_H
+63 -4
View File
@@ -127,17 +127,57 @@ coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_r
U64 section_count = dim_1u64(section_table_range) / sizeof(COFF_SectionHeader);
COFF_SectionHeader **section_table = push_array_no_zero(arena, COFF_SectionHeader *, section_count+1);
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
for (U64 i = 0; i < section_count; ++i) {
section_table[i+1] = str8_deserial_get_raw_ptr(data, section_table_range.min + i*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
for EachIndex(sect_idx, section_count) {
section_table[sect_idx + 1] = str8_deserial_get_raw_ptr(data, section_table_range.min + sect_idx*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
}
return section_table;
}
internal COFF_SectionHeader *
coff_section_header_from_name(String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name)
{
for EachIndex(sect_idx, section_count) {
if (str8_match(coff_name_from_section_header(string_table, &section_table[sect_idx]), name, 0)) {
return &section_table[sect_idx];
}
}
return 0;
}
internal COFF_SectionHeaderArray
coff_section_header_array_from_name(Arena *arena, String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name)
{
U64 match_count = 0;
for EachIndex(sect_idx, section_count) {
if (str8_match(coff_name_from_section_header(string_table, &section_table[sect_idx]), name, 0)) {
match_count += 1;
}
}
COFF_SectionHeader *matches = push_array(arena, COFF_SectionHeader, match_count);
for (U64 sect_idx = 0, match_idx = 0; sect_idx < section_count; sect_idx += 1) {
if (str8_match(coff_name_from_section_header(string_table, &section_table[sect_idx]), name, 0)) {
matches[match_idx] = section_table[sect_idx];
match_idx += 1;
}
}
return (COFF_SectionHeaderArray){ .count = match_count, .v = matches };
}
internal COFF_ParsedSymbol
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
{
COFF_ParsedSymbol result = {0};
COFF_ParsedSymbol result = coff_parse_symbol32_no_name(sym32);
result.name = coff_read_symbol_name(string_table, &sym32->name);
return result;
}
internal force_inline COFF_ParsedSymbol
coff_parse_symbol32_no_name(COFF_Symbol32 *sym32)
{
COFF_ParsedSymbol result = {0};
result.value = sym32->value;
result.section_number = sym32->section_number;
result.type = sym32->type;
@@ -150,8 +190,15 @@ coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
internal COFF_ParsedSymbol
coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
{
COFF_ParsedSymbol result = {0};
COFF_ParsedSymbol result = coff_parse_symbol16_no_name(sym16);
result.name = coff_read_symbol_name(string_table, &sym16->name);
return result;
}
internal force_inline COFF_ParsedSymbol
coff_parse_symbol16_no_name(COFF_Symbol16 *sym16)
{
COFF_ParsedSymbol result = {0};
result.value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) {
result.section_number = COFF_Symbol_DebugSection32;
@@ -179,6 +226,18 @@ coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symb
return symbol;
}
internal force_inline COFF_ParsedSymbol
coff_parse_symbol_no_name(COFF_FileHeaderInfo header, String8 symbol_table, U32 symbol_idx)
{
COFF_ParsedSymbol symbol;
if (header.is_big_obj) {
symbol = coff_parse_symbol32_no_name((COFF_Symbol32 *)symbol_table.str + symbol_idx);
} else {
symbol = coff_parse_symbol16_no_name((COFF_Symbol16 *)symbol_table.str + symbol_idx);
}
return symbol;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
{
+8 -2
View File
@@ -251,14 +251,20 @@ internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff);
////////////////////////////////
// Section
internal COFF_SectionHeader ** coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range);
internal COFF_SectionHeader ** coff_section_table_from_data (Arena *arena, String8 data, Rng1U64 section_table_range);
internal COFF_SectionHeader * coff_section_header_from_name (String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name);
internal COFF_SectionHeaderArray coff_section_header_array_from_name(Arena *arena, String8 string_table, COFF_SectionHeader *section_table, U64 section_count, String8 name);
internal String8 coff_name_from_section_header (String8 string_table, COFF_SectionHeader *header);
////////////////////////////////
// Symbol
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16);
internal COFF_ParsedSymbol coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
internal COFF_ParsedSymbol coff_parse_symbol (COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
internal force_inline COFF_ParsedSymbol coff_parse_symbol32_no_name(COFF_Symbol32 *sym32);
internal force_inline COFF_ParsedSymbol coff_parse_symbol16_no_name(COFF_Symbol16 *sym16);
internal force_inline COFF_ParsedSymbol coff_parse_symbol_no_name (COFF_FileHeaderInfo header, String8 symbol_table, U32 symbol_idx);
internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
+64
View File
@@ -0,0 +1,64 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#define BUILD_CONSOLE_INTERFACE 1
#define BUILD_TITLE "The RAD Debugger (Command Line Launcher)"
#include "base/base_inc.h"
#include "base/base_inc.c"
internal void
entry_point(CmdLine *cmd_line)
{
Temp scratch = scratch_begin(0, 0);
B32 wait_for_process = cmd_line_has_flag(cmd_line, s("cli")) || cmd_line_has_flag(cmd_line, s("bin"));
String8List command_parts = {0};
String8 exe_name = str8f(scratch.arena, "%S.exe", str8_chop_last_dot(cmd_line->exe_name));
if(str8_match(exe_name, cmd_line->exe_name, 0))
{
fprintf(stderr,
"ERROR: Attempting to launch %.*s recursively.\n"
"\n"
"This executable needs to be used with a .com extension next to the real target\n"
"executable, with the same name, but with a .exe extension. This guarantees that\n"
"cmd.exe will prefer launching this .com file when the executable name is used,\n"
"allowing the same executable to be used in the Windows command-line subsystem\n"
"style when launched from the command line, but used graphically when launched\n"
"via Explorer.\n\n", str8_varg(exe_name));
fflush(stderr);
}
else
{
// NOTE(rjf): sub-processes must be killed if the parent process
// is killed, if we're waiting for it
if(wait_for_process)
{
#if OS_WINDOWS
HANDLE job_handle = CreateJobObjectA(0, 0);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = { .BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE };
SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info));
AssignProcessToJobObject(job_handle, GetCurrentProcess());
#endif
}
str8_list_push(scratch.arena, &command_parts, exe_name);
str8_list_push(scratch.arena, &command_parts, s("--cli"));
for EachIndex(idx, cmd_line->argc)
{
String8 arg = str8_cstring(cmd_line->argv[idx]);
str8_list_push(scratch.arena, &command_parts, arg);
}
StringJoin join = {.sep = s(" ")};
String8 command = str8_list_join(scratch.arena, &command_parts, &join);
Process process = launch_cmd_line(command);
if(wait_for_process)
{
U64 exit_code = 0;
process_join(process, max_U64, &exit_code);
abort_self(exit_code);
}
else
{
process_detach(process);
}
}
scratch_end(scratch);
}
+7 -7
View File
@@ -24,21 +24,21 @@ cfg_key_map_from_cfg(Arena *arena)
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
{
if(0){}
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= WM_Modifier_Ctrl; }
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= WM_Modifier_Alt; }
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= WM_Modifier_Shift; }
else
{
OS_Key key = OS_Key_Null;
for EachEnumVal(OS_Key, k)
WM_Key key = WM_Key_Null;
for EachEnumVal(WM_Key, k)
{
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
if(str8_match(child->string, wm_key_cfg_name_table[k], StringMatchFlag_CaseInsensitive))
{
key = k;
break;
}
}
if(key != OS_Key_Null)
if(key != WM_Key_Null)
{
binding.key = key;
}
+2 -2
View File
@@ -7,8 +7,8 @@
typedef struct CFG_Binding CFG_Binding;
struct CFG_Binding
{
OS_Key key;
OS_Modifiers modifiers;
WM_Key key;
WM_Modifiers modifiers;
};
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
+2 -2
View File
@@ -649,13 +649,13 @@ cfg_node_release(CFG_State *state, CFG_Node *node)
for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next)
{
CFG_Node *c = n->v;
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
U64 slot_idx = hash%state->ctx.id_slots_count;
cfg_string_release(state, c->string);
SLLStackPush(state->free, c);
c->first = c->last = c->prev = c->parent = 0;
c->id = 0;
c->string = str8_zero();
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
U64 slot_idx = hash%state->ctx.id_slots_count;
for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next)
{
if(n->v == c)
+1 -1
View File
@@ -3,6 +3,6 @@
#include "config_core.c"
#include "config_panels.c"
#if defined(OS_GFX_H)
#if defined(WINDOW_MANAGER_H)
# include "config_bindings.c"
#endif
+1 -1
View File
@@ -6,7 +6,7 @@
#include "config_core.h"
#include "config_panels.h"
#if defined(OS_GFX_H)
#if defined(WINDOW_MANAGER_H)
# include "config_bindings.h"
#endif
+3 -3
View File
@@ -46,7 +46,7 @@ c_init(void)
c_shared = push_array(arena, C_Shared, 1);
c_shared->arena = arena;
c_shared->blob_slots_count = 16384;
c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, os_get_system_info()->logical_processor_count);
c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, get_system_info()->logical_processor_count);
c_shared->blob_slots = push_array(arena, C_BlobSlot, c_shared->blob_slots_count);
c_shared->blob_stripes = push_array(arena, C_Stripe, c_shared->blob_stripes_count);
c_shared->blob_stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->blob_stripes_count);
@@ -58,7 +58,7 @@ c_init(void)
stripe->cv = cond_var_alloc();
}
c_shared->key_slots_count = 4096;
c_shared->key_stripes_count = Min(c_shared->key_slots_count, os_get_system_info()->logical_processor_count);
c_shared->key_stripes_count = Min(c_shared->key_slots_count, get_system_info()->logical_processor_count);
c_shared->key_slots = push_array(arena, C_KeySlot, c_shared->key_slots_count);
c_shared->key_stripes = push_array(arena, C_Stripe, c_shared->key_stripes_count);
c_shared->key_stripes_free_nodes = push_array(arena, C_KeyNode *, c_shared->key_stripes_count);
@@ -70,7 +70,7 @@ c_init(void)
stripe->cv = cond_var_alloc();
}
c_shared->root_slots_count = 4096;
c_shared->root_stripes_count = Min(c_shared->root_slots_count, os_get_system_info()->logical_processor_count);
c_shared->root_stripes_count = Min(c_shared->root_slots_count, get_system_info()->logical_processor_count);
c_shared->root_slots = push_array(arena, C_RootSlot, c_shared->root_slots_count);
c_shared->root_stripes = push_array(arena, C_Stripe, c_shared->root_stripes_count);
c_shared->root_stripes_free_nodes = push_array(arena, C_RootNode *, c_shared->root_stripes_count);
+3
View File
@@ -238,6 +238,9 @@ internal String8 c_data_from_hash(Access *access, U128 hash);
////////////////////////////////
//~ rjf: Asynchronous Tick
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void c_async_tick(void);
#endif // CONTENT_H
-192
View File
@@ -1,192 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Entity Kinds
@table(name code_name display_string)
CTRL_EntityKindTable:
{
{Root root "Root" }
{Machine machine "Machine" }
{Process process "Process" }
{Thread thread "Thread" }
{Module module "Module" }
{EntryPoint entry_point "Entry Point" }
{DebugInfoPath debug_info_path "Debug Info Path" }
{PendingThreadName pending_thread_name "Pending Thread Name" }
{PendingThreadColor pending_thread_color "Pending Thread Color" }
{Breakpoint breakpoint "Breakpoint" }
{AddressRangeAnnotation address_range_annotation "Address Range Annotation" }
}
@enum CTRL_EntityKind:
{
Null,
@expand(CTRL_EntityKindTable a) `$(a.name)`,
COUNT,
}
@data(String8) ctrl_entity_kind_code_name_table:
{
`{0}`,
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.code_name)")`
}
@data(String8) ctrl_entity_kind_display_string_table:
{
`{0}`,
@expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.display_name)")`
}
////////////////////////////////
//~ rjf: Exception Codes
@table(name lower_name code default display_string)
CTRL_ExceptionCodeKindTable:
{
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
{Win32DirectXDebugLayer win32_directx_debug_layer 0x0000087a 1 "(Win32) DirectX Debug Layer" }
}
@enum CTRL_ExceptionCodeKind:
{
Null,
@expand(CTRL_ExceptionCodeKindTable a) `$(a.name)`,
COUNT,
}
@data(U32) ctrl_exception_code_kind_code_table:
{
`0`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code)`;
}
@data(String8) ctrl_exception_code_kind_display_string_table:
{
`{0}`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`;
}
@data(String8) ctrl_exception_code_kind_lowercase_code_string_table:
{
`{0}`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`;
}
@data(B8) ctrl_exception_code_kind_default_enable_table:
{
`0`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default)`;
}
////////////////////////////////
//~ rjf: Exception Sub-Codes
@table(name, value)
CTRL_ExceptionSubCodeKindTable:
{
{ W32_FAST_FAIL_LEGACY_GS_VIOLATION 0 }
{ W32_FAST_FAIL_VTGUARD_CHECK_FAILURE 1 }
{ W32_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2 }
{ W32_FAST_FAIL_CORRUPT_LIST_ENTRY 3 }
{ W32_FAST_FAIL_INCORRECT_STACK 4 }
{ W32_FAST_FAIL_INVALID_ARG 5 }
{ W32_FAST_FAIL_GS_COOKIE_INIT 6 }
{ W32_FAST_FAIL_FATAL_APP_EXIT 7 }
{ W32_FAST_FAIL_RANGE_CHECK_FAILURE 8 }
{ W32_FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10 }
{ W32_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11 }
{ W32_FAST_FAIL_INVALID_FIBER_SWITCH 12 }
{ W32_FAST_FAIL_INVALID_SET_OF_CONTEXT 13 }
{ W32_FAST_FAIL_INVALID_REFERENCE_COUNT 14 }
{ W32_FAST_FAIL_INVALID_JUMP_BUFFER 18 }
{ W32_FAST_FAIL_MRDATA_MODIFIED 19 }
{ W32_FAST_FAIL_CERTIFICATION_FAILURE 20 }
{ W32_FAST_FAIL_INVALID_EXCEPTION_CHAIN 21 }
{ W32_FAST_FAIL_CRYPTO_LIBRARY 22 }
{ W32_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23 }
{ W32_FAST_FAIL_INVALID_IMAGE_BASE 24 }
{ W32_FAST_FAIL_DLOAD_PROTECTION_FAILURE 25 }
{ W32_FAST_FAIL_UNSAFE_EXTENSION_CALL 26 }
{ W32_FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27 }
{ W32_FAST_FAIL_INVALID_BUFFER_ACCESS 28 }
{ W32_FAST_FAIL_INVALID_BALANCED_TREE 29 }
{ W32_FAST_FAIL_INVALID_NEXT_THREAD 30 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 }
{ W32_FAST_FAIL_APCS_DISABLED 32 }
{ W32_FAST_FAIL_INVALID_IDLE_STATE 33 }
{ W32_FAST_FAIL_MRDATA_PROTECTION_FAILURE 34 }
{ W32_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35 }
{ W32_FAST_FAIL_INVALID_LOCK_STATE 36 }
{ W32_FAST_FAIL_GUARD_JUMPTABLE 37 }
{ W32_FAST_FAIL_INVALID_LONGJUMP_TARGET 38 }
{ W32_FAST_FAIL_INVALID_DISPATCH_CONTEXT 39 }
{ W32_FAST_FAIL_INVALID_THREAD 40 }
{ W32_FAST_FAIL_INVALID_SYSCALL_NUMBER 41 }
{ W32_FAST_FAIL_INVALID_FILE_OPERATION 42 }
{ W32_FAST_FAIL_LPAC_ACCESS_DENIED 43 }
{ W32_FAST_FAIL_GUARD_SS_FAILURE 44 }
{ W32_FAST_FAIL_LOADER_CONTINUITY_FAILURE 45 }
{ W32_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE 46 }
{ W32_FAST_FAIL_INVALID_CONTROL_STACK 47 }
{ W32_FAST_FAIL_SET_CONTEXT_DENIED 48 }
{ W32_FAST_FAIL_INVALID_IAT 49 }
{ W32_FAST_FAIL_HEAP_METADATA_CORRUPTION 50 }
{ W32_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION 51 }
{ W32_FAST_FAIL_LOW_LABEL_ACCESS_DENIED 52 }
{ W32_FAST_FAIL_ENCLAVE_CALL_FAILURE 53 }
{ W32_FAST_FAIL_UNHANDLED_LSS_EXCEPTON 54 }
{ W32_FAST_FAIL_ADMINLESS_ACCESS_DENIED 55 }
{ W32_FAST_FAIL_UNEXPECTED_CALL 56 }
{ W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS 57 }
{ W32_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR 58 }
{ W32_FAST_FAIL_FLAGS_CORRUPTION 59 }
{ W32_FAST_FAIL_VEH_CORRUPTION 60 }
{ W32_FAST_FAIL_ETW_CORRUPTION 61 }
{ W32_FAST_FAIL_RIO_ABORT 62 }
{ W32_FAST_FAIL_INVALID_PFN 63 }
{ W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG 64 }
{ W32_FAST_FAIL_CAST_GUARD 65 }
{ W32_FAST_FAIL_HOST_VISIBILITY_CHANGE 66 }
{ W32_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST 67 }
{ W32_FAST_FAIL_PATCH_CALLBACK_FAILED 68 }
{ W32_FAST_FAIL_NTDLL_PATCH_FAILED 69 }
{ W32_FAST_FAIL_INVALID_FLS_DATA 70 }
}
-6739
View File
File diff suppressed because it is too large Load Diff
-1032
View File
File diff suppressed because it is too large Load Diff
-77
View File
@@ -1,77 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CTRL_INC_H
#define CTRL_INC_H
////////////////////////////////
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
//
// This layer's purpose is to provide access to the asynchronously-running, low
// level parts of a debugger, running on the debugger client. This primarily
// consists of process control, using the Demon layer (the lower level
// abstraction layer for process control, across multiple OSes), but including
// higher-level concepts, like stepping, breakpoint resolution, conditional
// breakpoint evaluation, and so on. Right now, this just includes process
// control *local to the debugger client machine*. But in the future, this can
// also include communication to multiple target machines, all running their
// own process controller, using the Demon layer.
//
// This part of a debugger must run asynchronously to prevent blocking the UI -
// ideally our debugger is designed such that, if targets are running, the
// debugger frontend is still usable for a variety of purposes. So, in short,
// the asynchronously-running "control thread", implemented by this layer, is
// tasked with communicating with a separately executing "user thread". This
// communication happens in two directions - `user -> ctrl`, and the reverse,
// `ctrl -> user`.
//
// In the case of `user -> ctrl` communication, this is done with a ring buffer
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
// include commands like: launching targets, attaching to targets, killing
// targets, detaching from targets, stepping/running, or single stepping.
//
// In the case of `ctrl -> user` communication, this is done with a ring buffer
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
// include information about what happened during the execution of targets -
// including: process/module/thread creation, process/module/thread deletion,
// debug strings, thread name events, memory allocation events, and stop events
// (where stops can be caused by: user breakpoints, traps set for stepping,
// exceptions, halts, or errors).
//
// The various stepping algorithms are implemented with two concepts: (a) the
// "trap net", and (b) "spoofs".
//
// A "trap net" is a term which refers to a set of addresses paired with a set
// of behavioral flags. Before targets run, trap instructions are written to
// these addresses. After targets stop, these addresses are reset to their
// original bytes. These trap instructions cause the debugger's targets to
// stop executing, and based on which behavioral flags are associated with
// the instruction causing the stop, the control thread may adjust parameters
// used for running, then continue execution, or it will not resume target
// execution, and will report stopped events. These behavioral flags can
// include: single-stepping the stopped thread to execute the instruction at
// the trap location, saving a stack pointer "check value" (where this check
// value is compared against when making decisions about whether to continue
// running or not), and so on. It's complicated to unpack why exactly these
// behaviors are useful, but the TL;DR of it is that they are used for a
// variety of stepping behaviors. For example, when doing a "step into" step,
// a `call` instruction can have a trap set at it, and will be marked with
// a "single-step-after" trap flag, as well as the "end stepping" trap flag,
// such that the step operation will complete after the `call` has executed.
//
// A "spoof" is a feature the control layer uses to detect when some thread
// returns from a particular sub-callstack. This is useful when implementing
// "step over" in functions that may be recursive. In short, unlike a trap,
// which writes a trap instruction (like `int3`) into an instruction stream,
// a spoof overwrites a *return address* on some thread's *stack*. This return
// address is not a valid address for executing code -- it is simply a value
// that the debugger can recognize, such that it is notified when the thread
// returns from some level in a callstack. When the thread exits some function,
// it will return to the "spoofed" address, and it will immediately hit an
// exception, because the spoofed address will not be a valid address for
// code execution. At that point, the debugger can move the thread back to
// the pre-spoof return address, and resume execution.
#include "ctrl_core.h"
#endif // CTRL_INC_H
-208
View File
@@ -1,208 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
C_LINKAGE_BEGIN
String8 ctrl_entity_kind_code_name_table[12] =
{
{0},
str8_lit_comp("root"),
str8_lit_comp("machine"),
str8_lit_comp("process"),
str8_lit_comp("thread"),
str8_lit_comp("module"),
str8_lit_comp("entry_point"),
str8_lit_comp("debug_info_path"),
str8_lit_comp("pending_thread_name"),
str8_lit_comp("pending_thread_color"),
str8_lit_comp("breakpoint"),
str8_lit_comp("address_range_annotation"),
};
String8 ctrl_entity_kind_display_string_table[12] =
{
{0},
str8_lit_comp("Root"),
str8_lit_comp("Machine"),
str8_lit_comp("Process"),
str8_lit_comp("Thread"),
str8_lit_comp("Module"),
str8_lit_comp("EntryPoint"),
str8_lit_comp("DebugInfoPath"),
str8_lit_comp("PendingThreadName"),
str8_lit_comp("PendingThreadColor"),
str8_lit_comp("Breakpoint"),
str8_lit_comp("AddressRangeAnnotation"),
};
U32 ctrl_exception_code_kind_code_table[38] =
{
0,
0x40010005,
0x40010008,
0x40080201,
0x40080202,
0x0000071a,
0x80000002,
0xc0000005,
0xc0000006,
0xc0000008,
0xc0000017,
0xc000001d,
0xc0000025,
0xc0000026,
0xc000008c,
0xc000008d,
0xc000008e,
0xc000008f,
0xc0000090,
0xc0000091,
0xc0000092,
0xc0000093,
0xc0000094,
0xc0000095,
0xc0000096,
0xc00000fd,
0xc0000135,
0xc0000138,
0xc0000139,
0xc0000142,
0xc00002b4,
0xc00002b5,
0xc0000420,
0xc06d007e,
0xc06d007f,
0xe073616e,
0xe0736171,
0x0000087a,
};
String8 ctrl_exception_code_kind_display_string_table[38] =
{
{0},
str8_lit_comp("(Win32) Control-C"),
str8_lit_comp("(Win32) Control-Break"),
str8_lit_comp("(Win32) WinRT Originate Error"),
str8_lit_comp("(Win32) WinRT Transform Error"),
str8_lit_comp("(Win32) RPC Call Cancelled"),
str8_lit_comp("(Win32) Data Type Misalignment"),
str8_lit_comp("(Win32) Access Violation"),
str8_lit_comp("(Win32) In Page Error"),
str8_lit_comp("(Win32) Invalid Handle Specified"),
str8_lit_comp("(Win32) Not Enough Quota"),
str8_lit_comp("(Win32) Illegal Instruction"),
str8_lit_comp("(Win32) Cannot Continue From Exception"),
str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"),
str8_lit_comp("(Win32) Array Bounds Exceeded"),
str8_lit_comp("(Win32) Floating-Point Denormal Operand"),
str8_lit_comp("(Win32) Floating-Point Division By Zero"),
str8_lit_comp("(Win32) Floating-Point Inexact Result"),
str8_lit_comp("(Win32) Floating-Point Invalid Operation"),
str8_lit_comp("(Win32) Floating-Point Overflow"),
str8_lit_comp("(Win32) Floating-Point Stack Check"),
str8_lit_comp("(Win32) Floating-Point Underflow"),
str8_lit_comp("(Win32) Integer Division By Zero"),
str8_lit_comp("(Win32) Integer Overflow"),
str8_lit_comp("(Win32) Privileged Instruction"),
str8_lit_comp("(Win32) Stack Overflow"),
str8_lit_comp("(Win32) Unable To Locate DLL"),
str8_lit_comp("(Win32) Ordinal Not Found"),
str8_lit_comp("(Win32) Entry Point Not Found"),
str8_lit_comp("(Win32) DLL Initialization Failed"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"),
str8_lit_comp("(Win32) Assertion Failed"),
str8_lit_comp("(Win32) Module Not Found"),
str8_lit_comp("(Win32) Procedure Not Found"),
str8_lit_comp("(Win32) Sanitizer Error Detected"),
str8_lit_comp("(Win32) Sanitizer Raw Access Violation"),
str8_lit_comp("(Win32) DirectX Debug Layer"),
};
String8 ctrl_exception_code_kind_lowercase_code_string_table[38] =
{
{0},
str8_lit_comp("win32_ctrl_c"),
str8_lit_comp("win32_ctrl_break"),
str8_lit_comp("win32_win_rt_originate_error"),
str8_lit_comp("win32_win_rt_transform_error"),
str8_lit_comp("win32_rpc_call_cancelled"),
str8_lit_comp("win32_datatype_misalignment"),
str8_lit_comp("win32_access_violation"),
str8_lit_comp("win32_in_page_error"),
str8_lit_comp("win32_invalid_handle"),
str8_lit_comp("win32_not_enough_quota"),
str8_lit_comp("win32_illegal_instruction"),
str8_lit_comp("win32_cannot_continue_exception"),
str8_lit_comp("win32_invalid_exception_disposition"),
str8_lit_comp("win32_array_bounds_exceeded"),
str8_lit_comp("win32_floating_point_denormal_operand"),
str8_lit_comp("win32_floating_point_division_by_zero"),
str8_lit_comp("win32_floating_point_inexact_result"),
str8_lit_comp("win32_floating_point_invalid_operation"),
str8_lit_comp("win32_floating_point_overflow"),
str8_lit_comp("win32_floating_point_stack_check"),
str8_lit_comp("win32_floating_point_underflow"),
str8_lit_comp("win32_integer_division_by_zero"),
str8_lit_comp("win32_integer_overflow"),
str8_lit_comp("win32_privileged_instruction"),
str8_lit_comp("win32_stack_overflow"),
str8_lit_comp("win32_unable_to_locate_dll"),
str8_lit_comp("win32_ordinal_not_found"),
str8_lit_comp("win32_entry_point_not_found"),
str8_lit_comp("win32_dll_initialization_failed"),
str8_lit_comp("win32_floating_point_sse_multiple_faults"),
str8_lit_comp("win32_floating_point_sse_multiple_traps"),
str8_lit_comp("win32_assertion_failed"),
str8_lit_comp("win32_module_not_found"),
str8_lit_comp("win32_procedure_not_found"),
str8_lit_comp("win32_sanitizer_error_detected"),
str8_lit_comp("win32_sanitizer_raw_access_violation"),
str8_lit_comp("win32_directx_debug_layer"),
};
B8 ctrl_exception_code_kind_default_enable_table[38] =
{
0,
1,
1,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
1,
};
C_LINKAGE_END
-79
View File
@@ -1,79 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
#ifndef CTRL_META_H
#define CTRL_META_H
typedef enum CTRL_EntityKind
{
CTRL_EntityKind_Null,
CTRL_EntityKind_Root,
CTRL_EntityKind_Machine,
CTRL_EntityKind_Process,
CTRL_EntityKind_Thread,
CTRL_EntityKind_Module,
CTRL_EntityKind_EntryPoint,
CTRL_EntityKind_DebugInfoPath,
CTRL_EntityKind_PendingThreadName,
CTRL_EntityKind_PendingThreadColor,
CTRL_EntityKind_Breakpoint,
CTRL_EntityKind_AddressRangeAnnotation,
CTRL_EntityKind_COUNT,
} CTRL_EntityKind;
typedef enum CTRL_ExceptionCodeKind
{
CTRL_ExceptionCodeKind_Null,
CTRL_ExceptionCodeKind_Win32CtrlC,
CTRL_ExceptionCodeKind_Win32CtrlBreak,
CTRL_ExceptionCodeKind_Win32WinRTOriginateError,
CTRL_ExceptionCodeKind_Win32WinRTTransformError,
CTRL_ExceptionCodeKind_Win32RPCCallCancelled,
CTRL_ExceptionCodeKind_Win32DatatypeMisalignment,
CTRL_ExceptionCodeKind_Win32AccessViolation,
CTRL_ExceptionCodeKind_Win32InPageError,
CTRL_ExceptionCodeKind_Win32InvalidHandle,
CTRL_ExceptionCodeKind_Win32NotEnoughQuota,
CTRL_ExceptionCodeKind_Win32IllegalInstruction,
CTRL_ExceptionCodeKind_Win32CannotContinueException,
CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition,
CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded,
CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand,
CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero,
CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult,
CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation,
CTRL_ExceptionCodeKind_Win32FloatingPointOverflow,
CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck,
CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow,
CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero,
CTRL_ExceptionCodeKind_Win32IntegerOverflow,
CTRL_ExceptionCodeKind_Win32PrivilegedInstruction,
CTRL_ExceptionCodeKind_Win32StackOverflow,
CTRL_ExceptionCodeKind_Win32UnableToLocateDLL,
CTRL_ExceptionCodeKind_Win32OrdinalNotFound,
CTRL_ExceptionCodeKind_Win32EntryPointNotFound,
CTRL_ExceptionCodeKind_Win32DLLInitializationFailed,
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults,
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps,
CTRL_ExceptionCodeKind_Win32AssertionFailed,
CTRL_ExceptionCodeKind_Win32ModuleNotFound,
CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
CTRL_ExceptionCodeKind_Win32DirectXDebugLayer,
CTRL_ExceptionCodeKind_COUNT,
} CTRL_ExceptionCodeKind;
C_LINKAGE_BEGIN
extern String8 ctrl_entity_kind_code_name_table[12];
extern String8 ctrl_entity_kind_display_string_table[12];
extern U32 ctrl_exception_code_kind_code_table[38];
extern String8 ctrl_exception_code_kind_display_string_table[38];
extern String8 ctrl_exception_code_kind_lowercase_code_string_table[38];
extern B8 ctrl_exception_code_kind_default_enable_table[38];
C_LINKAGE_END
#endif // CTRL_META_H

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