Compare commits

...

272 Commits

Author SHA1 Message Date
Ty Lamontagne
c9642b70f6 CDVD: Only take ADR and track index/num from host IOCTL SUBQ
Fixes the OSDSYS CD player minute:second counter
2024-11-25 10:02:23 -05:00
Ty Lamontagne
849fa57bf6 CDVD: Adjust register logging 2024-11-25 10:02:23 -05:00
Ty Lamontagne
2c95ef76f1 CDVD: Minor cleanup and fix off-by-one TOC filling issue 2024-11-25 10:02:23 -05:00
Ty Lamontagne
4d9cb885b2 CDVD: Use disc track indexes for our track array. 2024-11-25 10:02:23 -05:00
Ty Lamontagne
e375f98f7a CDVD: Fix OSDSYS Audio CD regression.
There is still an existing issue with the tracks.
2024-11-25 10:02:23 -05:00
lightningterror
1b80f3aea2 Vif: Cleanup code a bit.
Const, casts, nullptr.
2024-11-25 14:02:59 +01:00
Jordan
b0496645f1 GameDB: Various fixes (#12030)
Fixes texture flickering in mission screens on PTO IV Pacific Theater of Operations and corrupted textures banding lighting in levels and bloom misalignment in MOH European Assault.
2024-11-24 19:39:05 +01:00
lightningterror
235cb13647 Vif: Replace some asserts with logs.
The conditions need hardware testing.
Use logs instead so the games don't crash and are still playable.
2024-11-23 13:13:19 +01:00
lightningterror
504dd9f513 Vif: Rename/remove new prefix from files. 2024-11-23 13:13:19 +01:00
Ty Lamontagne
e3fedf1676 QT: Use SetStatusText instead of passing a formatted string as a fmt
This caused crashes when file names had percent signs in them because we passed the file name as the format to SetFormattedStatusText. I opted to continue to use fmt for consistency.
2024-11-22 19:28:55 -05:00
lightningterror
f113a51783 DEV9: Code cleanup.
Casts, constants, unused functions, switch cases.
2024-11-23 00:21:41 +01:00
chaoticgd
f69d5835b8 PINE: Fix stack buffer overflow for long XDG_RUNTIME_DIR paths 2024-11-22 14:10:32 -05:00
PCSX2 Bot
8e8277c0c9 [ci skip] Qt: Update Base Translation. 2024-11-21 01:42:41 +01:00
secondsabre
c6c4eaf31c GameDB: Atelier Iris (SLUS-21113) fixes (#12021) 2024-11-20 15:33:34 -05:00
KamFretoZ
6324722b65 Qt: Add Volume indicator to verbose status 2024-11-20 15:56:15 +01:00
KamFretoZ
efd8c9ec69 OSD: Move VU stats above SW threads. 2024-11-20 15:56:15 +01:00
TellowKrinkle
9858aa1aa5 CMake: Try to put /usr/local/include last 2024-11-18 02:22:30 -06:00
PCSX2 Bot
256a946f96 [ci skip] Qt: Update Base Translation. 2024-11-17 14:43:32 +01:00
chaoticgd
a507964f33 Debugger: Generate a name map for label symbols 2024-11-16 11:50:19 -05:00
chaoticgd
7584a6bb29 Debugger: Allow symbols starting with an underscore in expressions 2024-11-16 11:50:19 -05:00
chaoticgd
ce6103be30 Debugger: Improve function scanner performance for unmapped addresses 2024-11-16 11:50:19 -05:00
chaoticgd
9da4459ab3 Debugger: Run the function scanner on the main symbol database 2024-11-16 11:50:19 -05:00
chaoticgd
3b9b9a84cd Debugger: Use expressions for the function scanner address range 2024-11-16 11:50:19 -05:00
chaoticgd
cce0ae4369 Debugger: Allow loading symbols conditionally and with a base address 2024-11-16 11:50:19 -05:00
chaoticgd
efb43ac7f9 Debugger: Make the expression parser thread safe 2024-11-16 11:50:19 -05:00
lightningterror
8132a8a7f8 USB: Cleanup eyetoy code a bit.
Types, casts, consts.
2024-11-15 15:58:23 +01:00
PCSX2 Bot
9c753cb692 [ci skip] Qt: Update Base Translation. 2024-11-15 14:26:08 +01:00
Berylskid
514e6675c4 GameDB: Fix Enemies Stuck in Armored Core Nine Breaker 2024-11-14 11:22:00 -05:00
Chromaryu
18454fd5d0 GameDB: Add TexInRT on SLPM-62482 2024-11-14 11:20:03 -05:00
chaoticgd
eeb919325e Misc: Minimise the amount of work done when svnrev.h is updated 2024-11-12 09:14:39 -05:00
Julien Reichardt
959be142ed Deps: Update Flatpak dependencies 2024-11-12 08:36:52 -05:00
PCSX2 Bot
42be91d48d PAD: Update to latest controller database. 2024-11-11 14:20:57 -05:00
Bobby Smith
908f916656 GameDB: NBA 2K6 fix hangs on PAL version 2024-11-11 11:52:44 -05:00
Ty Lamontagne
5441c7ed59 Debugger: Use native separators when using external symbol files 2024-11-06 17:06:37 -05:00
chaoticgd
bea471a0e3 Debugger: Fix loading symbols from ELF files other than the boot ELF 2024-11-06 16:58:07 -05:00
chaoticgd
4dafee17e0 Debugger: Refactor nocash symbol importer 2024-11-06 14:23:22 -05:00
PCSX2 Bot
af10be9036 [ci skip] Qt: Update Base Translation. 2024-11-05 19:06:39 -05:00
KamFretoZ
1a4e3ab581 OSD: Fix Pause indicator not showing up 2024-11-05 10:38:49 -05:00
lightningterror
d9e9cf8967 workflows: Fix commit name for daily translations.
Also keep [ci skip] at the start of the commit name as some workflows may require it at the start.
2024-11-05 14:38:58 +01:00
PCSX2 Bot
041b0cb561 PAD: Update to latest controller database. 2024-11-04 17:37:11 +01:00
JordanTheToaster
4ad5dde780 3rdparty: Sync cpuinfo to commit 8df44962d437a0477f07ba6b8843d0b6a48646a4 2024-11-04 12:41:54 +01:00
JordanTheToaster
0bc043a0bb 3rdparty: Update LZMA/7zipSDK to 24.08 2024-11-04 12:41:54 +01:00
JordanTheToaster
c936b7db29 Deps: Update SDL to 2.30.9 2024-11-04 12:41:54 +01:00
JordanTheToaster
2793c49694 Deps: Update Freetype to 2.13.3
a
2024-11-04 12:41:54 +01:00
JordanTheToaster
c578859122 3rdparty: Update xbyak to 7.21 2024-11-04 12:41:54 +01:00
JordanTheToaster
43e6f06a9e Deps: Update libpng to 1.6.44 2024-11-04 12:41:54 +01:00
JordanTheToaster
cf8e9f773e Deps: Update Harfbuzz to 10.0.1 2024-11-04 12:41:54 +01:00
PCSX2 Bot
ed3bdc61f4 Qt: Update Base Translation 2024-11-04 12:40:42 +01:00
TheLastRar
e57f7d92c3 FSUI: Don't move IMGUI cursor unnecessarily in DrawGameGrid() 2024-11-04 12:40:31 +01:00
Gd7
b95eb5cd74 GameDB: Final Fantasy X Optimal FPU config. (#11958)
Fixes the vast majority of FFX's FPU glitches as well as fixing a major cutscene bug without breaking anything more than what the current config already breaks.

EE clamping fixes reverse controls and characters and enemies facing the wrong way during battles, everything else is affected by EE rounding and EE division rounding.

VU0 clamping affects nothing.
2024-11-04 12:40:16 +01:00
KamFretoZ
b865bbb0d3 CI: Add ci skip to base translation update workflow 2024-11-04 12:39:04 +01:00
KamFretoZ
ca6e1c9a46 Qt: Cleanup Unused InputRec Menu 2024-11-04 12:39:04 +01:00
KamFretoZ
ea8a2deae6 Qt: Icon Tweaks 2024-11-04 12:39:04 +01:00
KamFretoZ
c67237672c Qt/Savestate: Add option to disable savestate selector UI 2024-11-04 12:39:04 +01:00
Ty Lamontagne
2d5faa627f CI: Default to flatpak beta branch 2024-10-31 09:22:11 -04:00
Tyler Wilding
1562ba4ca0 translations: Syncing Crowdin translations (#11970) 2024-10-31 09:21:06 -04:00
Ty Lamontagne
a5d94ac454 Patches: Fix a regression that broke gamedb dynpatches 2024-10-30 17:07:07 -04:00
Ty Lamontagne
943fbd8719 Dis5900asm: Fix an out of bounds access on invalid pmfhl formats 2024-10-30 09:15:17 -04:00
Ty Lamontagne
eea1d57e7e PAD: Fix negon and jogcon BPM crash 2024-10-29 18:52:44 -04:00
PCSX2 Bot
74645aa1b7 PAD: Update to latest controller database. 2024-10-28 17:56:47 +01:00
PCSX2 Bot
dfd23d9a25 Qt: Update Base Translation 2024-10-27 20:07:36 -04:00
KamFretoZ
27cf16a09c CI: Fix Translation Workflow Scripts Order of Operation
[ci skip]
2024-10-27 10:20:02 -04:00
PCSX2 Bot
0dee9e3ff1 Qt: Update Base Translation 2024-10-26 21:06:14 -04:00
KamFretoZ
9b47dc0ee3 OSD: Fix Input Overlay Clipping 2024-10-26 11:20:49 -04:00
KamFretoZ
c7b9ee92b7 Qt: Properly Grey Out Checkboxes When Perf OSD is Disabled 2024-10-26 11:20:49 -04:00
KamFretoZ
ac32e6ca92 FSUI: Fix and Tweak BPM Buttons and Legends 2024-10-26 11:20:49 -04:00
TheLastRar
0c204c3ebb Qt: Hackfix settings icon stretching on Windows themes 2024-10-24 12:23:36 -04:00
PCSX2 Bot
016b871734 Qt: Update Base Translation 2024-10-23 20:04:03 -04:00
lightningterror
22413b8e7f GS/OGL: Only paste all available extensions in dev/debug build. 2024-10-23 10:11:06 -04:00
lightningterror
1b50057764 GS/Qt: Adjust how we handle Default adapter.
Try to resolve it again since it annoys me.

Treat is as empty.

Also do NOT translate Default adapter,
it messes with the ini config.
2024-10-23 10:11:06 -04:00
lightningterror
9e15058634 GS/D3D12: Disable DX12 if feature level is not detected.
Intel Haswell doesn't actually support DX12 even tho the device is created which results in a crash,
to get around this check if device can be created using feature level 12 (skylake+).
2024-10-23 10:11:06 -04:00
lightningterror
2a81a7af9e GS: Check feature level 12 as a requirement when selecting auto renderer on intel.
Just to be on the safe side when selecting OpenGL.
2024-10-23 10:11:06 -04:00
chaoticgd
6d3d5ebdc5 Qt: Fix symbol sources list in per-game settings dialog 2024-10-23 09:58:59 -04:00
chaoticgd
7d63a9e51c Debugger: Avoid resetting symbol trees while single stepping 2024-10-23 09:58:02 -04:00
JordanTheToaster
56a2b3b5ad VMManager: Add renderer selection warning 2024-10-23 09:55:36 -04:00
badfontkeming
f46f788d80 USB: Fix FFB quality and dropouts for most wheels, make workaround optional
The original workaround for FFB issues simply restarted the constant force
each time it was updated. Turns out that a lot of wheels don't behave
perfectly during this. A better fix was found, which is to set the effect
duration to infinite. However, some wheels are so bugged that they don't even
respect THAT, so the workaround needs to stick around in some capacity.
2024-10-23 08:40:47 -04:00
TheLastRar
a044b7cf6e DEV9: Set/Clear SEEK bit in all relevent commands (#11931)
* DEV9: Set SEEK on all successful seeks

* DEV9: Complete HDD_Flush immediately when write queue is empty

Also set SEEK when write queue isn't empty

* DEV9: Lock reported value of SEEK when errored
2024-10-23 08:36:16 -04:00
Rares-Alexandru Fodor
8afd29e1a2 Qt: Add search bar for cheats 2024-10-23 08:34:47 -04:00
Rares-Alexandru Fodor
d89b051e6d Qt: Replace QTreeWidget with QTreeView for cheat list 2024-10-23 08:34:47 -04:00
Ty Lamontagne
47cf69d2b3 TraceLogging: Fix SIF trace logging 2024-10-23 08:30:37 -04:00
PCSX2 Bot
35c3c912e7 PAD: Update to latest controller database. 2024-10-21 12:02:59 -04:00
Ziemas
67c5f0229b EE: vtlb handler for writes to IOP mem 2024-10-21 11:14:29 -04:00
github-actions[bot]
5dcc79555d Qt: Update Base Translation (#11932)
Co-authored-by: PCSX2 Bot <PCSX2Bot@users.noreply.github.com>
2024-10-20 20:04:11 -04:00
TheLastRar
82f741e1dc DEV9: Add ATA commands used by PS2 Linux (#11925) 2024-10-19 20:05:34 -04:00
Ty Lamontagne
ab21d22514 Misc: wire up and refactor trace logging 2024-10-19 20:04:02 -04:00
PCSX2 Bot
0a599e7337 Qt: Update Base Translation 2024-10-18 20:26:49 -04:00
chaoticgd
f77bf1ec6b Debugger: Be smarter about deciding when functions should be hashed 2024-10-18 13:57:05 -04:00
chaoticgd
ed4fbb4f5a Debugger: Hash functions scanned in by the MIPS analyst 2024-10-18 13:57:05 -04:00
chaoticgd
f963291970 Debugger: Cache hash match results on symbol tree nodes 2024-10-18 13:57:05 -04:00
chaoticgd
2c3abe33d5 Debugger: Add settings to control the analysis passes 2024-10-18 13:57:05 -04:00
chaoticgd
0fd7e1d7c2 Debugger: Split out SymbolImporter into its own class 2024-10-18 13:57:05 -04:00
TheLastRar
1e23e7efc4 DEV9: Add note regarding IF_CTRL bit 3 2024-10-17 16:10:38 -04:00
TheLastRar
46d5d24fcd DEV9: Correct SPD_XFR_DMAEN define 2024-10-17 16:10:38 -04:00
TheLastRar
3276c0db9c DEV9: Correct implementation of SPD_R_DBUF_STAT reset 2024-10-17 16:10:38 -04:00
TheLastRar
1bdd53a6c5 DEV9: Don't fake the FIFO 2024-10-17 16:10:38 -04:00
TheLastRar
1f2d9ab4e5 IOP: Seperate completing DMA8 to a seperate function 2024-10-17 16:10:38 -04:00
TheLastRar
0806ca442a DEV9: Use ReceivedPayload more in TCP_Session
Instead of shuffling a unique_ptr around
Fixes handling of connection failure in ConnectTCPComplete()
2024-10-15 08:51:09 -04:00
TheLastRar
e3a666bfe4 DEV9: Move adapter detection hack 2024-10-15 08:37:21 -04:00
TheLastRar
6b2dc7a68c DEV9: Move call to network backend reset
SMAP_R_EMAC3_TxMODE1_L is unrelated to resetting the adapter
2024-10-15 08:37:21 -04:00
PCSX2 Bot
18c492d9da Qt: Update Base Translation 2024-10-15 12:28:13 +02:00
TheLastRar
6065caaf19 DEV9: Allow writes to ATA_R_CONTROL while busy 2024-10-15 12:22:03 +02:00
TheLastRar
bb4c456f35 DEV9: Disable interrupts on reset 2024-10-15 12:22:03 +02:00
TheLastRar
078a10dcdb DEV9: Implement ATA pending interrupts 2024-10-15 12:22:03 +02:00
TheLastRar
a8a0c5c0bf DEV9: Rewrite suppression of diagnostics IRQ during reset 2024-10-15 12:22:03 +02:00
TheLastRar
1a95bd3088 DEV9: Support 8bit reads/writes for most ATA regs 2024-10-15 12:22:03 +02:00
PCSX2 Bot
cf157fd2d7 PAD: Update to latest controller database. 2024-10-14 18:12:02 +02:00
Ziemas
35ada362d4 IOP/EE: Add SBUS interrupts
Lets the CPUs trigger an interrupt on the other.
2024-10-14 09:15:42 -04:00
KamFretoZ
444b110411 GSDevice11: Don't try to get the adapter name twice 2024-10-14 14:42:01 +02:00
KamFretoZ
1b82fac70e OSD: Clarify Min/Avg/Max label to Frametime counter 2024-10-14 14:42:01 +02:00
badfontkeming
dafca1e264 USB: Work around FFB dropouts with modern wheels
Certain modern direct-drive wheels such as the Moza R5, R9, etc. implement
timeouts for FFB constant forces, and expect the forces to be re-run
rather than updated in order to refresh these timeouts.
2024-10-13 17:58:52 -04:00
lightningterror
69de95df8b GS: Default to OpenGL on intel GPUs that support it.
Feature level 12 requirement.
2024-10-13 23:15:22 +02:00
JordanTheToaster
ca9f64a08b GameDB: Various fixes 2024-10-13 11:03:22 -04:00
PCSX2 Bot
3b3e35beb7 Qt: Update Base Translation 2024-10-13 00:05:55 +02:00
TheLastRar
c087fc430b DEV9: Allow 8bit reads/writes to all SPEED regs 2024-10-11 19:13:06 -04:00
TheLastRar
d1a4733939 DEV9: Replace incorrect SPD_R_20 behaviour 2024-10-11 19:13:06 -04:00
Bobby Smith
5845109b75 Qt: Call 'map_text_to_keycode()' only when Shift modifier is being used 2024-10-10 18:35:36 -04:00
Ty Lamontagne
7dd2ebdf49 Translations: hotfix a translation mistake causing fmt to crash 2024-10-09 19:24:08 -04:00
TheLastRar
3e78322ea4 DEV9: Rework tx_process based on HW tests 2024-10-09 10:37:54 -04:00
Chromaryu
8d6633fcf9 OSD: Update OSD Text on SW mode so no overlap keyword appears (#11881) 2024-10-09 08:25:30 -04:00
Ty Lamontagne
1c1f67c091 IOP HLE: Only track handles to valid files.
Bonus check for file validity when saving states.
2024-10-08 18:01:11 -04:00
PCSX2 Bot
324b1464e4 Qt: Update Base Translation 2024-10-08 22:13:02 +02:00
JordanTheToaster
1e9a248a0c Deps: Update to Qt 6.8.0 on Windows and Linux 2024-10-08 16:00:37 -04:00
TheLastRar
4319094b02 QT: Clear m_status_verbose_widget text on VM stop 2024-10-08 15:44:59 -04:00
chaoticgd
60abebb3a5 Debugger: Fix crash in symbol tree menu code 2024-10-08 09:47:41 -04:00
PCSX2 Bot
62f20a4809 PAD: Update to latest controller database. 2024-10-07 18:06:16 +02:00
Ty Lamontagne
924326460c Debugger: Destroy and re-create the debugger on theme change 2024-10-07 11:24:09 -04:00
pips3
bba85dc08f HostFS: Retain File Handles in Save States
[SAVEVERSION+]
Save file handle information in save states, and reopen handles when states are loaded.
2024-10-07 09:56:31 -04:00
KamFretoZ
68678ac4ec CI: Add other translations related scripts script to the daily workflow
[ci skip]
2024-10-06 09:31:31 -04:00
PCSX2 Bot
7f9f383324 Qt: Update Base Translation 2024-10-05 20:06:55 -04:00
wxvu
1239c94fba GameDB: Add hwfixes to Armored Core 3 and Sandlot titles. (#11873)
Adds Merge Sprite to Armored Core 3 and adds HPO Native + Autoflush to all Sandlot titles.
2024-10-06 00:38:34 +02:00
KamFretoZ
2ab24bbf28 Qt: Move savestate related options to its new home 2024-10-05 11:04:39 -04:00
KamFretoZ
a304959933 OSD/Savestate: Add close menu hint to the selector
Don't you hate it when you come up with more ideas just minutes AFTER the PR has been merged?
2024-10-05 11:04:39 -04:00
lightningterror
5f0bc729d7 GS/TC: Clamp TW/TH to 11 in source flush.
Clamp TW/TH to 11, as GS memory loops around 2048, anything higher than 12 causes a crash when texture mapping isn't supported like in Direct3D11.
2024-10-03 17:25:23 +02:00
JordanTheToaster
e2421bf3c6 Deps: Update to SDL 2.30.8 2024-10-02 12:53:27 -04:00
JordanTheToaster
9b4b21887f 3rdparty: Update Vulkan-Headers to v1.3.296 2024-10-02 09:52:13 -04:00
PCSX2 Bot
cc9eaef477 Qt: Update Base Translation 2024-10-01 20:18:11 -04:00
KamFretoZ
c1eecb3512 Savestate: Make selector dismissible by opening pause menu 2024-10-01 19:05:51 -04:00
KamFretoZ
58a26dbca4 Qt: Update Glyph Ranges 2024-10-01 19:05:51 -04:00
KamFretoZ
d06700276f Tools: Add shebang to generate fs translation script 2024-10-01 19:05:51 -04:00
KamFretoZ
ab5b622d70 Qt: Fix VPS Counter 2024-10-01 19:05:51 -04:00
KamFretoZ
60e21e2530 SaveState: Add configurable compression type and level 2024-10-01 19:05:51 -04:00
Ty Lamontagne
a694c1bd26 Debugger: Use safe VTLB functions for memory reading and writing 2024-09-29 10:23:00 -04:00
Ty Lamontagne
84d16802a3 iop/hostfs: don't replace back slashes with forward slashes on Windows 2024-09-29 10:20:31 -04:00
JordanTheToaster
02fda478ea Deps: Update to libzip 1.11.1 2024-09-29 10:17:43 -04:00
chaoticgd
31dcda05b7 DebugTools: Scan for functions from the ELF instead of from memory 2024-09-28 12:17:55 -04:00
PCSX2 Bot
5479ab1b8a Qt: Update Base Translation 2024-09-26 20:24:43 -04:00
Ty Lamontagne
cc9c0f9b12 Patches: Implement dynamic patching support in pnaches 2024-09-26 17:15:31 -04:00
Tyler Wilding
aa5a94df5a translations: Syncing Crowdin translations (#11849) 2024-09-26 16:42:42 -04:00
PCSX2 Bot
d9b7f413ff Qt: Update Base Translation 2024-09-26 02:47:57 +02:00
crashGG
6c3cf12df6 GS: Add a 10:7 pixel ration option 2024-09-25 11:46:09 -04:00
lightningterror
13e0546f56 GS/HW: Make sure it's not a channel shuffle when the alpha of a target is used as source.
The alpha of a target used a source is meaningless to us,
since it's not really an indexed texture.
2024-09-23 23:57:09 +02:00
PCSX2 Bot
c01dc20284 Qt: Update Base Translation 2024-09-23 23:56:16 +02:00
PCSX2 Bot
3faf22256e PAD: Update to latest controller database. 2024-09-23 18:01:50 +02:00
Matthew
ac4d827a9c Qt: Add a permission error dialog when converting memorycards in a R/O directory 2024-09-22 14:15:22 -04:00
weirdbeardgame
95201409e3 CDVD: 0 index into tracks array 2024-09-21 10:49:26 -04:00
weirdbeardgame
89cd474278 CDVD: Added cdvdTrack, cdvdTrackIndex
used IOCtl SubQ reads to get proper control register
Added Checks for Control fields.
2024-09-21 10:49:26 -04:00
Joe Wagner
fc715d58f0 Qt: Fix keyboard SHIFT for non-alpha characters 2024-09-20 03:01:33 +02:00
Stuart Kenny
217e1c8fae GS: Update lottes crt shader. 2024-09-19 17:51:29 +02:00
lightningterror
5486eed151 GS/HW: Merge blend ad a mask separate conditions in to one.
Duplicate code.
2024-09-19 00:19:05 +02:00
Ty Lamontagne
d1721360ff DebugInterface: Fix formatting 2024-09-18 16:57:20 -04:00
Ty Lamontagne
0a0f99dd1b DebugInterface: Try to show the kernel memory mappings, again 2024-09-18 12:50:48 -04:00
PCSX2 Bot
eb5ea6f64e Qt: Update Base Translation 2024-09-18 17:38:09 +02:00
lightningterror
1d449e9675 FullscreenUI: Remove unused function.
CopyGlobalControllerSettingsToGame.
2024-09-17 23:19:00 +02:00
Ty Lamontagne
c82671fce4 microVU: fix block clearing regression 2024-09-16 16:46:23 -04:00
oltolm
4c267c4206 microvu: fix ASAN container-overflow in mVUsetupRange 2024-09-16 13:48:00 -04:00
PCSX2 Bot
158e67cf6d Qt: Update Base Translation 2024-09-16 18:41:23 +02:00
Pyra Drake
1afff1a064 GameDB: Pro Race Driver fixes
Pro Race Driver fixes for upscaling lines.
2024-09-16 18:41:05 +02:00
JordanTheToaster
904874d959 OSD: Improve main window stat spacing 2024-09-16 18:40:20 +02:00
PCSX2 Bot
d33168d31f PAD: Update to latest controller database. 2024-09-16 18:39:49 +02:00
Ty
2b7c4ae438 gh: update the feature request template labels
We are trying out a new feature request labelling system.
2024-09-15 14:40:05 -04:00
lightningterror
6483565d47 GS/HW: Fix/cleanup pabe optimization condition.
We should check only if As max is 128, also make sure we are checking the original Alpha C value as it could have been modified for an optimization.
2024-09-15 20:39:41 +02:00
JordanTheToaster
11704f7f0c GameDB: Various fixes 2024-09-15 14:38:38 -04:00
chaoticgd
8d3f4fac23 Debugger: Prevent flicker when resetting symbol tree node children 2024-09-15 08:57:12 -04:00
chaoticgd
93b18412f5 Debugger: Make check box widgets in the symbol tree more responsive 2024-09-15 08:57:12 -04:00
JordanTheToaster
d9c5f22d1e OSD: Rename various fields 2024-09-15 08:41:12 -04:00
KamFretoZ
d12ef2b17c OSD: Add GPU Info (#11808)
* OSD: Add GPU Info

* Qt: More Translatable Strings
2024-09-15 08:24:05 -04:00
lightningterror
e8e0b97f6d GS/HW: Reduce sw/hdr colclip in more cases.
When doing `Cs*Alpha + Cd*(1 - Alpha)` or `Cd*Alpha + Cs*(1 - Alpha)` with an alpha of 128 or lower
we don't really need to hdr or sw colclip blend it because colour range of the result will be
between 0-1 (0-255) without it overflowing.

Also update previous optimizations to include Ad cases when RTA is already scaled.
2024-09-15 01:09:28 +02:00
PCSX2 Bot
f50083e47a Qt: Update Base Translation 2024-09-14 18:07:20 +02:00
Farran666
461ee350c2 GameDB: Add Skip MPEG Hack to Never7 2024-09-13 16:45:43 -04:00
TheLastRar
0cf4b76876 Common: Fix Recursive CreateDirectoryPath() on Windows 2024-09-12 15:45:45 -04:00
KamFretoZ
4e1979427d Qt: Make Settings List Word Wrapped 2024-09-12 15:42:00 -04:00
KamFretoZ
110426ac9f DiscordRPC: Further improve icon url call 2024-09-12 15:42:00 -04:00
OctopusButtons
4565a62634 UI: Update mipmapping help description
Added mipmapping description similar to the help/hover text of other items. Wording is my own phrasing.
2024-09-12 15:36:19 -04:00
JordanTheToaster
f75da73fca 3rdparty/ffmpeg: Bump headers to version 7.0.2 2024-09-12 11:19:05 -04:00
Ziemas
5c83edb7b2 ExpressionParser: Add missing include in header 2024-09-11 09:09:38 -04:00
Ty Lamontagne
bb1162f6cc Achievements: Reset client state on system reset 2024-09-10 16:58:58 -04:00
Martino Fontana
a4d2332f9c Config: Set {ntsc,pal}FrameRate bounds to 10-300 Hz 2024-09-10 11:58:42 -04:00
Nenderus
4963ea9b11 CMake: Install translations in PACKAGE MODE 2024-09-09 20:11:21 -04:00
PCSX2 Bot
11caae46c1 Qt: Update Base Translation 2024-09-09 20:10:18 -04:00
dependabot[bot]
bfaad9f9bf Bump peter-evans/create-pull-request from 6 to 7 in the ci-deps group
Bumps the ci-deps group with 1 update: [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request).


Updates `peter-evans/create-pull-request` from 6 to 7
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v6...v7)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 20:03:17 -04:00
RedPanda4552
0792ceb21a Config: Prevent pad settings lingering in game properties blocking profiles 2024-09-09 15:06:28 -04:00
smasimar@gmail.com
2886f825aa Added "SaveStateAndSelectNextSlot" hotkey for alternative save slot cycling functionality. 2024-09-09 14:58:15 -04:00
smasimar@gmail.com
22c9b70ca3 Flipped the order of "SaveStateAndSelectNextSlot" to "SelectNextSlotAndSaveState" 2024-09-09 14:58:15 -04:00
PCSX2 Bot
6dbbebeafb PAD: Update to latest controller database. 2024-09-09 18:28:55 +02:00
KamFretoZ
f54eeca1fd FSUI: Move Texture Preloading to Advanced 2024-09-08 14:37:28 -04:00
PCSX2 Bot
7d6f74083b Qt: Update Base Translation 2024-09-06 18:59:17 +02:00
KamFretoZ
28e4b10fda Translation: Remove excess double quote (#11777)
* Translation: Remove excess double quote on the train controller

* Qt: Add Train Controller Icon

* Qt: Expand controller input list

* FSUI: Base Translation Update

* Qt: Update Base Translations
2024-09-03 12:09:54 -04:00
JordanTheToaster
b8405ef7a6 Deps: Update to SDL 2.30.7 2024-09-03 10:26:12 +02:00
PCSX2 Bot
d178bb3904 Qt: Update Base Translation 2024-09-03 10:24:50 +02:00
KamFretoZ
1ea512655a FileSystem: Fix handling of symlinks
Revert of c8a3e5a9ec
2024-09-02 16:18:01 -04:00
chaoticgd
90463a4a6c Debugger: Bring back the expression parser 2024-09-02 16:16:05 -04:00
PCSX2 Bot
f340b5ebd0 Qt: Update Base Translation 2024-09-01 19:07:18 +02:00
Joe Stringer
ab2d18ebf0 USB: Add passthrough support to DenshaCon
Enable an option to use native Densha De Go! controllers and pass the axis inputs from the controller directly through to the game.
2024-08-31 20:47:29 +02:00
Joe Stringer
8d3bb1ad80 Settings: Add DenshaCon bindings UI 2024-08-31 20:47:29 +02:00
Joe Stringer
ed3405b5a9 USB: Add support for Ryojouhen DenshaCon
Add support for TCPP20014 controllers, datasheets courtesy of Marc Riera. Tested with a One Handle MasCon for Nintendo Switch as the controller device.

Link: https://marcriera.github.io/ddgo-controller-docs/controllers/usb/tcpp20014/
2024-08-31 20:47:29 +02:00
Joe Stringer
904d6b9c78 USB: Add support for Shinkansen DenshaCon
Add support for TCPP20011 controllers, datasheets courtesy of Marc Riera. Tested with a One Handle MasCon for Nintendo Switch as the controller device.

Link: https://marcriera.github.io/ddgo-controller-docs/controllers/usb/tcpp20011
2024-08-31 20:47:29 +02:00
Joe Stringer
edcd1d0f9f USB: Add support for Type 2 DenshaCon
Add support for TCPP20009 controllers, datasheets courtesy of Marc Riera. Tested with a One Handle MasCon for Nintendo Switch as the controller device.

Link: https://marcriera.github.io/ddgo-controller-docs/controllers/usb/tcpp20009/
2024-08-31 20:47:29 +02:00
Ty Lamontagne
a8ce6a9f0e UI: Enable "System" and toolbar savestate options in OSDSYS
Saving state in OSDSYS was supported and worked fine with hotkeys, the UI just didn't reflect that.
2024-08-29 11:40:20 -04:00
chaoticgd
42e4a47bfc DebugTools: Fix some compiler warnings 2024-08-28 23:29:35 +02:00
Jordan
e423fd10c6 Misc: Minor text and settings changes (#11751)
* VMManager: Update CPU detection text

* Settings: Move texture preload to advanced

* Settings: Move spin during readback to advanced

* Translations: Add extra comment to mailbox presentation

Update GraphicsSettingsWidget.ui
2024-08-28 16:08:49 -04:00
PCSX2 Bot
f73a9e89f6 Qt: Update Base Translation 2024-08-28 01:02:56 +02:00
chaoticgd
48de49b85d DebugTools: Fix iterator invalidation bug in IopBios.cpp 2024-08-27 18:13:25 -04:00
lightningterror
da1ee3a3b9 GS/HW: Add afix to alphas log. 2024-08-27 19:35:19 +02:00
chaoticgd
79dbc272b8 Debugger: Add symbol tree widgets for functions and variables
This adds three new tabs in the debugger: The Globals tab, the Locals
tab and the Parameters tab. In addition, it rewrites the Functions tab.

All four of these tabs use the new symbol tree widgets and the
associated model. This allows the user the inspect complex data
structures in memory with full type information.

Lastly, new dialogs have been added for creating symbols.
2024-08-27 12:48:40 -04:00
chaoticgd
c83cca1d87 Debugger: Add GNU demangler
This code is taken from GCC 13.2.0 with a number of modifications
applied. See the included readme for more information.
2024-08-27 12:48:40 -04:00
chaoticgd
44b50bee26 Debugger: Replace SymbolMap class with new SymbolGuardian class
This new class uses the CCC library I added in the last commit and
parses the symbol tables on a worker thread.
2024-08-27 12:48:40 -04:00
chaoticgd
87b03fdc28 3rdparty: Add CCC v2.1
This is the symbol table parser that I'm replacing the existing ELF
symbol table parser with. It supports STABS symbols in .mdebug sections
as well as ELF symbols and SNDLL symbols.

It includes its own symbol database, and an AST which facilitates
debugging tools that let the user inspect complex data structures with
full type information.

More information is provided in the included readme.
2024-08-27 12:48:40 -04:00
chaoticgd
b43e05a8fc Debugger: Remove the Avast demangler
This library doesn't support the demangling scheme used by GCC 2.x
compilers and hence doesn't work in lots of cases.
2024-08-27 12:48:40 -04:00
lightningterror
67d7744f7f GS/HW: Further expand blend multipass.
For formulas:
Cs*Alpha + Cd*(1 - Alpha).
Cd*Alpha + Cs*(1 - Alpha).
Where Alpha is higher than 1 and is either As or Af.
2024-08-27 13:38:44 +02:00
RedPanda4552
27fb7dc26e Big Picture: Remove ability to make per-game controls
Replace with profile selector instead
2024-08-26 19:36:25 -04:00
PCSX2 Bot
04168a0359 PAD: Update to latest controller database. 2024-08-26 18:42:50 +02:00
deanff
1131db784f Qt: Set focus to Game Library for improved keyboard navigation (#11719)
Improved keyboard navigation. Users can navigate the Library and play/exit games with just the arrow keys and Enter/Esc.
2024-08-24 18:00:34 +02:00
Florin9doi
517fba3686 USB: Fix CaptureEye corruption on dark images 2024-08-24 17:28:17 +02:00
KamFretoZ
64e17fce3f Qt: Fix a couple of instances of inconsistent sorting
Backport from 7927ec647f
2024-08-24 17:27:39 +02:00
KamFretoZ
518728ca36 Qt: Center type icon in game list
Backport from: 93836636a1
2024-08-24 17:27:39 +02:00
KamFretoZ
d1a7430f80 Qt: Fix incorrect sort indicator on loading
Backport from: a56ebf24b2
2024-08-24 17:27:39 +02:00
KamFretoZ
973c522756 Qt: Ensure fullscreen UI is stopped on exiting
Backport from: 533022bb7d
2024-08-24 17:27:39 +02:00
KamFretoZ
5536342f9d ImGuiManager: Fix stutter when multiple OSD messages lapse
fe55446c25
2024-08-24 17:27:39 +02:00
KamFretoZ
d9ddab1a33 ImGuiFullscreen: Fix incorrect notification width
Backport from: e455a5e371
2024-08-24 17:27:39 +02:00
KamFretoZ
c915aac1fa FileSystem: Correctly use lstat() on Linux
Backport from: 81295c8a7d
2024-08-24 17:27:39 +02:00
KamFretoZ
a3c2a4db5f GSTextureVK: Fix download inside render pass
Backport from: 5f8082734e
2024-08-24 17:27:39 +02:00
KamFretoZ
aebebf5115 Qt: Work around theme switching bug
backport from: b2577ef8bd
2024-08-24 17:27:39 +02:00
KamFretoZ
9a50218400 Image: Fix crash loading corrupted/invalid JPEG files
Backport from: afea18f65e
2024-08-24 17:27:39 +02:00
TellowKrinkle
fd5a652270 Vk: Don't try to transition present source during present 2024-08-23 20:59:26 -05:00
Farran666
c647a30aa9 GameDB: Add multiple fixes 2024-08-23 15:22:51 +02:00
lightningterror
40d5c78573 GS/HW: Implement PABE(Per pixel alpha blending) on accumulation blend and add optimizations.
PABE accumulation blend:
Idea is to achieve final output Cs when As < 1, we do this with manipulating Cd using the src1 output.
This can't be done with reverse subtraction as we want Cd to be 0 when As < 1.
Blend mix is excluded as no games were found, otherwise it can be added.

PABE Disable blending:
We can disable blending here as an optimization since alpha max is 128
which if alpha is 1 in the formula Cs*Alpha + Cd*(1 - Alpha) will give us a result of Cs.
2024-08-22 21:39:19 +02:00
xperia64
fe2a9fc2cd GameDB: Correct two Phoenix Games title names 2024-08-22 11:34:51 -04:00
squidbus
83f9add68b Config: Allow specifying portable directory relative path in portable.txt 2024-08-21 12:32:10 -04:00
KamFretoZ
ffe8d16df4 DiscordRPC: Add game icon support. 2024-08-21 12:28:56 -04:00
PCSX2 Bot
31b5672870 Qt: Update Base Translation 2024-08-20 10:11:20 +02:00
Florin9doi
777fc444ae USB: Rename singstar to usb_mic 2024-08-20 10:09:21 +02:00
Florin9doi
cd5c961dc4 USB: Konami ON-SAY microphone emulation 2024-08-20 10:09:21 +02:00
Florin9doi
c2ea8c4eab USB: Audio support for EyeToy 2024-08-20 10:09:21 +02:00
Florin9doi
d6507a945b USB: Merge Singstar and Logitech mics in a single device with 2 subtypes 2024-08-20 10:09:21 +02:00
PCSX2 Bot
f1abee5d0b Qt: Update Base Translation 2024-08-19 09:15:02 +02:00
Jordan
e4dccc237c Misc: Minor cleanup. (#11717)
Changes video max bitrate to 200,000kbps default audio from 160kbps to 192kbps and adds a missing name I forgot to add previously.
2024-08-19 09:14:27 +02:00
KamFretoZ
92d8c740d4 Qt: Fix a couple of theme switching glitches
Backport from: 6f9e8efee5
2024-08-19 08:54:35 +02:00
KamFretoZ
b6eddade00 Qt: Slightly increase game list title size 2024-08-19 08:54:35 +02:00
KamFretoZ
04fdd09d1e ImGuiFullscreen: Display checkmark on right of choice dialog
Backport from: f5815f3183
2024-08-19 08:54:35 +02:00
KamFretoZ
69574aecc6 ImGuiFullscreen: Fix choice popup selected drawing over border
Backport from 05f9f33ec6
2024-08-19 08:54:35 +02:00
KamFretoZ
c72d98d4cd FullscreenUI: Fix popup close resetting window scroll
Backport from 13a37418e6
2024-08-19 08:54:35 +02:00
Florin9doi
4f405adea9 USB: Store unique disk images for MSD and PictureParadise 2024-08-18 19:29:09 +02:00
Florin9doi
5217ec375d USB: Fix Konami Capture Eye assert 2024-08-18 19:27:48 +02:00
JordanTheToaster
10b264b9ec 3rdparty/imgui: Disable the nav menu
Courtesy to Fobes for figuring this out because I was not getting anywhere.
2024-08-16 11:27:24 -04:00
JordanTheToaster
dc741e95bd 3rdparty/imgui: General cleanup
Clean up and replacing obsolete functions.
2024-08-16 11:27:24 -04:00
PCSX2 Bot
a1ca0a9a02 Qt: Update Base Translation 2024-08-15 19:14:14 +02:00
lightningterror
c076c50b68 GS/DX11: Fix feedback write 1 null pointer crash.
We were using the wrong texture as the source, should be dTex when copying.
2024-08-15 10:26:27 +02:00
lightningterror
c688db8f08 GS/HW: Rename blend second pass to blend multi pass.
Easier if I want to add more passes.
2024-08-14 12:35:52 +02:00
PCSX2 Bot
469053de9b Qt: Update Base Translation 2024-08-13 19:42:38 +02:00
squidbus
185b85f86a Config: Use directory containing bundle as AppRoot on macOS. 2024-08-12 22:50:49 -04:00
PCSX2 Bot
11096a520e PAD: Update to latest controller database. 2024-08-12 19:01:26 -04:00
Florin9doi
07fd035aa2 USB: Set actual_length value for Get HID descriptor 2024-08-12 19:01:08 -04:00
seta-san
6bedcd768f Qt: Update Trilinear Filtering Description 2024-08-12 19:00:28 -04:00
weirdbeardgame
0c949db506 CMake: Added PACKAGE_MODE option
Set paths, add check in SetResourcesDir
2024-08-12 11:33:02 -04:00
PCSX2 Bot
4c5253c0f5 Qt: Update Base Translation 2024-08-11 07:46:00 +02:00
Mrlinkwii
325133e54c GameDB: add missing serial 2024-08-11 00:50:33 +02:00
JordanTheToaster
4113ac574d GameDB: ATV Offroad Fury 2 Fixes
Adds bilinear upscale nearest to fix garbage textures.
2024-08-11 00:47:48 +02:00
JordanTheToaster
2d6c687913 GSTextureCache: Extend Bilinear Upscale to dirty depth 2024-08-11 00:47:48 +02:00
lightningterror
f9fbecc783 GS: Match data types in shaders to be the same when doing bitwise operations. 2024-08-11 00:35:42 +02:00
seta-san
c5ceba35b6 Qt: Update Texture Filtering Description
Qt: Update Texture Filtering Description
2024-08-10 18:25:44 -04:00
oltolm
c7a53703b1 iR5900: fix heap-buffer-overflow in recompileNextInstruction 2024-08-10 17:47:39 -04:00
JordanTheToaster
2151ffcb6a GameDB: Various fixes 2024-08-10 22:21:46 +02:00
659 changed files with 281058 additions and 151353 deletions

View File

@@ -2,7 +2,7 @@
name: Feature request
description: Suggest a new feature or improve an existing one
title: "[Feature Request]: "
labels: ["Enhancement / Feature Request"]
labels: ["Enhancement / Feature Request", "FR: Awaiting Consideration"]
# assignees:
# - octocat
body:

View File

@@ -43,7 +43,7 @@ jobs:
compiler: clang
cmakeflags: ""
publish: true
branch: stable
fetchTags: true
stableBuild: false
secrets: inherit

View File

@@ -17,10 +17,10 @@ jobs:
run: ./.github/workflows/scripts/common/update_base_translation.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
title: "Qt: Update Base Translation"
commit-message: "Qt: Update Base Translation"
commit-message: "[ci skip] Qt: Update Base Translation."
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
body: "Daily update of base translation sources."

View File

@@ -19,7 +19,7 @@ jobs:
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
title: "PAD: Update to latest controller database"
commit-message: "PAD: Update to latest controller database."

View File

@@ -23,10 +23,6 @@ on:
cmakeflags:
required: true
type: string
branch:
required: false
type: string
default: "stable"
publish:
required: false
type: boolean
@@ -98,7 +94,8 @@ jobs:
run: |
flatpak-builder-lint manifest .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
- name: Build Flatpak
- name: Build Flatpak (beta)
if: ${{ inputs.stableBuild == false || inputs.stableBuild == 'false' }}
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
@@ -108,17 +105,33 @@ jobs:
build-bundle: true
verbose: true
mirror-screenshots-url: https://dl.flathub.org/media
branch: ${{ inputs.branch }}
branch: beta
cache: true
restore-cache: true
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
- name: Build Flatpak (stable)
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
upload-artifact: false
manifest-path: .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
arch: x86_64
build-bundle: true
verbose: true
mirror-screenshots-url: https://dl.flathub.org/media
branch: stable
cache: true
restore-cache: true
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
#- name: Validate build
# run: |
# flatpak-builder-lint repo repo
- name: Push to Flathub beta
if: inputs.publish == true && inputs.branch == 'beta'
- name: Push to Flathub (beta)
if: ${{ inputs.publish == true && (inputs.stableBuild == false || inputs.stableBuild == 'false') }}
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
flat-manager-url: https://hub.flathub.org/
@@ -126,8 +139,8 @@ jobs:
token: ${{ secrets.FLATHUB_BETA_TOKEN }}
build-log-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: Push to Flathub stable
if: inputs.publish == true && inputs.branch == 'stable'
- name: Push to Flathub (stable)
if: ${{ inputs.publish == true && (inputs.stableBuild == true || inputs.stableBuild == 'true') }}
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
flat-manager-url: https://hub.flathub.org/

View File

@@ -114,7 +114,6 @@ jobs:
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
compiler: clang
cmakeflags: ""
branch: "stable"
publish: false
fetchTags: true
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}

View File

@@ -6,6 +6,9 @@ set -e
# While we use custom Qt builds for our releases, the Qt6 package will be good enough
# for just updating translations. Saves building it for this action alone.
"$SCRIPTDIR/../../../../tools/retry.sh" sudo apt-get -y install qt6-l10n-tools
"$SCRIPTDIR/../../../../tools/retry.sh" sudo apt-get -y install qt6-l10n-tools python3
"$SCRIPTDIR/../../../../tools/generate_fullscreen_ui_translation_strings.py"
"$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_glyph_ranges.py"
"$SCRIPTDIR/../../../../tools/generate_update_fa_glyph_ranges.py"
PATH=/usr/lib/qt6/bin:$PATH "$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_base_translation.sh"

View File

@@ -16,11 +16,11 @@ fi
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
LIBJPEG=9f
LIBPNG=1.6.43
LIBPNG=1.6.44
LIBWEBP=1.4.0
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
SDL=SDL2-2.30.6
QT=6.7.2
SDL=SDL2-2.30.9
QT=6.8.0
ZSTD=1.5.6
SHADERC=2024.1
@@ -34,24 +34,24 @@ cd deps-build
cat > SHASUMS <<EOF
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c libpng-$LIBPNG.tar.xz
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
c6ef64ca18a19d13df6eb22df9aff19fb0db65610a74cc81dae33a82235cacd4 $SDL.tar.gz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 $SDL.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 qtbase-everywhere-src-$QT.tar.xz
e1a1d8785fae67d16ad0a443b01d5f32663a6b68d275f1806ebab257485ce5d6 qtimageformats-everywhere-src-$QT.tar.xz
fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 qtsvg-everywhere-src-$QT.tar.xz
58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a qttools-everywhere-src-$QT.tar.xz
9845780b5dc1b7279d57836db51aeaf2e4a1160c42be09750616f39157582ca9 qttranslations-everywhere-src-$QT.tar.xz
a2a057e1dd644bd44abb9990fecc194b2e25c2e0f39e81aa9fee4c1e5e2a8a5b qtwayland-everywhere-src-$QT.tar.xz
1bad481710aa27f872de6c9f72651f89a6107f0077003d0ebfcc9fd15cba3c75 qtbase-everywhere-src-$QT.tar.xz
595bf8557b91e1f8ebc726f1e09868a3c7e610ff5045068f2d4ea2428c49a5d4 qtimageformats-everywhere-src-$QT.tar.xz
cf7a593d5e520f8177240610d9e55d5b75b0887fe5f385554ff64377f1646199 qtsvg-everywhere-src-$QT.tar.xz
403115d8268503c6cc6e43310c8ae28eb9e605072a5d04e4a2de8b6af39981f7 qttools-everywhere-src-$QT.tar.xz
84bf2b67c243cd0c50a08acd7bfa9df2b1965028511815c1b6b65a0687437cb6 qttranslations-everywhere-src-$QT.tar.xz
175758591638ebf1c6fbb66ac11c7fa0eb8d4ed52e9243cc59075d06a6a2060a qtwayland-everywhere-src-$QT.tar.xz
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
curl -C - -L \
curl -L \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
-O "https://ijg.org/files/jpegsrc.v$LIBJPEG.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
@@ -150,7 +150,7 @@ tar xf "qtbase-everywhere-src-$QT.tar.xz"
cd "qtbase-everywhere-src-$QT"
mkdir build
cd build
../configure -prefix "$INSTALLDIR" -release -dbus-linked -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -xcb -gtk -- -DFEATURE_dbus=ON -DFEATURE_icu=OFF -DFEATURE_sql=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
../configure -prefix "$INSTALLDIR" -release -dbus-linked -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -xcb -gtk -- -DFEATURE_dbus=ON -DFEATURE_icu=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
cmake --build . --parallel
ninja install
cd ../../

View File

@@ -8,8 +8,8 @@
{
"type": "git",
"url": "https://github.com/the-tcpdump-group/libpcap.git",
"tag": "libpcap-1.10.4",
"commit": "104271ba4a14de6743e43bcf87536786d8fddea4"
"tag": "libpcap-1.10.5",
"commit": "bbcbc9174df3298a854daee2b3e666a4b6e5383a"
}
],
"cleanup": [

View File

@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL2-2.30.6.tar.gz",
"sha256": "c6ef64ca18a19d13df6eb22df9aff19fb0db65610a74cc81dae33a82235cacd4"
"url": "https://libsdl.org/release/SDL2-2.30.9.tar.gz",
"sha256": "24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4"
}
],
"cleanup": [

View File

@@ -1,15 +1,15 @@
{
"app-id": "net.pcsx2.PCSX2",
"runtime": "org.kde.Platform",
"runtime-version": "6.7",
"runtime-version": "6.8",
"sdk": "org.kde.Sdk",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.llvm17"
"org.freedesktop.Sdk.Extension.llvm18"
],
"add-extensions": {
"org.freedesktop.Platform.ffmpeg-full": {
"directory": "lib/ffmpeg",
"version": "23.08",
"version": "24.08",
"add-ld-path": ".",
"autodownload": true
}
@@ -44,8 +44,8 @@
"config-opts": [
"-DCMAKE_BUILD_TYPE=Release",
"-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON",
"-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm17/bin/clang",
"-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm17/bin/clang++",
"-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm18/bin/clang",
"-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm18/bin/clang++",
"-DCMAKE_EXE_LINKER_FLAGS_INIT=-fuse-ld=lld",
"-DCMAKE_MODULE_LINKER_FLAGS_INIT=-fuse-ld=lld",
"-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld",

View File

@@ -38,17 +38,17 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
FREETYPE=2.13.2
HARFBUZZ=8.3.1
SDL=SDL2-2.30.3
ZSTD=1.5.5
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL=SDL2-2.30.9
ZSTD=1.5.6
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
LIBPNG=1.6.43
LIBPNG=1.6.44
LIBJPEG=9f
LIBWEBP=1.3.2
LIBWEBP=1.4.0
FFMPEG=6.0
MOLTENVK=1.2.8
QT=6.7.1
MOLTENVK=1.2.9
QT=6.7.2
SHADERC=2024.1
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
@@ -74,21 +74,21 @@ CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cat > SHASUMS <<EOF
12991c4e55c506dd7f9b765933e62fd2be2e06d421505d7950a132e4f1bb484d freetype-$FREETYPE.tar.xz
19a54fe9596f7a47c502549fce8e8a10978c697203774008cc173f8360b19a9a harfbuzz-$HARFBUZZ.tar.gz
820440072f8f5b50188c1dae104f2ad25984de268785be40c41a099a510f0aec $SDL.tar.gz
9c4396cc829cfae319a6e2615202e82aad41372073482fce286fac78646d3ee4 zstd-$ZSTD.tar.gz
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 $SDL.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c libpng-$LIBPNG.tar.xz
2a499607df669e40258e53d0ade8035ba4ec0175244869d1025d460562aa09b4 libwebp-$LIBWEBP.tar.gz
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
85beaf8abfcc54d9da0ff0257ae311abd9e7aa96e53da37e1c37d6bc04ac83cd v$MOLTENVK.tar.gz
b7338da1bdccb4d861e714efffaa83f174dfe37e194916bfd7ec82279a6ace19 qtbase-everywhere-src-$QT.tar.xz
a733b98f771064d000476b8861f822143982749448ba8abf9f1813edb8dfe79f qtimageformats-everywhere-src-$QT.tar.xz
3ed5b80f7228c41dd463b7a57284ed273d224d1c323c0dd78c5209635807cbce qtsvg-everywhere-src-$QT.tar.xz
0953cddf6248f3959279a10904892e8a98eb3e463d729a174b6fc47febd99824 qttools-everywhere-src-$QT.tar.xz
03d71565872b0e0e7303349071df031ab0f922f6dbdd3a5ec1ade9e188e4fbf4 qttranslations-everywhere-src-$QT.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 qtbase-everywhere-src-$QT.tar.xz
e1a1d8785fae67d16ad0a443b01d5f32663a6b68d275f1806ebab257485ce5d6 qtimageformats-everywhere-src-$QT.tar.xz
fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 qtsvg-everywhere-src-$QT.tar.xz
58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a qttools-everywhere-src-$QT.tar.xz
9845780b5dc1b7279d57836db51aeaf2e4a1160c42be09750616f39157582ca9 qttranslations-everywhere-src-$QT.tar.xz
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
@@ -330,20 +330,6 @@ echo "Installing Qt Tools..."
rm -fr "qttools-everywhere-src-$QT"
tar xf "qttools-everywhere-src-$QT.tar.xz"
cd "qttools-everywhere-src-$QT"
# Linguist relies on a library in the Designer target, which takes 5-7 minutes to build on the CI
# Avoid it by not building Linguist, since we only need the tools that come with it
patch -u src/linguist/CMakeLists.txt <<EOF
--- src/linguist/CMakeLists.txt
+++ src/linguist/CMakeLists.txt
@@ -14,7 +14,7 @@
add_subdirectory(lrelease-pro)
add_subdirectory(lupdate)
add_subdirectory(lupdate-pro)
-if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png)
+if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND TARGET Qt::PrintSupport AND NOT no-png)
add_subdirectory(linguist)
endif()
EOF
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF

View File

@@ -20,12 +20,12 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
FREETYPE=2.13.2
HARFBUZZ=8.3.1
SDL=SDL2-2.30.6
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL=SDL2-2.30.9
ZSTD=1.5.6
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
LIBPNG=1.6.43
LIBPNG=1.6.44
LIBJPEG=9f
LIBWEBP=1.4.0
FFMPEG=6.0
@@ -54,12 +54,12 @@ CMAKE_COMMON=(
)
cat > SHASUMS <<EOF
12991c4e55c506dd7f9b765933e62fd2be2e06d421505d7950a132e4f1bb484d freetype-$FREETYPE.tar.xz
19a54fe9596f7a47c502549fce8e8a10978c697203774008cc173f8360b19a9a harfbuzz-$HARFBUZZ.tar.gz
c6ef64ca18a19d13df6eb22df9aff19fb0db65610a74cc81dae33a82235cacd4 $SDL.tar.gz
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 $SDL.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c libpng-$LIBPNG.tar.xz
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz

View File

@@ -42,14 +42,14 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set FREETYPE=2.13.2
set HARFBUZZ=8.3.1
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set LIBJPEG=9f
set LIBPNG=1643
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
set QT=6.7.2
set QTMINOR=6.7
set SDL=SDL2-2.30.6
set QT=6.8.0
set QTMINOR=6.8
set SDL=SDL2-2.30.9
set WEBP=1.4.0
set ZLIB=1.3.1
set ZLIBSHORT=131
@@ -60,18 +60,18 @@ set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
set SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 1ac27e16c134a7f2ccea177faba19801131116fd682efc1f5737037c5db224b5 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip b2bc56184ae37324bc4829fde7d3f9e6916866ad711ee85792e457547c9fd127 || goto error
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1643.zip fc466a1e638e635d6c66363bdf3f38555b81b0141d0b06ba45b49ccca327436d || goto error
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 6d4e00fcbee9fd8985cc2869edeb0b1a751912b87506cf2fb6471e73d981e1f4 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 488119aad60719a085a1e45c31641ac2406ef86fc088a3c99885c18e9d6b4bb9 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 8e736b02db7dd67dbe834d56503b242344ce85d3532da692f1812b30ccf80997 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 85a22142270a92be0dd0ab5d27cc53617b2a2f1a45fc0a3890024164032f8475 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 9e15f1fdbd83e4123e733bff20aff1b45921c09056c3790fa42eb71d0a5cd01f || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" d1f25e0f68a1282feffdd5fe795a027ee5f16ad19e3b1fa2e04a51cea19110ec || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error

View File

@@ -40,14 +40,14 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set FREETYPE=2.13.2
set HARFBUZZ=8.3.1
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set LIBJPEG=9f
set LIBPNG=1643
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
set QT=6.7.2
set QTMINOR=6.7
set SDL=SDL2-2.30.6
set QT=6.8.0
set QTMINOR=6.8
set SDL=SDL2-2.30.9
set WEBP=1.4.0
set ZLIB=1.3.1
set ZLIBSHORT=131
@@ -58,18 +58,18 @@ set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
set SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 1ac27e16c134a7f2ccea177faba19801131116fd682efc1f5737037c5db224b5 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip b2bc56184ae37324bc4829fde7d3f9e6916866ad711ee85792e457547c9fd127 || goto error
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1643.zip fc466a1e638e635d6c66363bdf3f38555b81b0141d0b06ba45b49ccca327436d || goto error
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 6d4e00fcbee9fd8985cc2869edeb0b1a751912b87506cf2fb6471e73d981e1f4 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 488119aad60719a085a1e45c31641ac2406ef86fc088a3c99885c18e9d6b4bb9 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 8e736b02db7dd67dbe834d56503b242344ce85d3532da692f1812b30ccf80997 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 85a22142270a92be0dd0ab5d27cc53617b2a2f1a45fc0a3890024164032f8475 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 9e15f1fdbd83e4123e733bff20aff1b45921c09056c3790fa42eb71d0a5cd01f || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" d1f25e0f68a1282feffdd5fe795a027ee5f16ad19e3b1fa2e04a51cea19110ec || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
@@ -195,6 +195,9 @@ cd "qtbase-everywhere-src-%QT%" || goto error
rem Disable the PCRE2 JIT, it doesn't properly verify AVX2 support.
%PATCH% -p1 < "%SCRIPTDIR%\qtbase-disable-pcre2-jit.patch" || goto error
rem Hackfix settings icon stretching
%PATCH% -p1 < "%SCRIPTDIR%\qtbase-fix-icon-stretch.patch" || goto error
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error

View File

@@ -0,0 +1,13 @@
diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
index 208420d7e8..26ef6f31ef 100644
--- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
@@ -4232,8 +4232,6 @@ QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption
case SE_ItemViewItemDecoration:
rect = QWindowsStyle::subElementRect(element, option, widget);
- if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
- rect.adjust(-2, 0, 2, 0);
break;
case SE_ItemViewItemFocusRect:

1
.gitignore vendored
View File

@@ -119,3 +119,4 @@ oprofile_data/
CMakeSettings.json
/ci-artifacts/
/out/
/.cache/

41
3rdparty/ccc/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.14)
project(ccc)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_library(ccc STATIC
src/ccc/ast.cpp
src/ccc/ast.h
src/ccc/elf.cpp
src/ccc/elf.h
src/ccc/elf_symtab.cpp
src/ccc/elf_symtab.h
src/ccc/importer_flags.cpp
src/ccc/importer_flags.h
src/ccc/mdebug_analysis.cpp
src/ccc/mdebug_analysis.h
src/ccc/mdebug_importer.cpp
src/ccc/mdebug_importer.h
src/ccc/mdebug_section.cpp
src/ccc/mdebug_section.h
src/ccc/mdebug_symbols.cpp
src/ccc/mdebug_symbols.h
src/ccc/sndll.cpp
src/ccc/sndll.h
src/ccc/stabs.cpp
src/ccc/stabs.h
src/ccc/stabs_to_ast.cpp
src/ccc/stabs_to_ast.h
src/ccc/symbol_database.cpp
src/ccc/symbol_database.h
src/ccc/symbol_file.cpp
src/ccc/symbol_file.h
src/ccc/symbol_table.cpp
src/ccc/symbol_table.h
src/ccc/util.cpp
src/ccc/util.h
)
target_include_directories(ccc PUBLIC src)

37
3rdparty/ccc/README.md vendored Normal file
View File

@@ -0,0 +1,37 @@
# Chaos Compiler Collection
This code was originally developed in the following repository and was copied
into PCSX2 by the author:
- [https://github.com/chaoticgd/ccc](https://github.com/chaoticgd/ccc)
It includes additional resources that are not present in the PCSX2 repository.
## Documentation
### DWARF (.debug) Section
- [DWARF Debugging Information Format](https://dwarfstd.org/doc/dwarf_1_1_0.pdf)
### MIPS Debug (.mdebug) Section
- [Third Eye Software and the MIPS symbol table (Peter Rowell)](http://datahedron.com/mips.html)
- [MIPS Mdebug Debugging Information (David Anderson, 1996)](https://www.prevanders.net/Mdebug.ps)
- MIPS Assembly Language Programmer's Guide, Symbol Table Chapter (Silicon Graphics, 1992)
- Tru64 UNIX Object File and Symbol Table Format Specification, Symbol Table Chapter
- `mdebugread.c` from gdb (reading)
- `ecoff.c` from gas (writing)
- `include/coff/sym.h` from binutils (headers)
### MIPS EABI
- [MIPS EABI](https://sourceware.org/legacy-ml/binutils/2003-06/msg00436.html)
### STABS
- [The "stabs" representation of debugging information (Julia Menapace, Jim Kingdon, and David MacKenzie, 1992-???)](https://sourceware.org/gdb/onlinedocs/stabs.html)
- `stabs.c` from binutils (reading)
- `stabsread.c` from gdb (reading)
- `dbxread.c` from gdb (reading)
- `dbxout.c` from gcc (writing)
- `stab.def` from gcc (symbol codes)

75
3rdparty/ccc/ccc.vcxproj vendored Normal file
View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{2589F8CE-EA77-4B73-911E-64074569795B}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset Condition="!$(Configuration.Contains(Clang))">$(DefaultPlatformToolset)</PlatformToolset>
<PlatformToolset Condition="$(Configuration.Contains(Clang))">ClangCL</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<ClInclude Include="src\ccc\ast.h" />
<ClInclude Include="src\ccc\elf.h" />
<ClInclude Include="src\ccc\elf_symtab.h" />
<ClInclude Include="src\ccc\importer_flags.h" />
<ClInclude Include="src\ccc\mdebug_analysis.h" />
<ClInclude Include="src\ccc\mdebug_importer.h" />
<ClInclude Include="src\ccc\mdebug_section.h" />
<ClInclude Include="src\ccc\mdebug_symbols.h" />
<ClInclude Include="src\ccc\sndll.h" />
<ClInclude Include="src\ccc\stabs.h" />
<ClInclude Include="src\ccc\stabs_to_ast.h" />
<ClInclude Include="src\ccc\symbol_database.h" />
<ClInclude Include="src\ccc\symbol_file.h" />
<ClInclude Include="src\ccc\symbol_table.h" />
<ClInclude Include="src\ccc\util.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\ccc\ast.cpp" />
<ClCompile Include="src\ccc\elf.cpp" />
<ClCompile Include="src\ccc\elf_symtab.cpp" />
<ClCompile Include="src\ccc\importer_flags.cpp" />
<ClCompile Include="src\ccc\mdebug_analysis.cpp" />
<ClCompile Include="src\ccc\mdebug_importer.cpp" />
<ClCompile Include="src\ccc\mdebug_section.cpp" />
<ClCompile Include="src\ccc\mdebug_symbols.cpp" />
<ClCompile Include="src\ccc\sndll.cpp" />
<ClCompile Include="src\ccc\stabs.cpp" />
<ClCompile Include="src\ccc\stabs_to_ast.cpp" />
<ClCompile Include="src\ccc\symbol_database.cpp" />
<ClCompile Include="src\ccc\symbol_file.cpp" />
<ClCompile Include="src\ccc\symbol_table.cpp" />
<ClCompile Include="src\ccc\util.cpp" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

111
3rdparty/ccc/ccc.vcxproj.filters vendored Normal file
View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\ccc\ast.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\elf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\elf_symtab.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\importer_flags.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\mdebug_analysis.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\mdebug_importer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\mdebug_section.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\mdebug_symbols.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\sndll.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\stabs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\stabs_to_ast.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\symbol_database.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\symbol_file.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\symbol_table.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ccc\util.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\ccc\ast.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\elf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\elf_symtab.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\importer_flags.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\mdebug_analysis.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\mdebug_importer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\mdebug_section.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\mdebug_symbols.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\sndll.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\stabs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\stabs_to_ast.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\symbol_database.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\symbol_file.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\symbol_table.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ccc\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

562
3rdparty/ccc/src/ccc/ast.cpp vendored Normal file
View File

@@ -0,0 +1,562 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "ast.h"
#include "importer_flags.h"
#include "symbol_database.h"
namespace ccc::ast {
static bool compare_nodes_and_merge(
CompareResult& dest, const Node& node_lhs, const Node& node_rhs, const SymbolDatabase* database);
static bool try_to_match_wobbly_typedefs(
const Node& node_lhs, const Node& node_rhs, const SymbolDatabase& database);
void Node::set_access_specifier(AccessSpecifier specifier, u32 importer_flags)
{
if((importer_flags & NO_ACCESS_SPECIFIERS) == 0) {
access_specifier = specifier;
}
}
std::pair<Node*, DataType*> Node::physical_type(SymbolDatabase& database, s32 max_depth)
{
Node* type = this;
DataType* symbol = nullptr;
for(s32 i = 0; i < max_depth && type->descriptor == TYPE_NAME; i++) {
DataType* data_type = database.data_types.symbol_from_handle(type->as<TypeName>().data_type_handle);
if (!data_type || !data_type->type()) {
break;
}
type = data_type->type();
symbol = data_type;
}
return std::pair(type, symbol);
}
std::pair<const Node*, const DataType*> Node::physical_type(const SymbolDatabase& database, s32 max_depth) const
{
return const_cast<Node*>(this)->physical_type(const_cast<SymbolDatabase&>(database), max_depth);
}
const char* member_function_modifier_to_string(MemberFunctionModifier modifier)
{
switch(modifier) {
case MemberFunctionModifier::NONE: return "none";
case MemberFunctionModifier::STATIC: return "static";
case MemberFunctionModifier::VIRTUAL: return "virtual";
}
return "";
}
bool StructOrUnion::flatten_fields(
std::vector<FlatField>& output,
const DataType* symbol,
const SymbolDatabase& database,
bool skip_statics,
s32 base_offset,
s32 max_fields,
s32 max_depth) const
{
if(max_depth == 0) {
return false;
}
for(const std::unique_ptr<Node>& type_name : base_classes) {
if(type_name->descriptor != TYPE_NAME) {
continue;
}
s32 new_base_offset = base_offset + type_name->offset_bytes;
DataTypeHandle handle = type_name->as<TypeName>().data_type_handle;
const DataType* base_class_symbol = database.data_types.symbol_from_handle(handle);
if(!base_class_symbol || !base_class_symbol->type() || base_class_symbol->type()->descriptor != STRUCT_OR_UNION) {
continue;
}
const StructOrUnion& base_class = base_class_symbol->type()->as<StructOrUnion>();
if(!base_class.flatten_fields(output, base_class_symbol, database, skip_statics, new_base_offset, max_fields, max_depth - 1)) {
return false;
}
}
for(const std::unique_ptr<Node>& field : fields) {
if(skip_statics && field->storage_class == STORAGE_CLASS_STATIC) {
continue;
}
if((s32) output.size() >= max_fields) {
return false;
}
FlatField& flat = output.emplace_back();
flat.node = field.get();
flat.symbol = symbol;
flat.base_offset = base_offset;
}
return true;
}
const char* type_name_source_to_string(TypeNameSource source)
{
switch(source) {
case TypeNameSource::REFERENCE: return "reference";
case TypeNameSource::CROSS_REFERENCE: return "cross_reference";
case TypeNameSource::UNNAMED_THIS: return "this";
}
return "";
}
const char* forward_declared_type_to_string(ForwardDeclaredType type)
{
switch(type) {
case ForwardDeclaredType::STRUCT: return "struct";
case ForwardDeclaredType::UNION: return "union";
case ForwardDeclaredType::ENUM: return "enum";
}
return "";
}
DataTypeHandle TypeName::data_type_handle_unless_forward_declared() const
{
if(!is_forward_declared) {
return data_type_handle;
} else {
return DataTypeHandle();
}
}
CompareResult compare_nodes(
const Node& node_lhs, const Node& node_rhs, const SymbolDatabase* database, bool check_intrusive_fields)
{
CompareResult result = CompareResultType::MATCHES_NO_SWAP;
if(node_lhs.descriptor != node_rhs.descriptor) {
return CompareFailReason::DESCRIPTOR;
}
if(check_intrusive_fields) {
if(node_lhs.storage_class != node_rhs.storage_class) {
// In some cases we can determine that a type was typedef'd for C
// translation units, but not for C++ translation units, so we need
// to add a special case for that here.
if(node_lhs.storage_class == STORAGE_CLASS_TYPEDEF && node_rhs.storage_class == STORAGE_CLASS_NONE) {
result = CompareResultType::MATCHES_FAVOUR_LHS;
} else if(node_lhs.storage_class == STORAGE_CLASS_NONE && node_rhs.storage_class == STORAGE_CLASS_TYPEDEF) {
result = CompareResultType::MATCHES_FAVOUR_RHS;
} else {
return CompareFailReason::STORAGE_CLASS;
}
}
// Vtable pointers and constructors can sometimes contain type numbers
// that are different between translation units, so we don't want to
// compare them.
bool is_vtable_pointer = node_lhs.is_vtable_pointer && node_rhs.is_vtable_pointer;
bool is_numbered_constructor = node_lhs.name.starts_with("$_") && node_rhs.name.starts_with("$_");
if(node_lhs.name != node_rhs.name && !is_vtable_pointer && !is_numbered_constructor) {
return CompareFailReason::NAME;
}
if(node_lhs.offset_bytes != node_rhs.offset_bytes) {
return CompareFailReason::RELATIVE_OFFSET_BYTES;
}
if(node_lhs.size_bits != node_rhs.size_bits) {
return CompareFailReason::SIZE_BITS;
}
if(node_lhs.is_const != node_rhs.is_const) {
return CompareFailReason::CONSTNESS;
}
}
switch(node_lhs.descriptor) {
case ARRAY: {
const auto [lhs, rhs] = Node::as<Array>(node_lhs, node_rhs);
if(compare_nodes_and_merge(result, *lhs.element_type.get(), *rhs.element_type.get(), database)) {
return result;
}
if(lhs.element_count != rhs.element_count) {
return CompareFailReason::ARRAY_ELEMENT_COUNT;
}
break;
}
case BITFIELD: {
const auto [lhs, rhs] = Node::as<BitField>(node_lhs, node_rhs);
if(lhs.bitfield_offset_bits != rhs.bitfield_offset_bits) {
return CompareFailReason::BITFIELD_OFFSET_BITS;
}
if(compare_nodes_and_merge(result, *lhs.underlying_type.get(), *rhs.underlying_type.get(), database)) {
return result;
}
break;
}
case BUILTIN: {
const auto [lhs, rhs] = Node::as<BuiltIn>(node_lhs, node_rhs);
if(lhs.bclass != rhs.bclass) {
return CompareFailReason::BUILTIN_CLASS;
}
break;
}
case ENUM: {
const auto [lhs, rhs] = Node::as<Enum>(node_lhs, node_rhs);
if(lhs.constants != rhs.constants) {
return CompareFailReason::ENUM_CONSTANTS;
}
break;
}
case ERROR_NODE: {
break;
}
case FUNCTION: {
const auto [lhs, rhs] = Node::as<Function>(node_lhs, node_rhs);
if(lhs.return_type.has_value() != rhs.return_type.has_value()) {
return CompareFailReason::FUNCTION_RETURN_TYPE_HAS_VALUE;
}
if(lhs.return_type.has_value()) {
if(compare_nodes_and_merge(result, *lhs.return_type->get(), *rhs.return_type->get(), database)) {
return result;
}
}
if(lhs.parameters.has_value() && rhs.parameters.has_value()) {
if(lhs.parameters->size() != rhs.parameters->size()) {
return CompareFailReason::FUNCTION_PARAMAETER_COUNT;
}
for(size_t i = 0; i < lhs.parameters->size(); i++) {
if(compare_nodes_and_merge(result, *(*lhs.parameters)[i].get(), *(*rhs.parameters)[i].get(), database)) {
return result;
}
}
} else if(lhs.parameters.has_value() != rhs.parameters.has_value()) {
return CompareFailReason::FUNCTION_PARAMETERS_HAS_VALUE;
}
if(lhs.modifier != rhs.modifier) {
return CompareFailReason::FUNCTION_MODIFIER;
}
break;
}
case POINTER_OR_REFERENCE: {
const auto [lhs, rhs] = Node::as<PointerOrReference>(node_lhs, node_rhs);
if(lhs.is_pointer != rhs.is_pointer) {
return CompareFailReason::DESCRIPTOR;
}
if(compare_nodes_and_merge(result, *lhs.value_type.get(), *rhs.value_type.get(), database)) {
return result;
}
break;
}
case POINTER_TO_DATA_MEMBER: {
const auto [lhs, rhs] = Node::as<PointerToDataMember>(node_lhs, node_rhs);
if(compare_nodes_and_merge(result, *lhs.class_type.get(), *rhs.class_type.get(), database)) {
return result;
}
if(compare_nodes_and_merge(result, *lhs.member_type.get(), *rhs.member_type.get(), database)) {
return result;
}
break;
}
case STRUCT_OR_UNION: {
const auto [lhs, rhs] = Node::as<StructOrUnion>(node_lhs, node_rhs);
if(lhs.is_struct != rhs.is_struct) {
return CompareFailReason::DESCRIPTOR;
}
if(lhs.base_classes.size() != rhs.base_classes.size()) {
return CompareFailReason::BASE_CLASS_COUNT;
}
for(size_t i = 0; i < lhs.base_classes.size(); i++) {
if(compare_nodes_and_merge(result, *lhs.base_classes[i].get(), *rhs.base_classes[i].get(), database)) {
return result;
}
}
if(lhs.fields.size() != rhs.fields.size()) {
return CompareFailReason::FIELDS_SIZE;
}
for(size_t i = 0; i < lhs.fields.size(); i++) {
if(compare_nodes_and_merge(result, *lhs.fields[i].get(), *rhs.fields[i].get(), database)) {
return result;
}
}
if(lhs.member_functions.size() != rhs.member_functions.size()) {
return CompareFailReason::MEMBER_FUNCTION_COUNT;
}
for(size_t i = 0; i < lhs.member_functions.size(); i++) {
if(compare_nodes_and_merge(result, *lhs.member_functions[i].get(), *rhs.member_functions[i].get(), database)) {
return result;
}
}
break;
}
case TYPE_NAME: {
const auto [lhs, rhs] = Node::as<TypeName>(node_lhs, node_rhs);
// Don't check the source so that REFERENCE and CROSS_REFERENCE are
// treated as the same.
if(lhs.data_type_handle != rhs.data_type_handle) {
return CompareFailReason::TYPE_NAME;
}
const TypeName::UnresolvedStabs* lhs_unresolved_stabs = lhs.unresolved_stabs.get();
const TypeName::UnresolvedStabs* rhs_unresolved_stabs = rhs.unresolved_stabs.get();
if(lhs_unresolved_stabs && rhs_unresolved_stabs) {
if(lhs_unresolved_stabs->type_name != rhs_unresolved_stabs->type_name) {
return CompareFailReason::TYPE_NAME;
}
} else if(lhs_unresolved_stabs || rhs_unresolved_stabs) {
return CompareFailReason::TYPE_NAME;
}
break;
}
}
return result;
}
static bool compare_nodes_and_merge(
CompareResult& dest, const Node& node_lhs, const Node& node_rhs, const SymbolDatabase* database)
{
CompareResult result = compare_nodes(node_lhs, node_rhs, database, true);
if(database) {
if(result.type == CompareResultType::DIFFERS && try_to_match_wobbly_typedefs(node_lhs, node_rhs, *database)) {
result.type = CompareResultType::MATCHES_FAVOUR_LHS;
} else if(result.type == CompareResultType::DIFFERS && try_to_match_wobbly_typedefs(node_rhs, node_lhs, *database)) {
result.type = CompareResultType::MATCHES_FAVOUR_RHS;
}
}
if(dest.type != result.type) {
if(dest.type == CompareResultType::DIFFERS || result.type == CompareResultType::DIFFERS) {
// If any of the inner types differ, the outer type does too.
dest.type = CompareResultType::DIFFERS;
} else if(dest.type == CompareResultType::MATCHES_CONFUSED || result.type == CompareResultType::MATCHES_CONFUSED) {
// Propagate confusion.
dest.type = CompareResultType::MATCHES_CONFUSED;
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_LHS && result.type == CompareResultType::MATCHES_FAVOUR_RHS) {
// One of the results favours the LHS node and the other favours the
// RHS node so we are confused.
dest.type = CompareResultType::MATCHES_CONFUSED;
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_RHS && result.type == CompareResultType::MATCHES_FAVOUR_LHS) {
// One of the results favours the LHS node and the other favours the
// RHS node so we are confused.
dest.type = CompareResultType::MATCHES_CONFUSED;
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_LHS || result.type == CompareResultType::MATCHES_FAVOUR_LHS) {
// One of the results favours the LHS node and the other is neutral
// so go with the LHS node.
dest.type = CompareResultType::MATCHES_FAVOUR_LHS;
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_RHS || result.type == CompareResultType::MATCHES_FAVOUR_RHS) {
// One of the results favours the RHS node and the other is neutral
// so go with the RHS node.
dest.type = CompareResultType::MATCHES_FAVOUR_RHS;
}
}
if(dest.fail_reason == CompareFailReason::NONE) {
dest.fail_reason = result.fail_reason;
}
return dest.type == CompareResultType::DIFFERS;
}
static bool try_to_match_wobbly_typedefs(
const Node& type_name_node, const Node& raw_node, const SymbolDatabase& database)
{
// Detect if one side has a typedef when the other just has the plain type.
// This was previously a common reason why type deduplication would fail.
if(type_name_node.descriptor != TYPE_NAME) {
return false;
}
const TypeName& type_name = type_name_node.as<TypeName>();
if(const TypeName::UnresolvedStabs* unresolved_stabs = type_name.unresolved_stabs.get()) {
if(unresolved_stabs->referenced_file_handle == (u32) -1 || !unresolved_stabs->stabs_type_number.valid()) {
return false;
}
const SourceFile* source_file =
database.source_files.symbol_from_handle(unresolved_stabs->referenced_file_handle);
CCC_ASSERT(source_file);
auto handle = source_file->stabs_type_number_to_handle.find(unresolved_stabs->stabs_type_number);
if(handle != source_file->stabs_type_number_to_handle.end()) {
const DataType* referenced_type = database.data_types.symbol_from_handle(handle->second);
CCC_ASSERT(referenced_type && referenced_type->type());
// Don't compare 'intrusive' fields e.g. the offset.
CompareResult new_result = compare_nodes(*referenced_type->type(), raw_node, &database, false);
if(new_result.type != CompareResultType::DIFFERS) {
return true;
}
}
}
return false;
}
const char* compare_fail_reason_to_string(CompareFailReason reason)
{
switch(reason) {
case CompareFailReason::NONE: return "error";
case CompareFailReason::DESCRIPTOR: return "descriptor";
case CompareFailReason::STORAGE_CLASS: return "storage class";
case CompareFailReason::NAME: return "name";
case CompareFailReason::RELATIVE_OFFSET_BYTES: return "relative offset";
case CompareFailReason::ABSOLUTE_OFFSET_BYTES: return "absolute offset";
case CompareFailReason::BITFIELD_OFFSET_BITS: return "bitfield offset";
case CompareFailReason::SIZE_BITS: return "size";
case CompareFailReason::CONSTNESS: return "constness";
case CompareFailReason::ARRAY_ELEMENT_COUNT: return "array element count";
case CompareFailReason::BUILTIN_CLASS: return "builtin class";
case CompareFailReason::FUNCTION_RETURN_TYPE_HAS_VALUE: return "function return type has value";
case CompareFailReason::FUNCTION_PARAMAETER_COUNT: return "function paramaeter count";
case CompareFailReason::FUNCTION_PARAMETERS_HAS_VALUE: return "function parameter";
case CompareFailReason::FUNCTION_MODIFIER: return "function modifier";
case CompareFailReason::ENUM_CONSTANTS: return "enum constant";
case CompareFailReason::BASE_CLASS_COUNT: return "base class count";
case CompareFailReason::FIELDS_SIZE: return "fields size";
case CompareFailReason::MEMBER_FUNCTION_COUNT: return "member function count";
case CompareFailReason::VTABLE_GLOBAL: return "vtable global";
case CompareFailReason::TYPE_NAME: return "type name";
case CompareFailReason::VARIABLE_CLASS: return "variable class";
case CompareFailReason::VARIABLE_TYPE: return "variable type";
case CompareFailReason::VARIABLE_STORAGE: return "variable storage";
case CompareFailReason::VARIABLE_BLOCK: return "variable block";
}
return "";
}
const char* node_type_to_string(const Node& node)
{
switch(node.descriptor) {
case ARRAY: return "array";
case BITFIELD: return "bitfield";
case BUILTIN: return "builtin";
case ENUM: return "enum";
case ERROR_NODE: return "error";
case FUNCTION: return "function";
case POINTER_OR_REFERENCE: {
const PointerOrReference& pointer_or_reference = node.as<PointerOrReference>();
if(pointer_or_reference.is_pointer) {
return "pointer";
} else {
return "reference";
}
}
case POINTER_TO_DATA_MEMBER: return "pointer_to_data_member";
case STRUCT_OR_UNION: {
const StructOrUnion& struct_or_union = node.as<StructOrUnion>();
if(struct_or_union.is_struct) {
return "struct";
} else {
return "union";
}
}
case TYPE_NAME: return "type_name";
}
return "";
}
const char* storage_class_to_string(StorageClass storage_class)
{
switch(storage_class) {
case STORAGE_CLASS_NONE: return "none";
case STORAGE_CLASS_TYPEDEF: return "typedef";
case STORAGE_CLASS_EXTERN: return "extern";
case STORAGE_CLASS_STATIC: return "static";
case STORAGE_CLASS_AUTO: return "auto";
case STORAGE_CLASS_REGISTER: return "register";
}
return "";
}
const char* access_specifier_to_string(AccessSpecifier specifier)
{
switch(specifier) {
case AS_PUBLIC: return "public";
case AS_PROTECTED: return "protected";
case AS_PRIVATE: return "private";
}
return "";
}
const char* builtin_class_to_string(BuiltInClass bclass)
{
switch(bclass) {
case BuiltInClass::VOID_TYPE: return "void";
case BuiltInClass::UNSIGNED_8: return "8-bit unsigned integer";
case BuiltInClass::SIGNED_8: return "8-bit signed integer";
case BuiltInClass::UNQUALIFIED_8: return "8-bit integer";
case BuiltInClass::BOOL_8: return "8-bit boolean";
case BuiltInClass::UNSIGNED_16: return "16-bit unsigned integer";
case BuiltInClass::SIGNED_16: return "16-bit signed integer";
case BuiltInClass::UNSIGNED_32: return "32-bit unsigned integer";
case BuiltInClass::SIGNED_32: return "32-bit signed integer";
case BuiltInClass::FLOAT_32: return "32-bit floating point";
case BuiltInClass::UNSIGNED_64: return "64-bit unsigned integer";
case BuiltInClass::SIGNED_64: return "64-bit signed integer";
case BuiltInClass::FLOAT_64: return "64-bit floating point";
case BuiltInClass::UNSIGNED_128: return "128-bit unsigned integer";
case BuiltInClass::SIGNED_128: return "128-bit signed integer";
case BuiltInClass::UNQUALIFIED_128: return "128-bit integer";
case BuiltInClass::FLOAT_128: return "128-bit floating point";
}
return "";
}
s32 builtin_class_size(BuiltInClass bclass)
{
switch(bclass) {
case BuiltInClass::VOID_TYPE: return 0;
case BuiltInClass::UNSIGNED_8: return 1;
case BuiltInClass::SIGNED_8: return 1;
case BuiltInClass::UNQUALIFIED_8: return 1;
case BuiltInClass::BOOL_8: return 1;
case BuiltInClass::UNSIGNED_16: return 2;
case BuiltInClass::SIGNED_16: return 2;
case BuiltInClass::UNSIGNED_32: return 4;
case BuiltInClass::SIGNED_32: return 4;
case BuiltInClass::FLOAT_32: return 4;
case BuiltInClass::UNSIGNED_64: return 8;
case BuiltInClass::SIGNED_64: return 8;
case BuiltInClass::FLOAT_64: return 8;
case BuiltInClass::UNSIGNED_128: return 16;
case BuiltInClass::SIGNED_128: return 16;
case BuiltInClass::UNQUALIFIED_128: return 16;
case BuiltInClass::FLOAT_128: return 16;
}
return 0;
}
}

377
3rdparty/ccc/src/ccc/ast.h vendored Normal file
View File

@@ -0,0 +1,377 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "symbol_database.h"
namespace ccc::ast {
enum NodeDescriptor : u8 {
ARRAY,
BITFIELD,
BUILTIN,
ENUM,
ERROR_NODE,
FUNCTION,
POINTER_OR_REFERENCE,
POINTER_TO_DATA_MEMBER,
STRUCT_OR_UNION,
TYPE_NAME
};
enum AccessSpecifier {
AS_PUBLIC = 0,
AS_PROTECTED = 1,
AS_PRIVATE = 2
};
// To add a new type of node:
// 1. Add it to the NodeDescriptor enum.
// 2. Create a struct for it.
// 3. Add support for it in for_each_node.
// 4. Add support for it in compute_size_bytes_recursive.
// 5. Add support for it in compare_nodes.
// 6. Add support for it in node_type_to_string.
// 7. Add support for it in CppPrinter::ast_node.
// 8. Add support for it in write_json.
// 9. Add support for it in refine_node.
struct Node {
const NodeDescriptor descriptor;
u8 is_const : 1 = false;
u8 is_volatile : 1 = false;
u8 is_virtual_base_class : 1 = false;
u8 is_vtable_pointer : 1 = false;
u8 is_constructor_or_destructor : 1 = false;
u8 is_special_member_function : 1 = false;
u8 is_operator_member_function : 1 = false;
u8 cannot_compute_size : 1 = false;
u8 storage_class : 4 = STORAGE_CLASS_NONE;
u8 access_specifier : 2 = AS_PUBLIC;
s32 size_bytes = -1;
// If the name isn't populated for a given node, the name from the last
// ancestor to have one should be used i.e. when processing the tree you
// should pass the name down.
std::string name;
s32 offset_bytes = -1; // Offset relative to start of last inline struct/union.
s32 size_bits = -1; // Size stored in the .mdebug symbol table, may not be set.
Node(NodeDescriptor d) : descriptor(d) {}
Node(const Node& rhs) = default;
virtual ~Node() {}
template <typename SubType>
SubType& as() {
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
return *static_cast<SubType*>(this);
}
template <typename SubType>
const SubType& as() const {
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
return *static_cast<const SubType*>(this);
}
template <typename SubType>
static std::pair<const SubType&, const SubType&> as(const Node& lhs, const Node& rhs) {
CCC_ASSERT(lhs.descriptor == SubType::DESCRIPTOR && rhs.descriptor == SubType::DESCRIPTOR);
return std::pair<const SubType&, const SubType&>(static_cast<const SubType&>(lhs), static_cast<const SubType&>(rhs));
}
void set_access_specifier(AccessSpecifier specifier, u32 importer_flags);
// If this node is a type name, repeatedly resolve it to the type it's
// referencing, otherwise return (this, nullptr).
std::pair<Node*, DataType*> physical_type(SymbolDatabase& database, s32 max_depth = 100);
std::pair<const Node*, const DataType*> physical_type(const SymbolDatabase& database, s32 max_depth = 100) const;
};
struct Array : Node {
std::unique_ptr<Node> element_type;
s32 element_count = -1;
Array() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = ARRAY;
};
struct BitField : Node {
s32 bitfield_offset_bits = -1; // Offset relative to the last byte (not the position of the underlying type!).
std::unique_ptr<Node> underlying_type;
BitField() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = BITFIELD;
};
enum class BuiltInClass {
VOID_TYPE,
UNSIGNED_8, SIGNED_8, UNQUALIFIED_8, BOOL_8,
UNSIGNED_16, SIGNED_16,
UNSIGNED_32, SIGNED_32, FLOAT_32,
UNSIGNED_64, SIGNED_64, FLOAT_64,
UNSIGNED_128, SIGNED_128, UNQUALIFIED_128, FLOAT_128
};
struct BuiltIn : Node {
BuiltInClass bclass = BuiltInClass::VOID_TYPE;
BuiltIn() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = BUILTIN;
};
struct Enum : Node {
std::vector<std::pair<s32, std::string>> constants;
Enum() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = ENUM;
};
struct Error : Node {
std::string message;
Error() : Node(ERROR_NODE) {}
static const constexpr NodeDescriptor DESCRIPTOR = ERROR_NODE;
};
enum class MemberFunctionModifier {
NONE,
STATIC,
VIRTUAL
};
const char* member_function_modifier_to_string(MemberFunctionModifier modifier);
struct Function : Node {
std::optional<std::unique_ptr<Node>> return_type;
std::optional<std::vector<std::unique_ptr<Node>>> parameters;
MemberFunctionModifier modifier = MemberFunctionModifier::NONE;
s32 vtable_index = -1;
FunctionHandle definition_handle; // Filled in by fill_in_pointers_to_member_function_definitions.
Function() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = FUNCTION;
};
struct PointerOrReference : Node {
bool is_pointer = true;
std::unique_ptr<Node> value_type;
PointerOrReference() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = POINTER_OR_REFERENCE;
};
struct PointerToDataMember : Node {
std::unique_ptr<Node> class_type;
std::unique_ptr<Node> member_type;
PointerToDataMember() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = POINTER_TO_DATA_MEMBER;
};
struct StructOrUnion : Node {
bool is_struct = true;
std::vector<std::unique_ptr<Node>> base_classes;
std::vector<std::unique_ptr<Node>> fields;
std::vector<std::unique_ptr<Node>> member_functions;
StructOrUnion() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = STRUCT_OR_UNION;
struct FlatField {
// The field itself.
const Node* node;
// The symbol that owns the node.
const DataType* symbol;
// Offset of the innermost enclosing base class in the object.
s32 base_offset = 0;
};
// Generate a flat list of all the fields in this class as well as all the
// base classes recursively, but only until the max_fields or max_depth
// limits are reached. Return true if all the fields were enumerated.
bool flatten_fields(
std::vector<FlatField>& output,
const DataType* symbol,
const SymbolDatabase& database,
bool skip_statics,
s32 base_offset = 0,
s32 max_fields = 100000,
s32 max_depth = 100) const;
};
enum class TypeNameSource : u8 {
REFERENCE, // A STABS type reference.
CROSS_REFERENCE, // A STABS cross reference.
UNNAMED_THIS // A this parameter (or return type) referencing an unnamed type.
};
const char* type_name_source_to_string(TypeNameSource source);
enum class ForwardDeclaredType {
STRUCT,
UNION,
ENUM // Should be illegal but STABS supports cross references to enums so it's here.
};
const char* forward_declared_type_to_string(ForwardDeclaredType type);
struct TypeName : Node {
DataTypeHandle data_type_handle;
TypeNameSource source = TypeNameSource::REFERENCE;
bool is_forward_declared = false;
DataTypeHandle data_type_handle_unless_forward_declared() const;
struct UnresolvedStabs {
std::string type_name;
SourceFileHandle referenced_file_handle;
StabsTypeNumber stabs_type_number;
std::optional<ForwardDeclaredType> type;
};
std::unique_ptr<UnresolvedStabs> unresolved_stabs;
TypeName() : Node(DESCRIPTOR) {}
static const constexpr NodeDescriptor DESCRIPTOR = TYPE_NAME;
};
enum class CompareResultType {
MATCHES_NO_SWAP, // Both lhs and rhs are identical.
MATCHES_CONFUSED, // Both lhs and rhs are almost identical, and we don't which is better.
MATCHES_FAVOUR_LHS, // Both lhs and rhs are almost identical, but lhs is better.
MATCHES_FAVOUR_RHS, // Both lhs and rhs are almost identical, but rhs is better.
DIFFERS, // The two nodes differ substantially.
};
enum class CompareFailReason {
NONE,
DESCRIPTOR,
STORAGE_CLASS,
NAME,
RELATIVE_OFFSET_BYTES,
ABSOLUTE_OFFSET_BYTES,
BITFIELD_OFFSET_BITS,
SIZE_BITS,
CONSTNESS,
ARRAY_ELEMENT_COUNT,
BUILTIN_CLASS,
FUNCTION_RETURN_TYPE_HAS_VALUE,
FUNCTION_PARAMAETER_COUNT,
FUNCTION_PARAMETERS_HAS_VALUE,
FUNCTION_MODIFIER,
ENUM_CONSTANTS,
BASE_CLASS_COUNT,
FIELDS_SIZE,
MEMBER_FUNCTION_COUNT,
VTABLE_GLOBAL,
TYPE_NAME,
VARIABLE_CLASS,
VARIABLE_TYPE,
VARIABLE_STORAGE,
VARIABLE_BLOCK
};
struct CompareResult {
CompareResult(CompareResultType type) : type(type), fail_reason(CompareFailReason::NONE) {}
CompareResult(CompareFailReason reason) : type(CompareResultType::DIFFERS), fail_reason(reason) {}
CompareResultType type;
CompareFailReason fail_reason;
};
// Compare two AST nodes and their children recursively. This will only check
// fields that will be equal for two versions of the same type from different
// translation units.
CompareResult compare_nodes(const Node& lhs, const Node& rhs, const SymbolDatabase* database, bool check_intrusive_fields);
const char* compare_fail_reason_to_string(CompareFailReason reason);
const char* node_type_to_string(const Node& node);
const char* storage_class_to_string(StorageClass storage_class);
const char* access_specifier_to_string(AccessSpecifier specifier);
const char* builtin_class_to_string(BuiltInClass bclass);
s32 builtin_class_size(BuiltInClass bclass);
enum TraversalOrder {
PREORDER_TRAVERSAL,
POSTORDER_TRAVERSAL
};
enum ExplorationMode {
EXPLORE_CHILDREN,
DONT_EXPLORE_CHILDREN
};
template <typename ThisNode, typename Callback>
void for_each_node(ThisNode& node, TraversalOrder order, Callback callback)
{
if(order == PREORDER_TRAVERSAL && callback(node) == DONT_EXPLORE_CHILDREN) {
return;
}
switch(node.descriptor) {
case ARRAY: {
auto& array = node.template as<Array>();
for_each_node(*array.element_type.get(), order, callback);
break;
}
case BITFIELD: {
auto& bitfield = node.template as<BitField>();
for_each_node(*bitfield.underlying_type.get(), order, callback);
break;
}
case BUILTIN: {
break;
}
case ENUM: {
break;
}
case ERROR_NODE: {
break;
}
case FUNCTION: {
auto& func = node.template as<Function>();
if(func.return_type.has_value()) {
for_each_node(*func.return_type->get(), order, callback);
}
if(func.parameters.has_value()) {
for(auto& child : *func.parameters) {
for_each_node(*child.get(), order, callback);
}
}
break;
}
case POINTER_OR_REFERENCE: {
auto& pointer_or_reference = node.template as<PointerOrReference>();
for_each_node(*pointer_or_reference.value_type.get(), order, callback);
break;
}
case POINTER_TO_DATA_MEMBER: {
auto& pointer = node.template as<PointerToDataMember>();
for_each_node(*pointer.class_type.get(), order, callback);
for_each_node(*pointer.member_type.get(), order, callback);
break;
}
case STRUCT_OR_UNION: {
auto& struct_or_union = node.template as<StructOrUnion>();
for(auto& child : struct_or_union.base_classes) {
for_each_node(*child.get(), order, callback);
}
for(auto& child : struct_or_union.fields) {
for_each_node(*child.get(), order, callback);
}
for(auto& child : struct_or_union.member_functions) {
for_each_node(*child.get(), order, callback);
}
break;
}
case TYPE_NAME: {
break;
}
}
if(order == POSTORDER_TRAVERSAL) {
callback(node);
}
}
}

127
3rdparty/ccc/src/ccc/elf.cpp vendored Normal file
View File

@@ -0,0 +1,127 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "elf.h"
namespace ccc {
Result<ElfFile> ElfFile::parse(std::vector<u8> image)
{
ElfFile elf;
elf.image = std::move(image);
const ElfIdentHeader* ident = get_packed<ElfIdentHeader>(elf.image, 0);
CCC_CHECK(ident, "ELF ident header out of range.");
CCC_CHECK(ident->magic == CCC_FOURCC("\x7f\x45\x4c\x46"), "Not an ELF file.");
CCC_CHECK(ident->e_class == ElfIdentClass::B32, "Wrong ELF class (not 32 bit).");
const ElfFileHeader* header = get_packed<ElfFileHeader>(elf.image, sizeof(ElfIdentHeader));
CCC_CHECK(header, "ELF file header out of range.");
elf.file_header = *header;
const ElfSectionHeader* shstr_section_header = get_packed<ElfSectionHeader>(elf.image, header->shoff + header->shstrndx * sizeof(ElfSectionHeader));
CCC_CHECK(shstr_section_header, "ELF section name header out of range.");
for(u32 i = 0; i < header->shnum; i++) {
u64 header_offset = header->shoff + i * sizeof(ElfSectionHeader);
const ElfSectionHeader* section_header = get_packed<ElfSectionHeader>(elf.image, header_offset);
CCC_CHECK(section_header, "ELF section header out of range.");
const char* name = get_string(elf.image, shstr_section_header->offset + section_header->name);
CCC_CHECK(section_header, "ELF section name out of range.");
ElfSection& section = elf.sections.emplace_back();
section.name = name;
section.header = *section_header;
}
for(u32 i = 0; i < header->phnum; i++) {
u64 header_offset = header->phoff + i * sizeof(ElfProgramHeader);
const ElfProgramHeader* program_header = get_packed<ElfProgramHeader>(elf.image, header_offset);
CCC_CHECK(program_header, "ELF program header out of range.");
elf.segments.emplace_back(*program_header);
}
return elf;
}
Result<void> ElfFile::create_section_symbols(
SymbolDatabase& database, const SymbolGroup& group) const
{
for(const ElfSection& section : sections) {
Address address = Address::non_zero(section.header.addr);
Result<Section*> symbol = database.sections.create_symbol(
section.name, address, group.source, group.module_symbol);
CCC_RETURN_IF_ERROR(symbol);
(*symbol)->set_size(section.header.size);
}
return Result<void>();
}
const ElfSection* ElfFile::lookup_section(const char* name) const
{
for(const ElfSection& section : sections) {
if(section.name == name) {
return &section;
}
}
return nullptr;
}
std::optional<u32> ElfFile::file_offset_to_virtual_address(u32 file_offset) const
{
for(const ElfProgramHeader& segment : segments) {
if(file_offset >= segment.offset && file_offset < segment.offset + segment.filesz) {
return segment.vaddr + file_offset - segment.offset;
}
}
return std::nullopt;
}
const ElfProgramHeader* ElfFile::entry_point_segment() const
{
const ccc::ElfProgramHeader* entry_segment = nullptr;
for(const ccc::ElfProgramHeader& segment : segments) {
if(file_header.entry >= segment.vaddr && file_header.entry < segment.vaddr + segment.filesz) {
entry_segment = &segment;
}
}
return entry_segment;
}
std::optional<std::span<const u8>> ElfFile::get_virtual(u32 address, u32 size) const
{
u32 end_address = address + size;
if(end_address >= address) {
for(const ElfProgramHeader& segment : segments) {
if(address >= segment.vaddr && end_address <= segment.vaddr + segment.filesz) {
size_t begin_offset = segment.offset + (address - segment.vaddr);
size_t end_offset = begin_offset + size;
if(begin_offset <= image.size() && end_offset <= image.size()) {
return std::span<const u8>(image.data() + begin_offset, image.data() + end_offset);
}
}
}
}
return std::nullopt;
}
bool ElfFile::copy_virtual(u8* dest, u32 address, u32 size) const
{
std::optional<std::span<const u8>> block = get_virtual(address, size);
if(!block.has_value()) {
return false;
}
memcpy(dest, block->data(), size);
return true;
}
}

160
3rdparty/ccc/src/ccc/elf.h vendored Normal file
View File

@@ -0,0 +1,160 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "symbol_database.h"
namespace ccc {
enum class ElfIdentClass : u8 {
B32 = 0x1,
B64 = 0x2
};
CCC_PACKED_STRUCT(ElfIdentHeader,
/* 0x0 */ u32 magic; // 7f 45 4c 46
/* 0x4 */ ElfIdentClass e_class;
/* 0x5 */ u8 endianess;
/* 0x6 */ u8 version;
/* 0x7 */ u8 os_abi;
/* 0x8 */ u8 abi_version;
/* 0x9 */ u8 pad[7];
)
enum class ElfFileType : u16 {
NONE = 0x00,
REL = 0x01,
EXEC = 0x02,
DYN = 0x03,
CORE = 0x04,
LOOS = 0xfe00,
HIOS = 0xfeff,
LOPROC = 0xff00,
HIPROC = 0xffff
};
enum class ElfMachine : u16 {
MIPS = 0x08
};
CCC_PACKED_STRUCT(ElfFileHeader,
/* 0x10 */ ElfFileType type;
/* 0x12 */ ElfMachine machine;
/* 0x14 */ u32 version;
/* 0x18 */ u32 entry;
/* 0x1c */ u32 phoff;
/* 0x20 */ u32 shoff;
/* 0x24 */ u32 flags;
/* 0x28 */ u16 ehsize;
/* 0x2a */ u16 phentsize;
/* 0x2c */ u16 phnum;
/* 0x2e */ u16 shentsize;
/* 0x30 */ u16 shnum;
/* 0x32 */ u16 shstrndx;
)
enum class ElfSectionType : u32 {
NULL_SECTION = 0x0,
PROGBITS = 0x1,
SYMTAB = 0x2,
STRTAB = 0x3,
RELA = 0x4,
HASH = 0x5,
DYNAMIC = 0x6,
NOTE = 0x7,
NOBITS = 0x8,
REL = 0x9,
SHLIB = 0xa,
DYNSYM = 0xb,
INIT_ARRAY = 0xe,
FINI_ARRAY = 0xf,
PREINIT_ARRAY = 0x10,
GROUP = 0x11,
SYMTAB_SHNDX = 0x12,
NUM = 0x13,
LOOS = 0x60000000,
MIPS_DEBUG = 0x70000005
};
CCC_PACKED_STRUCT(ElfSectionHeader,
/* 0x00 */ u32 name;
/* 0x04 */ ElfSectionType type;
/* 0x08 */ u32 flags;
/* 0x0c */ u32 addr;
/* 0x10 */ u32 offset;
/* 0x14 */ u32 size;
/* 0x18 */ u32 link;
/* 0x1c */ u32 info;
/* 0x20 */ u32 addralign;
/* 0x24 */ u32 entsize;
)
struct ElfSection {
std::string name;
ElfSectionHeader header;
};
CCC_PACKED_STRUCT(ElfProgramHeader,
/* 0x00 */ u32 type;
/* 0x04 */ u32 offset;
/* 0x08 */ u32 vaddr;
/* 0x0c */ u32 paddr;
/* 0x10 */ u32 filesz;
/* 0x14 */ u32 memsz;
/* 0x18 */ u32 flags;
/* 0x1c */ u32 align;
)
struct ElfFile {
ElfFileHeader file_header;
std::vector<u8> image;
std::vector<ElfSection> sections;
std::vector<ElfProgramHeader> segments;
// Parse the ELF file header, section headers and program headers.
static Result<ElfFile> parse(std::vector<u8> image);
// Create a section object for each section header in the ELF file.
Result<void> create_section_symbols(SymbolDatabase& database, const SymbolGroup& group) const;
const ElfSection* lookup_section(const char* name) const;
std::optional<u32> file_offset_to_virtual_address(u32 file_offset) const;
// Find the program header for the segment that contains the entry point.
const ElfProgramHeader* entry_point_segment() const;
// Retrieve a block of data in an ELF file given its address and size.
std::optional<std::span<const u8>> get_virtual(u32 address, u32 size) const;
// Copy a block of data in an ELF file to the destination buffer given its
// address and size.
bool copy_virtual(u8* dest, u32 address, u32 size) const;
// Retrieve an object of type T from an ELF file given its address.
template <typename T>
std::optional<T> get_object_virtual(u32 address) const
{
std::optional<std::span<const u8>> result = get_virtual(address, sizeof(T));
if(!result.has_value()) {
return std::nullopt;
}
return *(T*) result->data();
}
// Retrieve an array of objects of type T from an ELF file given its
// address and element count.
template <typename T>
std::optional<std::span<const T>> get_array_virtual(u32 address, u32 element_count) const
{
std::optional<std::span<const u8>> result = get_virtual(address, element_count * sizeof(T));
if(!result.has_value()) {
return std::nullopt;
}
return std::span<const T>((T*) result->data(), (T*) (result->data() + result->size()));
}
};
}

213
3rdparty/ccc/src/ccc/elf_symtab.cpp vendored Normal file
View File

@@ -0,0 +1,213 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "elf_symtab.h"
#include "importer_flags.h"
namespace ccc::elf {
enum class SymbolBind : u8 {
LOCAL = 0,
GLOBAL = 1,
WEAK = 2,
NUM = 3,
GNU_UNIQUE = 10
};
enum class SymbolType : u8 {
NOTYPE = 0,
OBJECT = 1,
FUNC = 2,
SECTION = 3,
FILE = 4,
COMMON = 5,
TLS = 6,
NUM = 7,
GNU_IFUNC = 10
};
enum class SymbolVisibility {
DEFAULT = 0,
INTERNAL = 1,
HIDDEN = 2,
PROTECTED = 3
};
CCC_PACKED_STRUCT(Symbol,
/* 0x0 */ u32 name;
/* 0x4 */ u32 value;
/* 0x8 */ u32 size;
/* 0xc */ u8 info;
/* 0xd */ u8 other;
/* 0xe */ u16 shndx;
SymbolType type() const { return (SymbolType) (info & 0xf); }
SymbolBind bind() const { return (SymbolBind) (info >> 4); }
SymbolVisibility visibility() const { return (SymbolVisibility) (other & 0x3); }
)
static const char* symbol_bind_to_string(SymbolBind bind);
static const char* symbol_type_to_string(SymbolType type);
static const char* symbol_visibility_to_string(SymbolVisibility visibility);
Result<void> import_symbols(
SymbolDatabase& database,
const SymbolGroup& group,
std::span<const u8> symtab,
std::span<const u8> strtab,
u32 importer_flags,
DemanglerFunctions demangler)
{
for(u32 i = 0; i < symtab.size() / sizeof(Symbol); i++) {
const Symbol* symbol = get_packed<Symbol>(symtab, i * sizeof(Symbol));
CCC_ASSERT(symbol);
Address address;
if(symbol->value != 0) {
address = symbol->value;
}
if(!address.valid() || symbol->visibility() != SymbolVisibility::DEFAULT) {
continue;
}
if(!(importer_flags & DONT_DEDUPLICATE_SYMBOLS)) {
if(database.functions.first_handle_from_starting_address(address).valid()) {
continue;
}
if(database.global_variables.first_handle_from_starting_address(address).valid()) {
continue;
}
if(database.local_variables.first_handle_from_starting_address(address).valid()) {
continue;
}
}
const char* string = get_string(strtab, symbol->name);
CCC_CHECK(string, "Symbol string out of range.");
switch(symbol->type()) {
case SymbolType::NOTYPE: {
Result<Label*> label = database.labels.create_symbol(
string, group.source, group.module_symbol, address, importer_flags, demangler);
CCC_RETURN_IF_ERROR(label);
// These symbols get emitted at the same addresses as functions
// and aren't extremely useful, so we want to mark them to
// prevent them from possibly being used as function names.
(*label)->is_junk =
(*label)->name() == "__gnu_compiled_c" ||
(*label)->name() == "__gnu_compiled_cplusplus" ||
(*label)->name() == "gcc2_compiled.";
break;
}
case SymbolType::OBJECT: {
if(symbol->size != 0) {
Result<GlobalVariable*> global_variable = database.global_variables.create_symbol(
string, group.source, group.module_symbol, address, importer_flags, demangler);
CCC_RETURN_IF_ERROR(global_variable);
if(*global_variable) {
(*global_variable)->set_size(symbol->size);
}
} else {
Result<Label*> label = database.labels.create_symbol(
string, group.source, group.module_symbol, address, importer_flags, demangler);
CCC_RETURN_IF_ERROR(label);
}
break;
}
case SymbolType::FUNC: {
Result<Function*> function = database.functions.create_symbol(
string, group.source, group.module_symbol, address, importer_flags, demangler);
CCC_RETURN_IF_ERROR(function);
if(*function) {
(*function)->set_size(symbol->size);
}
break;
}
case SymbolType::FILE: {
Result<SourceFile*> source_file = database.source_files.create_symbol(
string, group.source, group.module_symbol);
CCC_RETURN_IF_ERROR(source_file);
break;
}
default: {}
}
}
return Result<void>();
}
Result<void> print_symbol_table(FILE* out, std::span<const u8> symtab, std::span<const u8> strtab)
{
fprintf(out, "ELF SYMBOLS:\n");
fprintf(out, " Num: Value Size Type Bind Vis Ndx Name\n");
for(u32 i = 0; i < symtab.size() / sizeof(Symbol); i++) {
const Symbol* symbol = get_packed<Symbol>(symtab, i * sizeof(Symbol));
CCC_ASSERT(symbol);
const char* type = symbol_type_to_string(symbol->type());
const char* bind = symbol_bind_to_string(symbol->bind());
const char* visibility = symbol_visibility_to_string(symbol->visibility());
const char* string = get_string(strtab, symbol->name);
CCC_CHECK(string, "Symbol string out of range.");
fprintf(out, "%6u: %08x %5u %-7s %-7s %-7s %3u %s\n",
i, symbol->value, symbol->size, type, bind, visibility, symbol->shndx, string);
}
return Result<void>();
}
static const char* symbol_bind_to_string(SymbolBind bind)
{
switch(bind) {
case SymbolBind::LOCAL: return "LOCAL";
case SymbolBind::GLOBAL: return "GLOBAL";
case SymbolBind::WEAK: return "WEAK";
case SymbolBind::NUM: return "NUM";
case SymbolBind::GNU_UNIQUE: return "GNU_UNIQUE";
}
return "ERROR";
}
static const char* symbol_type_to_string(SymbolType type)
{
switch(type) {
case SymbolType::NOTYPE: return "NOTYPE";
case SymbolType::OBJECT: return "OBJECT";
case SymbolType::FUNC: return "FUNC";
case SymbolType::SECTION: return "SECTION";
case SymbolType::FILE: return "FILE";
case SymbolType::COMMON: return "COMMON";
case SymbolType::TLS: return "TLS";
case SymbolType::NUM: return "NUM";
case SymbolType::GNU_IFUNC: return "GNU_IFUNC";
}
return "ERROR";
}
static const char* symbol_visibility_to_string(SymbolVisibility visibility)
{
switch(visibility) {
case SymbolVisibility::DEFAULT: return "DEFAULT";
case SymbolVisibility::INTERNAL: return "INTERNAL";
case SymbolVisibility::HIDDEN: return "HIDDEN";
case SymbolVisibility::PROTECTED: return "PROTECTED";
}
return "ERROR";
}
}

20
3rdparty/ccc/src/ccc/elf_symtab.h vendored Normal file
View File

@@ -0,0 +1,20 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "symbol_database.h"
namespace ccc::elf {
Result<void> import_symbols(
SymbolDatabase& database,
const SymbolGroup& group,
std::span<const u8> symtab,
std::span<const u8> strtab,
u32 importer_flags,
DemanglerFunctions demangler);
Result<void> print_symbol_table(FILE* out, std::span<const u8> symtab, std::span<const u8> strtab);
}

95
3rdparty/ccc/src/ccc/importer_flags.cpp vendored Normal file
View File

@@ -0,0 +1,95 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "importer_flags.h"
namespace ccc {
const std::vector<ImporterFlagInfo> IMPORTER_FLAGS = {
{DEMANGLE_PARAMETERS, "--demangle-parameters", {
"Include parameters in demangled function names."
}},
{DEMANGLE_RETURN_TYPE, "--demangle-return-type", {
"Include return types at the end of demangled",
"function names if they're available."
}},
{DONT_DEDUPLICATE_SYMBOLS, "--dont-deduplicate-symbols", {
"Do not deduplicate matching symbols from",
"different symbol tables. This options has no",
"effect on data types."
}},
{DONT_DEDUPLICATE_TYPES, "--dont-deduplicate-types", {
"Do not deduplicate data types from different",
"translation units."
}},
{DONT_DEMANGLE_NAMES, "--dont-demangle-names", {
"Do not demangle function names, global variable",
"names, or overloaded operator names."
}},
{INCLUDE_GENERATED_MEMBER_FUNCTIONS, "--include-generated-functions", {
"Output member functions that were likely",
"automatically generated by the compiler."
}},
{NO_ACCESS_SPECIFIERS, "--no-access-specifiers", {
"Do not print access specifiers."
}},
{NO_MEMBER_FUNCTIONS, "--no-member-functions", {
"Do not print member functions."
}},
{NO_OPTIMIZED_OUT_FUNCTIONS, "--no-optimized-out-functions", {
"Discard functions that were optimized out."
}},
{STRICT_PARSING, "--strict", {
"Make more types of errors fatal."
}},
{TYPEDEF_ALL_ENUMS, "--typedef-all-enums", {
"Force all emitted C++ enums to be defined using",
"a typedef. With STABS, it is not always possible",
"to determine if an enum was like this in the",
"original source code, so this option should be",
"useful for reverse engineering C projects."
}},
{TYPEDEF_ALL_STRUCTS, "--typedef-all-structs", {
"Force all emitted C++ structure types to be",
"defined using a typedef."
}},
{TYPEDEF_ALL_UNIONS, "--typedef-all-unions", {
"Force all emitted C++ union types to be defined",
"using a typedef."
}},
{UNIQUE_FUNCTIONS, "--unique-functions", {
" If multiple identical .mdebug function symbols",
"are present, find the one that seems to have",
"actually been included in the linked binary, and",
"remove the addresses from all the rest. Using",
"this importer flag in combination with",
"--no-optimized-out-functions will remove these",
"duplicate function symbols entirely."
}}
};
u32 parse_importer_flag(const char* argument)
{
for(const ImporterFlagInfo& flag : IMPORTER_FLAGS) {
if(strcmp(flag.argument, argument) == 0) {
return flag.flag;
}
}
return NO_IMPORTER_FLAGS;
}
void print_importer_flags_help(FILE* out)
{
for(const ImporterFlagInfo& flag : IMPORTER_FLAGS) {
fprintf(out, "\n");
fprintf(out, " %-29s ", flag.argument);
for(size_t i = 0; i < flag.help_text.size(); i++) {
if(i > 0) {
fprintf(out, " ");
}
fprintf(out, "%s\n", flag.help_text[i]);
}
}
}
}

39
3rdparty/ccc/src/ccc/importer_flags.h vendored Normal file
View File

@@ -0,0 +1,39 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "util.h"
namespace ccc {
enum ImporterFlags {
NO_IMPORTER_FLAGS = 0,
DEMANGLE_PARAMETERS = (1 << 0),
DEMANGLE_RETURN_TYPE = (1 << 1),
DONT_DEDUPLICATE_SYMBOLS = (1 << 2),
DONT_DEDUPLICATE_TYPES = (1 << 3),
DONT_DEMANGLE_NAMES = (1 << 4),
INCLUDE_GENERATED_MEMBER_FUNCTIONS = (1 << 5),
NO_ACCESS_SPECIFIERS = (1 << 6),
NO_MEMBER_FUNCTIONS = (1 << 7),
NO_OPTIMIZED_OUT_FUNCTIONS = (1 << 8),
STRICT_PARSING = (1 << 9),
TYPEDEF_ALL_ENUMS = (1 << 10),
TYPEDEF_ALL_STRUCTS = (1 << 11),
TYPEDEF_ALL_UNIONS = (1 << 12),
UNIQUE_FUNCTIONS = (1 << 13)
};
struct ImporterFlagInfo {
ImporterFlags flag;
const char* argument;
std::vector<const char*> help_text;
};
extern const std::vector<ImporterFlagInfo> IMPORTER_FLAGS;
u32 parse_importer_flag(const char* argument);
void print_importer_flags_help(FILE* out);
}

349
3rdparty/ccc/src/ccc/mdebug_analysis.cpp vendored Normal file
View File

@@ -0,0 +1,349 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "mdebug_analysis.h"
#include "stabs_to_ast.h"
namespace ccc::mdebug {
Result<void> LocalSymbolTableAnalyser::stab_magic(const char* magic)
{
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::source_file(const char* path, Address text_address)
{
if(m_next_relative_path.empty()) {
m_next_relative_path = m_source_file.command_line_path;
}
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::data_type(const ParsedSymbol& symbol)
{
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(
*symbol.name_colon_type.type.get(), nullptr, m_stabs_to_ast_state, 0, false, false);
CCC_RETURN_IF_ERROR(node);
if(symbol.is_typedef && (*node)->descriptor == ast::STRUCT_OR_UNION) {
ast::StructOrUnion& struct_or_union = (*node)->as<ast::StructOrUnion>();
const std::string& name = symbol.name_colon_type.name;
StabsTypeNumber type_number = symbol.name_colon_type.type->type_number;
fix_recursively_emitted_structures(struct_or_union, name, type_number, m_stabs_to_ast_state.file_handle);
}
bool is_struct = (*node)->descriptor == ast::STRUCT_OR_UNION && (*node)->as<ast::StructOrUnion>().is_struct;
bool force_typedef =
((m_context.importer_flags & TYPEDEF_ALL_ENUMS) && (*node)->descriptor == ast::ENUM) ||
((m_context.importer_flags & TYPEDEF_ALL_STRUCTS) && (*node)->descriptor == ast::STRUCT_OR_UNION && is_struct) ||
((m_context.importer_flags & TYPEDEF_ALL_UNIONS) && (*node)->descriptor == ast::STRUCT_OR_UNION && !is_struct);
(*node)->name = (symbol.name_colon_type.name == " ") ? "" : symbol.name_colon_type.name;
if(symbol.is_typedef || force_typedef) {
(*node)->storage_class = STORAGE_CLASS_TYPEDEF;
}
const char* name = (*node)->name.c_str();
StabsTypeNumber number = symbol.name_colon_type.type->type_number;
if(m_context.importer_flags & DONT_DEDUPLICATE_TYPES) {
Result<DataType*> data_type = m_database.data_types.create_symbol(
name, m_context.group.source, m_context.group.module_symbol);
CCC_RETURN_IF_ERROR(data_type);
m_source_file.stabs_type_number_to_handle[number] = (*data_type)->handle();
(*data_type)->set_type(std::move(*node));
(*data_type)->files = {m_source_file.handle()};
} else {
Result<ccc::DataType*> type = m_database.create_data_type_if_unique(
std::move(*node), number, name, m_source_file, m_context.group);
CCC_RETURN_IF_ERROR(type);
}
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::global_variable(
const char* mangled_name, Address address, const StabsType& type, bool is_static, GlobalStorageLocation location)
{
Result<GlobalVariable*> global = m_database.global_variables.create_symbol(
mangled_name, m_context.group.source, m_context.group.module_symbol, address, m_context.importer_flags, m_context.demangler);
CCC_RETURN_IF_ERROR(global);
CCC_ASSERT(*global);
m_global_variables.emplace_back((*global)->handle());
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(type, nullptr, m_stabs_to_ast_state, 0, true, false);
CCC_RETURN_IF_ERROR(node);
if(is_static) {
(*global)->storage_class = STORAGE_CLASS_STATIC;
}
(*global)->set_type(std::move(*node));
(*global)->storage.location = location;
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::sub_source_file(const char* path, Address text_address)
{
if(m_current_function && m_state == IN_FUNCTION_BEGINNING) {
Function::SubSourceFile& sub = m_current_function->sub_source_files.emplace_back();
sub.address = text_address;
sub.relative_path = path;
} else {
m_next_relative_path = path;
}
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::procedure(
const char* mangled_name, Address address, const ProcedureDescriptor* procedure_descriptor, bool is_static)
{
if(!m_current_function || strcmp(mangled_name, m_current_function->mangled_name().c_str()) != 0) {
Result<void> result = create_function(mangled_name, address);
CCC_RETURN_IF_ERROR(result);
}
if(is_static) {
m_current_function->storage_class = STORAGE_CLASS_STATIC;
}
if(procedure_descriptor) {
m_current_function->stack_frame_size = procedure_descriptor->frame_size;
}
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::label(const char* label, Address address, s32 line_number)
{
if(address.valid() && m_current_function && label[0] == '$') {
Function::LineNumberPair& pair = m_current_function->line_numbers.emplace_back();
pair.address = address;
pair.line_number = line_number;
}
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::text_end(const char* name, s32 function_size)
{
if(m_state == IN_FUNCTION_BEGINNING) {
CCC_CHECK(m_current_function, "END TEXT symbol outside of function.");
m_current_function->set_size(function_size);
m_state = IN_FUNCTION_END;
}
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::function(const char* mangled_name, const StabsType& return_type, Address address)
{
if(!m_current_function || strcmp(mangled_name, m_current_function->mangled_name().c_str()) != 0) {
Result<void> result = create_function(mangled_name, address);
CCC_RETURN_IF_ERROR(result);
} else {
// For MTV Music Maker 2, the addresses for static functions stored in
// the PROC symbols are relative to the translation unit, while the
// addresses stored in the FUN symbol are absolute. This is the only
// game I've found that seems to have this problem, but since in all
// other cases it seems all these addresses are all absolute, I may as
// well add in a hack here to deal with it.
bool no_module_base_address = m_context.group.module_symbol && m_context.group.module_symbol->address().get_or_zero() == 0;
bool new_address_greater = address.valid() && address > m_current_function->address();
if(no_module_base_address && new_address_greater) {
m_database.functions.move_symbol(m_current_function->handle(), address);
}
}
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(return_type, nullptr, m_stabs_to_ast_state, 0, true, true);
CCC_RETURN_IF_ERROR(node);
m_current_function->set_type(std::move(*node));
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::function_end()
{
if(m_current_function) {
m_current_function->set_parameter_variables(std::move(m_current_parameter_variables), m_database);
m_current_function->set_local_variables(std::move(m_current_local_variables), m_database);
}
m_current_function = nullptr;
m_current_parameter_variables = std::vector<ParameterVariableHandle>();
m_current_local_variables = std::vector<LocalVariableHandle>();
m_blocks.clear();
m_pending_local_variables.clear();
m_state = NOT_IN_FUNCTION;
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::parameter(
const char* name, const StabsType& type, bool is_stack, s32 value, bool is_by_reference)
{
CCC_CHECK(m_current_function, "Parameter symbol before first func/proc symbol.");
Result<ParameterVariable*> parameter_variable = m_database.parameter_variables.create_symbol(
name, m_context.group.source, m_context.group.module_symbol);
CCC_RETURN_IF_ERROR(parameter_variable);
m_current_parameter_variables.emplace_back((*parameter_variable)->handle());
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(type, nullptr, m_stabs_to_ast_state, 0, true, true);
CCC_RETURN_IF_ERROR(node);
(*parameter_variable)->set_type(std::move(*node));
if(is_stack) {
StackStorage& stack_storage = (*parameter_variable)->storage.emplace<StackStorage>();
stack_storage.stack_pointer_offset = value;
} else {
RegisterStorage& register_storage = (*parameter_variable)->storage.emplace<RegisterStorage>();
register_storage.dbx_register_number = value;
register_storage.is_by_reference = is_by_reference;
}
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::local_variable(
const char* name, const StabsType& type, u32 value, StabsSymbolDescriptor desc, SymbolClass sclass)
{
if(!m_current_function) {
return Result<void>();
}
Address address = (desc == StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE) ? value : Address();
Result<LocalVariable*> local_variable = m_database.local_variables.create_symbol(
name, address, m_context.group.source, m_context.group.module_symbol);
CCC_RETURN_IF_ERROR(local_variable);
m_current_local_variables.emplace_back((*local_variable)->handle());
m_pending_local_variables.emplace_back((*local_variable)->handle());
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(type, nullptr, m_stabs_to_ast_state, 0, true, false);
CCC_RETURN_IF_ERROR(node);
if(desc == StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE) {
GlobalStorage& global_storage = (*local_variable)->storage.emplace<GlobalStorage>();
std::optional<GlobalStorageLocation> location_opt =
symbol_class_to_global_variable_location(sclass);
CCC_CHECK(location_opt.has_value(),
"Invalid static local variable location %s.",
symbol_class(sclass));
global_storage.location = *location_opt;
(*node)->storage_class = STORAGE_CLASS_STATIC;
} else if(desc == StabsSymbolDescriptor::REGISTER_VARIABLE) {
RegisterStorage& register_storage = (*local_variable)->storage.emplace<RegisterStorage>();
register_storage.dbx_register_number = (s32) value;
} else if(desc == StabsSymbolDescriptor::LOCAL_VARIABLE) {
StackStorage& stack_storage = (*local_variable)->storage.emplace<StackStorage>();
stack_storage.stack_pointer_offset = (s32) value;
} else {
return CCC_FAILURE("LocalSymbolTableAnalyser::local_variable() called with bad symbol descriptor.");
}
(*local_variable)->set_type(std::move(*node));
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::lbrac(s32 begin_offset)
{
for(LocalVariableHandle local_variable_handle : m_pending_local_variables) {
if(LocalVariable* local_variable = m_database.local_variables.symbol_from_handle(local_variable_handle)) {
local_variable->live_range.low = m_source_file.address().value + begin_offset;
}
}
m_blocks.emplace_back(std::move(m_pending_local_variables));
m_pending_local_variables = {};
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::rbrac(s32 end_offset)
{
CCC_CHECK(!m_blocks.empty(), "RBRAC symbol without a matching LBRAC symbol.");
std::vector<LocalVariableHandle>& variables = m_blocks.back();
for(LocalVariableHandle local_variable_handle : variables) {
if(LocalVariable* local_variable = m_database.local_variables.symbol_from_handle(local_variable_handle)) {
local_variable->live_range.high = m_source_file.address().value + end_offset;
}
}
m_blocks.pop_back();
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::finish()
{
CCC_CHECK(m_state != IN_FUNCTION_BEGINNING,
"Unexpected end of symbol table for '%s'.", m_source_file.name().c_str());
if(m_current_function) {
Result<void> result = function_end();
CCC_RETURN_IF_ERROR(result);
}
m_source_file.set_functions(std::move(m_functions), m_database);
m_source_file.set_global_variables(std::move(m_global_variables), m_database);
return Result<void>();
}
Result<void> LocalSymbolTableAnalyser::create_function(const char* mangled_name, Address address)
{
if(m_current_function) {
Result<void> result = function_end();
CCC_RETURN_IF_ERROR(result);
}
Result<Function*> function = m_database.functions.create_symbol(
mangled_name, m_context.group.source, m_context.group.module_symbol, address, m_context.importer_flags, m_context.demangler);
CCC_RETURN_IF_ERROR(function);
CCC_ASSERT(*function);
m_current_function = *function;
m_functions.emplace_back(m_current_function->handle());
m_state = IN_FUNCTION_BEGINNING;
if(!m_next_relative_path.empty() && m_current_function->relative_path != m_source_file.command_line_path) {
m_current_function->relative_path = m_next_relative_path;
}
return Result<void>();
}
std::optional<GlobalStorageLocation> symbol_class_to_global_variable_location(SymbolClass symbol_class)
{
std::optional<GlobalStorageLocation> location;
switch(symbol_class) {
case SymbolClass::NIL: location = GlobalStorageLocation::NIL; break;
case SymbolClass::DATA: location = GlobalStorageLocation::DATA; break;
case SymbolClass::BSS: location = GlobalStorageLocation::BSS; break;
case SymbolClass::ABS: location = GlobalStorageLocation::ABS; break;
case SymbolClass::SDATA: location = GlobalStorageLocation::SDATA; break;
case SymbolClass::SBSS: location = GlobalStorageLocation::SBSS; break;
case SymbolClass::RDATA: location = GlobalStorageLocation::RDATA; break;
case SymbolClass::COMMON: location = GlobalStorageLocation::COMMON; break;
case SymbolClass::SCOMMON: location = GlobalStorageLocation::SCOMMON; break;
case SymbolClass::SUNDEFINED: location = GlobalStorageLocation::SUNDEFINED; break;
default: {}
}
return location;
}
}

99
3rdparty/ccc/src/ccc/mdebug_analysis.h vendored Normal file
View File

@@ -0,0 +1,99 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "importer_flags.h"
#include "mdebug_section.h"
#include "mdebug_symbols.h"
#include "stabs.h"
#include "stabs_to_ast.h"
#include "symbol_database.h"
namespace ccc::mdebug {
struct AnalysisContext {
const mdebug::SymbolTableReader* reader = nullptr;
const std::map<u32, const mdebug::Symbol*>* external_functions = nullptr;
const std::map<std::string, const mdebug::Symbol*>* external_globals = nullptr;
SymbolGroup group;
u32 importer_flags = NO_IMPORTER_FLAGS;
DemanglerFunctions demangler;
};
class LocalSymbolTableAnalyser {
public:
LocalSymbolTableAnalyser(SymbolDatabase& database, const StabsToAstState& stabs_to_ast_state, const AnalysisContext& context, SourceFile& source_file)
: m_database(database)
, m_context(context)
, m_stabs_to_ast_state(stabs_to_ast_state)
, m_source_file(source_file) {}
// Functions for processing individual symbols.
//
// In most cases these symbols will appear in the following order:
// PROC TEXT
// ... line numbers ... ($LM<N>)
// END TEXT
// LABEL TEXT FUN
// ... parameters ...
// ... blocks ... (... local variables ... LBRAC ... subblocks ... RBRAC)
// NIL NIL FUN
//
// For some compiler versions the symbols can appear in this order:
// LABEL TEXT FUN
// ... parameters ...
// first line number ($LM1)
// PROC TEXT
// ... line numbers ... ($LM<N>)
// END TEXT
// ... blocks ... (... local variables ... LBRAC ... subblocks ... RBRAC)
Result<void> stab_magic(const char* magic);
Result<void> source_file(const char* path, Address text_address);
Result<void> data_type(const ParsedSymbol& symbol);
Result<void> global_variable(
const char* mangled_name, Address address, const StabsType& type, bool is_static, GlobalStorageLocation location);
Result<void> sub_source_file(const char* name, Address text_address);
Result<void> procedure(
const char* mangled_name, Address address, const ProcedureDescriptor* procedure_descriptor, bool is_static);
Result<void> label(const char* label, Address address, s32 line_number);
Result<void> text_end(const char* name, s32 function_size);
Result<void> function(const char* mangled_name, const StabsType& return_type, Address address);
Result<void> function_end();
Result<void> parameter(
const char* name, const StabsType& type, bool is_stack, s32 value, bool is_by_reference);
Result<void> local_variable(
const char* name, const StabsType& type, u32 value, StabsSymbolDescriptor desc, SymbolClass sclass);
Result<void> lbrac(s32 begin_offset);
Result<void> rbrac(s32 end_offset);
Result<void> finish();
Result<void> create_function(const char* mangled_name, Address address);
protected:
enum AnalysisState {
NOT_IN_FUNCTION,
IN_FUNCTION_BEGINNING,
IN_FUNCTION_END
};
SymbolDatabase& m_database;
const AnalysisContext& m_context;
const StabsToAstState& m_stabs_to_ast_state;
AnalysisState m_state = NOT_IN_FUNCTION;
SourceFile& m_source_file;
std::vector<FunctionHandle> m_functions;
std::vector<GlobalVariableHandle> m_global_variables;
Function* m_current_function = nullptr;
std::vector<ParameterVariableHandle> m_current_parameter_variables;
std::vector<LocalVariableHandle> m_current_local_variables;
std::vector<std::vector<LocalVariableHandle>> m_blocks;
std::vector<LocalVariableHandle> m_pending_local_variables;
std::string m_next_relative_path;
};
std::optional<GlobalStorageLocation> symbol_class_to_global_variable_location(SymbolClass symbol_class);
};

668
3rdparty/ccc/src/ccc/mdebug_importer.cpp vendored Normal file
View File

@@ -0,0 +1,668 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "mdebug_importer.h"
namespace ccc::mdebug {
static Result<void> resolve_type_names(
SymbolDatabase& database, const SymbolGroup& group, u32 importer_flags);
static Result<void> resolve_type_name(
ast::TypeName& type_name,
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags);
static void compute_size_bytes(ast::Node& node, SymbolDatabase& database);
static void detect_duplicate_functions(SymbolDatabase& database, const SymbolGroup& group);
static void detect_fake_functions(SymbolDatabase& database, const std::map<u32, const mdebug::Symbol*>& external_functions, const SymbolGroup& group);
static void destroy_optimized_out_functions(
SymbolDatabase& database, const SymbolGroup& group);
Result<void> import_symbol_table(
SymbolDatabase& database,
std::span<const u8> elf,
s32 section_offset,
const SymbolGroup& group,
u32 importer_flags,
const DemanglerFunctions& demangler,
const std::atomic_bool* interrupt)
{
SymbolTableReader reader;
Result<void> reader_result = reader.init(elf, section_offset);
CCC_RETURN_IF_ERROR(reader_result);
Result<std::vector<mdebug::Symbol>> external_symbols = reader.parse_external_symbols();
CCC_RETURN_IF_ERROR(external_symbols);
// The addresses of the global variables aren't present in the local symbol
// table, so here we extract them from the external table. In addition, for
// some games we need to cross reference the function symbols in the local
// symbol table with the entries in the external symbol table.
std::map<u32, const mdebug::Symbol*> external_functions;
std::map<std::string, const mdebug::Symbol*> external_globals;
for(const mdebug::Symbol& external : *external_symbols) {
if(external.symbol_type == mdebug::SymbolType::PROC) {
external_functions[external.value] = &external;
}
if(external.symbol_type == mdebug::SymbolType::GLOBAL
&& (external.symbol_class != mdebug::SymbolClass::UNDEFINED)) {
external_globals[external.string] = &external;
}
}
// Bundle together some unchanging state to pass to import_files.
AnalysisContext context;
context.reader = &reader;
context.external_functions = &external_functions;
context.external_globals = &external_globals;
context.group = group;
context.importer_flags = importer_flags;
context.demangler = demangler;
Result<void> result = import_files(database, context, interrupt);
CCC_RETURN_IF_ERROR(result);
return Result<void>();
}
Result<void> import_files(SymbolDatabase& database, const AnalysisContext& context, const std::atomic_bool* interrupt)
{
Result<s32> file_count = context.reader->file_count();
CCC_RETURN_IF_ERROR(file_count);
for(s32 i = 0; i < *file_count; i++) {
if(interrupt && *interrupt) {
return CCC_FAILURE("Operation interrupted by user.");
}
Result<mdebug::File> file = context.reader->parse_file(i);
CCC_RETURN_IF_ERROR(file);
Result<void> result = import_file(database, *file, context);
CCC_RETURN_IF_ERROR(result);
}
// The files field may be modified by further analysis passes, so we
// need to save this information here.
for(DataType& data_type : database.data_types) {
if(context.group.is_in_group(data_type) && data_type.files.size() == 1) {
data_type.only_defined_in_single_translation_unit = true;
}
}
// Lookup data types and store data type handles in type names.
Result<void> type_name_result = resolve_type_names(database, context.group, context.importer_flags);
CCC_RETURN_IF_ERROR(type_name_result);
// Compute the size in bytes of all the AST nodes.
database.for_each_symbol([&](ccc::Symbol& symbol) {
if(context.group.is_in_group(symbol) && symbol.type()) {
compute_size_bytes(*symbol.type(), database);
}
});
// Propagate the size information to the global variable symbols.
for(GlobalVariable& global_variable : database.global_variables) {
if(global_variable.type() && global_variable.type()->size_bytes > -1) {
global_variable.set_size((u32) global_variable.type()->size_bytes);
}
}
// Propagate the size information to the static local variable symbols.
for(LocalVariable& local_variable : database.local_variables) {
bool is_static_local = std::holds_alternative<GlobalStorage>(local_variable.storage);
if(is_static_local && local_variable.type() && local_variable.type()->size_bytes > -1) {
local_variable.set_size((u32) local_variable.type()->size_bytes);
}
}
// Some games (e.g. Jet X2O) have multiple function symbols across different
// translation units with the same name and address.
if(context.importer_flags & UNIQUE_FUNCTIONS) {
detect_duplicate_functions(database, context.group);
}
// If multiple functions appear at the same address, discard the addresses
// of all of them except the real one.
if(context.external_functions) {
detect_fake_functions(database, *context.external_functions, context.group);
}
// Remove functions with no address. If there are any such functions, this
// will invalidate all pointers to symbols.
if(context.importer_flags & NO_OPTIMIZED_OUT_FUNCTIONS) {
destroy_optimized_out_functions(database, context.group);
}
return Result<void>();
}
Result<void> import_file(SymbolDatabase& database, const mdebug::File& input, const AnalysisContext& context)
{
// Parse the stab strings into a data structure that's vaguely
// one-to-one with the text-based representation.
u32 importer_flags_for_this_file = context.importer_flags;
Result<std::vector<ParsedSymbol>> symbols = parse_symbols(input.symbols, importer_flags_for_this_file);
CCC_RETURN_IF_ERROR(symbols);
// In stabs, types can be referenced by their number from other stabs,
// so here we build a map of type numbers to the parsed types.
std::map<StabsTypeNumber, const StabsType*> stabs_types;
for(const ParsedSymbol& symbol : *symbols) {
if(symbol.type == ParsedSymbolType::NAME_COLON_TYPE) {
symbol.name_colon_type.type->enumerate_numbered_types(stabs_types);
}
}
Result<SourceFile*> source_file = database.source_files.create_symbol(
input.full_path, input.address, context.group.source, context.group.module_symbol);
CCC_RETURN_IF_ERROR(source_file);
(*source_file)->working_dir = input.working_dir;
(*source_file)->command_line_path = input.command_line_path;
// Sometimes the INFO symbols contain information about what toolchain
// version was used for building the executable.
for(const mdebug::Symbol& symbol : input.symbols) {
if(symbol.symbol_class == mdebug::SymbolClass::INFO && strcmp(symbol.string, "@stabs") != 0) {
(*source_file)->toolchain_version_info.emplace(symbol.string);
}
}
StabsToAstState stabs_to_ast_state;
stabs_to_ast_state.file_handle = (*source_file)->handle().value;
stabs_to_ast_state.stabs_types = &stabs_types;
stabs_to_ast_state.importer_flags = importer_flags_for_this_file;
stabs_to_ast_state.demangler = context.demangler;
// Convert the parsed stabs symbols to a more standard C AST.
LocalSymbolTableAnalyser analyser(database, stabs_to_ast_state, context, **source_file);
for(const ParsedSymbol& symbol : *symbols) {
if(symbol.duplicate) {
continue;
}
switch(symbol.type) {
case ParsedSymbolType::NAME_COLON_TYPE: {
switch(symbol.name_colon_type.descriptor) {
case StabsSymbolDescriptor::LOCAL_FUNCTION:
case StabsSymbolDescriptor::GLOBAL_FUNCTION: {
const char* name = symbol.name_colon_type.name.c_str();
const StabsType& type = *symbol.name_colon_type.type.get();
Result<void> result = analyser.function(name, type, symbol.raw->value);
CCC_RETURN_IF_ERROR(result);
break;
}
case StabsSymbolDescriptor::REFERENCE_PARAMETER_A:
case StabsSymbolDescriptor::REGISTER_PARAMETER:
case StabsSymbolDescriptor::VALUE_PARAMETER:
case StabsSymbolDescriptor::REFERENCE_PARAMETER_V: {
const char* name = symbol.name_colon_type.name.c_str();
const StabsType& type = *symbol.name_colon_type.type.get();
bool is_stack_variable = symbol.name_colon_type.descriptor == StabsSymbolDescriptor::VALUE_PARAMETER;
bool is_by_reference = symbol.name_colon_type.descriptor == StabsSymbolDescriptor::REFERENCE_PARAMETER_A
|| symbol.name_colon_type.descriptor == StabsSymbolDescriptor::REFERENCE_PARAMETER_V;
Result<void> result = analyser.parameter(name, type, is_stack_variable, symbol.raw->value, is_by_reference);
CCC_RETURN_IF_ERROR(result);
break;
}
case StabsSymbolDescriptor::REGISTER_VARIABLE:
case StabsSymbolDescriptor::LOCAL_VARIABLE:
case StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE: {
const char* name = symbol.name_colon_type.name.c_str();
const StabsType& type = *symbol.name_colon_type.type.get();
Result<void> result = analyser.local_variable(
name, type, symbol.raw->value, symbol.name_colon_type.descriptor, symbol.raw->symbol_class);
CCC_RETURN_IF_ERROR(result);
break;
}
case StabsSymbolDescriptor::GLOBAL_VARIABLE:
case StabsSymbolDescriptor::STATIC_GLOBAL_VARIABLE: {
const char* name = symbol.name_colon_type.name.c_str();
u32 address = -1;
std::optional<GlobalStorageLocation> location =
symbol_class_to_global_variable_location(symbol.raw->symbol_class);
if(symbol.name_colon_type.descriptor == StabsSymbolDescriptor::GLOBAL_VARIABLE) {
// The address for non-static global variables is
// only stored in the external symbol table (and
// the ELF symbol table), so we pull that
// information in here.
if(context.external_globals) {
auto global_symbol = context.external_globals->find(symbol.name_colon_type.name);
if(global_symbol != context.external_globals->end()) {
address = (u32) global_symbol->second->value;
location = symbol_class_to_global_variable_location(global_symbol->second->symbol_class);
}
}
} else {
// And for static global variables it's just stored
// in the local symbol table.
address = (u32) symbol.raw->value;
}
CCC_CHECK(location.has_value(), "Invalid global variable location.")
const StabsType& type = *symbol.name_colon_type.type.get();
bool is_static = symbol.name_colon_type.descriptor == StabsSymbolDescriptor::STATIC_GLOBAL_VARIABLE;
Result<void> result = analyser.global_variable(name, address, type, is_static, *location);
CCC_RETURN_IF_ERROR(result);
break;
}
case StabsSymbolDescriptor::TYPE_NAME:
case StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG: {
Result<void> result = analyser.data_type(symbol);
CCC_RETURN_IF_ERROR(result);
break;
}
}
break;
}
case ParsedSymbolType::SOURCE_FILE: {
Result<void> result = analyser.source_file(symbol.raw->string, symbol.raw->value);
CCC_RETURN_IF_ERROR(result);
break;
}
case ParsedSymbolType::SUB_SOURCE_FILE: {
Result<void> result = analyser.sub_source_file(symbol.raw->string, symbol.raw->value);
CCC_RETURN_IF_ERROR(result);
break;
}
case ParsedSymbolType::LBRAC: {
Result<void> result = analyser.lbrac(symbol.raw->value);
CCC_RETURN_IF_ERROR(result);
break;
}
case ParsedSymbolType::RBRAC: {
Result<void> result = analyser.rbrac(symbol.raw->value);
CCC_RETURN_IF_ERROR(result);
break;
}
case ParsedSymbolType::FUNCTION_END: {
Result<void> result = analyser.function_end();
CCC_RETURN_IF_ERROR(result);
break;
}
case ParsedSymbolType::NON_STABS: {
if(symbol.raw->symbol_class == mdebug::SymbolClass::TEXT) {
if(symbol.raw->symbol_type == mdebug::SymbolType::PROC) {
Result<void> result = analyser.procedure(symbol.raw->string, symbol.raw->value, symbol.raw->procedure_descriptor, false);
CCC_RETURN_IF_ERROR(result);
} else if(symbol.raw->symbol_type == mdebug::SymbolType::STATICPROC) {
Result<void> result = analyser.procedure(symbol.raw->string, symbol.raw->value, symbol.raw->procedure_descriptor, true);
CCC_RETURN_IF_ERROR(result);
} else if(symbol.raw->symbol_type == mdebug::SymbolType::LABEL) {
Result<void> result = analyser.label(symbol.raw->string, symbol.raw->value, symbol.raw->index);
CCC_RETURN_IF_ERROR(result);
} else if(symbol.raw->symbol_type == mdebug::SymbolType::END) {
Result<void> result = analyser.text_end(symbol.raw->string, symbol.raw->value);
CCC_RETURN_IF_ERROR(result);
}
}
break;
}
}
}
Result<void> result = analyser.finish();
CCC_RETURN_IF_ERROR(result);
return Result<void>();
}
static Result<void> resolve_type_names(
SymbolDatabase& database, const SymbolGroup& group, u32 importer_flags)
{
Result<void> result;
database.for_each_symbol([&](ccc::Symbol& symbol) {
if(group.is_in_group(symbol) && symbol.type()) {
ast::for_each_node(*symbol.type(), ast::PREORDER_TRAVERSAL, [&](ast::Node& node) {
if(node.descriptor == ast::TYPE_NAME) {
Result<void> type_name_result = resolve_type_name(node.as<ast::TypeName>(), database, group, importer_flags);
if(!type_name_result.success()) {
result = std::move(type_name_result);
}
}
return ast::EXPLORE_CHILDREN;
});
}
});
return result;
}
static Result<void> resolve_type_name(
ast::TypeName& type_name,
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags)
{
ast::TypeName::UnresolvedStabs* unresolved_stabs = type_name.unresolved_stabs.get();
if(!unresolved_stabs) {
return Result<void>();
}
// Lookup the type by its STABS type number. This path ensures that the
// correct type is found even if multiple types have the same name.
if(unresolved_stabs->referenced_file_handle != (u32) -1 && unresolved_stabs->stabs_type_number.valid()) {
const SourceFile* source_file = database.source_files.symbol_from_handle(unresolved_stabs->referenced_file_handle);
CCC_ASSERT(source_file);
auto handle = source_file->stabs_type_number_to_handle.find(unresolved_stabs->stabs_type_number);
if(handle != source_file->stabs_type_number_to_handle.end()) {
type_name.data_type_handle = handle->second.value;
type_name.is_forward_declared = false;
type_name.unresolved_stabs.reset();
return Result<void>();
}
}
// Looking up the type by its STABS type number failed, so look for it by
// its name instead. This happens when a type is forward declared but not
// defined in a given translation unit.
if(!unresolved_stabs->type_name.empty()) {
for(auto& name_handle : database.data_types.handles_from_name(unresolved_stabs->type_name)) {
DataType* data_type = database.data_types.symbol_from_handle(name_handle.second);
if(data_type && group.is_in_group(*data_type)) {
type_name.data_type_handle = name_handle.second.value;
type_name.is_forward_declared = true;
type_name.unresolved_stabs.reset();
return Result<void>();
}
}
}
// If this branch is taken it means the type name was probably from an
// automatically generated member function of a nested struct trying to
// reference the struct (for the this parameter). We shouldn't create a
// forward declared type in this case.
if(type_name.source == ast::TypeNameSource::UNNAMED_THIS) {
return Result<void>();
}
// Type lookup failed. This happens when a type is forward declared in a
// translation unit with symbols but is not defined in one. We haven't
// already created a forward declared type, so we create one now.
std::unique_ptr<ast::Node> forward_declared_node;
if(unresolved_stabs->type.has_value()) {
switch(*unresolved_stabs->type) {
case ast::ForwardDeclaredType::STRUCT: {
std::unique_ptr<ast::StructOrUnion> node = std::make_unique<ast::StructOrUnion>();
node->is_struct = true;
forward_declared_node = std::move(node);
break;
}
case ast::ForwardDeclaredType::UNION: {
std::unique_ptr<ast::StructOrUnion> node = std::make_unique<ast::StructOrUnion>();
node->is_struct = false;
forward_declared_node = std::move(node);
break;
}
case ast::ForwardDeclaredType::ENUM: {
std::unique_ptr<ast::Enum> node = std::make_unique<ast::Enum>();
forward_declared_node = std::move(node);
break;
}
}
}
if(forward_declared_node) {
Result<DataType*> forward_declared_type = database.data_types.create_symbol(
unresolved_stabs->type_name, group.source, group.module_symbol);
CCC_RETURN_IF_ERROR(forward_declared_type);
(*forward_declared_type)->set_type(std::move(forward_declared_node));
(*forward_declared_type)->not_defined_in_any_translation_unit = true;
type_name.data_type_handle = (*forward_declared_type)->handle().value;
type_name.is_forward_declared = true;
type_name.unresolved_stabs.reset();
return Result<void>();
}
const char* error_message = "Unresolved %s type name '%s' with STABS type number (%d,%d).";
if(importer_flags & STRICT_PARSING) {
return CCC_FAILURE(error_message,
ast::type_name_source_to_string(type_name.source),
type_name.unresolved_stabs->type_name.c_str(),
type_name.unresolved_stabs->stabs_type_number.file,
type_name.unresolved_stabs->stabs_type_number.type);
} else {
CCC_WARN(error_message,
ast::type_name_source_to_string(type_name.source),
type_name.unresolved_stabs->type_name.c_str(),
type_name.unresolved_stabs->stabs_type_number.file,
type_name.unresolved_stabs->stabs_type_number.type);
}
return Result<void>();
}
static void compute_size_bytes(ast::Node& node, SymbolDatabase& database)
{
for_each_node(node, ast::POSTORDER_TRAVERSAL, [&](ast::Node& node) {
// Skip nodes that have already been processed.
if(node.size_bytes > -1 || node.cannot_compute_size) {
return ast::EXPLORE_CHILDREN;
}
// Can't compute size recursively.
node.cannot_compute_size = true;
switch(node.descriptor) {
case ast::ARRAY: {
ast::Array& array = node.as<ast::Array>();
if(array.element_type->size_bytes > -1) {
array.size_bytes = array.element_type->size_bytes * array.element_count;
}
break;
}
case ast::BITFIELD: {
break;
}
case ast::BUILTIN: {
ast::BuiltIn& built_in = node.as<ast::BuiltIn>();
built_in.size_bytes = builtin_class_size(built_in.bclass);
break;
}
case ast::FUNCTION: {
break;
}
case ast::ENUM: {
node.size_bytes = 4;
break;
}
case ast::ERROR_NODE: {
break;
}
case ast::STRUCT_OR_UNION: {
node.size_bytes = node.size_bits / 8;
break;
}
case ast::POINTER_OR_REFERENCE: {
node.size_bytes = 4;
break;
}
case ast::POINTER_TO_DATA_MEMBER: {
break;
}
case ast::TYPE_NAME: {
ast::TypeName& type_name = node.as<ast::TypeName>();
DataType* resolved_type = database.data_types.symbol_from_handle(type_name.data_type_handle_unless_forward_declared());
if(resolved_type) {
ast::Node* resolved_node = resolved_type->type();
CCC_ASSERT(resolved_node);
if(resolved_node->size_bytes < 0 && !resolved_node->cannot_compute_size) {
compute_size_bytes(*resolved_node, database);
}
type_name.size_bytes = resolved_node->size_bytes;
}
break;
}
}
if(node.size_bytes > -1) {
node.cannot_compute_size = false;
}
return ast::EXPLORE_CHILDREN;
});
}
static void detect_duplicate_functions(SymbolDatabase& database, const SymbolGroup& group)
{
std::vector<FunctionHandle> duplicate_functions;
for(Function& test_function : database.functions) {
if(!test_function.address().valid() && !group.is_in_group(test_function)) {
continue;
}
// Find cases where there are two or more functions at the same address.
auto functions_with_same_address = database.functions.handles_from_starting_address(test_function.address());
if(functions_with_same_address.begin() == functions_with_same_address.end()) {
continue;
}
if(++functions_with_same_address.begin() == functions_with_same_address.end()) {
continue;
}
// Try to figure out the address of the translation unit which the
// version of the function that actually ended up in the linked binary
// comes from. We can't just check which source file the symbol comes
// from because it may be present in multiple.
u32 source_file_address = UINT32_MAX;
for(SourceFile& source_file : database.source_files) {
if(source_file.address() < test_function.address()) {
source_file_address = std::min(source_file.address().value, source_file_address);
}
}
if(source_file_address == UINT32_MAX) {
continue;
}
// Remove the addresses from all the matching symbols from other
// translation units.
FunctionHandle best_handle;
u32 best_offset = UINT32_MAX;
for(const auto& [address, handle] : functions_with_same_address) {
ccc::Function* function = database.functions.symbol_from_handle(handle);
if(!function || !group.is_in_group(*function) || function->mangled_name() != test_function.mangled_name()) {
continue;
}
if(address - source_file_address < best_offset) {
if(best_handle.valid()) {
duplicate_functions.emplace_back(best_handle);
}
best_handle = function->handle();
best_offset = address - source_file_address;
} else {
duplicate_functions.emplace_back(function->handle());
}
}
for(FunctionHandle duplicate_function : duplicate_functions) {
database.functions.move_symbol(duplicate_function, Address());
}
duplicate_functions.clear();
}
}
static void detect_fake_functions(SymbolDatabase& database, const std::map<u32, const mdebug::Symbol*>& external_functions, const SymbolGroup& group)
{
// Find cases where multiple fake function symbols were emitted for a given
// address and cross-reference with the external symbol table to try and
// find which one is the real one.
s32 fake_function_count = 0;
for(Function& function : database.functions) {
if(!function.address().valid() || !group.is_in_group(function)) {
continue;
}
// Find cases where there are two or more functions at the same address.
auto functions_with_same_address = database.functions.handles_from_starting_address(function.address());
if(functions_with_same_address.begin() == functions_with_same_address.end()) {
continue;
}
if(++functions_with_same_address.begin() == functions_with_same_address.end()) {
continue;
}
auto external_function = external_functions.find(function.address().value);
if(external_function == external_functions.end() || strcmp(function.mangled_name().c_str(), external_function->second->string) != 0) {
database.functions.move_symbol(function.handle(), Address());
if(fake_function_count < 10) {
CCC_WARN("Discarding address of function symbol '%s' as it is probably incorrect.", function.mangled_name().c_str());
} else if(fake_function_count == 10) {
CCC_WARN("Discarding more addresses of function symbols.");
}
fake_function_count++;
}
}
}
static void destroy_optimized_out_functions(
SymbolDatabase& database, const SymbolGroup& group)
{
bool marked = false;
for(Function& function : database.functions) {
if(group.is_in_group(function) && !function.address().valid()) {
function.mark_for_destruction();
marked = true;
}
}
if(marked) {
// This will invalidate all pointers to symbols in the database.
database.destroy_marked_symbols();
}
}
void fill_in_pointers_to_member_function_definitions(SymbolDatabase& database)
{
// Fill in pointers from member function declaration to corresponding definitions.
for(Function& function : database.functions) {
const std::string& qualified_name = function.name();
std::string::size_type name_separator_pos = qualified_name.find_last_of("::");
if(name_separator_pos == std::string::npos || name_separator_pos < 2) {
continue;
}
std::string function_name = qualified_name.substr(name_separator_pos + 1);
// This won't work for some template types.
std::string::size_type type_separator_pos = qualified_name.find_last_of("::", name_separator_pos - 2);
std::string type_name;
if(type_separator_pos != std::string::npos) {
type_name = qualified_name.substr(type_separator_pos + 1, name_separator_pos - type_separator_pos - 2);
} else {
type_name = qualified_name.substr(0, name_separator_pos - 1);
}
for(const auto& name_handle : database.data_types.handles_from_name(type_name)) {
DataType* data_type = database.data_types.symbol_from_handle(name_handle.second);
if(!data_type || !data_type->type() || data_type->type()->descriptor != ast::STRUCT_OR_UNION) {
continue;
}
ast::StructOrUnion& struct_or_union = data_type->type()->as<ast::StructOrUnion>();
for(std::unique_ptr<ast::Node>& declaration : struct_or_union.member_functions) {
if(declaration->name == function_name) {
declaration->as<ast::Function>().definition_handle = function.handle().value;
function.is_member_function_ish = true;
break;
}
}
if(function.is_member_function_ish) {
break;
}
}
}
}
}

31
3rdparty/ccc/src/ccc/mdebug_importer.h vendored Normal file
View File

@@ -0,0 +1,31 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include <atomic>
#include "mdebug_analysis.h"
#include "mdebug_section.h"
#include "symbol_database.h"
namespace ccc::mdebug {
// Perform all the main analysis passes on the mdebug symbol table and convert
// it to a set of C++ ASTs.
Result<void> import_symbol_table(
SymbolDatabase& database,
std::span<const u8> elf,
s32 section_offset,
const SymbolGroup& group,
u32 importer_flags,
const DemanglerFunctions& demangler,
const std::atomic_bool* interrupt);
Result<void> import_files(SymbolDatabase& database, const AnalysisContext& context, const std::atomic_bool* interrupt);
Result<void> import_file(SymbolDatabase& database, const mdebug::File& input, const AnalysisContext& context);
// Try to add pointers from member function declarations to their definitions
// using a heuristic.
void fill_in_pointers_to_member_function_definitions(SymbolDatabase& database);
}

474
3rdparty/ccc/src/ccc/mdebug_section.cpp vendored Normal file
View File

@@ -0,0 +1,474 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "mdebug_section.h"
namespace ccc::mdebug {
// MIPS debug symbol table headers.
// See include/coff/sym.h from GNU binutils for more information.
CCC_PACKED_STRUCT(SymbolicHeader,
/* 0x00 */ s16 magic;
/* 0x02 */ s16 version_stamp;
/* 0x04 */ s32 line_number_count;
/* 0x08 */ s32 line_numbers_size_bytes;
/* 0x0c */ s32 line_numbers_offset;
/* 0x10 */ s32 dense_numbers_count;
/* 0x14 */ s32 dense_numbers_offset;
/* 0x18 */ s32 procedure_descriptor_count;
/* 0x1c */ s32 procedure_descriptors_offset;
/* 0x20 */ s32 local_symbol_count;
/* 0x24 */ s32 local_symbols_offset;
/* 0x28 */ s32 optimization_symbols_count;
/* 0x2c */ s32 optimization_symbols_offset;
/* 0x30 */ s32 auxiliary_symbol_count;
/* 0x34 */ s32 auxiliary_symbols_offset;
/* 0x38 */ s32 local_strings_size_bytes;
/* 0x3c */ s32 local_strings_offset;
/* 0x40 */ s32 external_strings_size_bytes;
/* 0x44 */ s32 external_strings_offset;
/* 0x48 */ s32 file_descriptor_count;
/* 0x4c */ s32 file_descriptors_offset;
/* 0x50 */ s32 relative_file_descriptor_count;
/* 0x54 */ s32 relative_file_descriptors_offset;
/* 0x58 */ s32 external_symbols_count;
/* 0x5c */ s32 external_symbols_offset;
)
CCC_PACKED_STRUCT(FileDescriptor,
/* 0x00 */ u32 address;
/* 0x04 */ s32 file_path_string_offset;
/* 0x08 */ s32 strings_offset;
/* 0x0c */ s32 cb_ss;
/* 0x10 */ s32 isym_base;
/* 0x14 */ s32 symbol_count;
/* 0x18 */ s32 line_number_entry_index_base;
/* 0x1c */ s32 cline;
/* 0x20 */ s32 optimization_entry_index_base;
/* 0x24 */ s32 copt;
/* 0x28 */ u16 ipd_first;
/* 0x2a */ u16 procedure_descriptor_count;
/* 0x2c */ s32 iaux_base;
/* 0x30 */ s32 caux;
/* 0x34 */ s32 rfd_base;
/* 0x38 */ s32 crfd;
/* 0x3c */ u32 lang : 5;
/* 0x3c */ u32 f_merge : 1;
/* 0x3c */ u32 f_readin : 1;
/* 0x3c */ u32 f_big_endian : 1;
/* 0x3c */ u32 reserved_1 : 22;
/* 0x40 */ s32 line_number_offset;
/* 0x44 */ s32 cb_line;
)
static_assert(sizeof(FileDescriptor) == 0x48);
CCC_PACKED_STRUCT(SymbolHeader,
/* 0x0 */ u32 iss;
/* 0x4 */ u32 value;
/* 0x8 */ u32 st : 6;
/* 0x8 */ u32 sc : 5;
/* 0x8 */ u32 reserved : 1;
/* 0x8 */ u32 index : 20;
)
static_assert(sizeof(SymbolHeader) == 0xc);
CCC_PACKED_STRUCT(ExternalSymbolHeader,
/* 0x0 */ u16 flags;
/* 0x2 */ s16 ifd;
/* 0x4 */ SymbolHeader symbol;
)
static_assert(sizeof(ExternalSymbolHeader) == 0x10);
static void print_symbol(FILE* out, const Symbol& symbol);
static void print_procedure_descriptor(FILE* out, const ProcedureDescriptor& procedure_descriptor);
static Result<s32> get_corruption_fixing_fudge_offset(s32 section_offset, const SymbolicHeader& hdrr);
static Result<Symbol> get_symbol(const SymbolHeader& header, std::span<const u8> elf, s32 strings_offset);
Result<void> SymbolTableReader::init(std::span<const u8> elf, s32 section_offset)
{
m_elf = elf;
m_section_offset = section_offset;
m_hdrr = get_packed<SymbolicHeader>(m_elf, m_section_offset);
CCC_CHECK(m_hdrr != nullptr, "MIPS debug section header out of bounds.");
CCC_CHECK(m_hdrr->magic == 0x7009, "Invalid symbolic header.");
Result<s32> fudge_offset = get_corruption_fixing_fudge_offset(m_section_offset, *m_hdrr);
CCC_RETURN_IF_ERROR(fudge_offset);
m_fudge_offset = *fudge_offset;
m_ready = true;
return Result<void>();
}
s32 SymbolTableReader::file_count() const
{
CCC_ASSERT(m_ready);
return m_hdrr->file_descriptor_count;
}
Result<File> SymbolTableReader::parse_file(s32 index) const
{
CCC_ASSERT(m_ready);
File file;
u64 fd_offset = m_hdrr->file_descriptors_offset + index * sizeof(FileDescriptor);
const FileDescriptor* fd_header = get_packed<FileDescriptor>(m_elf, fd_offset + m_fudge_offset);
CCC_CHECK(fd_header != nullptr, "MIPS debug file descriptor out of bounds.");
CCC_CHECK(fd_header->f_big_endian == 0, "Not little endian or bad file descriptor table.");
file.address = fd_header->address;
s32 rel_raw_path_offset = fd_header->strings_offset + fd_header->file_path_string_offset;
s32 raw_path_offset = m_hdrr->local_strings_offset + rel_raw_path_offset + m_fudge_offset;
const char* command_line_path = get_string(m_elf, raw_path_offset);
if(command_line_path) {
file.command_line_path = command_line_path;
}
// Parse local symbols.
for(s64 j = 0; j < fd_header->symbol_count; j++) {
u64 rel_symbol_offset = (fd_header->isym_base + j) * sizeof(SymbolHeader);
u64 symbol_offset = m_hdrr->local_symbols_offset + rel_symbol_offset + m_fudge_offset;
const SymbolHeader* symbol_header = get_packed<SymbolHeader>(m_elf, symbol_offset);
CCC_CHECK(symbol_header != nullptr, "Symbol header out of bounds.");
s32 strings_offset = m_hdrr->local_strings_offset + fd_header->strings_offset + m_fudge_offset;
Result<Symbol> sym = get_symbol(*symbol_header, m_elf, strings_offset);
CCC_RETURN_IF_ERROR(sym);
bool string_offset_equal = (s32) symbol_header->iss == fd_header->file_path_string_offset;
if(file.working_dir.empty() && string_offset_equal && sym->is_stabs() && sym->code() == N_SO && file.symbols.size() > 2) {
const Symbol& working_dir = file.symbols.back();
if(working_dir.is_stabs() && working_dir.code() == N_SO) {
file.working_dir = working_dir.string;
}
}
file.symbols.emplace_back(std::move(*sym));
}
// Parse procedure descriptors.
for(s64 i = 0; i < fd_header->procedure_descriptor_count; i++) {
u64 rel_procedure_offset = (fd_header->ipd_first + i) * sizeof(ProcedureDescriptor);
u64 procedure_offset = m_hdrr->procedure_descriptors_offset + rel_procedure_offset + m_fudge_offset;
const ProcedureDescriptor* procedure_descriptor = get_packed<ProcedureDescriptor>(m_elf, procedure_offset);
CCC_CHECK(procedure_descriptor != nullptr, "Procedure descriptor out of bounds.");
CCC_CHECK(procedure_descriptor->symbol_index < file.symbols.size(), "Symbol index out of bounds.");
file.symbols[procedure_descriptor->symbol_index].procedure_descriptor = procedure_descriptor;
}
file.full_path = merge_paths(file.working_dir, file.command_line_path);
return file;
}
Result<std::vector<Symbol>> SymbolTableReader::parse_external_symbols() const
{
CCC_ASSERT(m_ready);
std::vector<Symbol> external_symbols;
for(s64 i = 0; i < m_hdrr->external_symbols_count; i++) {
u64 sym_offset = m_hdrr->external_symbols_offset + i * sizeof(ExternalSymbolHeader);
const ExternalSymbolHeader* external_header = get_packed<ExternalSymbolHeader>(m_elf, sym_offset + m_fudge_offset);
CCC_CHECK(external_header != nullptr, "External header out of bounds.");
Result<Symbol> sym = get_symbol(external_header->symbol, m_elf, m_hdrr->external_strings_offset + m_fudge_offset);
CCC_RETURN_IF_ERROR(sym);
external_symbols.emplace_back(std::move(*sym));
}
return external_symbols;
}
void SymbolTableReader::print_header(FILE* dest) const
{
CCC_ASSERT(m_ready);
fprintf(dest, "Symbolic Header, magic = %hx, vstamp = %hx:\n",
(u16) m_hdrr->magic,
(u16) m_hdrr->version_stamp);
fprintf(dest, "\n");
fprintf(dest, " Offset Size (Bytes) Count\n");
fprintf(dest, " ------ ------------ -----\n");
fprintf(dest, " Line Numbers 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->line_numbers_offset,
(u32) m_hdrr->line_numbers_size_bytes,
m_hdrr->line_number_count);
fprintf(dest, " Dense Numbers 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->dense_numbers_offset,
(u32) m_hdrr->dense_numbers_count * 8,
m_hdrr->dense_numbers_count);
fprintf(dest, " Procedure Descriptors 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->procedure_descriptors_offset,
(u32) m_hdrr->procedure_descriptor_count * (u32) sizeof(ProcedureDescriptor),
m_hdrr->procedure_descriptor_count);
fprintf(dest, " Local Symbols 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->local_symbols_offset,
(u32) m_hdrr->local_symbol_count * (u32) sizeof(SymbolHeader),
m_hdrr->local_symbol_count);
fprintf(dest, " Optimization Symbols 0x%-8x " "- " "%-8d\n",
(u32) m_hdrr->optimization_symbols_offset,
m_hdrr->optimization_symbols_count);
fprintf(dest, " Auxiliary Symbols 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->auxiliary_symbols_offset,
(u32) m_hdrr->auxiliary_symbol_count * 4,
m_hdrr->auxiliary_symbol_count);
fprintf(dest, " Local Strings 0x%-8x " "0x%-8x " "-\n",
(u32) m_hdrr->local_strings_offset,
(u32) m_hdrr->local_strings_size_bytes);
fprintf(dest, " External Strings 0x%-8x " "0x%-8x " "-\n",
(u32) m_hdrr->external_strings_offset,
(u32) m_hdrr->external_strings_size_bytes);
fprintf(dest, " File Descriptors 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->file_descriptors_offset,
(u32) m_hdrr->file_descriptor_count * (u32) sizeof(FileDescriptor),
m_hdrr->file_descriptor_count);
fprintf(dest, " Relative File Descriptors 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->relative_file_descriptors_offset,
(u32) m_hdrr->relative_file_descriptor_count * 4,
m_hdrr->relative_file_descriptor_count);
fprintf(dest, " External Symbols 0x%-8x " "0x%-8x " "%-8d\n",
(u32) m_hdrr->external_symbols_offset,
(u32) m_hdrr->external_symbols_count * 16,
m_hdrr->external_symbols_count);
}
Result<void> SymbolTableReader::print_symbols(FILE* out, bool print_locals, bool print_procedure_descriptors, bool print_externals) const
{
if(print_locals || print_procedure_descriptors) {
s32 count = file_count();
for(s32 i = 0; i < count; i++) {
Result<File> file = parse_file(i);
CCC_RETURN_IF_ERROR(file);
fprintf(out, "FILE %s:\n", file->command_line_path.c_str());
for(const Symbol& symbol : file->symbols) {
if(print_locals || symbol.procedure_descriptor) {
print_symbol(out, symbol);
}
if(print_procedure_descriptors && symbol.procedure_descriptor) {
print_procedure_descriptor(out, *symbol.procedure_descriptor);
}
}
}
}
if(print_externals) {
fprintf(out, "EXTERNAL SYMBOLS:\n");
Result<std::vector<Symbol>> external_symbols = parse_external_symbols();
CCC_RETURN_IF_ERROR(external_symbols);
for(const Symbol& symbol : *external_symbols) {
print_symbol(out, symbol);
}
}
return Result<void>();
}
static void print_symbol(FILE* out, const Symbol& symbol)
{
fprintf(out, " %8x ", symbol.value);
const char* symbol_type_str = symbol_type(symbol.symbol_type);
if(symbol_type_str) {
fprintf(out, "%-11s ", symbol_type_str);
} else {
fprintf(out, "ST(%7u) ", (u32) symbol.symbol_type);
}
const char* symbol_class_str = symbol_class(symbol.symbol_class);
if(symbol_class_str) {
fprintf(out, "%-4s ", symbol_class_str);
} else if ((u32) symbol.symbol_class == 0) {
fprintf(out, " ");
} else {
fprintf(out, "SC(%4u) ", (u32) symbol.symbol_class);
}
if(symbol.is_stabs()) {
fprintf(out, "%-8s ", stabs_code_to_string(symbol.code()));
} else {
fprintf(out, "SI(%4u) ", symbol.index);
}
fprintf(out, "%s\n", symbol.string);
}
static void print_procedure_descriptor(FILE* out, const ProcedureDescriptor& procedure_descriptor)
{
fprintf(out, " Address 0x%08x\n", procedure_descriptor.address);
fprintf(out, " Symbol Index %d\n", procedure_descriptor.symbol_index);
fprintf(out, " Line Number Entry Index %d\n", procedure_descriptor.line_number_entry_index);
fprintf(out, " Saved Register Mask 0x%08x\n", procedure_descriptor.saved_register_mask);
fprintf(out, " Saved Register Offset %d\n", procedure_descriptor.saved_register_offset);
fprintf(out, " Optimization Entry Index %d\n", procedure_descriptor.optimization_entry_index);
fprintf(out, " Saved Float Register Mask 0x%08x\n", procedure_descriptor.saved_float_register_mask);
fprintf(out, " Saved Float Register Offset %d\n", procedure_descriptor.saved_float_register_offset);
fprintf(out, " Frame Size %d\n", procedure_descriptor.frame_size);
fprintf(out, " Frame Pointer Register %hd\n", procedure_descriptor.frame_pointer_register);
fprintf(out, " Return PC Register %hd\n", procedure_descriptor.return_pc_register);
fprintf(out, " Line Number Low %d\n", procedure_descriptor.line_number_low);
fprintf(out, " Line Number High %d\n", procedure_descriptor.line_number_high);
fprintf(out, " Line Number Offset %d\n", procedure_descriptor.line_number_offset);
}
static Result<s32> get_corruption_fixing_fudge_offset(s32 section_offset, const SymbolicHeader& hdrr)
{
// GCC will always put the first part of the symbol table right after the
// header, so if the header says it's somewhere else we know the section has
// probably been moved without updating its contents.
s32 right_after_header = INT32_MAX;
if(hdrr.line_numbers_offset > 0) right_after_header = std::min(hdrr.line_numbers_offset, right_after_header);
if(hdrr.dense_numbers_offset > 0) right_after_header = std::min(hdrr.dense_numbers_offset, right_after_header);
if(hdrr.procedure_descriptors_offset > 0) right_after_header = std::min(hdrr.procedure_descriptors_offset, right_after_header);
if(hdrr.local_symbols_offset > 0) right_after_header = std::min(hdrr.local_symbols_offset, right_after_header);
if(hdrr.optimization_symbols_offset > 0) right_after_header = std::min(hdrr.optimization_symbols_offset, right_after_header);
if(hdrr.auxiliary_symbols_offset > 0) right_after_header = std::min(hdrr.auxiliary_symbols_offset, right_after_header);
if(hdrr.local_strings_offset > 0) right_after_header = std::min(hdrr.local_strings_offset, right_after_header);
if(hdrr.external_strings_offset > 0) right_after_header = std::min(hdrr.external_strings_offset, right_after_header);
if(hdrr.file_descriptors_offset > 0) right_after_header = std::min(hdrr.file_descriptors_offset, right_after_header);
if(hdrr.relative_file_descriptors_offset > 0) right_after_header = std::min(hdrr.relative_file_descriptors_offset, right_after_header);
if(hdrr.external_symbols_offset > 0) right_after_header = std::min(hdrr.external_symbols_offset, right_after_header);
CCC_CHECK(right_after_header >= 0 && right_after_header < INT32_MAX, "Invalid symbolic header.");
// Figure out how much we need to adjust all the file offsets by.
s32 fudge_offset = section_offset - (right_after_header - sizeof(SymbolicHeader));
if(fudge_offset != 0) {
CCC_WARN("The .mdebug section was moved without updating its contents. Adjusting file offsets by %d bytes.", fudge_offset);
}
return fudge_offset;
}
static Result<Symbol> get_symbol(const SymbolHeader& header, std::span<const u8> elf, s32 strings_offset)
{
Symbol symbol;
const char* string = get_string(elf, strings_offset + header.iss);
CCC_CHECK(string, "Symbol has invalid string.");
symbol.string = string;
symbol.value = header.value;
symbol.symbol_type = (SymbolType) header.st;
symbol.symbol_class = (SymbolClass) header.sc;
symbol.index = header.index;
if(symbol.is_stabs()) {
CCC_CHECK(stabs_code_to_string(symbol.code()) != nullptr, "Bad stabs symbol code '%x'.", symbol.code());
}
return symbol;
}
const char* symbol_type(SymbolType type)
{
switch(type) {
case SymbolType::NIL: return "NIL";
case SymbolType::GLOBAL: return "GLOBAL";
case SymbolType::STATIC: return "STATIC";
case SymbolType::PARAM: return "PARAM";
case SymbolType::LOCAL: return "LOCAL";
case SymbolType::LABEL: return "LABEL";
case SymbolType::PROC: return "PROC";
case SymbolType::BLOCK: return "BLOCK";
case SymbolType::END: return "END";
case SymbolType::MEMBER: return "MEMBER";
case SymbolType::TYPEDEF: return "TYPEDEF";
case SymbolType::FILE_SYMBOL: return "FILE";
case SymbolType::STATICPROC: return "STATICPROC";
case SymbolType::CONSTANT: return "CONSTANT";
}
return nullptr;
}
const char* symbol_class(SymbolClass symbol_class)
{
switch(symbol_class) {
case SymbolClass::NIL: return "NIL";
case SymbolClass::TEXT: return "TEXT";
case SymbolClass::DATA: return "DATA";
case SymbolClass::BSS: return "BSS";
case SymbolClass::REGISTER: return "REGISTER";
case SymbolClass::ABS: return "ABS";
case SymbolClass::UNDEFINED: return "UNDEFINED";
case SymbolClass::LOCAL: return "LOCAL";
case SymbolClass::BITS: return "BITS";
case SymbolClass::DBX: return "DBX";
case SymbolClass::REG_IMAGE: return "REG_IMAGE";
case SymbolClass::INFO: return "INFO";
case SymbolClass::USER_STRUCT: return "USER_STRUCT";
case SymbolClass::SDATA: return "SDATA";
case SymbolClass::SBSS: return "SBSS";
case SymbolClass::RDATA: return "RDATA";
case SymbolClass::VAR: return "VAR";
case SymbolClass::COMMON: return "COMMON";
case SymbolClass::SCOMMON: return "SCOMMON";
case SymbolClass::VAR_REGISTER: return "VAR_REGISTER";
case SymbolClass::VARIANT: return "VARIANT";
case SymbolClass::SUNDEFINED: return "SUNDEFINED";
case SymbolClass::INIT: return "INIT";
case SymbolClass::BASED_VAR: return "BASED_VAR";
case SymbolClass::XDATA: return "XDATA";
case SymbolClass::PDATA: return "PDATA";
case SymbolClass::FINI: return "FINI";
case SymbolClass::NONGP: return "NONGP";
}
return nullptr;
}
const char* stabs_code_to_string(StabsCode code)
{
switch(code) {
case STAB: return "STAB";
case N_GSYM: return "GSYM";
case N_FNAME: return "FNAME";
case N_FUN: return "FUN";
case N_STSYM: return "STSYM";
case N_LCSYM: return "LCSYM";
case N_MAIN: return "MAIN";
case N_PC: return "PC";
case N_NSYMS: return "NSYMS";
case N_NOMAP: return "NOMAP";
case N_OBJ: return "OBJ";
case N_OPT: return "OPT";
case N_RSYM: return "RSYM";
case N_M2C: return "M2C";
case N_SLINE: return "SLINE";
case N_DSLINE: return "DSLINE";
case N_BSLINE: return "BSLINE";
case N_EFD: return "EFD";
case N_EHDECL: return "EHDECL";
case N_CATCH: return "CATCH";
case N_SSYM: return "SSYM";
case N_SO: return "SO";
case N_LSYM: return "LSYM";
case N_BINCL: return "BINCL";
case N_SOL: return "SOL";
case N_PSYM: return "PSYM";
case N_EINCL: return "EINCL";
case N_ENTRY: return "ENTRY";
case N_LBRAC: return "LBRAC";
case N_EXCL: return "EXCL";
case N_SCOPE: return "SCOPE";
case N_RBRAC: return "RBRAC";
case N_BCOMM: return "BCOMM";
case N_ECOMM: return "ECOMM";
case N_ECOML: return "ECOML";
case N_NBTEXT: return "NBTEXT";
case N_NBDATA: return "NBDATA";
case N_NBBSS: return "NBBSS";
case N_NBSTS: return "NBSTS";
case N_NBLCS: return "NBLCS";
case N_LENG: return "LENG";
}
return nullptr;
}
}

176
3rdparty/ccc/src/ccc/mdebug_section.h vendored Normal file
View File

@@ -0,0 +1,176 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "util.h"
namespace ccc::mdebug {
struct SymbolicHeader;
enum class SymbolType : u32 {
NIL = 0,
GLOBAL = 1,
STATIC = 2,
PARAM = 3,
LOCAL = 4,
LABEL = 5,
PROC = 6,
BLOCK = 7,
END = 8,
MEMBER = 9,
TYPEDEF = 10,
FILE_SYMBOL = 11,
STATICPROC = 14,
CONSTANT = 15
};
enum class SymbolClass : u32 {
NIL = 0,
TEXT = 1,
DATA = 2,
BSS = 3,
REGISTER = 4,
ABS = 5,
UNDEFINED = 6,
LOCAL = 7,
BITS = 8,
DBX = 9,
REG_IMAGE = 10,
INFO = 11,
USER_STRUCT = 12,
SDATA = 13,
SBSS = 14,
RDATA = 15,
VAR = 16,
COMMON = 17,
SCOMMON = 18,
VAR_REGISTER = 19,
VARIANT = 20,
SUNDEFINED = 21,
INIT = 22,
BASED_VAR = 23,
XDATA = 24,
PDATA = 25,
FINI = 26,
NONGP = 27
};
// See stab.def from gcc for documentation on what all these are.
enum StabsCode {
STAB = 0x00,
N_GSYM = 0x20,
N_FNAME = 0x22,
N_FUN = 0x24,
N_STSYM = 0x26,
N_LCSYM = 0x28,
N_MAIN = 0x2a,
N_PC = 0x30,
N_NSYMS = 0x32,
N_NOMAP = 0x34,
N_OBJ = 0x38,
N_OPT = 0x3c,
N_RSYM = 0x40,
N_M2C = 0x42,
N_SLINE = 0x44,
N_DSLINE = 0x46,
N_BSLINE = 0x48,
N_EFD = 0x4a,
N_EHDECL = 0x50,
N_CATCH = 0x54,
N_SSYM = 0x60,
N_SO = 0x64,
N_LSYM = 0x80,
N_BINCL = 0x82,
N_SOL = 0x84,
N_PSYM = 0xa0,
N_EINCL = 0xa2,
N_ENTRY = 0xa4,
N_LBRAC = 0xc0,
N_EXCL = 0xc2,
N_SCOPE = 0xc4,
N_RBRAC = 0xe0,
N_BCOMM = 0xe2,
N_ECOMM = 0xe4,
N_ECOML = 0xe8,
N_NBTEXT = 0xf0,
N_NBDATA = 0xf2,
N_NBBSS = 0xf4,
N_NBSTS = 0xf6,
N_NBLCS = 0xf8,
N_LENG = 0xfe
};
CCC_PACKED_STRUCT(ProcedureDescriptor,
/* 0x00 */ u32 address;
/* 0x04 */ u32 symbol_index;
/* 0x08 */ s32 line_number_entry_index;
/* 0x0c */ s32 saved_register_mask;
/* 0x10 */ s32 saved_register_offset;
/* 0x14 */ s32 optimization_entry_index;
/* 0x18 */ s32 saved_float_register_mask;
/* 0x1c */ s32 saved_float_register_offset;
/* 0x20 */ s32 frame_size;
/* 0x24 */ s16 frame_pointer_register;
/* 0x26 */ s16 return_pc_register;
/* 0x28 */ s32 line_number_low;
/* 0x2c */ s32 line_number_high;
/* 0x30 */ u32 line_number_offset;
)
static_assert(sizeof(ProcedureDescriptor) == 0x34);
struct Symbol {
u32 value;
SymbolType symbol_type;
SymbolClass symbol_class;
u32 index;
const char* string;
const ProcedureDescriptor* procedure_descriptor = nullptr;
bool is_stabs() const {
return (index & 0xfff00) == 0x8f300;
}
StabsCode code() const {
return (StabsCode) (index - 0x8f300);
}
};
struct File {
std::vector<Symbol> symbols;
u32 address = 0;
std::string working_dir; // The working directory of gcc.
std::string command_line_path; // The source file path passed on the command line to gcc.
std::string full_path; // The full combined path.
};
class SymbolTableReader {
public:
Result<void> init(std::span<const u8> elf, s32 section_offset);
s32 file_count() const;
Result<File> parse_file(s32 index) const;
Result<std::vector<Symbol>> parse_external_symbols() const;
void print_header(FILE* out) const;
Result<void> print_symbols(FILE* out, bool print_locals, bool print_procedure_descriptors, bool print_externals) const;
protected:
bool m_ready = false;
std::span<const u8> m_elf;
s32 m_section_offset;
// If the .mdebug section was moved without updating its contents all the
// absolute file offsets stored within will be incorrect by a fixed amount.
s32 m_fudge_offset;
const SymbolicHeader* m_hdrr;
};
const char* symbol_type(SymbolType type);
const char* symbol_class(SymbolClass symbol_class);
const char* stabs_code_to_string(StabsCode code);
}

220
3rdparty/ccc/src/ccc/mdebug_symbols.cpp vendored Normal file
View File

@@ -0,0 +1,220 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "mdebug_symbols.h"
#include "importer_flags.h"
namespace ccc::mdebug {
static void mark_duplicate_symbols(std::vector<ParsedSymbol>& symbols);
Result<std::vector<ParsedSymbol>> parse_symbols(const std::vector<mdebug::Symbol>& input, u32& importer_flags)
{
std::vector<ParsedSymbol> output;
std::string prefix;
for(const mdebug::Symbol& symbol : input) {
if(symbol.is_stabs()) {
switch(symbol.code()) {
case mdebug::N_GSYM: // Global variable
case mdebug::N_FUN: // Function
case mdebug::N_STSYM: // Data section static global variable
case mdebug::N_LCSYM: // BSS section static global variable
case mdebug::N_RSYM: // Register variable
case mdebug::N_LSYM: // Automatic variable or type definition
case mdebug::N_PSYM: { // Parameter variable
// Some STABS symbols are split between multiple strings.
if(symbol.string[0] != '\0') {
if(symbol.string[strlen(symbol.string) - 1] == '\\') {
prefix += std::string(symbol.string, symbol.string + strlen(symbol.string) - 1);
} else {
std::string merged_string;
const char* string;
if(!prefix.empty()) {
merged_string = prefix + symbol.string;
string = merged_string.c_str();
prefix.clear();
} else {
string = symbol.string;
}
const char* input = string;
Result<StabsSymbol> parse_result = parse_stabs_symbol(input);
if(parse_result.success()) {
if(*input != '\0') {
if(importer_flags & STRICT_PARSING) {
return CCC_FAILURE("Unknown data '%s' at the end of the '%s' stab.", input, parse_result->name.c_str());
} else {
CCC_WARN("Unknown data '%s' at the end of the '%s' stab.", input, parse_result->name.c_str());
}
}
ParsedSymbol& parsed = output.emplace_back();
parsed.type = ParsedSymbolType::NAME_COLON_TYPE;
parsed.raw = &symbol;
parsed.name_colon_type = std::move(*parse_result);
} else if(parse_result.error().message == STAB_TRUNCATED_ERROR_MESSAGE) {
// Symbol truncated due to a GCC bug. Report a
// warning and try to tolerate further faults
// caused as a result of this.
CCC_WARN("%s Symbol string: %s", STAB_TRUNCATED_ERROR_MESSAGE, string);
importer_flags &= ~STRICT_PARSING;
} else {
return CCC_FAILURE("%s Symbol string: %s",
parse_result.error().message.c_str(), string);
}
}
} else {
CCC_CHECK(prefix.empty(), "Invalid STABS continuation.");
if(symbol.code() == mdebug::N_FUN) {
ParsedSymbol& func_end = output.emplace_back();
func_end.type = ParsedSymbolType::FUNCTION_END;
func_end.raw = &symbol;
}
}
break;
}
case mdebug::N_SOL: { // Sub-source file
ParsedSymbol& sub = output.emplace_back();
sub.type = ParsedSymbolType::SUB_SOURCE_FILE;
sub.raw = &symbol;
break;
}
case mdebug::N_LBRAC: { // Begin block
ParsedSymbol& begin_block = output.emplace_back();
begin_block.type = ParsedSymbolType::LBRAC;
begin_block.raw = &symbol;
break;
}
case mdebug::N_RBRAC: { // End block
ParsedSymbol& end_block = output.emplace_back();
end_block.type = ParsedSymbolType::RBRAC;
end_block.raw = &symbol;
break;
}
case mdebug::N_SO: { // Source filename
ParsedSymbol& so_symbol = output.emplace_back();
so_symbol.type = ParsedSymbolType::SOURCE_FILE;
so_symbol.raw = &symbol;
break;
}
case mdebug::STAB:
case mdebug::N_OPT:
case mdebug::N_BINCL:
case mdebug::N_EINCL: {
break;
}
case mdebug::N_FNAME:
case mdebug::N_MAIN:
case mdebug::N_PC:
case mdebug::N_NSYMS:
case mdebug::N_NOMAP:
case mdebug::N_OBJ:
case mdebug::N_M2C:
case mdebug::N_SLINE:
case mdebug::N_DSLINE:
case mdebug::N_BSLINE:
case mdebug::N_EFD:
case mdebug::N_EHDECL:
case mdebug::N_CATCH:
case mdebug::N_SSYM:
case mdebug::N_ENTRY:
case mdebug::N_EXCL:
case mdebug::N_SCOPE:
case mdebug::N_BCOMM:
case mdebug::N_ECOMM:
case mdebug::N_ECOML:
case mdebug::N_NBTEXT:
case mdebug::N_NBDATA:
case mdebug::N_NBBSS:
case mdebug::N_NBSTS:
case mdebug::N_NBLCS:
case mdebug::N_LENG: {
CCC_WARN("Unhandled N_%s symbol: %s", mdebug::stabs_code_to_string(symbol.code()), symbol.string);
break;
}
}
} else {
ParsedSymbol& non_stabs_symbol = output.emplace_back();
non_stabs_symbol.type = ParsedSymbolType::NON_STABS;
non_stabs_symbol.raw = &symbol;
}
}
mark_duplicate_symbols(output);
return output;
}
static void mark_duplicate_symbols(std::vector<ParsedSymbol>& symbols)
{
std::map<StabsTypeNumber, size_t> stabs_type_number_to_symbol;
for(size_t i = 0; i < symbols.size(); i++) {
ParsedSymbol& symbol = symbols[i];
if(symbol.type == ParsedSymbolType::NAME_COLON_TYPE) {
StabsType& type = *symbol.name_colon_type.type;
if(type.type_number.valid() && type.descriptor.has_value()) {
stabs_type_number_to_symbol.emplace(type.type_number, i);
}
}
}
for(ParsedSymbol& symbol : symbols) {
symbol.is_typedef =
symbol.type == ParsedSymbolType::NAME_COLON_TYPE &&
symbol.name_colon_type.descriptor == StabsSymbolDescriptor::TYPE_NAME &&
symbol.name_colon_type.type->descriptor != StabsTypeDescriptor::ENUM;
}
for(size_t i = 0; i < symbols.size(); i++) {
ParsedSymbol& symbol = symbols[i];
if(symbol.type != ParsedSymbolType::NAME_COLON_TYPE) {
continue;
}
bool is_type =
symbol.name_colon_type.descriptor == StabsSymbolDescriptor::TYPE_NAME ||
symbol.name_colon_type.descriptor == StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG;
if(!is_type) {
continue;
}
StabsType& type = *symbol.name_colon_type.type;
if(!type.descriptor.has_value()) {
auto referenced_index = stabs_type_number_to_symbol.find(type.type_number);
if(referenced_index != stabs_type_number_to_symbol.end()) {
ParsedSymbol& referenced = symbols[referenced_index->second];
if(referenced.name_colon_type.name == symbol.name_colon_type.name) {
// symbol: "Struct:T(1,1)=s1;"
// referenced: "Struct:t(1,1)"
symbol.duplicate = true;
}
}
}
if(type.descriptor.has_value() && type.descriptor == StabsTypeDescriptor::TYPE_REFERENCE) {
auto referenced_index = stabs_type_number_to_symbol.find(type.as<StabsTypeReferenceType>().type->type_number);
if(referenced_index != stabs_type_number_to_symbol.end() && referenced_index->second != i) {
ParsedSymbol& referenced = symbols[referenced_index->second];
if(referenced.name_colon_type.name == " ") {
// referenced: " :T(1,1)=e;"
// symbol: "ErraticEnum:t(1,2)=(1,1)"
referenced.name_colon_type.name = symbol.name_colon_type.name;
referenced.is_typedef = true;
symbol.duplicate = true;
}
if(referenced.name_colon_type.name == symbol.name_colon_type.name) {
// referenced: "NamedTypedefedStruct:T(1,1)=s1;"
// symbol: "NamedTypedefedStruct:t(1,2)=(1,1)"
referenced.is_typedef = true;
symbol.duplicate = true;
}
}
}
}
}
}

32
3rdparty/ccc/src/ccc/mdebug_symbols.h vendored Normal file
View File

@@ -0,0 +1,32 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "util.h"
#include "stabs.h"
#include "mdebug_section.h"
namespace ccc::mdebug {
enum class ParsedSymbolType {
NAME_COLON_TYPE,
SOURCE_FILE,
SUB_SOURCE_FILE,
LBRAC,
RBRAC,
FUNCTION_END,
NON_STABS
};
struct ParsedSymbol {
ParsedSymbolType type;
const mdebug::Symbol* raw;
StabsSymbol name_colon_type;
bool duplicate = false;
bool is_typedef = false;
};
Result<std::vector<ParsedSymbol>> parse_symbols(const std::vector<mdebug::Symbol>& input, u32& importer_flags);
}

191
3rdparty/ccc/src/ccc/sndll.cpp vendored Normal file
View File

@@ -0,0 +1,191 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "sndll.h"
#include "importer_flags.h"
namespace ccc {
CCC_PACKED_STRUCT(SNDLLHeaderCommon,
/* 0x00 */ u32 magic;
/* 0x04 */ u32 relocations;
/* 0x08 */ u32 relocation_count;
/* 0x0c */ u32 symbols;
/* 0x10 */ u32 symbol_count;
/* 0x14 */ u32 elf_path;
/* 0x18 */ u32 load_func;
/* 0x1c */ u32 unload_func;
/* 0x20 */ u32 unknown_20;
/* 0x24 */ u32 unknown_24;
/* 0x28 */ u32 unknown_28;
/* 0x2c */ u32 file_size;
/* 0x30 */ u32 unknown_30;
)
CCC_PACKED_STRUCT(SNDLLHeaderV1,
/* 0x00 */ SNDLLHeaderCommon common;
)
CCC_PACKED_STRUCT(SNDLLHeaderV2,
/* 0x00 */ SNDLLHeaderCommon common;
/* 0x34 */ u32 unknown_34;
/* 0x38 */ u32 unknown_38;
)
CCC_PACKED_STRUCT(SNDLLRelocation,
/* 0x0 */ u32 unknown_0;
/* 0x4 */ u32 unknown_4;
/* 0x8 */ u32 unknown_8;
)
CCC_PACKED_STRUCT(SNDLLSymbolHeader,
/* 0x0 */ u32 string;
/* 0x4 */ u32 value;
/* 0x8 */ u8 unknown_8;
/* 0x9 */ u8 unknown_9;
/* 0xa */ SNDLLSymbolType type;
/* 0xb */ u8 processed;
)
static Result<SNDLLFile> parse_sndll_common(
std::span<const u8> image, Address address, SNDLLType type, const SNDLLHeaderCommon& common, SNDLLVersion version);
static const char* sndll_symbol_type_to_string(SNDLLSymbolType type);
Result<SNDLLFile> parse_sndll_file(std::span<const u8> image, Address address, SNDLLType type)
{
const u32* magic = get_packed<u32>(image, 0);
CCC_CHECK((*magic & 0xffffff) == CCC_FOURCC("SNR\00"), "Not a SNDLL %s.", address.valid() ? "section" : "file");
char version = *magic >> 24;
switch(version) {
case '1': {
const SNDLLHeaderV1* header = get_packed<SNDLLHeaderV1>(image, 0);
CCC_CHECK(header, "File too small to contain SNDLL V1 header.");
return parse_sndll_common(image, address, type, header->common, SNDLL_V1);
}
case '2': {
const SNDLLHeaderV2* header = get_packed<SNDLLHeaderV2>(image, 0);
CCC_CHECK(header, "File too small to contain SNDLL V2 header.");
return parse_sndll_common(image, address, type, header->common, SNDLL_V2);
}
}
return CCC_FAILURE("Unknown SNDLL version '%c'.", version);
}
static Result<SNDLLFile> parse_sndll_common(
std::span<const u8> image, Address address, SNDLLType type, const SNDLLHeaderCommon& common, SNDLLVersion version)
{
SNDLLFile sndll;
sndll.address = address;
sndll.type = type;
sndll.version = version;
if(common.elf_path) {
const char* elf_path = get_string(image, common.elf_path);
if(elf_path) {
sndll.elf_path = elf_path;
}
}
CCC_CHECK(common.symbol_count < (32 * 1024 * 1024) / sizeof(SNDLLSymbol), "SNDLL symbol count is too high.");
sndll.symbols.reserve(common.symbol_count);
for(u32 i = 0; i < common.symbol_count; i++) {
u32 symbol_offset = common.symbols - address.get_or_zero() + i * sizeof(SNDLLSymbolHeader);
const SNDLLSymbolHeader* symbol_header = get_packed<SNDLLSymbolHeader>(image, symbol_offset);
CCC_CHECK(symbol_header, "SNDLL symbol out of range.");
const char* string = nullptr;
if(symbol_header->string) {
string = get_string(image, symbol_header->string - address.get_or_zero());
}
SNDLLSymbol& symbol = sndll.symbols.emplace_back();
symbol.type = symbol_header->type;
symbol.value = symbol_header->value;
symbol.string = string;
}
return sndll;
}
Result<void> import_sndll_symbols(
SymbolDatabase& database,
const SNDLLFile& sndll,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler)
{
for(const SNDLLSymbol& symbol : sndll.symbols) {
if(symbol.value == 0 || symbol.string.empty()) {
continue;
}
u32 address = symbol.value;
if(symbol.type != SNDLL_ABSOLUTE && sndll.type == SNDLLType::DYNAMIC_LIBRARY) {
address += sndll.address.get_or_zero();
}
if(!(importer_flags & DONT_DEDUPLICATE_SYMBOLS)) {
if(database.functions.first_handle_from_starting_address(address).valid()) {
continue;
}
if(database.global_variables.first_handle_from_starting_address(address).valid()) {
continue;
}
if(database.local_variables.first_handle_from_starting_address(address).valid()) {
continue;
}
}
const Section* section = database.sections.symbol_overlapping_address(address);
if(section) {
if(section->contains_code()) {
Result<Function*> function = database.functions.create_symbol(
symbol.string, group.source, group.module_symbol, address, importer_flags, demangler);
CCC_RETURN_IF_ERROR(function);
continue;
} else if(section->contains_data()) {
Result<GlobalVariable*> global_variable = database.global_variables.create_symbol(
symbol.string, group.source, group.module_symbol, address, importer_flags, demangler);
CCC_RETURN_IF_ERROR(global_variable);
continue;
}
}
Result<Label*> label = database.labels.create_symbol(
symbol.string, group.source, group.module_symbol, address, importer_flags, demangler);
CCC_RETURN_IF_ERROR(label);
}
return Result<void>();
}
void print_sndll_symbols(FILE* out, const SNDLLFile& sndll)
{
fprintf(out, "SNDLL SYMBOLS:\n");
for(const SNDLLSymbol& symbol : sndll.symbols) {
const char* type = sndll_symbol_type_to_string(symbol.type);
const char* string = !symbol.string.empty() ? symbol.string.c_str() : "(no string)";
fprintf(out, "%8s %08x %s\n", type, symbol.value, string);
}
}
static const char* sndll_symbol_type_to_string(SNDLLSymbolType type)
{
switch(type) {
case SNDLL_NIL: return "NIL";
case SNDLL_EXTERNAL: return "EXTERNAL";
case SNDLL_RELATIVE: return "RELATIVE";
case SNDLL_WEAK: return "WEAK";
case SNDLL_ABSOLUTE: return "ABSOLUTE";
}
return "invalid";
}
}

55
3rdparty/ccc/src/ccc/sndll.h vendored Normal file
View File

@@ -0,0 +1,55 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "symbol_database.h"
namespace ccc {
enum class SNDLLType {
SNDATA_SECTION,
DYNAMIC_LIBRARY
};
enum SNDLLVersion {
SNDLL_V1,
SNDLL_V2
};
enum SNDLLSymbolType : u8 {
SNDLL_NIL = 0, // I think this is just so that the first real symbol has an index of 1.
SNDLL_EXTERNAL = 1, // Symbol with an empty value, to be filled in from another module.
SNDLL_RELATIVE = 2, // Global symbol, value is relative to the start of the SNDLL file.
SNDLL_WEAK = 3, // Weak symbol, value is relative to the start of the SNDLL file.
SNDLL_ABSOLUTE = 4 // Global symbol, value is an absolute address.
};
struct SNDLLSymbol {
SNDLLSymbolType type = SNDLL_NIL;
u32 value = 0;
std::string string;
};
struct SNDLLFile {
Address address;
SNDLLType type;
SNDLLVersion version;
std::string elf_path;
std::vector<SNDLLSymbol> symbols;
};
// If a valid address is passed, the pointers in the header will be treated as
// addresses, otherwise they will be treated as file offsets.
Result<SNDLLFile> parse_sndll_file(std::span<const u8> image, Address address, SNDLLType type);
Result<void> import_sndll_symbols(
SymbolDatabase& database,
const SNDLLFile& sndll,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler);
void print_sndll_symbols(FILE* out, const SNDLLFile& sndll);
}

835
3rdparty/ccc/src/ccc/stabs.cpp vendored Normal file
View File

@@ -0,0 +1,835 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "stabs.h"
namespace ccc {
#define STABS_DEBUG(...) //__VA_ARGS__
#define STABS_DEBUG_PRINTF(...) STABS_DEBUG(printf(__VA_ARGS__);)
static bool validate_symbol_descriptor(StabsSymbolDescriptor descriptor);
static Result<std::unique_ptr<StabsType>> parse_stabs_type(const char*& input);
static Result<std::vector<StabsStructOrUnionType::Field>> parse_field_list(const char*& input);
static Result<std::vector<StabsStructOrUnionType::MemberFunctionSet>> parse_member_functions(const char*& input);
static Result<StabsStructOrUnionType::Visibility> parse_visibility_character(const char*& input);
STABS_DEBUG(static void print_field(const StabsStructOrUnionType::Field& field);)
const char* STAB_TRUNCATED_ERROR_MESSAGE =
"STABS symbol truncated. This was probably caused by a GCC bug. "
"Other symbols from the same translation unit may also be invalid.";
Result<StabsSymbol> parse_stabs_symbol(const char*& input)
{
STABS_DEBUG_PRINTF("PARSING %s\n", input);
StabsSymbol symbol;
Result<std::string> name = parse_dodgy_stabs_identifier(input, ':');
CCC_RETURN_IF_ERROR(name);
symbol.name = *name;
CCC_EXPECT_CHAR(input, ':', "identifier");
CCC_CHECK(*input != '\0', "Unexpected end of input.");
if((*input >= '0' && *input <= '9') || *input == '(') {
symbol.descriptor = StabsSymbolDescriptor::LOCAL_VARIABLE;
} else {
char symbol_descriptor = *(input++);
CCC_CHECK(symbol_descriptor != '\0', "Failed to parse symbol descriptor.");
symbol.descriptor = (StabsSymbolDescriptor) symbol_descriptor;
}
CCC_CHECK(validate_symbol_descriptor(symbol.descriptor),
"Invalid symbol descriptor '%c'.",
(char) symbol.descriptor);
CCC_CHECK(*input != '\0', "Unexpected end of input.");
if(*input == 't') {
input++;
}
auto type = parse_top_level_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
// Handle nested functions.
bool is_function =
symbol.descriptor == StabsSymbolDescriptor::LOCAL_FUNCTION ||
symbol.descriptor == StabsSymbolDescriptor::GLOBAL_FUNCTION;
if(is_function && input[0] == ',') {
input++;
while(*input != ',' && *input != '\0') input++; // enclosing function
CCC_EXPECT_CHAR(input, ',', "nested function suffix");
while(*input != ',' && *input != '\0') input++; // function
}
symbol.type = std::move(*type);
// Make sure that variable names aren't used as type names e.g. the STABS
// symbol "somevar:P123=*456" may be referenced by the type number 123, but
// the type name is not "somevar".
bool is_type = symbol.descriptor == StabsSymbolDescriptor::TYPE_NAME
|| symbol.descriptor == StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG;
if(is_type) {
symbol.type->name = symbol.name;
}
symbol.type->is_typedef = symbol.descriptor == StabsSymbolDescriptor::TYPE_NAME;
symbol.type->is_root = true;
return symbol;
}
static bool validate_symbol_descriptor(StabsSymbolDescriptor descriptor)
{
bool valid;
switch(descriptor) {
case StabsSymbolDescriptor::LOCAL_VARIABLE:
case StabsSymbolDescriptor::REFERENCE_PARAMETER_A:
case StabsSymbolDescriptor::LOCAL_FUNCTION:
case StabsSymbolDescriptor::GLOBAL_FUNCTION:
case StabsSymbolDescriptor::GLOBAL_VARIABLE:
case StabsSymbolDescriptor::REGISTER_PARAMETER:
case StabsSymbolDescriptor::VALUE_PARAMETER:
case StabsSymbolDescriptor::REGISTER_VARIABLE:
case StabsSymbolDescriptor::STATIC_GLOBAL_VARIABLE:
case StabsSymbolDescriptor::TYPE_NAME:
case StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG:
case StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE:
case StabsSymbolDescriptor::REFERENCE_PARAMETER_V:
valid = true;
break;
default:
valid = false;
break;
}
return valid;
}
Result<std::unique_ptr<StabsType>> parse_top_level_stabs_type(const char*& input)
{
Result<std::unique_ptr<StabsType>> type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
// Handle first base class suffixes.
if((*type)->descriptor == StabsTypeDescriptor::STRUCT && input[0] == '~' && input[1] == '%') {
input += 2;
Result<std::unique_ptr<StabsType>> first_base_class = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(first_base_class);
(*type)->as<StabsStructType>().first_base_class = std::move(*first_base_class);
CCC_EXPECT_CHAR(input, ';', "first base class suffix");
}
// Handle extra live range information.
if(input[0] == ';' && input[1] == 'l') {
input += 2;
CCC_EXPECT_CHAR(input, '(', "live range suffix");
CCC_EXPECT_CHAR(input, '#', "live range suffix");
std::optional<s32> start = parse_number_s32(input);
CCC_CHECK(start.has_value(), "Failed to parse live range suffix.");
CCC_EXPECT_CHAR(input, ',', "live range suffix");
CCC_EXPECT_CHAR(input, '#', "live range suffix");
std::optional<s32> end = parse_number_s32(input);
CCC_CHECK(end.has_value(), "Failed to parse live range suffix.");
CCC_EXPECT_CHAR(input, ')', "live range suffix");
}
return type;
}
static Result<std::unique_ptr<StabsType>> parse_stabs_type(const char*& input)
{
StabsTypeNumber type_number;
CCC_CHECK(*input != '\0', "Unexpected end of input.");
if(*input == '(') {
// This file has type numbers made up of two pieces: an include file
// index and a type number.
input++;
std::optional<s32> file_index = parse_number_s32(input);
CCC_CHECK(file_index.has_value(), "Failed to parse type number (file index).");
CCC_EXPECT_CHAR(input, ',', "type number");
std::optional<s32> type_index = parse_number_s32(input);
CCC_CHECK(type_index.has_value(), "Failed to parse type number (type index).");
CCC_EXPECT_CHAR(input, ')', "type number");
type_number.file = *file_index;
type_number.type = *type_index;
if(*input != '=') {
return std::make_unique<StabsType>(type_number);
}
input++;
} else if(*input >= '0' && *input <= '9') {
// This file has type numbers which are just a single number. This is
// the more common case for games.
std::optional<s32> type_index = parse_number_s32(input);
CCC_CHECK(type_index.has_value(), "Failed to parse type number.");
type_number.type = *type_index;
if(*input != '=') {
return std::make_unique<StabsType>(type_number);
}
input++;
}
CCC_CHECK(*input != '\0', "Unexpected end of input.");
StabsTypeDescriptor descriptor;
if((*input >= '0' && *input <= '9') || *input == '(') {
descriptor = StabsTypeDescriptor::TYPE_REFERENCE;
} else {
char descriptor_char = *(input++);
CCC_CHECK(descriptor_char != '\0', "Failed to parse type descriptor.");
descriptor = (StabsTypeDescriptor) descriptor_char;
}
std::unique_ptr<StabsType> out_type;
switch(descriptor) {
case StabsTypeDescriptor::TYPE_REFERENCE: { // 0..9
auto type_reference = std::make_unique<StabsTypeReferenceType>(type_number);
auto type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
type_reference->type = std::move(*type);
out_type = std::move(type_reference);
break;
}
case StabsTypeDescriptor::ARRAY: { // a
auto array = std::make_unique<StabsArrayType>(type_number);
auto index_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(index_type);
array->index_type = std::move(*index_type);
auto element_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(element_type);
array->element_type = std::move(*element_type);
out_type = std::move(array);
break;
}
case StabsTypeDescriptor::ENUM: { // e
auto enum_type = std::make_unique<StabsEnumType>(type_number);
STABS_DEBUG_PRINTF("enum {\n");
while(*input != ';') {
std::optional<std::string> name = parse_stabs_identifier(input, ':');
CCC_CHECK(name.has_value(), "Failed to parse enum field name.");
CCC_EXPECT_CHAR(input, ':', "enum");
std::optional<s32> value = parse_number_s32(input);
CCC_CHECK(value.has_value(), "Failed to parse enum value.");
enum_type->fields.emplace_back(*value, std::move(*name));
CCC_EXPECT_CHAR(input, ',', "enum");
}
input++;
STABS_DEBUG_PRINTF("}\n");
out_type = std::move(enum_type);
break;
}
case StabsTypeDescriptor::FUNCTION: { // f
auto function = std::make_unique<StabsFunctionType>(type_number);
auto return_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(return_type);
function->return_type = std::move(*return_type);
out_type = std::move(function);
break;
}
case StabsTypeDescriptor::VOLATILE_QUALIFIER: { // B
auto volatile_qualifier = std::make_unique<StabsVolatileQualifierType>(type_number);
auto type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
volatile_qualifier->type = std::move(*type);
out_type = std::move(volatile_qualifier);
break;
}
case StabsTypeDescriptor::CONST_QUALIFIER: { // k
auto const_qualifier = std::make_unique<StabsConstQualifierType>(type_number);
auto type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
const_qualifier->type = std::move(*type);
out_type = std::move(const_qualifier);
break;
}
case StabsTypeDescriptor::RANGE: { // r
auto range = std::make_unique<StabsRangeType>(type_number);
auto type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
range->type = std::move(*type);
CCC_EXPECT_CHAR(input, ';', "range type descriptor");
std::optional<std::string> low = parse_stabs_identifier(input, ';');
CCC_CHECK(low.has_value(), "Failed to parse low part of range.");
CCC_EXPECT_CHAR(input, ';', "low range value");
std::optional<std::string> high = parse_stabs_identifier(input, ';');
CCC_CHECK(high.has_value(), "Failed to parse high part of range.");
CCC_EXPECT_CHAR(input, ';', "high range value");
range->low = std::move(*low);
range->high = std::move(*high);
out_type = std::move(range);
break;
}
case StabsTypeDescriptor::STRUCT: { // s
auto struct_type = std::make_unique<StabsStructType>(type_number);
STABS_DEBUG_PRINTF("struct {\n");
std::optional<s64> struct_size = parse_number_s64(input);
CCC_CHECK(struct_size.has_value(), "Failed to parse struct size.");
struct_type->size = *struct_size;
if(*input == '!') {
input++;
std::optional<s32> base_class_count = parse_number_s32(input);
CCC_CHECK(base_class_count.has_value(), "Failed to parse base class count.");
CCC_EXPECT_CHAR(input, ',', "base class section");
for(s64 i = 0; i < *base_class_count; i++) {
StabsStructOrUnionType::BaseClass base_class;
char is_virtual = *(input++);
switch(is_virtual) {
case '0': base_class.is_virtual = false; break;
case '1': base_class.is_virtual = true; break;
default: return CCC_FAILURE("Failed to parse base class (virtual character).");
}
Result<StabsStructOrUnionType::Visibility> visibility = parse_visibility_character(input);
CCC_RETURN_IF_ERROR(visibility);
base_class.visibility = *visibility;
std::optional<s32> offset = parse_number_s32(input);
CCC_CHECK(offset.has_value(), "Failed to parse base class offset.");
base_class.offset = (s32) *offset;
CCC_EXPECT_CHAR(input, ',', "base class section");
auto base_class_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(base_class_type);
base_class.type = std::move(*base_class_type);
CCC_EXPECT_CHAR(input, ';', "base class section");
struct_type->base_classes.emplace_back(std::move(base_class));
}
}
auto fields = parse_field_list(input);
CCC_RETURN_IF_ERROR(fields);
struct_type->fields = std::move(*fields);
auto member_functions = parse_member_functions(input);
CCC_RETURN_IF_ERROR(member_functions);
struct_type->member_functions = std::move(*member_functions);
STABS_DEBUG_PRINTF("}\n");
out_type = std::move(struct_type);
break;
}
case StabsTypeDescriptor::UNION: { // u
auto union_type = std::make_unique<StabsUnionType>(type_number);
STABS_DEBUG_PRINTF("union {\n");
std::optional<s64> union_size = parse_number_s64(input);
CCC_CHECK(union_size.has_value(), "Failed to parse struct size.");
union_type->size = *union_size;
auto fields = parse_field_list(input);
CCC_RETURN_IF_ERROR(fields);
union_type->fields = std::move(*fields);
auto member_functions = parse_member_functions(input);
CCC_RETURN_IF_ERROR(member_functions);
union_type->member_functions = std::move(*member_functions);
STABS_DEBUG_PRINTF("}\n");
out_type = std::move(union_type);
break;
}
case StabsTypeDescriptor::CROSS_REFERENCE: { // x
auto cross_reference = std::make_unique<StabsCrossReferenceType>(type_number);
char cross_reference_type = *(input++);
CCC_CHECK(cross_reference_type != '\0', "Failed to parse cross reference type.");
switch(cross_reference_type) {
case 'e': cross_reference->type = ast::ForwardDeclaredType::ENUM; break;
case 's': cross_reference->type = ast::ForwardDeclaredType::STRUCT; break;
case 'u': cross_reference->type = ast::ForwardDeclaredType::UNION; break;
default:
return CCC_FAILURE("Invalid cross reference type '%c'.", cross_reference->type);
}
Result<std::string> identifier = parse_dodgy_stabs_identifier(input, ':');
CCC_RETURN_IF_ERROR(identifier);
cross_reference->identifier = std::move(*identifier);
cross_reference->name = cross_reference->identifier;
CCC_EXPECT_CHAR(input, ':', "cross reference");
out_type = std::move(cross_reference);
break;
}
case StabsTypeDescriptor::FLOATING_POINT_BUILTIN: { // R
auto fp_builtin = std::make_unique<StabsFloatingPointBuiltInType>(type_number);
std::optional<s32> fpclass = parse_number_s32(input);
CCC_CHECK(fpclass.has_value(), "Failed to parse floating point built-in class.");
fp_builtin->fpclass = *fpclass;
CCC_EXPECT_CHAR(input, ';', "floating point builtin");
std::optional<s32> bytes = parse_number_s32(input);
CCC_CHECK(bytes.has_value(), "Failed to parse floating point built-in.");
fp_builtin->bytes = *bytes;
CCC_EXPECT_CHAR(input, ';', "floating point builtin");
std::optional<s32> value = parse_number_s32(input);
CCC_CHECK(value.has_value(), "Failed to parse floating point built-in.");
CCC_EXPECT_CHAR(input, ';', "floating point builtin");
out_type = std::move(fp_builtin);
break;
}
case StabsTypeDescriptor::METHOD: { // #
auto method = std::make_unique<StabsMethodType>(type_number);
if(*input == '#') {
input++;
auto return_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(return_type);
method->return_type = std::move(*return_type);
if(*input == ';') {
input++;
}
} else {
auto class_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(class_type);
method->class_type = std::move(*class_type);
CCC_EXPECT_CHAR(input, ',', "method");
auto return_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(return_type);
method->return_type = std::move(*return_type);
while(*input != '\0') {
if(*input == ';') {
input++;
break;
}
CCC_EXPECT_CHAR(input, ',', "method");
auto parameter_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(parameter_type);
method->parameter_types.emplace_back(std::move(*parameter_type));
}
}
out_type = std::move(method);
break;
}
case StabsTypeDescriptor::REFERENCE: { // &
auto reference = std::make_unique<StabsReferenceType>(type_number);
auto value_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(value_type);
reference->value_type = std::move(*value_type);
out_type = std::move(reference);
break;
}
case StabsTypeDescriptor::POINTER: { // *
auto pointer = std::make_unique<StabsPointerType>(type_number);
auto value_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(value_type);
pointer->value_type = std::move(*value_type);
out_type = std::move(pointer);
break;
}
case StabsTypeDescriptor::TYPE_ATTRIBUTE: { // @
if((*input >= '0' && *input <= '9') || *input == '(') {
auto member_pointer = std::make_unique<StabsPointerToDataMemberType>(type_number);
auto class_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(class_type);
member_pointer->class_type = std::move(*class_type);
CCC_EXPECT_CHAR(input, ',', "pointer to non-static data member");
auto member_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(member_type);
member_pointer->member_type = std::move(*member_type);
out_type = std::move(member_pointer);
} else {
auto type_attribute = std::make_unique<StabsSizeTypeAttributeType>(type_number);
CCC_CHECK(*input == 's', "Weird value following '@' type descriptor.");
input++;
std::optional<s64> size_bits = parse_number_s64(input);
CCC_CHECK(size_bits.has_value(), "Failed to parse type attribute.")
type_attribute->size_bits = *size_bits;
CCC_EXPECT_CHAR(input, ';', "type attribute");
auto type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
type_attribute->type = std::move(*type);
out_type = std::move(type_attribute);
}
break;
}
case StabsTypeDescriptor::BUILTIN: { // -
auto built_in = std::make_unique<StabsBuiltInType>(type_number);
std::optional<s64> type_id = parse_number_s64(input);
CCC_CHECK(type_id.has_value(), "Failed to parse built-in.");
built_in->type_id = *type_id;
CCC_EXPECT_CHAR(input, ';', "builtin");
out_type = std::move(built_in);
break;
}
default: {
return CCC_FAILURE(
"Invalid type descriptor '%c' (%02x).",
(u32) descriptor, (u32) descriptor);
}
}
return out_type;
}
static Result<std::vector<StabsStructOrUnionType::Field>> parse_field_list(const char*& input)
{
std::vector<StabsStructOrUnionType::Field> fields;
while(*input != '\0') {
if(*input == ';') {
input++;
break;
}
const char* before_field = input;
StabsStructOrUnionType::Field field;
Result<std::string> name = parse_dodgy_stabs_identifier(input, ':');
CCC_RETURN_IF_ERROR(name);
field.name = std::move(*name);
CCC_EXPECT_CHAR(input, ':', "identifier");
if(*input == '/') {
input++;
Result<StabsStructOrUnionType::Visibility> visibility = parse_visibility_character(input);
CCC_RETURN_IF_ERROR(visibility);
field.visibility = *visibility;
}
if(*input == ':') {
input = before_field;
break;
}
auto type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
field.type = std::move(*type);
if(field.name.size() >= 1 && field.name[0] == '$') {
// Virtual function table pointers and virtual base class pointers.
CCC_EXPECT_CHAR(input, ',', "field type");
std::optional<s32> offset_bits = parse_number_s32(input);
CCC_CHECK(offset_bits.has_value(), "Failed to parse field offset.");
field.offset_bits = *offset_bits;
CCC_EXPECT_CHAR(input, ';', "field offset");
} else if(*input == ':') {
// Static fields.
input++;
field.is_static = true;
std::optional<std::string> type_name = parse_stabs_identifier(input, ';');
CCC_CHECK(type_name.has_value(), "Failed to parse static field type name.");
field.type_name = std::move(*type_name);
CCC_EXPECT_CHAR(input, ';', "identifier");
} else if(*input == ',') {
// Normal fields.
input++;
std::optional<s32> offset_bits = parse_number_s32(input);
CCC_CHECK(offset_bits.has_value(), "Failed to parse field offset.");
field.offset_bits = *offset_bits;
CCC_EXPECT_CHAR(input, ',', "field offset");
std::optional<s32> size_bits = parse_number_s32(input);
CCC_CHECK(size_bits.has_value(), "Failed to parse field size.");
field.size_bits = *size_bits;
CCC_EXPECT_CHAR(input, ';', "field size");
} else {
return CCC_FAILURE("Expected ':' or ',', got '%c' (%hhx).", *input, *input);
}
STABS_DEBUG(print_field(field);)
fields.emplace_back(std::move(field));
}
return fields;
}
static Result<std::vector<StabsStructOrUnionType::MemberFunctionSet>> parse_member_functions(const char*& input)
{
// Check for if the next character is from an enclosing field list. If this
// is the case, the next character will be ',' for normal fields and ':' for
// static fields (see above).
if(*input == ',' || *input == ':') {
return std::vector<StabsStructOrUnionType::MemberFunctionSet>();
}
std::vector<StabsStructOrUnionType::MemberFunctionSet> member_functions;
while(*input != '\0') {
if(*input == ';') {
input++;
break;
}
StabsStructOrUnionType::MemberFunctionSet member_function_set;
std::optional<std::string> name = parse_stabs_identifier(input, ':');
CCC_CHECK(name.has_value(), "Failed to parse member function name.");
member_function_set.name = std::move(*name);
CCC_EXPECT_CHAR(input, ':', "member function");
CCC_EXPECT_CHAR(input, ':', "member function");
while(*input != '\0') {
if(*input == ';') {
input++;
break;
}
StabsStructOrUnionType::MemberFunction function;
auto type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(type);
function.type = std::move(*type);
CCC_EXPECT_CHAR(input, ':', "member function");
std::optional<std::string> identifier = parse_stabs_identifier(input, ';');
CCC_CHECK(identifier.has_value(), "Invalid member function identifier.");
CCC_EXPECT_CHAR(input, ';', "member function");
Result<StabsStructOrUnionType::Visibility> visibility = parse_visibility_character(input);
CCC_RETURN_IF_ERROR(visibility);
function.visibility = *visibility;
char modifiers = *(input++);
CCC_CHECK(modifiers != '\0', "Failed to parse member function modifiers.");
switch(modifiers) {
case 'A':
function.is_const = false;
function.is_volatile = false;
break;
case 'B':
function.is_const = true;
function.is_volatile = false;
break;
case 'C':
function.is_const = false;
function.is_volatile = true;
break;
case 'D':
function.is_const = true;
function.is_volatile = true;
break;
case '?':
case '.':
break;
default:
return CCC_FAILURE("Invalid member function modifiers.");
}
char flag = *(input++);
CCC_CHECK(flag != '\0', "Failed to parse member function type.");
switch(flag) {
case '.': { // normal member function
function.modifier = ast::MemberFunctionModifier::NONE;
break;
}
case '?': { // static member function
function.modifier = ast::MemberFunctionModifier::STATIC;
break;
}
case '*': { // virtual member function
std::optional<s32> vtable_index = parse_number_s32(input);
CCC_CHECK(vtable_index.has_value(), "Failed to parse vtable index.");
function.vtable_index = *vtable_index;
CCC_EXPECT_CHAR(input, ';', "virtual member function");
auto virtual_type = parse_stabs_type(input);
CCC_RETURN_IF_ERROR(virtual_type);
function.virtual_type = std::move(*virtual_type);
CCC_EXPECT_CHAR(input, ';', "virtual member function");
function.modifier = ast::MemberFunctionModifier::VIRTUAL;
break;
}
default:
return CCC_FAILURE("Invalid member function type.");
}
member_function_set.overloads.emplace_back(std::move(function));
}
STABS_DEBUG_PRINTF("member func: %s\n", member_function_set.name.c_str());
member_functions.emplace_back(std::move(member_function_set));
}
return member_functions;
}
static Result<StabsStructOrUnionType::Visibility> parse_visibility_character(const char*& input)
{
char visibility = *(input++);
switch(visibility) {
case '0': return StabsStructOrUnionType::Visibility::PRIVATE;
case '1': return StabsStructOrUnionType::Visibility::PROTECTED;
case '2': return StabsStructOrUnionType::Visibility::PUBLIC;
case '9': return StabsStructOrUnionType::Visibility::PUBLIC_OPTIMIZED_OUT;
default: break;
}
return CCC_FAILURE("Failed to parse visibility character.");
}
std::optional<s32> parse_number_s32(const char*& input)
{
char* end;
s64 value = strtoll(input, &end, 10);
if(end == input) {
return std::nullopt;
}
input = end;
return (s32) value;
}
std::optional<s64> parse_number_s64(const char*& input)
{
char* end;
s64 value = strtoll(input, &end, 10);
if(end == input) {
return std::nullopt;
}
input = end;
return value;
}
std::optional<std::string> parse_stabs_identifier(const char*& input, char terminator)
{
const char* begin = input;
for(; *input != '\0'; input++) {
if(*input == terminator) {
return std::string(begin, input);
}
}
return std::nullopt;
}
// The complexity here is because the input may contain an unescaped namespace
// separator '::' even if the field terminator is supposed to be a colon, as
// well as the raw contents of character literals. See test/ccc/stabs_tests.cpp
// for some examples.
Result<std::string> parse_dodgy_stabs_identifier(const char*& input, char terminator)
{
const char* begin = input;
s32 template_depth = 0;
for(; *input != '\0'; input++) {
// Skip past character literals.
if(*input == '\'') {
input++;
if(*input == '\'') {
input++; // Handle character literals containing a single quote.
}
while(*input != '\'' && *input != '\0') {
input++;
}
if(*input == '\0') {
break;
}
input++;
}
// Keep track of the template depth so we know when to expect the
// terminator character.
if(*input == '<') {
template_depth++;
}
if(*input == '>') {
template_depth--;
}
if(*input == terminator && template_depth == 0) {
return std::string(begin, input);
}
}
return CCC_FAILURE(STAB_TRUNCATED_ERROR_MESSAGE);
}
STABS_DEBUG(
static void print_field(const StabsStructOrUnionType::Field& field)
{
printf("\t%04x %04x %04x %04x %s\n", field.offset_bits / 8, field.size_bits / 8, field.offset_bits, field.size_bits, field.name.c_str());
}
)
const char* stabs_field_visibility_to_string(StabsStructOrUnionType::Visibility visibility)
{
switch(visibility) {
case StabsStructOrUnionType::Visibility::PRIVATE: return "private";
case StabsStructOrUnionType::Visibility::PROTECTED: return "protected";
case StabsStructOrUnionType::Visibility::PUBLIC: return "public";
case StabsStructOrUnionType::Visibility::PUBLIC_OPTIMIZED_OUT: return "public_optimizedout";
default: return "none";
}
return "";
}
}

379
3rdparty/ccc/src/ccc/stabs.h vendored Normal file
View File

@@ -0,0 +1,379 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "ast.h"
#include "util.h"
namespace ccc {
enum class StabsSymbolDescriptor : u8 {
LOCAL_VARIABLE = '_',
REFERENCE_PARAMETER_A = 'a',
LOCAL_FUNCTION = 'f',
GLOBAL_FUNCTION = 'F',
GLOBAL_VARIABLE = 'G',
REGISTER_PARAMETER = 'P',
VALUE_PARAMETER = 'p',
REGISTER_VARIABLE = 'r',
STATIC_GLOBAL_VARIABLE = 'S',
TYPE_NAME = 't',
ENUM_STRUCT_OR_TYPE_TAG = 'T',
STATIC_LOCAL_VARIABLE = 'V',
REFERENCE_PARAMETER_V = 'v'
};
struct StabsType;
struct StabsSymbol {
StabsSymbolDescriptor descriptor;
std::string name;
std::unique_ptr<StabsType> type;
};
Result<StabsSymbol> parse_stabs_symbol(const char*& input);
enum class StabsTypeDescriptor : u8 {
TYPE_REFERENCE = 0xef, // '0'..'9','('
ARRAY = 'a',
ENUM = 'e',
FUNCTION = 'f',
CONST_QUALIFIER = 'k',
RANGE = 'r',
STRUCT = 's',
UNION = 'u',
CROSS_REFERENCE = 'x',
VOLATILE_QUALIFIER = 'B',
FLOATING_POINT_BUILTIN = 'R',
METHOD = '#',
REFERENCE = '&',
POINTER = '*',
TYPE_ATTRIBUTE = '@',
POINTER_TO_DATA_MEMBER = 0xee, // also '@'
BUILTIN = '-'
};
struct StabsBaseClass;
struct StabsField;
struct StabsMemberFunctionSet;
// e.g. for "123=*456" 123 would be the type_number, the type descriptor would
// be of type POINTER and StabsPointerType::value_type would point to a type
// with type_number = 456.
struct StabsType {
StabsTypeNumber type_number;
// The name field is only populated for root types and cross references.
std::optional<std::string> name;
bool is_typedef = false;
bool is_root = false;
std::optional<StabsTypeDescriptor> descriptor;
StabsType(StabsTypeNumber n) : type_number(n) {}
StabsType(StabsTypeDescriptor d) : descriptor(d) {}
StabsType(StabsTypeNumber n, StabsTypeDescriptor d) : type_number(n), descriptor(d) {}
virtual ~StabsType() {}
template <typename SubType>
SubType& as()
{
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
return *static_cast<SubType*>(this);
}
template <typename SubType>
const SubType& as() const
{
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
return *static_cast<const SubType*>(this);
}
virtual void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const
{
if(type_number.valid() && descriptor.has_value()) {
output.emplace(type_number, this);
}
}
};
struct StabsTypeReferenceType : StabsType {
std::unique_ptr<StabsType> type;
StabsTypeReferenceType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::TYPE_REFERENCE;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
type->enumerate_numbered_types(output);
}
};
struct StabsArrayType : StabsType {
std::unique_ptr<StabsType> index_type;
std::unique_ptr<StabsType> element_type;
StabsArrayType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::ARRAY;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
index_type->enumerate_numbered_types(output);
element_type->enumerate_numbered_types(output);
}
};
struct StabsEnumType : StabsType {
std::vector<std::pair<s32, std::string>> fields;
StabsEnumType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::ENUM;
};
struct StabsFunctionType : StabsType {
std::unique_ptr<StabsType> return_type;
StabsFunctionType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::FUNCTION;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
return_type->enumerate_numbered_types(output);
}
};
struct StabsVolatileQualifierType : StabsType {
std::unique_ptr<StabsType> type;
StabsVolatileQualifierType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::VOLATILE_QUALIFIER;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
type->enumerate_numbered_types(output);
}
};
struct StabsConstQualifierType : StabsType {
std::unique_ptr<StabsType> type;
StabsConstQualifierType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::CONST_QUALIFIER;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
type->enumerate_numbered_types(output);
}
};
struct StabsRangeType : StabsType {
std::unique_ptr<StabsType> type;
std::string low;
std::string high; // Some compilers wrote out a wrapped around value here for zero (or variable?) length arrays.
StabsRangeType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::RANGE;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
type->enumerate_numbered_types(output);
}
};
struct StabsStructOrUnionType : StabsType {
enum class Visibility : u8 {
NONE,
PRIVATE,
PROTECTED,
PUBLIC,
PUBLIC_OPTIMIZED_OUT
};
struct BaseClass {
bool is_virtual;
Visibility visibility;
s32 offset = -1;
std::unique_ptr<StabsType> type;
};
struct Field {
std::string name;
Visibility visibility = Visibility::NONE;
std::unique_ptr<StabsType> type;
bool is_static = false;
s32 offset_bits = 0;
s32 size_bits = 0;
std::string type_name;
};
struct MemberFunction {
std::unique_ptr<StabsType> type;
std::unique_ptr<StabsType> virtual_type;
Visibility visibility;
bool is_const = false;
bool is_volatile = false;
ast::MemberFunctionModifier modifier = ast::MemberFunctionModifier::NONE;
s32 vtable_index = -1;
};
struct MemberFunctionSet {
std::string name;
std::vector<MemberFunction> overloads;
};
s64 size = -1;
std::vector<BaseClass> base_classes;
std::vector<Field> fields;
std::vector<MemberFunctionSet> member_functions;
std::unique_ptr<StabsType> first_base_class;
StabsStructOrUnionType(StabsTypeNumber n, StabsTypeDescriptor d) : StabsType(n, d) {}
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
for(const BaseClass& base_class : base_classes) {
base_class.type->enumerate_numbered_types(output);
}
for(const Field& field : fields) {
field.type->enumerate_numbered_types(output);
}
for(const MemberFunctionSet& member_function_set : member_functions) {
for(const MemberFunction& member_function : member_function_set.overloads) {
member_function.type->enumerate_numbered_types(output);
if(member_function.virtual_type.get()) {
member_function.virtual_type->enumerate_numbered_types(output);
}
}
}
if(first_base_class.get()) {
first_base_class->enumerate_numbered_types(output);
}
}
};
struct StabsStructType : StabsStructOrUnionType {
StabsStructType(StabsTypeNumber n) : StabsStructOrUnionType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::STRUCT;
};
struct StabsUnionType : StabsStructOrUnionType {
StabsUnionType(StabsTypeNumber n) : StabsStructOrUnionType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::UNION;
};
struct StabsCrossReferenceType : StabsType {
ast::ForwardDeclaredType type;
std::string identifier;
StabsCrossReferenceType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::CROSS_REFERENCE;
};
struct StabsFloatingPointBuiltInType : StabsType {
s32 fpclass = -1;
s32 bytes = -1;
StabsFloatingPointBuiltInType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::FLOATING_POINT_BUILTIN;
};
struct StabsMethodType : StabsType {
std::unique_ptr<StabsType> return_type;
std::optional<std::unique_ptr<StabsType>> class_type;
std::vector<std::unique_ptr<StabsType>> parameter_types;
StabsMethodType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::METHOD;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
return_type->enumerate_numbered_types(output);
if(class_type.has_value()) {
(*class_type)->enumerate_numbered_types(output);
}
for(const std::unique_ptr<StabsType>& parameter_type : parameter_types) {
parameter_type->enumerate_numbered_types(output);
}
}
};
struct StabsReferenceType : StabsType {
std::unique_ptr<StabsType> value_type;
StabsReferenceType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::REFERENCE;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
value_type->enumerate_numbered_types(output);
}
};
struct StabsPointerType : StabsType {
std::unique_ptr<StabsType> value_type;
StabsPointerType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::POINTER;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
value_type->enumerate_numbered_types(output);
}
};
struct StabsSizeTypeAttributeType : StabsType {
s64 size_bits = -1;
std::unique_ptr<StabsType> type;
StabsSizeTypeAttributeType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::TYPE_ATTRIBUTE;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
type->enumerate_numbered_types(output);
}
};
struct StabsPointerToDataMemberType : StabsType {
std::unique_ptr<StabsType> class_type;
std::unique_ptr<StabsType> member_type;
StabsPointerToDataMemberType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::POINTER_TO_DATA_MEMBER;
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
{
StabsType::enumerate_numbered_types(output);
class_type->enumerate_numbered_types(output);
member_type->enumerate_numbered_types(output);
}
};
struct StabsBuiltInType : StabsType {
s64 type_id = -1;
StabsBuiltInType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::BUILTIN;
};
extern const char* STAB_TRUNCATED_ERROR_MESSAGE;
Result<std::unique_ptr<StabsType>> parse_top_level_stabs_type(const char*& input);
std::optional<s32> parse_number_s32(const char*& input);
std::optional<s64> parse_number_s64(const char*& input);
std::optional<std::string> parse_stabs_identifier(const char*& input, char terminator);
Result<std::string> parse_dodgy_stabs_identifier(const char*& input, char terminator);
const char* stabs_field_visibility_to_string(StabsStructOrUnionType::Visibility visibility);
}

834
3rdparty/ccc/src/ccc/stabs_to_ast.cpp vendored Normal file
View File

@@ -0,0 +1,834 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "stabs_to_ast.h"
#include "importer_flags.h"
#define AST_DEBUG(...) //__VA_ARGS__
#define AST_DEBUG_PRINTF(...) AST_DEBUG(printf(__VA_ARGS__);)
namespace ccc {
struct MemberFunctionInfo {
std::string name;
bool is_constructor_or_destructor = false;
bool is_special_member_function = false;
bool is_operator_member_function = false;
};
static bool is_void_like(const StabsType& type);
static Result<ast::BuiltInClass> classify_range(const StabsRangeType& type);
static Result<std::unique_ptr<ast::Node>> field_to_ast(
const StabsStructOrUnionType::Field& field,
const StabsType& enclosing_struct,
const StabsToAstState& state,
s32 depth);
static Result<bool> detect_bitfield(const StabsStructOrUnionType::Field& field, const StabsToAstState& state);
static Result<std::vector<std::unique_ptr<ast::Node>>> member_functions_to_ast(
const StabsStructOrUnionType& type, const StabsToAstState& state, s32 depth);
static MemberFunctionInfo check_member_function(
const std::string& mangled_name,
std::string_view type_name_no_template_args,
const DemanglerFunctions& demangler,
u32 importer_flags);
Result<std::unique_ptr<ast::Node>> stabs_type_to_ast(
const StabsType& type,
const StabsType* enclosing_struct,
const StabsToAstState& state,
s32 depth,
bool substitute_type_name,
bool force_substitute)
{
AST_DEBUG_PRINTF("%-*stype desc=%hhx '%c' num=(%d,%d) name=%s\n",
depth * 4, "",
type.descriptor.has_value() ? (u8) *type.descriptor : 'X',
(type.descriptor.has_value() && isprint((u8) *type.descriptor)) ? (u8) *type.descriptor : '!',
type.type_number.file, type.type_number.type,
type.name.has_value() ? type.name->c_str() : "");
if(depth > 200) {
const char* error_message = "Call depth greater than 200 in stabs_type_to_ast, probably infinite recursion.";
if(state.importer_flags & STRICT_PARSING) {
return CCC_FAILURE(error_message);
} else {
CCC_WARN(error_message);
auto error = std::make_unique<ast::Error>();
error->message = error_message;
return std::unique_ptr<ast::Node>(std::move(error));
}
}
// This makes sure that types are replaced with their type name in cases
// where that would be more appropriate.
if(type.name.has_value()) {
bool try_substitute = depth > 0 && (type.is_root
|| type.descriptor == StabsTypeDescriptor::RANGE
|| type.descriptor == StabsTypeDescriptor::BUILTIN);
// GCC emits anonymous enums with a name of " " since apparently some
// debuggers can't handle zero-length names.
bool is_name_empty = type.name == "" || type.name == " ";
// Cross references will be handled below.
bool is_cross_reference = type.descriptor == StabsTypeDescriptor::CROSS_REFERENCE;
bool is_void = is_void_like(type);
if((substitute_type_name || try_substitute) && !is_name_empty && !is_cross_reference && !is_void) {
auto type_name = std::make_unique<ast::TypeName>();
type_name->source = ast::TypeNameSource::REFERENCE;
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
type_name->unresolved_stabs->type_name = *type.name;
type_name->unresolved_stabs->referenced_file_handle = state.file_handle;
type_name->unresolved_stabs->stabs_type_number = type.type_number;
return std::unique_ptr<ast::Node>(std::move(type_name));
}
}
// This prevents infinite recursion when an automatically generated member
// function references an unnamed type.
bool can_compare_type_numbers = type.type_number.valid() && enclosing_struct && enclosing_struct->type_number.valid();
if(force_substitute && can_compare_type_numbers && type.type_number == enclosing_struct->type_number) {
// It's probably a this parameter (or return type) for an unnamed type.
auto type_name = std::make_unique<ast::TypeName>();
type_name->source = ast::TypeNameSource::UNNAMED_THIS;
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
type_name->unresolved_stabs->type_name = enclosing_struct->name.has_value() ? *enclosing_struct->name : "";
type_name->unresolved_stabs->referenced_file_handle = state.file_handle;
type_name->unresolved_stabs->stabs_type_number = type.type_number;
return std::unique_ptr<ast::Node>(std::move(type_name));
}
if(!type.descriptor.has_value()) {
// The definition of the type has been defined previously, so we have to
// look it up by its type number.
CCC_CHECK(type.type_number.valid(), "Cannot lookup type (type is anonymous).");
auto stabs_type = state.stabs_types->find(type.type_number);
if(stabs_type == state.stabs_types->end()) {
std::string error_message = "Failed to lookup STABS type by its type number ("
+ std::to_string(type.type_number.file) + "," + std::to_string(type.type_number.type) + ").";
if(state.importer_flags & STRICT_PARSING) {
return CCC_FAILURE("%s", error_message.c_str());
} else {
CCC_WARN("%s", error_message.c_str());
std::unique_ptr<ast::Error> error = std::make_unique<ast::Error>();
error->message = std::move(error_message);
return std::unique_ptr<ast::Node>(std::move(error));
}
}
return stabs_type_to_ast(
*stabs_type->second,
enclosing_struct,
state,
depth + 1,
substitute_type_name,
force_substitute);
}
std::unique_ptr<ast::Node> result;
switch(*type.descriptor) {
case StabsTypeDescriptor::TYPE_REFERENCE: {
const auto& stabs_type_ref = type.as<StabsTypeReferenceType>();
if(!type.type_number.valid() || !stabs_type_ref.type->type_number.valid() || stabs_type_ref.type->type_number != type.type_number) {
auto node = stabs_type_to_ast(
*stabs_type_ref.type,
enclosing_struct,
state,
depth + 1,
substitute_type_name,
force_substitute);
CCC_RETURN_IF_ERROR(node);
result = std::move(*node);
} else {
// I still don't know why in STABS void is a reference to
// itself, maybe because I'm not a philosopher.
auto builtin = std::make_unique<ast::BuiltIn>();
builtin->bclass = ast::BuiltInClass::VOID_TYPE;
result = std::move(builtin);
}
break;
}
case StabsTypeDescriptor::ARRAY: {
auto array = std::make_unique<ast::Array>();
const auto& stabs_array = type.as<StabsArrayType>();
auto element_node = stabs_type_to_ast(
*stabs_array.element_type,
enclosing_struct,
state,
depth + 1,
true,
force_substitute);
CCC_RETURN_IF_ERROR(element_node);
array->element_type = std::move(*element_node);
const StabsRangeType& index = stabs_array.index_type->as<StabsRangeType>();
char* end = nullptr;
const char* low = index.low.c_str();
s64 low_value = strtoll(low, &end, 10);
CCC_CHECK(end != low, "Failed to parse low part of range as integer.");
CCC_CHECK(low_value == 0, "Invalid index type for array.");
const char* high = index.high.c_str();
s64 high_value = strtoll(high, &end, 10);
CCC_CHECK(end != high, "Failed to parse low part of range as integer.");
if(high_value == 4294967295) {
// Some compilers wrote out a wrapped around value here.
array->element_count = 0;
} else {
array->element_count = (s32) high_value + 1;
}
result = std::move(array);
break;
}
case StabsTypeDescriptor::ENUM: {
auto inline_enum = std::make_unique<ast::Enum>();
const auto& stabs_enum = type.as<StabsEnumType>();
inline_enum->constants = stabs_enum.fields;
result = std::move(inline_enum);
break;
}
case StabsTypeDescriptor::FUNCTION: {
auto function = std::make_unique<ast::Function>();
auto node = stabs_type_to_ast(
*type.as<StabsFunctionType>().return_type,
enclosing_struct,
state,
depth + 1,
true,
force_substitute);
CCC_RETURN_IF_ERROR(node);
function->return_type = std::move(*node);
result = std::move(function);
break;
}
case StabsTypeDescriptor::VOLATILE_QUALIFIER: {
const auto& volatile_qualifier = type.as<StabsVolatileQualifierType>();
auto node = stabs_type_to_ast(
*volatile_qualifier.type.get(),
enclosing_struct,
state,
depth + 1,
substitute_type_name,
force_substitute);
CCC_RETURN_IF_ERROR(node);
result = std::move(*node);
result->is_volatile = true;
break;
}
case StabsTypeDescriptor::CONST_QUALIFIER: {
const auto& const_qualifier = type.as<StabsConstQualifierType>();
auto node = stabs_type_to_ast(
*const_qualifier.type.get(),
enclosing_struct,
state,
depth + 1,
substitute_type_name,
force_substitute);
result = std::move(*node);
result->is_const = true;
break;
}
case StabsTypeDescriptor::RANGE: {
auto builtin = std::make_unique<ast::BuiltIn>();
Result<ast::BuiltInClass> bclass = classify_range(type.as<StabsRangeType>());
CCC_RETURN_IF_ERROR(bclass);
builtin->bclass = *bclass;
result = std::move(builtin);
break;
}
case StabsTypeDescriptor::STRUCT:
case StabsTypeDescriptor::UNION: {
const StabsStructOrUnionType* stabs_struct_or_union;
if(type.descriptor == StabsTypeDescriptor::STRUCT) {
stabs_struct_or_union = &type.as<StabsStructType>();
} else {
stabs_struct_or_union = &type.as<StabsUnionType>();
}
auto struct_or_union = std::make_unique<ast::StructOrUnion>();
struct_or_union->is_struct = type.descriptor == StabsTypeDescriptor::STRUCT;
struct_or_union->size_bits = (s32) stabs_struct_or_union->size * 8;
for(const StabsStructOrUnionType::BaseClass& stabs_base_class : stabs_struct_or_union->base_classes) {
auto base_class = stabs_type_to_ast(
*stabs_base_class.type,
&type,
state,
depth + 1,
true,
force_substitute);
CCC_RETURN_IF_ERROR(base_class);
(*base_class)->offset_bytes = stabs_base_class.offset;
(*base_class)->set_access_specifier(stabs_field_visibility_to_access_specifier(stabs_base_class.visibility), state.importer_flags);
if(stabs_base_class.is_virtual) {
(*base_class)->is_virtual_base_class = true;
}
struct_or_union->base_classes.emplace_back(std::move(*base_class));
}
AST_DEBUG_PRINTF("%-*s beginfields\n", depth * 4, "");
for(const StabsStructOrUnionType::Field& field : stabs_struct_or_union->fields) {
auto node = field_to_ast(field, type, state, depth);
CCC_RETURN_IF_ERROR(node);
struct_or_union->fields.emplace_back(std::move(*node));
}
AST_DEBUG_PRINTF("%-*s endfields\n", depth * 4, "");
AST_DEBUG_PRINTF("%-*s beginmemberfuncs\n", depth * 4, "");
Result<std::vector<std::unique_ptr<ast::Node>>> member_functions =
member_functions_to_ast(*stabs_struct_or_union, state, depth);
CCC_RETURN_IF_ERROR(member_functions);
struct_or_union->member_functions = std::move(*member_functions);
AST_DEBUG_PRINTF("%-*s endmemberfuncs\n", depth * 4, "");
result = std::move(struct_or_union);
break;
}
case StabsTypeDescriptor::CROSS_REFERENCE: {
const auto& cross_reference = type.as<StabsCrossReferenceType>();
auto type_name = std::make_unique<ast::TypeName>();
type_name->source = ast::TypeNameSource::CROSS_REFERENCE;
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
type_name->unresolved_stabs->type_name = cross_reference.identifier;
type_name->unresolved_stabs->type = cross_reference.type;
result = std::move(type_name);
break;
}
case ccc::StabsTypeDescriptor::FLOATING_POINT_BUILTIN: {
const auto& fp_builtin = type.as<StabsFloatingPointBuiltInType>();
auto builtin = std::make_unique<ast::BuiltIn>();
switch(fp_builtin.bytes) {
case 1: builtin->bclass = ast::BuiltInClass::UNSIGNED_8; break;
case 2: builtin->bclass = ast::BuiltInClass::UNSIGNED_16; break;
case 4: builtin->bclass = ast::BuiltInClass::UNSIGNED_32; break;
case 8: builtin->bclass = ast::BuiltInClass::UNSIGNED_64; break;
case 16: builtin->bclass = ast::BuiltInClass::UNSIGNED_128; break;
default: builtin->bclass = ast::BuiltInClass::UNSIGNED_8; break;
}
result = std::move(builtin);
break;
}
case StabsTypeDescriptor::METHOD: {
const auto& stabs_method = type.as<StabsMethodType>();
auto function = std::make_unique<ast::Function>();
auto return_node = stabs_type_to_ast(
*stabs_method.return_type.get(),
enclosing_struct,
state,
depth + 1,
true,
true);
CCC_RETURN_IF_ERROR(return_node);
function->return_type = std::move(*return_node);
function->parameters.emplace();
for(const std::unique_ptr<StabsType>& parameter_type : stabs_method.parameter_types) {
auto parameter_node = stabs_type_to_ast(
*parameter_type,
enclosing_struct,
state,
depth + 1,
true,
true);
CCC_RETURN_IF_ERROR(parameter_node);
function->parameters->emplace_back(std::move(*parameter_node));
}
result = std::move(function);
break;
}
case StabsTypeDescriptor::POINTER: {
auto pointer = std::make_unique<ast::PointerOrReference>();
pointer->is_pointer = true;
auto value_node = stabs_type_to_ast(
*type.as<StabsPointerType>().value_type,
enclosing_struct,
state,
depth + 1,
true,
force_substitute);
CCC_RETURN_IF_ERROR(value_node);
pointer->value_type = std::move(*value_node);
result = std::move(pointer);
break;
}
case StabsTypeDescriptor::REFERENCE: {
auto reference = std::make_unique<ast::PointerOrReference>();
reference->is_pointer = false;
auto value_node = stabs_type_to_ast(
*type.as<StabsReferenceType>().value_type,
enclosing_struct,
state,
depth + 1,
true,
force_substitute);
CCC_RETURN_IF_ERROR(value_node);
reference->value_type = std::move(*value_node);
result = std::move(reference);
break;
}
case StabsTypeDescriptor::TYPE_ATTRIBUTE: {
const auto& stabs_type_attribute = type.as<StabsSizeTypeAttributeType>();
auto node = stabs_type_to_ast(
*stabs_type_attribute.type,
enclosing_struct,
state,
depth + 1,
substitute_type_name,
force_substitute);
CCC_RETURN_IF_ERROR(node);
result = std::move(*node);
result->size_bits = (s32) stabs_type_attribute.size_bits;
break;
}
case StabsTypeDescriptor::POINTER_TO_DATA_MEMBER: {
const auto& stabs_member_pointer = type.as<StabsPointerToDataMemberType>();
auto member_pointer = std::make_unique<ast::PointerToDataMember>();
auto class_node = stabs_type_to_ast(
*stabs_member_pointer.class_type.get(),
enclosing_struct,
state,
depth + 1,
true,
true);
CCC_RETURN_IF_ERROR(class_node);
member_pointer->class_type = std::move(*class_node);
auto member_node = stabs_type_to_ast(
*stabs_member_pointer.member_type.get(),
enclosing_struct,
state,
depth + 1,
true,
true);
CCC_RETURN_IF_ERROR(member_node);
member_pointer->member_type = std::move(*member_node);
result = std::move(member_pointer);
break;
}
case StabsTypeDescriptor::BUILTIN: {
CCC_CHECK(type.as<StabsBuiltInType>().type_id == 16,
"Unknown built-in type!");
auto builtin = std::make_unique<ast::BuiltIn>();
builtin->bclass = ast::BuiltInClass::BOOL_8;
result = std::move(builtin);
break;
}
}
CCC_CHECK(result, "Result of stabs_type_to_ast call is nullptr.");
return result;
}
static bool is_void_like(const StabsType& type)
{
// Unfortunately, a common case seems to be that various types (most
// commonly __builtin_va_list) are indistinguishable from void or void*, so
// we have to output them as a void built-in.
if(type.descriptor.has_value()) {
switch(*type.descriptor) {
case StabsTypeDescriptor::POINTER: {
return is_void_like(*type.as<StabsPointerType>().value_type.get());
}
case StabsTypeDescriptor::TYPE_REFERENCE: {
return type.as<StabsTypeReferenceType>().type->type_number == type.type_number;
}
default: {
break;
}
}
}
return false;
}
static Result<ast::BuiltInClass> classify_range(const StabsRangeType& type)
{
const char* low = type.low.c_str();
const char* high = type.high.c_str();
// Handle some special cases and values that are too large to easily store
// in a 64-bit integer.
static const struct { const char* low; const char* high; ast::BuiltInClass classification; } strings[] = {
{"4", "0", ast::BuiltInClass::FLOAT_32},
{"000000000000000000000000", "001777777777777777777777", ast::BuiltInClass::UNSIGNED_64},
{"00000000000000000000000000000000000000000000", "00000000000000000000001777777777777777777777", ast::BuiltInClass::UNSIGNED_64},
{"0000000000000", "01777777777777777777777", ast::BuiltInClass::UNSIGNED_64}, // IOP
{"0", "18446744073709551615", ast::BuiltInClass::UNSIGNED_64},
{"001000000000000000000000", "000777777777777777777777", ast::BuiltInClass::SIGNED_64},
{"00000000000000000000001000000000000000000000", "00000000000000000000000777777777777777777777", ast::BuiltInClass::SIGNED_64},
{"01000000000000000000000", "0777777777777777777777", ast::BuiltInClass::SIGNED_64}, // IOP
{"-9223372036854775808", "9223372036854775807", ast::BuiltInClass::SIGNED_64},
{"8", "0", ast::BuiltInClass::FLOAT_64},
{"00000000000000000000000000000000000000000000", "03777777777777777777777777777777777777777777", ast::BuiltInClass::UNSIGNED_128},
{"02000000000000000000000000000000000000000000", "01777777777777777777777777777777777777777777", ast::BuiltInClass::SIGNED_128},
{"000000000000000000000000", "0377777777777777777777777777777777", ast::BuiltInClass::UNQUALIFIED_128},
{"16", "0", ast::BuiltInClass::FLOAT_128},
{"0", "-1", ast::BuiltInClass::UNQUALIFIED_128} // Old homebrew toolchain
};
for(const auto& range : strings) {
if(strcmp(range.low, low) == 0 && strcmp(range.high, high) == 0) {
return range.classification;
}
}
// For smaller values we actually parse the bounds as integers.
char* end = nullptr;
s64 low_value = strtoll(type.low.c_str(), &end, low[0] == '0' ? 8 : 10);
CCC_CHECK(end != low, "Failed to parse low part of range as integer.");
s64 high_value = strtoll(type.high.c_str(), &end, high[0] == '0' ? 8 : 10);
CCC_CHECK(end != high, "Failed to parse high part of range as integer.");
static const struct { s64 low; s64 high; ast::BuiltInClass classification; } integers[] = {
{0, 255, ast::BuiltInClass::UNSIGNED_8},
{-128, 127, ast::BuiltInClass::SIGNED_8},
{0, 127, ast::BuiltInClass::UNQUALIFIED_8},
{0, 65535, ast::BuiltInClass::UNSIGNED_16},
{-32768, 32767, ast::BuiltInClass::SIGNED_16},
{0, 4294967295, ast::BuiltInClass::UNSIGNED_32},
{-2147483648, 2147483647, ast::BuiltInClass::SIGNED_32},
};
for(const auto& range : integers) {
if((range.low == low_value || range.low == -low_value) && range.high == high_value) {
return range.classification;
}
}
return CCC_FAILURE("Failed to classify range.");
}
static Result<std::unique_ptr<ast::Node>> field_to_ast(
const StabsStructOrUnionType::Field& field,
const StabsType& enclosing_struct,
const StabsToAstState& state,
s32 depth)
{
AST_DEBUG_PRINTF("%-*s field %s\n", depth * 4, "", field.name.c_str());
Result<bool> is_bitfield = detect_bitfield(field, state);
CCC_RETURN_IF_ERROR(is_bitfield);
if(*is_bitfield) {
// Process bitfields.
auto bitfield_node = stabs_type_to_ast(
*field.type,
&enclosing_struct,
state,
depth + 1,
true,
false);
CCC_RETURN_IF_ERROR(bitfield_node);
std::unique_ptr<ast::BitField> bitfield = std::make_unique<ast::BitField>();
bitfield->name = (field.name == " ") ? "" : field.name;
bitfield->offset_bytes = field.offset_bits / 8;
bitfield->size_bits = field.size_bits;
bitfield->underlying_type = std::move(*bitfield_node);
bitfield->bitfield_offset_bits = field.offset_bits % 8;
bitfield->set_access_specifier(stabs_field_visibility_to_access_specifier(field.visibility), state.importer_flags);
return std::unique_ptr<ast::Node>(std::move(bitfield));
} else {
// Process a normal field.
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(
*field.type,
&enclosing_struct,
state,
depth + 1,
true,
false);
CCC_RETURN_IF_ERROR(node);
(*node)->name = field.name;
(*node)->offset_bytes = field.offset_bits / 8;
(*node)->size_bits = field.size_bits;
(*node)->set_access_specifier(stabs_field_visibility_to_access_specifier(field.visibility), state.importer_flags);
if(field.name.starts_with("$vf") || field.name.starts_with("_vptr$") || field.name.starts_with("_vptr.")) {
(*node)->is_vtable_pointer = true;
}
if(field.is_static) {
(*node)->storage_class = STORAGE_CLASS_STATIC;
}
return node;
}
}
static Result<bool> detect_bitfield(const StabsStructOrUnionType::Field& field, const StabsToAstState& state)
{
// Static fields can't be bitfields.
if(field.is_static) {
return false;
}
// Resolve type references.
const StabsType* type = field.type.get();
for(s32 i = 0; i < 50; i++) {
if(!type->descriptor.has_value()) {
if(!type->type_number.valid()) {
return false;
}
auto next_type = state.stabs_types->find(type->type_number);
if(next_type == state.stabs_types->end() || next_type->second == type) {
return false;
}
type = next_type->second;
} else if(type->descriptor == StabsTypeDescriptor::TYPE_REFERENCE) {
type = type->as<StabsTypeReferenceType>().type.get();
} else if(type->descriptor == StabsTypeDescriptor::CONST_QUALIFIER) {
type = type->as<StabsConstQualifierType>().type.get();
} else if(type->descriptor == StabsTypeDescriptor::VOLATILE_QUALIFIER) {
type = type->as<StabsVolatileQualifierType>().type.get();
} else {
break;
}
// Prevent an infinite loop if there's a cycle (fatal frame).
if(i == 49) {
return false;
}
}
// Determine the size of the underlying type.
s32 underlying_type_size_bits = 0;
switch(*type->descriptor) {
case ccc::StabsTypeDescriptor::RANGE: {
Result<ast::BuiltInClass> bclass = classify_range(type->as<StabsRangeType>());
CCC_RETURN_IF_ERROR(bclass);
underlying_type_size_bits = builtin_class_size(*bclass) * 8;
break;
}
case ccc::StabsTypeDescriptor::CROSS_REFERENCE: {
if(type->as<StabsCrossReferenceType>().type == ast::ForwardDeclaredType::ENUM) {
underlying_type_size_bits = 32;
} else {
return false;
}
break;
}
case ccc::StabsTypeDescriptor::TYPE_ATTRIBUTE: {
underlying_type_size_bits = (s32) type->as<StabsSizeTypeAttributeType>().size_bits;
break;
}
case ccc::StabsTypeDescriptor::BUILTIN: {
underlying_type_size_bits = 8; // bool
break;
}
default: {
return false;
}
}
if(underlying_type_size_bits == 0) {
return false;
}
return field.size_bits != underlying_type_size_bits;
}
static Result<std::vector<std::unique_ptr<ast::Node>>> member_functions_to_ast(
const StabsStructOrUnionType& type, const StabsToAstState& state, s32 depth)
{
if(state.importer_flags & NO_MEMBER_FUNCTIONS) {
return std::vector<std::unique_ptr<ast::Node>>();
}
std::string_view type_name_no_template_args;
if(type.name.has_value()) {
type_name_no_template_args =
std::string_view(*type.name).substr(0, type.name->find("<"));
}
std::vector<std::unique_ptr<ast::Node>> member_functions;
bool only_special_functions = true;
for(const StabsStructOrUnionType::MemberFunctionSet& function_set : type.member_functions) {
MemberFunctionInfo info = check_member_function(
function_set.name, type_name_no_template_args, state.demangler, state.importer_flags);
if(!info.is_special_member_function) {
only_special_functions = false;
}
for(const StabsStructOrUnionType::MemberFunction& stabs_func : function_set.overloads) {
auto node = stabs_type_to_ast(
*stabs_func.type,
&type,
state,
depth + 1,
true,
true);
CCC_RETURN_IF_ERROR(node);
(*node)->is_constructor_or_destructor = info.is_constructor_or_destructor;
(*node)->is_special_member_function = info.is_special_member_function;
(*node)->is_operator_member_function = info.is_operator_member_function;
(*node)->name = info.name;
(*node)->set_access_specifier(stabs_field_visibility_to_access_specifier(stabs_func.visibility), state.importer_flags);
if((*node)->descriptor == ast::FUNCTION) {
ast::Function& function = (*node)->as<ast::Function>();
function.modifier = stabs_func.modifier;
function.vtable_index = stabs_func.vtable_index;
}
member_functions.emplace_back(std::move(*node));
}
}
if(only_special_functions && (state.importer_flags & INCLUDE_GENERATED_MEMBER_FUNCTIONS) == 0) {
return std::vector<std::unique_ptr<ast::Node>>();
}
return member_functions;
}
static MemberFunctionInfo check_member_function(
const std::string& mangled_name,
std::string_view type_name_no_template_args,
const DemanglerFunctions& demangler,
u32 importer_flags)
{
MemberFunctionInfo info;
// Some compiler versions output gcc opnames for overloaded operators
// instead of their proper names.
if((importer_flags & DONT_DEMANGLE_NAMES) == 0 && demangler.cplus_demangle_opname) {
char* demangled_name = demangler.cplus_demangle_opname(mangled_name.c_str(), 0);
if(demangled_name) {
info.name = demangled_name;
free(reinterpret_cast<void*>(demangled_name));
}
}
if(info.name.empty()) {
info.name = mangled_name;
}
bool is_constructor =
info.name == "__ct" || // Takes a parameter to decide whether or not to construct virtual base classes.
info.name == "__comp_ctor" || // Constructs virtual base classes.
info.name == "__base_ctor"; // Does not construct virtual base classes.
if(!is_constructor && !type_name_no_template_args.empty()) {
is_constructor |= info.name == type_name_no_template_args; // Named constructor.
}
bool is_destructor =
info.name == "__dt" || // Takes parameters to decide whether or not to construct virtual base classes and/or delete the object.
info.name == "__comp_dtor" || // Destructs virtual base classes.
info.name == "__base_dtor" || // Does not construct virtual base classes.
info.name == "__deleting_dtor"; // Destructs virtual base clases then deletes the entire object.
if(!is_destructor && !info.name.empty()) {
is_destructor |= info.name[0] == '~' && std::string_view(info.name).substr(1) == type_name_no_template_args; // Named destructor.
}
info.is_constructor_or_destructor = is_constructor || is_destructor || info.name.starts_with("$_");
info.is_special_member_function = info.is_constructor_or_destructor || info.name == "operator=";
return info;
}
void fix_recursively_emitted_structures(
ast::StructOrUnion& outer_struct, const std::string& name, StabsTypeNumber type_number, SourceFileHandle file_handle)
{
// This is a rather peculiar case. For some compiler versions, when a struct
// or a union defined using a typedef is being emitted and it needs to
// reference itself from a member function parameter, it will emit its
// entire definition again in the middle of the first definition, although
// thankfully it won't recurse more than once.
//
// The game Sega Soccer Slam is affected by this. See the PeculiarParameter
// test case in mdebug_importer_tests.cpp for a bare bones example.
for(std::unique_ptr<ast::Node>& node : outer_struct.member_functions) {
if(node->descriptor != ast::FUNCTION) {
continue;
}
ast::Function& function = node->as<ast::Function>();
if(!function.parameters.has_value()) {
continue;
}
for(std::unique_ptr<ast::Node>& parameter : *function.parameters) {
if(parameter->descriptor != ast::POINTER_OR_REFERENCE) {
continue;
}
ast::PointerOrReference& pointer_or_reference = parameter->as<ast::PointerOrReference>();
if(pointer_or_reference.value_type->descriptor != ast::STRUCT_OR_UNION) {
continue;
}
ast::StructOrUnion& inner_struct = pointer_or_reference.value_type->as<ast::StructOrUnion>();
// Since C++ doesn't allow struct definitions in function parameter
// lists normally, and most of the time the member function
// parameters aren't even filled in by GCC, this is a really rare
// case, so here we only bother to do some very basic checks to
// verify that the inner struct is similar to the outer struct.
if(inner_struct.base_classes.size() != outer_struct.base_classes.size()) {
continue;
}
if(inner_struct.fields.size() != outer_struct.fields.size()) {
continue;
}
if(inner_struct.member_functions.size() != outer_struct.member_functions.size()) {
continue;
}
auto type_name = std::make_unique<ast::TypeName>();
type_name->source = ast::TypeNameSource::REFERENCE;
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
type_name->unresolved_stabs->type_name = name;
type_name->unresolved_stabs->referenced_file_handle = file_handle;
type_name->unresolved_stabs->stabs_type_number = type_number;
pointer_or_reference.value_type = std::move(type_name);
}
}
}
ast::AccessSpecifier stabs_field_visibility_to_access_specifier(StabsStructOrUnionType::Visibility visibility)
{
ast::AccessSpecifier access_specifier = ast::AS_PUBLIC;
switch(visibility) {
case StabsStructOrUnionType::Visibility::NONE: access_specifier = ast::AS_PUBLIC; break;
case StabsStructOrUnionType::Visibility::PUBLIC: access_specifier = ast::AS_PUBLIC; break;
case StabsStructOrUnionType::Visibility::PROTECTED: access_specifier = ast::AS_PROTECTED; break;
case StabsStructOrUnionType::Visibility::PRIVATE: access_specifier = ast::AS_PRIVATE; break;
case StabsStructOrUnionType::Visibility::PUBLIC_OPTIMIZED_OUT: access_specifier = ast::AS_PUBLIC; break;
}
return access_specifier;
}
}

29
3rdparty/ccc/src/ccc/stabs_to_ast.h vendored Normal file
View File

@@ -0,0 +1,29 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "ast.h"
#include "stabs.h"
namespace ccc {
struct StabsToAstState {
u32 file_handle;
std::map<StabsTypeNumber, const StabsType*>* stabs_types;
u32 importer_flags;
DemanglerFunctions demangler;
};
Result<std::unique_ptr<ast::Node>> stabs_type_to_ast(
const StabsType& type,
const StabsType* enclosing_struct,
const StabsToAstState& state,
s32 depth,
bool substitute_type_name,
bool force_substitute);
void fix_recursively_emitted_structures(
ast::StructOrUnion& outer_struct, const std::string& name, StabsTypeNumber type_number, SourceFileHandle file_handle);
ast::AccessSpecifier stabs_field_visibility_to_access_specifier(StabsStructOrUnionType::Visibility visibility);
}

1204
3rdparty/ccc/src/ccc/symbol_database.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

721
3rdparty/ccc/src/ccc/symbol_database.h vendored Normal file
View File

@@ -0,0 +1,721 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include <map>
#include <atomic>
#include <variant>
#include "util.h"
namespace ccc {
// An X macro for all the symbol types.
#define CCC_FOR_EACH_SYMBOL_TYPE_DO_X \
CCC_X(DataType, data_types) \
CCC_X(Function, functions) \
CCC_X(GlobalVariable, global_variables) \
CCC_X(Label, labels) \
CCC_X(LocalVariable, local_variables) \
CCC_X(Module, modules) \
CCC_X(ParameterVariable, parameter_variables) \
CCC_X(Section, sections) \
CCC_X(SourceFile, source_files) \
CCC_X(SymbolSource, symbol_sources)
// An enum for all the symbol types.
enum SymbolDescriptor {
DATA_TYPE = 1 << 0,
FUNCTION = 1 << 1,
GLOBAL_VARIABLE = 1 << 2,
LABEL = 1 << 3,
LOCAL_VARIABLE = 1 << 4,
MODULE = 1 << 5,
PARAMETER_VARIABLE = 1 << 6,
SECTION = 1 << 7,
SOURCE_FILE = 1 << 8,
SYMBOL_SOURCE = 1 << 9
};
enum {
ALL_SYMBOL_TYPES = 0xffff
};
// Forward declare all the different types of symbol objects.
#define CCC_X(SymbolType, symbol_list) class SymbolType;
CCC_FOR_EACH_SYMBOL_TYPE_DO_X
#undef CCC_X
class SymbolDatabase;
// Strongly typed handles for all of the symbol objects. These are here to solve
// the problem of dangling references to symbols.
template <typename SymbolType>
struct SymbolHandle {
u32 value = (u32) -1;
SymbolHandle() {}
SymbolHandle(u32 v) : value(v) {}
SymbolHandle(const SymbolType* symbol)
: value(symbol ? symbol->handle().value : (u32) -1) {}
// Check if this symbol handle has been initialised. Note that this doesn't
// determine whether or not the symbol it points to has been deleted!
bool valid() const { return value != (u32) -1; }
friend auto operator<=>(const SymbolHandle& lhs, const SymbolHandle& rhs) = default;
};
#define CCC_X(SymbolType, symbol_list) using SymbolType##Handle = SymbolHandle<SymbolType>;
CCC_FOR_EACH_SYMBOL_TYPE_DO_X
#undef CCC_X
enum SymbolFlag {
NO_SYMBOL_FLAGS = 0,
WITH_ADDRESS_MAP = 1 << 0,
WITH_NAME_MAP = 1 << 1,
NAME_NEEDS_DEMANGLING = 1 << 2
};
// A container class for symbols of a given type that maintains maps of their
// names and addresses depending on the value of SymbolType::FLAGS.
template <typename SymbolType>
class SymbolList {
public:
// Lookup symbols from their handles using binary search.
SymbolType* symbol_from_handle(SymbolHandle<SymbolType> handle);
const SymbolType* symbol_from_handle(SymbolHandle<SymbolType> handle) const;
// Lookup multiple symbols from their handles using binary search.
std::vector<SymbolType*> symbols_from_handles(const std::vector<SymbolHandle<SymbolType>>& handles);
std::vector<const SymbolType*> symbols_from_handles(const std::vector<SymbolHandle<SymbolType>>& handles) const;
std::vector<SymbolType*> optional_symbols_from_handles(const std::optional<std::vector<SymbolHandle<SymbolType>>>& handles);
std::vector<const SymbolType*> optional_symbols_from_handles(const std::optional<std::vector<SymbolHandle<SymbolType>>>& handles) const;
using Iterator = typename std::vector<SymbolType>::iterator;
using ConstIterator = typename std::vector<SymbolType>::const_iterator;
// For iterating over all the symbols.
Iterator begin();
ConstIterator begin() const;
Iterator end();
ConstIterator end() const;
using AddressToHandleMap = std::multimap<u32, SymbolHandle<SymbolType>>;
using NameToHandleMap = std::multimap<std::string, SymbolHandle<SymbolType>>;
template <typename Iterator>
class Iterators {
public:
Iterators(Iterator b, Iterator e)
: m_begin(b), m_end(e) {}
Iterator begin() const { return m_begin; }
Iterator end() const { return m_end; }
protected:
Iterator m_begin;
Iterator m_end;
};
using AddressToHandleMapIterators = Iterators<typename AddressToHandleMap::const_iterator>;
using NameToHandleMapIterators = Iterators<typename NameToHandleMap::const_iterator>;
// Lookup symbols by their address.
AddressToHandleMapIterators handles_from_starting_address(Address address) const;
AddressToHandleMapIterators handles_from_address_range(AddressRange range) const;
SymbolHandle<SymbolType> first_handle_from_starting_address(Address address) const;
SymbolHandle<SymbolType> first_handle_after_address(Address address) const;
// Lookup symbols by their name.
NameToHandleMapIterators handles_from_name(const std::string& name) const;
SymbolHandle<SymbolType> first_handle_from_name(const std::string& name) const;
// Find a symbol with an address range that contains the provided address.
// For example, to find which function an instruction belongs to.
SymbolType* symbol_overlapping_address(Address address);
const SymbolType* symbol_overlapping_address(Address address) const;
// Convert handles to underlying array indices.
s32 index_from_handle(SymbolHandle<SymbolType> handle) const;
// Index into the underlying array.
SymbolType& symbol_from_index(s32 index);
const SymbolType& symbol_from_index(s32 index) const;
// Determine if any symbols are being stored.
bool empty() const;
// Retrieve the number of symbols stored.
s32 size() const;
// Create a new symbol. If it's a SymbolSource symbol, source can be left
// empty, otherwise it has to be valid.
Result<SymbolType*> create_symbol(
std::string name, Address address, SymbolSourceHandle source, const Module* module_symbol = nullptr);
// Create a new symbol. Similar to above, but for symbols without addresses.
Result<SymbolType*> create_symbol(
std::string name, SymbolSourceHandle source, const Module* module_symbol = nullptr);
// Create a new symbol. Similar to above, but unless DONT_DEMANGLE_NAMES is
// set, the name of the symbol will be demangled.
Result<SymbolType*> create_symbol(
std::string name,
SymbolSourceHandle source,
const Module* module_symbol,
Address address,
u32 importer_flags,
DemanglerFunctions demangler);
// Update the address of a symbol without changing its handle.
bool move_symbol(SymbolHandle<SymbolType> handle, Address new_address);
// Update the name of a symbol without changing its handle.
bool rename_symbol(SymbolHandle<SymbolType> handle, std::string new_name);
// Move all the symbols from the passed list into this list.
void merge_from(SymbolList<SymbolType>& list);
// Mark a symbol for destruction. If the correct symbol database pointer is
// passed, all descendants will also be marked. For example, marking a
// function will also mark its parameters and local variables.
bool mark_symbol_for_destruction(SymbolHandle<SymbolType> handle, SymbolDatabase* database);
// Mark all the symbols from a given symbol source for destruction. For
// example you can use this to free a symbol table without destroying
// user-defined symbols. The behaviour for marking descendants is the same
// as destroy_symbol.
void mark_symbols_from_source_for_destruction(SymbolSourceHandle source, SymbolDatabase* database);
// Mark all the symbols from a given module for destruction. The behaviour
// for marking descendants is the same as destroy_symbol.
void mark_symbols_from_module_for_destruction(ModuleHandle module_handle, SymbolDatabase* database);
// Destroy all symbols that have previously been marked for destruction.
// This invalidates all pointers to symbols in this list.
void destroy_marked_symbols();
// Destroy all symbols, but don't reset m_next_handle so we don't have to
// worry about dangling handles.
void clear();
protected:
// Do a binary search for a handle, and return either its index, or the
// index where it could be inserted.
size_t binary_search(SymbolHandle<SymbolType> handle) const;
// Keep the address map in sync with the symbol list.
void link_address_map(SymbolType& symbol);
void unlink_address_map(SymbolType& symbol);
// Keep the name map in sync with the symbol list.
void link_name_map(SymbolType& symbol);
void unlink_name_map(SymbolType& symbol);
std::vector<SymbolType> m_symbols;
AddressToHandleMap m_address_to_handle;
NameToHandleMap m_name_to_handle;
// We share this between symbol lists of the same type so that we can merge
// them without having to rewrite all the handles.
static std::atomic<u32> m_next_handle;
};
// Base class for all the symbols.
class Symbol {
template <typename SymbolType>
friend class SymbolList;
public:
const std::string& name() const { return m_name; }
u32 raw_handle() const { return m_handle; }
SymbolSourceHandle source() const { return m_source; }
ModuleHandle module_handle() const { return m_module; }
Address address() const { return m_address; }
u32 size() const { return m_size; }
void set_size(u32 size) { m_size = size; }
AddressRange address_range() const { return AddressRange(m_address, m_address.get_or_zero() + m_size); }
ast::Node* type() { return m_type.get(); }
const ast::Node* type() const { return m_type.get(); }
void set_type(std::unique_ptr<ast::Node> type);
u32 generation() const { return m_generation; }
// This MUST be called after any AST nodes have been created/deleted/moved.
// For the set_type function this is done for you.
void invalidate_node_handles() { m_generation++; }
// Mark a single symbol for destruction, not including its descendants.
void mark_for_destruction() { m_marked_for_destruction = true; }
bool is_marked_for_destruction() { return m_marked_for_destruction; }
protected:
void on_create() {}
void on_destroy(SymbolDatabase* database) {}
u32 m_handle = (u32) -1;
SymbolSourceHandle m_source;
Address m_address;
u32 m_size = 0;
std::string m_name;
std::unique_ptr<ast::Node> m_type;
u32 m_generation : 31 = 0;
u32 m_marked_for_destruction : 1 = false;
ModuleHandle m_module;
};
// Variable storage types. This is different to whether the variable is a
// global, local or parameter. For example local variables can have global
// storage (static locals).
enum GlobalStorageLocation {
NIL,
DATA,
BSS,
ABS,
SDATA,
SBSS,
RDATA,
COMMON,
SCOMMON,
SUNDEFINED
};
const char* global_storage_location_to_string(GlobalStorageLocation location);
struct GlobalStorage {
GlobalStorageLocation location = GlobalStorageLocation::NIL;
GlobalStorage() {}
friend auto operator<=>(const GlobalStorage& lhs, const GlobalStorage& rhs) = default;
};
struct RegisterStorage {
s32 dbx_register_number = -1;
bool is_by_reference;
RegisterStorage() {}
friend auto operator<=>(const RegisterStorage& lhs, const RegisterStorage& rhs) = default;
};
struct StackStorage {
s32 stack_pointer_offset = -1;
StackStorage() {}
friend auto operator<=>(const StackStorage& lhs, const StackStorage& rhs) = default;
};
// The hashing algorithm for functions. If you change this algorithm make sure
// to bump the version number for the JSON format so we can know if a hash was
// generated using the new algorithm or not.
class FunctionHash {
public:
void update(u32 instruction)
{
// Separate out the opcode so that the hash remains the same regardless
// of if relocations are applied or not.
u32 opcode = instruction >> 26;
m_hash = m_hash * 31 + opcode;
}
u32 get() const
{
return m_hash;
}
protected:
u32 m_hash = 0;
};
// All the different types of symbol objects.
// A C/C++ data type.
class DataType : public Symbol {
friend SourceFile;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = DATA_TYPE;
static constexpr const char* NAME = "Data Type";
static constexpr const u32 FLAGS = WITH_NAME_MAP;
DataTypeHandle handle() const { return m_handle; }
std::vector<SourceFileHandle> files; // List of files for which a given top-level type is present.
const char* compare_fail_reason = nullptr;
bool not_defined_in_any_translation_unit : 1 = false;
bool only_defined_in_single_translation_unit : 1 = false;
};
// A function. The type stored is the return type.
class Function : public Symbol {
friend SourceFile;
friend SymbolList<Function>;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = FUNCTION;
static constexpr const char* NAME = "Function";
static constexpr const u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP | NAME_NEEDS_DEMANGLING;
FunctionHandle handle() const { return m_handle; }
SourceFileHandle source_file() const { return m_source_file; }
const std::optional<std::vector<ParameterVariableHandle>>& parameter_variables() const;
void set_parameter_variables(std::optional<std::vector<ParameterVariableHandle>> parameter_variables, SymbolDatabase& database);
const std::optional<std::vector<LocalVariableHandle>>& local_variables() const;
void set_local_variables(std::optional<std::vector<LocalVariableHandle>> local_variables, SymbolDatabase& database);
const std::string& mangled_name() const;
void set_mangled_name(std::string mangled);
// A hash of all the opcodes in the function, read from file.
u32 original_hash() const;
void set_original_hash(u32 hash);
// A hash of all the opcodes in the function, read from memory.
u32 current_hash() const;
void set_current_hash(FunctionHash hash);
struct LineNumberPair {
Address address;
s32 line_number;
};
struct SubSourceFile {
Address address;
std::string relative_path;
};
std::string relative_path;
StorageClass storage_class;
s32 stack_frame_size = -1;
std::vector<LineNumberPair> line_numbers;
std::vector<SubSourceFile> sub_source_files;
bool is_member_function_ish = false; // Filled in by fill_in_pointers_to_member_function_definitions.
bool is_no_return = false;
protected:
void on_destroy(SymbolDatabase* database);
SourceFileHandle m_source_file;
std::optional<std::vector<ParameterVariableHandle>> m_parameter_variables;
std::optional<std::vector<LocalVariableHandle>> m_local_variables;
std::string m_mangled_name;
u32 m_original_hash = 0;
u32 m_current_hash = 0;
};
// A global variable.
class GlobalVariable : public Symbol {
friend SourceFile;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = GLOBAL_VARIABLE;
static constexpr const char* NAME = "Global Variable";
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP | NAME_NEEDS_DEMANGLING;
GlobalVariableHandle handle() const { return m_handle; }
SourceFileHandle source_file() const { return m_source_file; };
const std::string& mangled_name() const;
void set_mangled_name(std::string mangled);
GlobalStorage storage;
StorageClass storage_class;
protected:
SourceFileHandle m_source_file;
std::string m_mangled_name;
};
// A label. This could be a label defined in assembly, C/C++, or just a symbol
// that we can't automatically determine the type of (e.g. SNDLL symbols).
class Label : public Symbol {
public:
static constexpr const SymbolDescriptor DESCRIPTOR = LABEL;
static constexpr const char* NAME = "Label";
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP;
LabelHandle handle() const { return m_handle; }
// Indicates that this label should not be used as a function name.
bool is_junk = false;
};
// A local variable. This includes static local variables which have global
// storage.
class LocalVariable : public Symbol {
friend Function;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = LOCAL_VARIABLE;
static constexpr const char* NAME = "Local Variable";
static constexpr u32 FLAGS = WITH_ADDRESS_MAP;
LocalVariableHandle handle() const { return m_handle; }
FunctionHandle function() const { return m_function; };
std::variant<GlobalStorage, RegisterStorage, StackStorage> storage;
AddressRange live_range;
protected:
FunctionHandle m_function;
};
// A program module e.g. an ELF file or an SNDLL file. Every symbol has a module
// field indicating what module the symbol belongs to. This can be used to
// delete all the symbols associated with a given module. Additionally, when a
// valid module pointer is passed to SymbolList<>::create_symbol, the address of
// the symbol will be added to the address of the new symbol.
class Module : public Symbol {
friend SymbolList<Module>;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = MODULE;
static constexpr const char* NAME = "Module";
static constexpr u32 FLAGS = WITH_NAME_MAP;
ModuleHandle handle() const { return m_handle; }
// These are used for IRX modules.
bool is_irx = false;
s32 version_major = -1;
s32 version_minor = -1;
protected:
void on_create();
};
// A parameter variable.
class ParameterVariable : public Symbol {
friend Function;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = PARAMETER_VARIABLE;
static constexpr const char* NAME = "Parameter Variable";
static constexpr u32 FLAGS = NO_SYMBOL_FLAGS;
ParameterVariableHandle handle() const { return m_handle; }
FunctionHandle function() const { return m_function; };
std::variant<RegisterStorage, StackStorage> storage;
protected:
FunctionHandle m_function;
};
// An ELF section. These are created from the ELF section headers.
class Section : public Symbol {
public:
static constexpr const SymbolDescriptor DESCRIPTOR = SECTION;
static constexpr const char* NAME = "Section";
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP;
SectionHandle handle() const { return m_handle; }
// Check if the section name is ".text".
bool contains_code() const;
// Check for known data section names.
bool contains_data() const;
};
// A source file (.c or .cpp file). One of these will be created for every
// translation unit in the program (but only if debugging symbols are present).
class SourceFile : public Symbol {
friend SymbolList<SourceFile>;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = SOURCE_FILE;
static constexpr const char* NAME = "Source File";
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP;
SourceFileHandle handle() const { return m_handle; }
const std::string& full_path() const { return name(); }
const std::vector<FunctionHandle>& functions() const;
void set_functions(std::vector<FunctionHandle> functions, SymbolDatabase& database);
const std::vector<GlobalVariableHandle>& global_variables() const;
void set_global_variables(std::vector<GlobalVariableHandle> global_variables, SymbolDatabase& database);
// Check whether at least half of the functions associated with the source
// file match their original hash (meaning they haven't been overwritten).
bool functions_match() const;
void check_functions_match(const SymbolDatabase& database);
std::string working_dir;
std::string command_line_path;
std::map<StabsTypeNumber, DataTypeHandle> stabs_type_number_to_handle;
std::set<std::string> toolchain_version_info;
protected:
void on_destroy(SymbolDatabase* database);
std::vector<FunctionHandle> m_functions;
std::vector<GlobalVariableHandle> m_global_variables;
bool m_functions_match = true;
};
// A symbol source. Every symbol has a symbol source field indicating how the
// symbol was created. For example, the symbol table importers will each create
// one of these (if it doesn't already exist).
class SymbolSource : public Symbol {
friend SymbolList<SymbolSource>;
public:
static constexpr const SymbolDescriptor DESCRIPTOR = SYMBOL_SOURCE;
static constexpr const char* NAME = "Symbol Source";
static constexpr u32 FLAGS = WITH_NAME_MAP;
SymbolSourceHandle handle() const { return m_handle; }
protected:
void on_create();
};
// Bundles together all the information needed to identify if a symbol came from
// a specific symbol table import operation. For example, this is used to make
// sure that we don't reference symbols from another symbol table during the
// import process.
struct SymbolGroup {
SymbolSourceHandle source;
Module* module_symbol = nullptr;
bool is_in_group(const Symbol& symbol) const;
};
// The symbol database itself. This owns all the symbols.
class SymbolDatabase {
public:
SymbolList<DataType> data_types;
SymbolList<Function> functions;
SymbolList<GlobalVariable> global_variables;
SymbolList<Label> labels;
SymbolList<LocalVariable> local_variables;
SymbolList<Module> modules;
SymbolList<ParameterVariable> parameter_variables;
SymbolList<Section> sections;
SymbolList<SourceFile> source_files;
SymbolList<SymbolSource> symbol_sources;
// Sum up the symbol counts for each symbol list.
s32 symbol_count() const;
// Find a symbol of any of the specified types given an address. Symbols of
// the types specified higher up in the CCC_FOR_EACH_SYMBOL_TYPE_DO_X macro
// are checked for first.
const Symbol* symbol_starting_at_address(
Address address, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
const Symbol* symbol_after_address(
Address address, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
const Symbol* symbol_overlapping_address(
Address address, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
// Find a symbol of any of the specified types given its name. Symbols of
// the types specified higher up in the CCC_FOR_EACH_SYMBOL_TYPE_DO_X macro
// are checked for first.
const Symbol* symbol_with_name(
const std::string& name, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
// Finds a symbol source object with the given name or creates one if it
// doesn't already exist.
Result<SymbolSourceHandle> get_symbol_source(const std::string& name);
// Deduplicate matching data types with the same name. May replace the
// existing data type with the new one if the new one is better.
Result<DataType*> create_data_type_if_unique(
std::unique_ptr<ast::Node> node,
StabsTypeNumber number,
const char* name,
SourceFile& source_file,
const SymbolGroup& group);
// Move all the symbols in the passed database into this database.
void merge_from(SymbolDatabase& database);
// Destroy all the symbols from a given symbol source. For example you can
// use this to free a symbol table without destroying user-defined symbols.
void destroy_symbols_from_source(SymbolSourceHandle source, bool destroy_descendants);
// Destroy all the symbols from a given module.
void destroy_symbols_from_module(ModuleHandle module_handle, bool destroy_descendants);
// Destroy all the symbols that have previously been marked for destruction.
// This invalidates all pointers to symbols in this database.
void destroy_marked_symbols();
// Destroy all the symbols in the symbol database.
void clear();
template <typename Callback>
void for_each_symbol(Callback callback) {
// Use indices here to avoid iterator invalidation.
#define CCC_X(SymbolType, symbol_list) \
for(s32 i = 0; i < symbol_list.size(); i++) { \
callback(symbol_list.symbol_from_index(i)); \
}
CCC_FOR_EACH_SYMBOL_TYPE_DO_X
#undef CCC_X
}
};
// A handle to a symbol of any type.
class MultiSymbolHandle {
public:
// Create an empty multi symbol handle.
MultiSymbolHandle();
// Create a multi symbol handle of the specified type.
template <typename SymbolType>
MultiSymbolHandle(const SymbolType& symbol);
MultiSymbolHandle(SymbolDescriptor descriptor, u32 handle);
bool valid() const;
SymbolDescriptor descriptor() const;
u32 handle() const;
Symbol* lookup_symbol(SymbolDatabase& database);
const Symbol* lookup_symbol(const SymbolDatabase& database) const;
bool is_flag_set(SymbolFlag flag) const;
bool move_symbol(Address new_address, SymbolDatabase& database) const;
bool rename_symbol(std::string new_name, SymbolDatabase& database) const;
bool destroy_symbol(SymbolDatabase& database, bool destroy_descendants) const;
friend auto operator<=>(const MultiSymbolHandle& lhs, const MultiSymbolHandle& rhs) = default;
protected:
SymbolDescriptor m_descriptor = DATA_TYPE;
u32 m_handle = (u32) -1;
};
// A handle to an AST node.
class NodeHandle {
friend SymbolDatabase;
public:
// Create an empty node handle.
NodeHandle();
// Create a node handle that will always allow accesses to its node. You
// should only use this if you know the lifetime of the handle is a subset
// of the lifetime of the node.
NodeHandle(const ast::Node* node);
// Create a node handle pointing to an AST node from a given symbol that
// will prevent accesses to the node if the symbol is deleted.
template <typename SymbolType>
NodeHandle(const SymbolType& symbol, const ast::Node* node);
NodeHandle(SymbolDescriptor descriptor, const Symbol& symbol, const ast::Node* node);
bool valid() const;
const MultiSymbolHandle& symbol() const;
const ast::Node* lookup_node(const SymbolDatabase& database) const;
NodeHandle handle_for_child(const ast::Node* child_node) const;
friend auto operator<=>(const NodeHandle& lhs, const NodeHandle& rhs) = default;
protected:
MultiSymbolHandle m_symbol;
const ast::Node* m_node = nullptr;
u32 m_generation = 0;
};
}

114
3rdparty/ccc/src/ccc/symbol_file.cpp vendored Normal file
View File

@@ -0,0 +1,114 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "symbol_file.h"
namespace ccc {
Result<std::unique_ptr<SymbolFile>> parse_symbol_file(std::vector<u8> image, std::string file_name)
{
const u32* magic = get_packed<u32>(image, 0);
CCC_CHECK(magic, "File too small.");
std::unique_ptr<SymbolFile> symbol_file;
switch(*magic) {
case CCC_FOURCC("\x7f""ELF"): {
Result<ElfFile> elf = ElfFile::parse(std::move(image));
CCC_RETURN_IF_ERROR(elf);
symbol_file = std::make_unique<ElfSymbolFile>(std::move(*elf), std::move(file_name));
break;
}
case CCC_FOURCC("SNR1"):
case CCC_FOURCC("SNR2"): {
Result<SNDLLFile> sndll = parse_sndll_file(image, Address(), SNDLLType::DYNAMIC_LIBRARY);
CCC_RETURN_IF_ERROR(sndll);
symbol_file = std::make_unique<SNDLLSymbolFile>(std::make_shared<SNDLLFile>(std::move(*sndll)));
break;
}
default: {
return CCC_FAILURE("Unknown file type.");
}
}
return symbol_file;
}
ElfSymbolFile::ElfSymbolFile(ElfFile elf, std::string elf_name)
: m_elf(std::move(elf)), m_name(std::move(elf_name)) {}
std::string ElfSymbolFile::name() const
{
return m_name;
}
Result<std::vector<std::unique_ptr<SymbolTable>>> ElfSymbolFile::get_all_symbol_tables() const
{
std::vector<std::unique_ptr<SymbolTable>> symbol_tables;
symbol_tables.emplace_back(std::make_unique<ElfSectionHeadersSymbolTable>(m_elf));
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
const SymbolTableFormatInfo& info = SYMBOL_TABLE_FORMATS[i];
const ElfSection* section = m_elf.lookup_section(info.section_name);
if(section) {
Result<std::unique_ptr<SymbolTable>> symbol_table = create_elf_symbol_table(*section, m_elf, info.format);
CCC_RETURN_IF_ERROR(symbol_table);
if(*symbol_table) {
symbol_tables.emplace_back(std::move(*symbol_table));
}
}
}
return symbol_tables;
}
Result<std::vector<std::unique_ptr<SymbolTable>>> ElfSymbolFile::get_symbol_tables_from_sections(
const std::vector<SymbolTableLocation>& sections) const
{
std::vector<std::unique_ptr<SymbolTable>> symbol_tables;
for(const SymbolTableLocation& location : sections) {
const ElfSection* section = m_elf.lookup_section(location.section_name.c_str());
CCC_CHECK(section, "No '%s' section.", location.section_name.c_str());
Result<std::unique_ptr<SymbolTable>> symbol_table = create_elf_symbol_table(*section, m_elf, location.format);
CCC_RETURN_IF_ERROR(symbol_table);
if(*symbol_table) {
symbol_tables.emplace_back(std::move(*symbol_table));
}
}
return symbol_tables;
}
const ElfFile& ElfSymbolFile::elf() const
{
return m_elf;
}
SNDLLSymbolFile::SNDLLSymbolFile(std::shared_ptr<SNDLLFile> sndll)
: m_sndll(std::move(sndll)) {}
std::string SNDLLSymbolFile::name() const
{
return m_sndll->elf_path;
}
Result<std::vector<std::unique_ptr<SymbolTable>>> SNDLLSymbolFile::get_all_symbol_tables() const
{
std::vector<std::unique_ptr<SymbolTable>> symbol_tables;
symbol_tables.emplace_back(std::make_unique<SNDLLSymbolTable>(m_sndll));
return symbol_tables;
}
Result<std::vector<std::unique_ptr<SymbolTable>>> SNDLLSymbolFile::get_symbol_tables_from_sections(
const std::vector<SymbolTableLocation>& sections) const
{
return CCC_FAILURE("An SNDLL file is not composed of sections.");
}
}

62
3rdparty/ccc/src/ccc/symbol_file.h vendored Normal file
View File

@@ -0,0 +1,62 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include "elf.h"
#include "sndll.h"
#include "symbol_table.h"
namespace ccc {
struct SymbolTableLocation {
std::string section_name;
SymbolTableFormat format;
};
class SymbolFile {
public:
virtual ~SymbolFile() {}
virtual std::string name() const = 0;
virtual Result<std::vector<std::unique_ptr<SymbolTable>>> get_all_symbol_tables() const = 0;
virtual Result<std::vector<std::unique_ptr<SymbolTable>>> get_symbol_tables_from_sections(
const std::vector<SymbolTableLocation>& sections) const = 0;
};
// Determine the type of the input file and parse it.
Result<std::unique_ptr<SymbolFile>> parse_symbol_file(std::vector<u8> image, std::string file_name);
class ElfSymbolFile : public SymbolFile {
public:
ElfSymbolFile(ElfFile elf, std::string elf_name);
std::string name() const override;
Result<std::vector<std::unique_ptr<SymbolTable>>> get_all_symbol_tables() const override;
Result<std::vector<std::unique_ptr<SymbolTable>>> get_symbol_tables_from_sections(
const std::vector<SymbolTableLocation>& sections) const override;
const ElfFile& elf() const;
protected:
ElfFile m_elf;
std::string m_name;
};
class SNDLLSymbolFile : public SymbolFile {
public:
SNDLLSymbolFile(std::shared_ptr<SNDLLFile> sndll);
std::string name() const override;
Result<std::vector<std::unique_ptr<SymbolTable>>> get_all_symbol_tables() const override;
Result<std::vector<std::unique_ptr<SymbolTable>>> get_symbol_tables_from_sections(
const std::vector<SymbolTableLocation>& sections) const override;
protected:
std::shared_ptr<SNDLLFile> m_sndll;
};
}

285
3rdparty/ccc/src/ccc/symbol_table.cpp vendored Normal file
View File

@@ -0,0 +1,285 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "symbol_table.h"
#include "elf.h"
#include "elf_symtab.h"
#include "mdebug_importer.h"
#include "mdebug_section.h"
#include "sndll.h"
namespace ccc {
const std::vector<SymbolTableFormatInfo> SYMBOL_TABLE_FORMATS = {
{MDEBUG, "mdebug", ".mdebug"}, // The infamous Third Eye symbol table.
{SYMTAB, "symtab", ".symtab"}, // The standard ELF symbol table.
{SNDLL, "sndll", ".sndata"} // The SNDLL symbol table.
};
const SymbolTableFormatInfo* symbol_table_format_from_enum(SymbolTableFormat format)
{
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
if(SYMBOL_TABLE_FORMATS[i].format == format) {
return &SYMBOL_TABLE_FORMATS[i];
}
}
return nullptr;
}
const SymbolTableFormatInfo* symbol_table_format_from_name(const char* format_name)
{
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
if(strcmp(SYMBOL_TABLE_FORMATS[i].format_name, format_name) == 0) {
return &SYMBOL_TABLE_FORMATS[i];
}
}
return nullptr;
}
const SymbolTableFormatInfo* symbol_table_format_from_section(const char* section_name)
{
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
if(strcmp(SYMBOL_TABLE_FORMATS[i].section_name, section_name) == 0) {
return &SYMBOL_TABLE_FORMATS[i];
}
}
return nullptr;
}
// *****************************************************************************
Result<std::unique_ptr<SymbolTable>> create_elf_symbol_table(
const ElfSection& section, const ElfFile& elf, SymbolTableFormat format)
{
std::unique_ptr<SymbolTable> symbol_table;
switch(format) {
case MDEBUG: {
symbol_table = std::make_unique<MdebugSymbolTable>(elf.image, (s32) section.header.offset);
break;
}
case SYMTAB: {
CCC_CHECK(section.header.offset + section.header.size <= elf.image.size(),
"Section '%s' out of range.", section.name.c_str());
std::span<const u8> data = std::span(elf.image).subspan(section.header.offset, section.header.size);
CCC_CHECK(section.header.link != 0, "Section '%s' has no linked string table.", section.name.c_str());
CCC_CHECK(section.header.link < elf.sections.size(),
"Section '%s' has out of range link field.", section.name.c_str());
const ElfSection& linked_section = elf.sections[section.header.link];
CCC_CHECK(linked_section.header.offset + linked_section.header.size <= elf.image.size(),
"Linked section '%s' out of range.", linked_section.name.c_str());
std::span<const u8> linked_data = std::span(elf.image).subspan(
linked_section.header.offset, linked_section.header.size);
symbol_table = std::make_unique<SymtabSymbolTable>(data, linked_data);
break;
}
case SNDLL: {
CCC_CHECK(section.header.offset + section.header.size <= elf.image.size(),
"Section '%s' out of range.", section.name.c_str());
std::span<const u8> data = std::span(elf.image).subspan(section.header.offset, section.header.size);
if(data.size() >= 4 && data[0] != '\0') {
Result<SNDLLFile> file = parse_sndll_file(data, Address::non_zero(section.header.addr), SNDLLType::SNDATA_SECTION);
CCC_RETURN_IF_ERROR(file);
symbol_table = std::make_unique<SNDLLSymbolTable>(std::make_shared<SNDLLFile>(std::move(*file)));
} else {
CCC_WARN("Invalid SNDLL section.");
}
break;
}
}
return symbol_table;
}
Result<ModuleHandle> import_symbol_tables(
SymbolDatabase& database,
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
std::string module_name,
Address base_address,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt)
{
Result<SymbolSourceHandle> module_source = database.get_symbol_source("Symbol Table Importer");
CCC_RETURN_IF_ERROR(module_source);
Result<Module*> module_symbol = database.modules.create_symbol(
std::move(module_name), base_address, *module_source, nullptr);
CCC_RETURN_IF_ERROR(module_symbol);
ModuleHandle module_handle = (*module_symbol)->handle();
for(const std::unique_ptr<SymbolTable>& symbol_table : symbol_tables) {
// Find a symbol source object with the right name, or create one if one
// doesn't already exist.
Result<SymbolSourceHandle> source = database.get_symbol_source(symbol_table->name());
if(!source.success()) {
database.destroy_symbols_from_module(module_handle, false);
return source;
}
// Import the symbol table.
SymbolGroup group;
group.source = *source;
group.module_symbol = database.modules.symbol_from_handle(module_handle);
Result<void> result = symbol_table->import(
database, group, importer_flags, demangler, interrupt);
if(!result.success()) {
database.destroy_symbols_from_module(module_handle, false);
return result;
}
}
return module_handle;
}
// *****************************************************************************
MdebugSymbolTable::MdebugSymbolTable(std::span<const u8> image, s32 section_offset)
: m_image(image), m_section_offset(section_offset) {}
const char* MdebugSymbolTable::name() const
{
return "MIPS Debug Symbol Table";
}
Result<void> MdebugSymbolTable::import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const
{
return mdebug::import_symbol_table(
database, m_image, m_section_offset, group, importer_flags, demangler, interrupt);
}
Result<void> MdebugSymbolTable::print_headers(FILE* out) const
{
mdebug::SymbolTableReader reader;
Result<void> reader_result = reader.init(m_image, m_section_offset);
CCC_RETURN_IF_ERROR(reader_result);
reader.print_header(out);
return Result<void>();
}
Result<void> MdebugSymbolTable::print_symbols(FILE* out, u32 flags) const
{
mdebug::SymbolTableReader reader;
Result<void> reader_result = reader.init(m_image, m_section_offset);
CCC_RETURN_IF_ERROR(reader_result);
Result<void> print_result = reader.print_symbols(
out, flags & PRINT_LOCALS, flags & PRINT_PROCEDURE_DESCRIPTORS, flags & PRINT_EXTERNALS);
CCC_RETURN_IF_ERROR(print_result);
return Result<void>();
}
// *****************************************************************************
SymtabSymbolTable::SymtabSymbolTable(std::span<const u8> symtab, std::span<const u8> strtab)
: m_symtab(symtab), m_strtab(strtab) {}
const char* SymtabSymbolTable::name() const
{
return "ELF Symbol Table";
}
Result<void> SymtabSymbolTable::import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const
{
return elf::import_symbols(database, group, m_symtab, m_strtab, importer_flags, demangler);
}
Result<void> SymtabSymbolTable::print_headers(FILE* out) const
{
return Result<void>();
}
Result<void> SymtabSymbolTable::print_symbols(FILE* out, u32 flags) const
{
Result<void> symbtab_result = elf::print_symbol_table(out, m_symtab, m_strtab);
CCC_RETURN_IF_ERROR(symbtab_result);
return Result<void>();
}
// *****************************************************************************
SNDLLSymbolTable::SNDLLSymbolTable(std::shared_ptr<SNDLLFile> sndll)
: m_sndll(std::move(sndll)) {}
const char* SNDLLSymbolTable::name() const
{
return "SNDLL Symbol Table";
}
Result<void> SNDLLSymbolTable::import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const
{
return import_sndll_symbols(database, *m_sndll, group, importer_flags, demangler);
}
Result<void> SNDLLSymbolTable::print_headers(FILE* out) const
{
return Result<void>();
}
Result<void> SNDLLSymbolTable::print_symbols(FILE* out, u32 flags) const
{
print_sndll_symbols(out, *m_sndll);
return Result<void>();
}
// *****************************************************************************
ElfSectionHeadersSymbolTable::ElfSectionHeadersSymbolTable(const ElfFile& elf)
: m_elf(elf) {}
const char* ElfSectionHeadersSymbolTable::name() const
{
return "ELF Section Headers";
}
Result<void> ElfSectionHeadersSymbolTable::import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const
{
return m_elf.create_section_symbols(database, group);
}
Result<void> ElfSectionHeadersSymbolTable::print_headers(FILE* out) const
{
return Result<void>();
}
Result<void> ElfSectionHeadersSymbolTable::print_symbols(FILE* out, u32 flags) const
{
return Result<void>();
}
}

164
3rdparty/ccc/src/ccc/symbol_table.h vendored Normal file
View File

@@ -0,0 +1,164 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include <atomic>
#include "symbol_database.h"
namespace ccc {
// Determine which symbol tables are present in a given file.
enum SymbolTableFormat {
MDEBUG = 0, // The infamous Third Eye symbol table
SYMTAB = 1, // Standard ELF symbol table
SNDLL = 2 // SNDLL section
};
struct SymbolTableFormatInfo {
SymbolTableFormat format;
const char* format_name;
const char* section_name;
};
// All the supported symbol table formats, sorted from best to worst.
extern const std::vector<SymbolTableFormatInfo> SYMBOL_TABLE_FORMATS;
const SymbolTableFormatInfo* symbol_table_format_from_enum(SymbolTableFormat format);
const SymbolTableFormatInfo* symbol_table_format_from_name(const char* format_name);
const SymbolTableFormatInfo* symbol_table_format_from_section(const char* section_name);
enum SymbolPrintFlags {
PRINT_LOCALS = 1 << 0,
PRINT_PROCEDURE_DESCRIPTORS = 1 << 1,
PRINT_EXTERNALS = 1 << 2
};
class SymbolTable {
public:
virtual ~SymbolTable() {}
virtual const char* name() const = 0;
// Imports this symbol table into the passed database.
virtual Result<void> import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const = 0;
// Print out all the field in the header structure if one exists.
virtual Result<void> print_headers(FILE* out) const = 0;
// Print out all the symbols in the symbol table. For .mdebug symbol tables
// the symbols are split between those that are local to a specific
// translation unit and those that are external, which is what the
// print_locals and print_externals parameters control.
virtual Result<void> print_symbols(FILE* out, u32 flags) const = 0;
};
struct ElfSection;
struct ElfFile;
// Create a symbol table from an ELF section. The return value may be null.
Result<std::unique_ptr<SymbolTable>> create_elf_symbol_table(
const ElfSection& section, const ElfFile& elf, SymbolTableFormat format);
// Utility function to call import_symbol_table on all the passed symbol tables
// and to generate a module handle.
Result<ModuleHandle> import_symbol_tables(
SymbolDatabase& database,
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
std::string module_name,
Address base_address,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt);
class MdebugSymbolTable : public SymbolTable {
public:
MdebugSymbolTable(std::span<const u8> image, s32 section_offset);
const char* name() const override;
Result<void> import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const override;
Result<void> print_headers(FILE* out) const override;
Result<void> print_symbols(FILE* out, u32 flags) const override;
protected:
std::span<const u8> m_image;
s32 m_section_offset;
};
class SymtabSymbolTable : public SymbolTable {
public:
SymtabSymbolTable(std::span<const u8> symtab, std::span<const u8> strtab);
const char* name() const override;
Result<void> import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const override;
Result<void> print_headers(FILE* out) const override;
Result<void> print_symbols(FILE* out, u32 flags) const override;
protected:
std::span<const u8> m_symtab;
std::span<const u8> m_strtab;
};
struct SNDLLFile;
class SNDLLSymbolTable : public SymbolTable {
public:
SNDLLSymbolTable(std::shared_ptr<SNDLLFile> sndll);
const char* name() const override;
Result<void> import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const override;
Result<void> print_headers(FILE* out) const override;
Result<void> print_symbols(FILE* out, u32 flags) const override;
protected:
std::shared_ptr<SNDLLFile> m_sndll;
};
class ElfSectionHeadersSymbolTable : public SymbolTable {
public:
ElfSectionHeadersSymbolTable(const ElfFile& elf);
const char* name() const override;
Result<void> import(
SymbolDatabase& database,
const SymbolGroup& group,
u32 importer_flags,
DemanglerFunctions demangler,
const std::atomic_bool* interrupt) const override;
Result<void> print_headers(FILE* out) const override;
Result<void> print_symbols(FILE* out, u32 flags) const override;
protected:
const ElfFile& m_elf;
};
}

173
3rdparty/ccc/src/ccc/util.cpp vendored Normal file
View File

@@ -0,0 +1,173 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#include "util.h"
namespace ccc {
static CustomErrorCallback custom_error_callback = nullptr;
Error format_error(const char* source_file, int source_line, const char* format, ...)
{
va_list args;
va_start(args, format);
char message[4096];
if(vsnprintf(message, sizeof(message), format, args) < 0) {
strncpy(message, "Failed to generate error message.", sizeof(message));
}
Error error;
error.message = message;
error.source_file = source_file;
error.source_line = source_line;
va_end(args);
return error;
}
void report_error(const Error& error)
{
if(custom_error_callback) {
custom_error_callback(error, ERROR_LEVEL_ERROR);
} else {
fprintf(stderr, "[%s:%d] " CCC_ANSI_COLOUR_RED "error:" CCC_ANSI_COLOUR_OFF " %s\n",
error.source_file, error.source_line, error.message.c_str());
}
}
void report_warning(const Error& warning)
{
if(custom_error_callback) {
custom_error_callback(warning, ERROR_LEVEL_WARNING);
} else {
fprintf(stderr, "[%s:%d] " CCC_ANSI_COLOUR_MAGENTA "warning:" CCC_ANSI_COLOUR_OFF " %s\n",
warning.source_file, warning.source_line, warning.message.c_str());
}
}
void set_custom_error_callback(CustomErrorCallback callback)
{
custom_error_callback = callback;
}
const char* get_string(std::span<const u8> bytes, u64 offset)
{
for(const unsigned char* c = bytes.data() + offset; c < bytes.data() + bytes.size(); c++) {
if(*c == '\0') {
return (const char*) &bytes[offset];
}
}
return nullptr;
}
std::string merge_paths(const std::string& base, const std::string& path)
{
// Try to figure out if we're dealing with a Windows path of a UNIX path.
bool is_windows_path = false;
if(base.empty()) {
is_windows_path = guess_is_windows_path(path.c_str());
} else {
is_windows_path = guess_is_windows_path(base.c_str());
}
// Actually merge the paths. If path is the entire path, we don't need to
// append base onto the front, so check for that now.
bool is_absolute_unix = (path.size() >= 1) && (path[0] == '/' || path[0] == '\\');
bool is_absolute_windows = (path.size() >= 3) && path[1] == ':' && (path[2] == '/' || path[2] == '\\');
if(base.empty() || is_absolute_unix || is_absolute_windows) {
return normalise_path(path.c_str(), is_windows_path);
}
return normalise_path((base + "/" + path).c_str(), is_windows_path);
}
std::string normalise_path(const char* input, bool use_backslashes_as_path_separators)
{
bool is_absolute = false;
std::optional<char> drive_letter;
std::vector<std::string> parts;
// Parse the beginning of the path.
if(*input == '/' || *input == '\\') { // UNIX path, drive relative Windows path or UNC Windows path.
is_absolute = true;
} else if(isalpha(*input) && input[1] == ':' && (input[2] == '/' || input[2] == '\\')) { // Absolute Windows path.
is_absolute = true;
drive_letter = toupper(*input);
input += 2;
} else {
parts.emplace_back();
}
// Parse the rest of the path.
while(*input != 0) {
if(*input == '/' || *input == '\\') {
while(*input == '/' || *input == '\\') input++;
parts.emplace_back();
} else {
parts.back() += *(input++);
}
}
// Remove "." and ".." parts.
for(s32 i = 0; i < (s32) parts.size(); i++) {
if(parts[i] == ".") {
parts.erase(parts.begin() + i);
i--;
} else if(parts[i] == ".." && i > 0 && parts[i - 1] != "..") {
parts.erase(parts.begin() + i);
parts.erase(parts.begin() + i - 1);
i -= 2;
}
}
// Output the path in a normal form.
std::string output;
if(is_absolute) {
if(drive_letter.has_value()) {
output += *drive_letter;
output += ":";
}
output += use_backslashes_as_path_separators ? '\\' : '/';
}
for(size_t i = 0; i < parts.size(); i++) {
output += parts[i];
if(i != parts.size() - 1) {
output += use_backslashes_as_path_separators ? '\\' : '/';
}
}
return output;
}
bool guess_is_windows_path(const char* path)
{
for(const char* ptr = path; *ptr != 0; ptr++) {
if(*ptr == '\\') {
return true;
} else if(*ptr == '/') {
return false;
}
}
return false;
}
std::string extract_file_name(const std::string& path)
{
std::string::size_type forward_pos = path.find_last_of('/');
std::string::size_type backward_pos = path.find_last_of('\\');
std::string::size_type pos;
if(forward_pos == std::string::npos) {
pos = backward_pos;
} else if(backward_pos == std::string::npos) {
pos = forward_pos;
} else {
pos = std::max(forward_pos, backward_pos);
}
if(pos + 1 != path.size() && pos != std::string::npos) {
return path.substr(pos + 1);
} else {
return path;
}
}
}

312
3rdparty/ccc/src/ccc/util.h vendored Normal file
View File

@@ -0,0 +1,312 @@
// This file is part of the Chaos Compiler Collection.
// SPDX-License-Identifier: MIT
#pragma once
#include <set>
#include <span>
#include <cstdio>
#include <vector>
#include <memory>
#include <string>
#include <cstdint>
#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <optional>
namespace ccc {
using u8 = unsigned char;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using s8 = signed char;
using s16 = int16_t;
using s32 = int32_t;
using s64 = int64_t;
#ifdef _WIN32
#define CCC_ANSI_COLOUR_OFF ""
#define CCC_ANSI_COLOUR_RED ""
#define CCC_ANSI_COLOUR_MAGENTA ""
#define CCC_ANSI_COLOUR_GRAY ""
#else
#define CCC_ANSI_COLOUR_OFF "\033[0m"
#define CCC_ANSI_COLOUR_RED "\033[31m"
#define CCC_ANSI_COLOUR_MAGENTA "\033[35m"
#define CCC_ANSI_COLOUR_GRAY "\033[90m"
#endif
struct Error {
std::string message;
const char* source_file;
s32 source_line;
};
enum ErrorLevel {
ERROR_LEVEL_ERROR,
ERROR_LEVEL_WARNING
};
typedef void (*CustomErrorCallback)(const Error& error, ErrorLevel level);
Error format_error(const char* source_file, int source_line, const char* format, ...);
void report_error(const Error& error);
void report_warning(const Error& warning);
void set_custom_error_callback(CustomErrorCallback callback);
#define CCC_FATAL(...) \
{ \
ccc::Error error = ccc::format_error(__FILE__, __LINE__, __VA_ARGS__); \
ccc::report_error(error); \
exit(1); \
}
#define CCC_CHECK_FATAL(condition, ...) \
if(!(condition)) { \
ccc::Error error = ccc::format_error(__FILE__, __LINE__, __VA_ARGS__); \
ccc::report_error(error); \
exit(1); \
}
#define CCC_ASSERT(condition) \
CCC_CHECK_FATAL(condition, #condition)
// The main error handling construct in CCC. This class is used to bundle
// together a return value and a pointer to error information, so that errors
// can be propagated up the stack.
template <typename Value>
class [[nodiscard]] Result {
template <typename OtherValue>
friend class Result;
protected:
Value m_value;
std::unique_ptr<Error> m_error;
Result() {}
public:
Result(Value value) : m_value(std::move(value)), m_error(nullptr) {}
// Used to propagate errors up the call stack.
template <typename OtherValue>
Result(Result<OtherValue>&& rhs)
{
CCC_ASSERT(rhs.m_error != nullptr);
m_error = std::move(rhs.m_error);
}
static Result<Value> failure(Error error)
{
Result<Value> result;
result.m_error = std::make_unique<Error>(std::move(error));
return result;
}
bool success() const
{
return m_error == nullptr;
}
const Error& error() const
{
CCC_ASSERT(m_error != nullptr);
return *m_error;
}
Value& operator*()
{
CCC_ASSERT(m_error == nullptr);
return m_value;
}
const Value& operator*() const
{
CCC_ASSERT(m_error == nullptr);
return m_value;
}
Value* operator->()
{
CCC_ASSERT(m_error == nullptr);
return &m_value;
}
const Value* operator->() const
{
CCC_ASSERT(m_error == nullptr);
return &m_value;
}
};
template <>
class [[nodiscard]] Result<void> : public Result<int> {
public:
Result() : Result<int>(0) {}
// Used to propagate errors up the call stack.
template <typename OtherValue>
Result(Result<OtherValue>&& rhs)
{
CCC_ASSERT(rhs.m_error != nullptr);
m_error = std::move(rhs.m_error);
}
};
#define CCC_FAILURE(...) ccc::Result<int>::failure(ccc::format_error(__FILE__, __LINE__, __VA_ARGS__))
#define CCC_CHECK(condition, ...) \
if(!(condition)) { \
return CCC_FAILURE(__VA_ARGS__); \
}
#define CCC_EXPECT_CHAR(input, c, context) \
CCC_CHECK(*(input++) == c, \
"Expected '%c' in %s, got '%c' (%02hhx)", \
c, context, *(input - 1), *(input - 1))
#define CCC_RETURN_IF_ERROR(result) \
if(!(result).success()) { \
return (result); \
}
#define CCC_EXIT_IF_ERROR(result) \
if(!(result).success()) { \
ccc::report_error((result).error()); \
exit(1); \
}
#define CCC_GTEST_FAIL_IF_ERROR(result) \
if(!(result).success()) { \
FAIL() << (result).error().message; \
}
template <typename... Args>
void warn_impl(const char* source_file, int source_line, const char* format, Args... args)
{
Error warning = format_error(source_file, source_line, format, args...);
report_warning(warning);
}
#define CCC_WARN(...) \
ccc::warn_impl(__FILE__, __LINE__, __VA_ARGS__)
#ifdef _MSC_VER
#define CCC_PACKED_STRUCT(name, ...) \
__pragma(pack(push, 1)) struct name { __VA_ARGS__ } __pragma(pack(pop));
#else
#define CCC_PACKED_STRUCT(name, ...) \
struct __attribute__((__packed__)) name { __VA_ARGS__ };
#endif
template <typename T>
const T* get_packed(std::span<const u8> bytes, u64 offset)
{
if(offset + sizeof(T) <= bytes.size()) {
return reinterpret_cast<const T*>(&bytes[offset]);
} else {
return nullptr;
}
}
const char* get_string(std::span<const u8> bytes, u64 offset);
#define CCC_BEGIN_END(x) (x).begin(), (x).end()
#define CCC_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define CCC_FOURCC(string) ((string)[0] | (string)[1] << 8 | (string)[2] << 16 | (string)[3] << 24)
struct Address {
u32 value = (u32) -1;
Address() {}
Address(u32 v) : value(v) {}
bool valid() const
{
return value != (u32) -1;
}
u32 get_or_zero() const
{
if(valid()) {
return value;
} else {
return 0;
}
}
Address add_base_address(Address base_address) const
{
if(valid()) {
return base_address.get_or_zero() + value;
} else {
return Address();
}
}
static Address non_zero(u32 address)
{
Address result;
if(address != 0) {
result = address;
}
return result;
}
friend auto operator<=>(const Address& lhs, const Address& rhs) = default;
};
struct AddressRange {
Address low;
Address high;
AddressRange() {}
AddressRange(Address address) : low(address), high(address) {}
AddressRange(Address l, Address h) : low(l), high(h) {}
friend auto operator<=>(const AddressRange& lhs, const AddressRange& rhs) = default;
};
// These functions are to be used only for source file paths present in the
// symbol table, since we want them to be handled consistently across different
// platforms, which with std::filesystem::path doesn't seem to be possible.
std::string merge_paths(const std::string& base, const std::string& path);
std::string normalise_path(const char* input, bool use_backslashes_as_path_separators);
bool guess_is_windows_path(const char* path);
std::string extract_file_name(const std::string& path);
namespace ast { struct Node; }
// These are used to reference STABS types from other types within a single
// translation unit. For most games these will just be a single number, the type
// number. In some cases, for example with the homebrew SDK, type numbers are a
// pair of two numbers surrounded by round brackets e.g. (1,23) where the first
// number is the index of the include file to use (includes are listed for each
// translation unit separately), and the second number is the type number.
struct StabsTypeNumber {
s32 file = -1;
s32 type = -1;
friend auto operator<=>(const StabsTypeNumber& lhs, const StabsTypeNumber& rhs) = default;
bool valid() const { return type > -1; }
};
enum StorageClass {
STORAGE_CLASS_NONE = 0,
STORAGE_CLASS_TYPEDEF = 1,
STORAGE_CLASS_EXTERN = 2,
STORAGE_CLASS_STATIC = 3,
STORAGE_CLASS_AUTO = 4,
STORAGE_CLASS_REGISTER = 5
};
// Function pointers for the GNU demangler functions, so we can build CCC as a
// library without linking against the demangler.
struct DemanglerFunctions {
char* (*cplus_demangle)(const char *mangled, int options) = nullptr;
char* (*cplus_demangle_opname)(const char *opname, int options) = nullptr;
};
}

View File

@@ -60,7 +60,7 @@ ssize_t CPUINFO_ABI cpuinfo_mock_read(int fd, void* buffer, size_t capacity);
void CPUINFO_ABI cpuinfo_set_hwcap(uint32_t hwcap);
#endif
#if CPUINFO_ARCH_ARM
void CPUINFO_ABI cpuinfo_set_hwcap2(uint32_t hwcap2);
void CPUINFO_ABI cpuinfo_set_hwcap2(uint64_t hwcap2);
#endif
#endif

View File

@@ -496,13 +496,19 @@ enum cpuinfo_uarch {
cpuinfo_uarch_cortex_x2 = 0x00300502,
/** ARM Cortex-X3. */
cpuinfo_uarch_cortex_x3 = 0x00300503,
/** ARM Cortex-X4. */
cpuinfo_uarch_cortex_x4 = 0x00300504,
/** ARM Cortex-A510. */
cpuinfo_uarch_cortex_a510 = 0x00300551,
/** ARM Cortex-A520. */
cpuinfo_uarch_cortex_a520 = 0x00300552,
/** ARM Cortex-A710. */
cpuinfo_uarch_cortex_a710 = 0x00300571,
/** ARM Cortex-A715. */
cpuinfo_uarch_cortex_a715 = 0x00300572,
/** ARM Cortex-A720. */
cpuinfo_uarch_cortex_a720 = 0x00300573,
/** Qualcomm Scorpion. */
cpuinfo_uarch_scorpion = 0x00400100,
@@ -1664,6 +1670,14 @@ struct cpuinfo_arm_isa {
bool sve;
bool sve2;
bool i8mm;
bool sme;
bool sme2;
bool sme2p1;
bool sme_i16i32;
bool sme_bi32i32;
bool sme_b16b16;
bool sme_f16f16;
uint32_t svelen;
#endif
bool rdm;
bool fp16arith;
@@ -2036,6 +2050,71 @@ static inline bool cpuinfo_has_arm_sve2(void) {
#endif
}
// Function to get the max SVE vector length on ARM CPU's which support SVE.
static inline uint32_t cpuinfo_get_max_arm_sve_length(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.svelen * 8; // bytes * 8 = bit length(vector length)
#else
return 0;
#endif
}
static inline bool cpuinfo_has_arm_sme(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme2(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme2;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme2p1(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme2p1;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_i16i32(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_i16i32;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_bi32i32(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_bi32i32;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_b16b16(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_b16b16;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_f16f16(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_f16f16;
#else
return false;
#endif
}
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
/* This structure is not a part of stable API. Use cpuinfo_has_riscv_* functions
* instead. */

View File

@@ -64,6 +64,7 @@ enum cpuinfo_arm_chipset_series {
cpuinfo_arm_chipset_series_telechips_tcc,
cpuinfo_arm_chipset_series_texas_instruments_omap,
cpuinfo_arm_chipset_series_unisoc_t,
cpuinfo_arm_chipset_series_unisoc_ums,
cpuinfo_arm_chipset_series_wondermedia_wm,
cpuinfo_arm_chipset_series_max,
};

View File

@@ -24,7 +24,7 @@ void cpuinfo_set_wcid(uint32_t wcid) {
void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
uint32_t features,
uint32_t features2,
uint64_t features2,
uint32_t midr,
uint32_t architecture_version,
uint32_t architecture_flags,
@@ -147,6 +147,8 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
"VDOT instructions disabled: cause occasional SIGILL on Spreadtrum SC9863A");
} else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_t && chipset->model == 310) {
cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc T310");
} else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_ums && chipset->model == 312) {
cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc UMS312");
} else {
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
case UINT32_C(0x4100D0B0): /* Cortex-A76 */

View File

@@ -3,9 +3,11 @@
#include <arm/linux/api.h>
#include <cpuinfo/log.h>
#include <sys/prctl.h>
void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
uint32_t features,
uint32_t features2,
uint64_t features2,
uint32_t midr,
const struct cpuinfo_arm_chipset chipset[restrict static 1],
struct cpuinfo_arm_isa isa[restrict static 1]) {
@@ -142,6 +144,27 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SVE2) {
isa->sve2 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME) {
isa->sme = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2) {
isa->sme2 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2P1) {
isa->sme2p1 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_I16I32) {
isa->sme_i16i32 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_BI32I32) {
isa->sme_bi32i32 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_B16B16) {
isa->sme_b16b16 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_F16F16) {
isa->sme_f16f16 = true;
}
// SVEBF16 is set iff SVE and BF16 are both supported, but the SVEBF16
// feature flag was added in Linux kernel before the BF16 feature flag,
// so we check for either.
@@ -151,4 +174,21 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDFHM) {
isa->fhm = true;
}
#ifndef PR_SVE_GET_VL
#define PR_SVE_GET_VL 51
#endif
#ifndef PR_SVE_VL_LEN_MASK
#define PR_SVE_VL_LEN_MASK 0xffff
#endif
int ret = prctl(PR_SVE_GET_VL);
if (ret < 0) {
cpuinfo_log_warning("No SVE support on this machine");
isa->svelen = 0; // Assume no SVE support if the call fails
} else {
// Mask out the SVE vector length bits
isa->svelen = ret & PR_SVE_VL_LEN_MASK;
}
}

View File

@@ -137,6 +137,13 @@ struct cpuinfo_arm_linux_proc_cpuinfo_cache {
#define CPUINFO_ARM_LINUX_FEATURE2_DGH UINT32_C(0x00008000)
#define CPUINFO_ARM_LINUX_FEATURE2_RNG UINT32_C(0x00010000)
#define CPUINFO_ARM_LINUX_FEATURE2_BTI UINT32_C(0x00020000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME UINT32_C(0x00800000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME2 UINT64_C(0x0000002000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME2P1 UINT64_C(0x0000004000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_I16I32 UINT64_C(0x0000008000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_BI32I32 UINT64_C(0x0000010000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_B16B16 UINT64_C(0x0000020000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_F16F16 UINT64_C(0x0000040000000000)
#endif
#define CPUINFO_ARM_LINUX_VALID_ARCHITECTURE UINT32_C(0x00010000)
@@ -172,7 +179,7 @@ struct cpuinfo_arm_linux_processor {
struct cpuinfo_arm_linux_proc_cpuinfo_cache proc_cpuinfo_cache;
#endif
uint32_t features;
uint32_t features2;
uint64_t features2;
/**
* Main ID Register value.
*/
@@ -295,14 +302,14 @@ CPUINFO_INTERNAL bool cpuinfo_arm_linux_parse_proc_cpuinfo(
#if CPUINFO_ARCH_ARM
CPUINFO_INTERNAL bool cpuinfo_arm_linux_hwcap_from_getauxval(
uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1]);
uint64_t hwcap2[restrict static 1]);
CPUINFO_INTERNAL bool cpuinfo_arm_linux_hwcap_from_procfs(
uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1]);
uint64_t hwcap2[restrict static 1]);
CPUINFO_INTERNAL void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
uint32_t features,
uint32_t features2,
uint64_t features2,
uint32_t midr,
uint32_t architecture_version,
uint32_t architecture_flags,
@@ -311,11 +318,11 @@ CPUINFO_INTERNAL void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
#elif CPUINFO_ARCH_ARM64
CPUINFO_INTERNAL void cpuinfo_arm_linux_hwcap_from_getauxval(
uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1]);
uint64_t hwcap2[restrict static 1]);
CPUINFO_INTERNAL void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
uint32_t features,
uint32_t features2,
uint64_t features2,
uint32_t midr,
const struct cpuinfo_arm_chipset chipset[restrict static 1],
struct cpuinfo_arm_isa isa[restrict static 1]);

View File

@@ -85,6 +85,7 @@ static enum cpuinfo_arm_chipset_vendor chipset_series_vendor[cpuinfo_arm_chipset
[cpuinfo_arm_chipset_series_telechips_tcc] = cpuinfo_arm_chipset_vendor_telechips,
[cpuinfo_arm_chipset_series_texas_instruments_omap] = cpuinfo_arm_chipset_vendor_texas_instruments,
[cpuinfo_arm_chipset_series_unisoc_t] = cpuinfo_arm_chipset_vendor_unisoc,
[cpuinfo_arm_chipset_series_unisoc_ums] = cpuinfo_arm_chipset_vendor_unisoc,
[cpuinfo_arm_chipset_series_wondermedia_wm] = cpuinfo_arm_chipset_vendor_wondermedia,
};
@@ -959,6 +960,70 @@ static bool match_t(const char* start, const char* end, struct cpuinfo_arm_chips
return true;
}
/**
* Tries to match, case-sentitively, /Unisoc UMS\d{3,4}/ signature for Unisoc UMS
* chipset. If match successful, extracts model information into \p chipset
* argument.
*
* @param start - start of the platform identifier (/proc/cpuinfo Hardware
* string, ro.product.board, ro.board.platform, or ro.chipname) to match.
* @param end - end of the platform identifier (/proc/cpuinfo Hardware string,
* ro.product.board, ro.board.platform, or ro.chipname) to match.
* @param[out] chipset - location where chipset information will be stored upon
* a successful match.
*
* @returns true if signature matched, false otherwise.
*/
static bool match_ums(const char* start, const char* end, struct cpuinfo_arm_chipset chipset[restrict static 1]) {
/* Expect 13-14 symbols: "Unisoc UMS" (10 symbols) + 3-4-digit model number
*/
const size_t length = end - start;
switch (length) {
case 13:
case 14:
break;
default:
return false;
}
/* Check that string starts with "Unisoc UMS". The first four characters
* are loaded as 32-bit little endian word */
const uint32_t expected_unis = load_u32le(start);
if (expected_unis != UINT32_C(0x73696E55) /* "sinU" = reverse("Unis") */) {
return false;
}
/* The next four characters are loaded as 32-bit little endian word */
const uint32_t expected_oc_u = load_u32le(start + 4);
if (expected_oc_u != UINT32_C(0x5520636F) /* "U co" = reverse("oc U") */) {
return false;
}
/* The next four characters are loaded as 16-bit little endian word */
const uint16_t expected_ms = load_u16le(start + 8);
if (expected_ms != UINT16_C(0x534D) /* "SM" = reverse("MS") */) {
return false;
}
/* Validate and parse 3-4 digit model number */
uint32_t model = 0;
for (uint32_t i = 10; i < length; i++) {
const uint32_t digit = (uint32_t)(uint8_t)start[i] - '0';
if (digit >= 10) {
/* Not really a digit */
return false;
}
model = model * 10 + digit;
}
*chipset = (struct cpuinfo_arm_chipset){
.vendor = cpuinfo_arm_chipset_vendor_unisoc,
.series = cpuinfo_arm_chipset_series_unisoc_ums,
.model = model,
};
return true;
}
/**
* Tries to match /lc\d{4}[a-z]?$/ signature for Leadcore LC chipsets.
* If match successful, extracts model information into \p chipset argument.
@@ -2508,6 +2573,16 @@ struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_ha
return chipset;
}
/* Check Unisoc UMS signature */
if (match_ums(hardware, hardware_end, &chipset)) {
cpuinfo_log_debug(
"matched Unisoc UMS signature in /proc/cpuinfo Hardware string \"%.*s\"",
(int)hardware_length,
hardware);
return chipset;
}
#if CPUINFO_ARCH_ARM
/* Check Marvell PXA signature */
if (match_pxa(hardware, hardware_end, &chipset)) {
@@ -3726,6 +3801,7 @@ static const char* chipset_series_string[cpuinfo_arm_chipset_series_max] = {
[cpuinfo_arm_chipset_series_telechips_tcc] = "TCC",
[cpuinfo_arm_chipset_series_texas_instruments_omap] = "OMAP",
[cpuinfo_arm_chipset_series_unisoc_t] = "T",
[cpuinfo_arm_chipset_series_unisoc_ums] = "UMS",
[cpuinfo_arm_chipset_series_wondermedia_wm] = "WM",
};

View File

@@ -31,8 +31,8 @@ void cpuinfo_set_hwcap(uint32_t hwcap) {
mock_hwcap = hwcap;
}
static uint32_t mock_hwcap2 = 0;
void cpuinfo_set_hwcap2(uint32_t hwcap2) {
static uint64_t mock_hwcap2 = 0;
void cpuinfo_set_hwcap2(uint64_t hwcap2) {
mock_hwcap2 = hwcap2;
}
#endif
@@ -40,7 +40,7 @@ void cpuinfo_set_hwcap2(uint32_t hwcap2) {
#if CPUINFO_ARCH_ARM
typedef unsigned long (*getauxval_function_t)(unsigned long);
bool cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint32_t hwcap2[restrict static 1]) {
bool cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint64_t hwcap2[restrict static 1]) {
#if CPUINFO_MOCK
*hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2;
@@ -83,13 +83,13 @@ cleanup:
}
#ifdef __ANDROID__
bool cpuinfo_arm_linux_hwcap_from_procfs(uint32_t hwcap[restrict static 1], uint32_t hwcap2[restrict static 1]) {
bool cpuinfo_arm_linux_hwcap_from_procfs(uint32_t hwcap[restrict static 1], uint64_t hwcap2[restrict static 1]) {
#if CPUINFO_MOCK
*hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2;
return true;
#else
uint32_t hwcaps[2] = {0, 0};
uint64_t hwcaps[2] = {0, 0};
bool result = false;
int file = -1;
@@ -113,7 +113,7 @@ bool cpuinfo_arm_linux_hwcap_from_procfs(uint32_t hwcap[restrict static 1], uint
hwcaps[0] = (uint32_t)elf_auxv.a_un.a_val;
break;
case AT_HWCAP2:
hwcaps[1] = (uint32_t)elf_auxv.a_un.a_val;
hwcaps[1] = (uint64_t)elf_auxv.a_un.a_val;
break;
}
} else {
@@ -141,13 +141,13 @@ cleanup:
}
#endif /* __ANDROID__ */
#elif CPUINFO_ARCH_ARM64
void cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint32_t hwcap2[restrict static 1]) {
void cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint64_t hwcap2[restrict static 1]) {
#if CPUINFO_MOCK
*hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2;
#else
*hwcap = (uint32_t)getauxval(AT_HWCAP);
*hwcap2 = (uint32_t)getauxval(AT_HWCAP2);
*hwcap2 = (uint64_t)getauxval(AT_HWCAP2);
return;
#endif
}

View File

@@ -247,7 +247,8 @@ void cpuinfo_arm_linux_init(void) {
#endif
#if CPUINFO_ARCH_ARM
uint32_t isa_features = 0, isa_features2 = 0;
uint32_t isa_features = 0;
uint64_t isa_features2 = 0;
#ifdef __ANDROID__
/*
* On Android before API 20, libc.so does not provide getauxval
@@ -299,7 +300,8 @@ void cpuinfo_arm_linux_init(void) {
&chipset,
&cpuinfo_isa);
#elif CPUINFO_ARCH_ARM64
uint32_t isa_features = 0, isa_features2 = 0;
uint32_t isa_features = 0;
uint64_t isa_features2 = 0;
/* getauxval is always available on ARM64 Android */
cpuinfo_arm_linux_hwcap_from_getauxval(&isa_features, &isa_features2);
cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
@@ -333,18 +335,52 @@ void cpuinfo_arm_linux_init(void) {
}
/* Propagate topology group IDs among siblings */
bool detected_core_siblings_list_node = false;
bool detected_cluster_cpus_list_node = false;
for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
if (!bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
continue;
}
if (arm_linux_processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_ID) {
if (!bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_PACKAGE_ID)) {
continue;
}
/* Use the cluster_cpus_list topology node if available. If not
* found, cache the result to avoid repeatedly attempting to
* read the non-existent paths.
* */
if (!detected_core_siblings_list_node && !detected_cluster_cpus_list_node) {
if (cpuinfo_linux_detect_cluster_cpus(
arm_linux_processors_count,
i,
(cpuinfo_siblings_callback)cluster_siblings_parser,
arm_linux_processors)) {
detected_cluster_cpus_list_node = true;
continue;
} else {
detected_core_siblings_list_node = true;
}
}
/* The cached result above will guarantee only one of the blocks
* below will execute, with a bias towards cluster_cpus_list.
**/
if (detected_core_siblings_list_node) {
cpuinfo_linux_detect_core_siblings(
arm_linux_processors_count,
i,
(cpuinfo_siblings_callback)cluster_siblings_parser,
arm_linux_processors);
}
if (detected_cluster_cpus_list_node) {
cpuinfo_linux_detect_cluster_cpus(
arm_linux_processors_count,
i,
(cpuinfo_siblings_callback)cluster_siblings_parser,
arm_linux_processors);
}
}
/* Propagate all cluster IDs */

View File

@@ -399,6 +399,16 @@ void cpuinfo_arm_mach_init(void) {
cpuinfo_isa.i8mm = true;
}
const uint32_t has_feat_sme = get_sys_info_by_name("hw.optional.arm.FEAT_SME");
if (has_feat_sme != 0) {
cpuinfo_isa.sme = true;
}
const uint32_t has_feat_sme2 = get_sys_info_by_name("hw.optional.arm.FEAT_SME2");
if (has_feat_sme2 != 0) {
cpuinfo_isa.sme2 = true;
}
uint32_t num_clusters = 1;
for (uint32_t i = 0; i < mach_topology.cores; i++) {
cores[i] = (struct cpuinfo_core){

View File

@@ -24,8 +24,10 @@ static char* sysctl_str(const char* name) {
size_t value_size = 0;
if (sysctlbyname(name, NULL, &value_size, NULL, 0) != 0) {
cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
return NULL;
} else if (value_size <= 0) {
cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value size %zu", name, value_size);
return NULL;
}
value_size += 1;
char* value = calloc(value_size, 1);
@@ -52,29 +54,22 @@ struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
if (!topology_spec) {
return topology;
}
const char* group_tag = "<group level=\"1\" cache-level=\"0\">";
char* p = strstr(topology_spec, group_tag);
while (p) {
const char* cpu_tag = "cpu count=\"";
char* q = strstr(p, cpu_tag);
if (q) {
p = q + strlen(cpu_tag);
topology.packages += atoi(p);
} else {
break;
}
}
if (topology.packages == 0) {
const char* group_tag = "<group level=\"1\"";
const char* group_tags[] = {"<group level=\"2\" cache-level=\"0\">", "<group level=\"1\" "};
for (size_t i = 0; i < sizeof(group_tags) / sizeof(group_tags[0]); i++) {
const char* group_tag = group_tags[i];
char* p = strstr(topology_spec, group_tag);
while (p) {
topology.packages += 1;
p++;
p = strstr(p, group_tag);
}
if (topology.packages > 0) {
break;
}
}
if (topology.packages == 0) {
cpuinfo_log_error("failed to parse topology_spec:%s", topology_spec);
cpuinfo_log_error("failed to parse topology_spec: %s", topology_spec);
free(topology_spec);
goto fail;
}
@@ -84,6 +79,7 @@ struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
goto fail;
}
if (topology.cores < topology.packages) {
cpuinfo_log_error("invalid numbers of package and core: %d %d", topology.packages, topology.cores);
goto fail;
}
topology.threads_per_core = sysctl_int("kern.smp.threads_per_core");

View File

@@ -135,6 +135,10 @@ void cpuinfo_x86_freebsd_init(void) {
if (x86_processor.cache.l1i.size != 0 || x86_processor.cache.l1d.size != 0) {
/* Assume that threads on the same core share L1 */
threads_per_l1 = freebsd_topology.threads / freebsd_topology.cores;
if (threads_per_l1 == 0) {
cpuinfo_log_error("failed to detect threads_per_l1");
goto cleanup;
}
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L1 cache; assume %" PRIu32,
@@ -154,6 +158,10 @@ void cpuinfo_x86_freebsd_init(void) {
* the same package share L2 */
threads_per_l2 = freebsd_topology.threads / freebsd_topology.packages;
}
if (threads_per_l2 == 0) {
cpuinfo_log_error("failed to detect threads_per_l1");
goto cleanup;
}
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L2 cache; assume %" PRIu32,
@@ -170,6 +178,10 @@ void cpuinfo_x86_freebsd_init(void) {
* may be L4 cache as well)
*/
threads_per_l3 = freebsd_topology.threads / freebsd_topology.packages;
if (threads_per_l3 == 0) {
cpuinfo_log_error("failed to detect threads_per_l3");
goto cleanup;
}
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L3 cache; assume %" PRIu32,
@@ -187,6 +199,10 @@ void cpuinfo_x86_freebsd_init(void) {
* shared L4 (like on IBM POWER8).
*/
threads_per_l4 = freebsd_topology.threads;
if (threads_per_l4 == 0) {
cpuinfo_log_error("failed to detect threads_per_l4");
goto cleanup;
}
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L4 cache; assume %" PRIu32,
@@ -203,7 +219,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L1I caches",
l1_count * sizeof(struct cpuinfo_cache),
l1_count);
return;
goto cleanup;
}
for (uint32_t c = 0; c < l1_count; c++) {
l1i[c] = (struct cpuinfo_cache){
@@ -230,7 +246,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L1D caches",
l1_count * sizeof(struct cpuinfo_cache),
l1_count);
return;
goto cleanup;
}
for (uint32_t c = 0; c < l1_count; c++) {
l1d[c] = (struct cpuinfo_cache){
@@ -257,7 +273,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L2 caches",
l2_count * sizeof(struct cpuinfo_cache),
l2_count);
return;
goto cleanup;
}
for (uint32_t c = 0; c < l2_count; c++) {
l2[c] = (struct cpuinfo_cache){
@@ -284,7 +300,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L3 caches",
l3_count * sizeof(struct cpuinfo_cache),
l3_count);
return;
goto cleanup;
}
for (uint32_t c = 0; c < l3_count; c++) {
l3[c] = (struct cpuinfo_cache){
@@ -311,7 +327,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L4 caches",
l4_count * sizeof(struct cpuinfo_cache),
l4_count);
return;
goto cleanup;
}
for (uint32_t c = 0; c < l4_count; c++) {
l4[c] = (struct cpuinfo_cache){

View File

@@ -1,6 +1,27 @@
add_library(demanglegnu STATIC
src/alloca.c
src/cp-demangle.c
src/cplus-dem.c
src/d-demangle.c
src/dyn-string.c
src/getopt1.c
src/getopt.c
src/rust-demangle.c
src/safe-ctype.c
src/xexit.c
src/xmalloc.c
src/xmemdup.c
src/xstrdup.c
)
cmake_minimum_required(VERSION 3.6)
set(GNU_DEMANGLER_FLAGS -DHAVE_DECL_BASENAME=1 -DHAVE_LIMITS_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1)
project(demangler CXX)
target_include_directories(demanglegnu PUBLIC include)
target_compile_definitions(demanglegnu PUBLIC ${GNU_DEMANGLER_FLAGS})
add_subdirectory(src)
add_executable(demangler_fuzzer testsuite/demangler-fuzzer.c)
add_executable(demangler_test testsuite/test-demangle.c)
target_link_libraries(demangler_fuzzer demanglegnu)
target_link_libraries(demangler_test demanglegnu)
target_compile_definitions(demangler_fuzzer PUBLIC ${GNU_DEMANGLER_FLAGS})
target_compile_definitions(demangler_test PUBLIC ${GNU_DEMANGLER_FLAGS})

View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,482 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

33
3rdparty/demangler/README vendored Normal file
View File

@@ -0,0 +1,33 @@
This code was taken from GCC 13.2.0 and specifically the libiberty library which
contains files licensed under the GPL and the LGPL.
Support for GCC 2.x-style symbols has been reintroduced by reversing the changes
made by the commit that removed it:
From: Jason Merrill <jason@redhat.com>
Date: Sun, 23 Dec 2018 00:06:34 +0000 (-0500)
Subject: Remove support for demangling GCC 2.x era mangling schemes.
X-Git-Tag: releases/gcc-9.1.0~2159
X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=6c8120c5ff130e03d32ff15a8f0d0e703592a2af
Remove support for demangling GCC 2.x era mangling schemes.
libiberty/
* cplus-dem.c: Remove cplus_mangle_opname, cplus_demangle_opname,
internal_cplus_demangle, and all subroutines.
(libiberty_demanglers): Remove entries for ancient GNU (pre-3.0),
Lucid, ARM, HP, and EDG demangling styles.
(cplus_demangle): Remove 'work' variable. Don't call
internal_cplus_demangle.
include/
* demangle.h: Remove support for ancient GNU (pre-3.0), Lucid,
ARM, HP, and EDG demangling styles.
From-SVN: r267363
In addition, the cplus_demangle_opname function has been modified to address a
memory safety issue:
/* CCC: Allocate the result on the heap to prevent buffer overruns. */
extern char *
cplus_demangle_opname (const char *opname, int options);

40
3rdparty/demangler/copy_demangler_files.sh vendored Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
set -e
# This script copies all the source files needed for the GNU demangler from a
# copy of GCC to the specified output directory.
if [ "$#" -ne 2 ]; then
echo "usage: $0 <gcc dir> <out dir>"
exit 1
fi
GCC_DIR=$1
OUT_DIR=$2
cp "$GCC_DIR/include/ansidecl.h" "$OUT_DIR/include/"
cp "$GCC_DIR/include/demangle.h" "$OUT_DIR/include/"
cp "$GCC_DIR/include/dyn-string.h" "$OUT_DIR/include/"
cp "$GCC_DIR/include/environ.h" "$OUT_DIR/include/"
cp "$GCC_DIR/include/getopt.h" "$OUT_DIR/include/"
cp "$GCC_DIR/include/libiberty.h" "$OUT_DIR/include/"
cp "$GCC_DIR/include/safe-ctype.h" "$OUT_DIR/include/"
cp "$GCC_DIR/libiberty/alloca.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/argv.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/cp-demangle.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/cp-demangle.h" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/cplus-dem.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/d-demangle.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/dyn-string.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/getopt.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/getopt1.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/rust-demangle.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/safe-ctype.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/xexit.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/xmalloc.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/xmemdup.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/xstrdup.c" "$OUT_DIR/src/"
cp "$GCC_DIR/libiberty/testsuite/demangle-expected" "$OUT_DIR/testsuite/"
cp "$GCC_DIR/libiberty/testsuite/demangler-fuzzer.c" "$OUT_DIR/testsuite/"
cp "$GCC_DIR/libiberty/testsuite/test-demangle.c" "$OUT_DIR/testsuite/"

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}</ProjectGuid>
<ProjectGuid>{D31A6DD1-99CA-41D8-A230-1FAE913C8989}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
@@ -30,29 +30,36 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="src\demangler.cpp" />
<ClCompile Include="src\demtools.cpp" />
<ClCompile Include="src\gparser.cpp" />
<ClCompile Include="src\igrams.cpp" />
<ClCompile Include="src\stgrammars\borlandll.cpp" />
<ClCompile Include="src\stgrammars\gccll.cpp" />
<ClCompile Include="src\stgrammars\msll.cpp" />
<ClInclude Include="include\ansidecl.h" />
<ClInclude Include="include\cp-demangle.h" />
<ClInclude Include="include\demangle.h" />
<ClInclude Include="include\dyn-string.h" />
<ClInclude Include="include\environ.h" />
<ClInclude Include="include\getopt.h" />
<ClInclude Include="include\libiberty.h" />
<ClInclude Include="include\safe-ctype.h" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\demangler\demangler.h" />
<ClInclude Include="include\demangler\demglobal.h" />
<ClInclude Include="include\demangler\demtools.h" />
<ClInclude Include="include\demangler\gparser.h" />
<ClInclude Include="include\demangler\igrams.h" />
<ClInclude Include="include\demangler\stgrammars\borlandll.h" />
<ClInclude Include="include\demangler\stgrammars\gccll.h" />
<ClInclude Include="include\demangler\stgrammars\msll.h" />
<ClCompile Include="src\alloca.c" />
<ClCompile Include="src\argv.c" />
<ClCompile Include="src\cp-demangle.c" />
<ClCompile Include="src\cplus-dem.c" />
<ClCompile Include="src\d-demangle.c" />
<ClCompile Include="src\dyn-string.c" />
<ClCompile Include="src\getopt.c" />
<ClCompile Include="src\getopt1.c" />
<ClCompile Include="src\rust-demangle.c" />
<ClCompile Include="src\safe-ctype.c" />
<ClCompile Include="src\xexit.c" />
<ClCompile Include="src\xmalloc.c" />
<ClCompile Include="src\xmemdup.c" />
<ClCompile Include="src\xstrdup.c" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>HAVE_DECL_BASENAME=1;HAVE_LIMITS_H;HAVE_STDLIB_H=1;HAVE_STRING_H=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@@ -1,22 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\demangler.cpp" />
<ClCompile Include="src\demtools.cpp" />
<ClCompile Include="src\gparser.cpp" />
<ClCompile Include="src\igrams.cpp" />
<ClCompile Include="src\stgrammars\borlandll.cpp" />
<ClCompile Include="src\stgrammars\gccll.cpp" />
<ClCompile Include="src\stgrammars\msll.cpp" />
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\demangler\demangler.h" />
<ClInclude Include="include\demangler\demglobal.h" />
<ClInclude Include="include\demangler\demtools.h" />
<ClInclude Include="include\demangler\gparser.h" />
<ClInclude Include="include\demangler\igrams.h" />
<ClInclude Include="include\demangler\stgrammars\borlandll.h" />
<ClInclude Include="include\demangler\stgrammars\gccll.h" />
<ClInclude Include="include\demangler\stgrammars\msll.h" />
<ClInclude Include="include\ansidecl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\cp-demangle.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\demangle.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\dyn-string.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\environ.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\getopt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\libiberty.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\safe-ctype.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\alloca.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\argv.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cp-demangle.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cplus-dem.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\d-demangle.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dyn-string.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\getopt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\getopt1.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\rust-demangle.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\safe-ctype.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\xexit.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\xmalloc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\xmemdup.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\xstrdup.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

354
3rdparty/demangler/include/ansidecl.h vendored Normal file
View File

@@ -0,0 +1,354 @@
/* Compiler compatibility macros
Copyright (C) 1991-2023 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/* For ease of writing code which uses GCC extensions but needs to be
portable to other compilers, we provide the GCC_VERSION macro that
simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
wrappers around __attribute__. Also, __extension__ will be #defined
to nothing if it doesn't work. See below. */
#ifndef _ANSIDECL_H
#define _ANSIDECL_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* Every source file includes this file,
so they will all get the switch for lint. */
/* LINTLIBRARY */
/* Using MACRO(x,y) in cpp #if conditionals does not work with some
older preprocessors. Thus we can't define something like this:
#define HAVE_GCC_VERSION(MAJOR, MINOR) \
(__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
and then test "#if HAVE_GCC_VERSION(2,7)".
So instead we use the macro below and test it against specific values. */
/* This macro simplifies testing whether we are using gcc, and if it
is of a particular minimum version. (Both major & minor numbers are
significant.) This macro will evaluate to 0 if we are not using
gcc at all. */
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#endif /* GCC_VERSION */
/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
it too, but it's not in C89. */
#undef inline
#if (!defined(__cplusplus) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__))
/* it's a keyword */
#else
# if GCC_VERSION >= 2007
# define inline __inline__ /* __inline__ prevents -pedantic warnings */
# else
# define inline /* nothing */
# endif
#endif
/* Define macros for some gcc attributes. This permits us to use the
macros freely, and know that they will come into play for the
version of gcc in which they are supported. */
#if (GCC_VERSION < 2007)
# define __attribute__(x)
#endif
/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
#ifndef ATTRIBUTE_MALLOC
# if (GCC_VERSION >= 2096)
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
# else
# define ATTRIBUTE_MALLOC
# endif /* GNUC >= 2.96 */
#endif /* ATTRIBUTE_MALLOC */
/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For
g++ an attribute on a label must be followed by a semicolon. */
#ifndef ATTRIBUTE_UNUSED_LABEL
# ifndef __cplusplus
# if GCC_VERSION >= 2093
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
# else
# define ATTRIBUTE_UNUSED_LABEL
# endif
# else
# if GCC_VERSION >= 4005
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ;
# else
# define ATTRIBUTE_UNUSED_LABEL
# endif
# endif
#endif
/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend
couldn't parse attributes placed after the identifier name, and now
the entire compiler is built with C++. */
#ifndef ATTRIBUTE_UNUSED
#if GCC_VERSION >= 3004
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#else
#define ATTRIBUTE_UNUSED
#endif
#endif /* ATTRIBUTE_UNUSED */
/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
identifier name. */
#if ! defined(__cplusplus) || (GCC_VERSION >= 3004)
# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED
#else /* !__cplusplus || GNUC >= 3.4 */
# define ARG_UNUSED(NAME) NAME
#endif /* !__cplusplus || GNUC >= 3.4 */
#ifndef ATTRIBUTE_NORETURN
#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
#endif /* ATTRIBUTE_NORETURN */
/* Attribute `nonnull' was valid as of gcc 3.3. */
#ifndef ATTRIBUTE_NONNULL
# if (GCC_VERSION >= 3003)
# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
# else
# define ATTRIBUTE_NONNULL(m)
# endif /* GNUC >= 3.3 */
#endif /* ATTRIBUTE_NONNULL */
/* Attribute `returns_nonnull' was valid as of gcc 4.9. */
#ifndef ATTRIBUTE_RETURNS_NONNULL
# if (GCC_VERSION >= 4009)
# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
# else
# define ATTRIBUTE_RETURNS_NONNULL
# endif /* GNUC >= 4.9 */
#endif /* ATTRIBUTE_RETURNS_NONNULL */
/* Attribute `pure' was valid as of gcc 3.0. */
#ifndef ATTRIBUTE_PURE
# if (GCC_VERSION >= 3000)
# define ATTRIBUTE_PURE __attribute__ ((__pure__))
# else
# define ATTRIBUTE_PURE
# endif /* GNUC >= 3.0 */
#endif /* ATTRIBUTE_PURE */
/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
This was the case for the `printf' format attribute by itself
before GCC 3.3, but as of 3.3 we need to add the `nonnull'
attribute to retain this behavior. */
#ifndef ATTRIBUTE_PRINTF
#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
#endif /* ATTRIBUTE_PRINTF */
/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on
a function pointer. Format attributes were allowed on function
pointers as of gcc 3.1. */
#ifndef ATTRIBUTE_FPTR_PRINTF
# if (GCC_VERSION >= 3001)
# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n)
# else
# define ATTRIBUTE_FPTR_PRINTF(m, n)
# endif /* GNUC >= 3.1 */
# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2)
# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3)
# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4)
# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5)
# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6)
#endif /* ATTRIBUTE_FPTR_PRINTF */
/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
NULL format specifier was allowed as of gcc 3.3. */
#ifndef ATTRIBUTE_NULL_PRINTF
# if (GCC_VERSION >= 3003)
# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
# else
# define ATTRIBUTE_NULL_PRINTF(m, n)
# endif /* GNUC >= 3.3 */
# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
#endif /* ATTRIBUTE_NULL_PRINTF */
/* Attribute `sentinel' was valid as of gcc 3.5. */
#ifndef ATTRIBUTE_SENTINEL
# if (GCC_VERSION >= 3005)
# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
# else
# define ATTRIBUTE_SENTINEL
# endif /* GNUC >= 3.5 */
#endif /* ATTRIBUTE_SENTINEL */
#ifndef ATTRIBUTE_ALIGNED_ALIGNOF
# if (GCC_VERSION >= 3000)
# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m))))
# else
# define ATTRIBUTE_ALIGNED_ALIGNOF(m)
# endif /* GNUC >= 3.0 */
#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
/* Useful for structures whose layout must match some binary specification
regardless of the alignment and padding qualities of the compiler. */
#ifndef ATTRIBUTE_PACKED
# define ATTRIBUTE_PACKED __attribute__ ((packed))
#endif
/* Attribute `hot' and `cold' was valid as of gcc 4.3. */
#ifndef ATTRIBUTE_COLD
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_COLD __attribute__ ((__cold__))
# else
# define ATTRIBUTE_COLD
# endif /* GNUC >= 4.3 */
#endif /* ATTRIBUTE_COLD */
#ifndef ATTRIBUTE_HOT
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_HOT __attribute__ ((__hot__))
# else
# define ATTRIBUTE_HOT
# endif /* GNUC >= 4.3 */
#endif /* ATTRIBUTE_HOT */
/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */
#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED
# if (GCC_VERSION >= 4009)
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined))
# else
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED
# endif /* GNUC >= 4.9 */
#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */
/* Attribute 'nonstring' was valid as of gcc 8. */
#ifndef ATTRIBUTE_NONSTRING
# if GCC_VERSION >= 8000
# define ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))
# else
# define ATTRIBUTE_NONSTRING
# endif
#endif
/* Attribute `alloc_size' was valid as of gcc 4.3. */
#ifndef ATTRIBUTE_RESULT_SIZE_1
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_RESULT_SIZE_1 __attribute__ ((alloc_size (1)))
# else
# define ATTRIBUTE_RESULT_SIZE_1
#endif
#endif
#ifndef ATTRIBUTE_RESULT_SIZE_2
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_RESULT_SIZE_2 __attribute__ ((alloc_size (2)))
# else
# define ATTRIBUTE_RESULT_SIZE_2
#endif
#endif
#ifndef ATTRIBUTE_RESULT_SIZE_1_2
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_RESULT_SIZE_1_2 __attribute__ ((alloc_size (1, 2)))
# else
# define ATTRIBUTE_RESULT_SIZE_1_2
#endif
#endif
/* Attribute `warn_unused_result' was valid as of gcc 3.3. */
#ifndef ATTRIBUTE_WARN_UNUSED_RESULT
# if GCC_VERSION >= 3003
# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
# else
# define ATTRIBUTE_WARN_UNUSED_RESULT
# endif
#endif
/* We use __extension__ in some places to suppress -pedantic warnings
about GCC extensions. This feature didn't work properly before
gcc 2.8. */
#if GCC_VERSION < 2008
#define __extension__
#endif
/* This is used to declare a const variable which should be visible
outside of the current compilation unit. Use it as
EXPORTED_CONST int i = 1;
This is because the semantics of const are different in C and C++.
"extern const" is permitted in C but it looks strange, and gcc
warns about it when -Wc++-compat is not used. */
#ifdef __cplusplus
#define EXPORTED_CONST extern const
#else
#define EXPORTED_CONST const
#endif
/* Be conservative and only use enum bitfields with C++ or GCC.
FIXME: provide a complete autoconf test for buggy enum bitfields. */
#ifdef __cplusplus
#define ENUM_BITFIELD(TYPE) enum TYPE
#elif (GCC_VERSION > 2000)
#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
#else
#define ENUM_BITFIELD(TYPE) unsigned int
#endif
#if defined(__cplusplus) && __cpp_constexpr >= 200704
#define CONSTEXPR constexpr
#else
#define CONSTEXPR
#endif
/* A macro to disable the copy constructor and assignment operator.
When building with C++11 and above, the methods are explicitly
deleted, causing a compile-time error if something tries to copy.
For C++03, this just declares the methods, causing a link-time
error if the methods end up called (assuming you don't
define them). For C++03, for best results, place the macro
under the private: access specifier, like this,
class name_lookup
{
private:
DISABLE_COPY_AND_ASSIGN (name_lookup);
};
so that most attempts at copy are caught at compile-time. */
#if defined(__cplusplus) && __cplusplus >= 201103
#define DISABLE_COPY_AND_ASSIGN(TYPE) \
TYPE (const TYPE&) = delete; \
void operator= (const TYPE &) = delete
#else
#define DISABLE_COPY_AND_ASSIGN(TYPE) \
TYPE (const TYPE&); \
void operator= (const TYPE &)
#endif /* __cplusplus >= 201103 */
#ifdef __cplusplus
}
#endif
#endif /* ansidecl.h */

201
3rdparty/demangler/include/cp-demangle.h vendored Normal file
View File

@@ -0,0 +1,201 @@
/* Internal demangler interface for g++ V3 ABI.
Copyright (C) 2003-2023 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@wasabisystems.com>.
This file is part of the libiberty library, which is part of GCC.
This file is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file. (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combined
executable.)
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* This file provides some definitions shared by cp-demangle.c and
cp-demint.c. It should not be included by any other files. */
/* Information we keep for operators. */
struct demangle_operator_info
{
/* Mangled name. */
const char *code;
/* Real name. */
const char *name;
/* Length of real name. */
int len;
/* Number of arguments. */
int args;
};
/* How to print the value of a builtin type. */
enum d_builtin_type_print
{
/* Print as (type)val. */
D_PRINT_DEFAULT,
/* Print as integer. */
D_PRINT_INT,
/* Print as unsigned integer, with trailing "u". */
D_PRINT_UNSIGNED,
/* Print as long, with trailing "l". */
D_PRINT_LONG,
/* Print as unsigned long, with trailing "ul". */
D_PRINT_UNSIGNED_LONG,
/* Print as long long, with trailing "ll". */
D_PRINT_LONG_LONG,
/* Print as unsigned long long, with trailing "ull". */
D_PRINT_UNSIGNED_LONG_LONG,
/* Print as bool. */
D_PRINT_BOOL,
/* Print as float--put value in square brackets. */
D_PRINT_FLOAT,
/* Print in usual way, but here to detect void. */
D_PRINT_VOID
};
/* Information we keep for a builtin type. */
struct demangle_builtin_type_info
{
/* Type name. */
const char *name;
/* Length of type name. */
int len;
/* Type name when using Java. */
const char *java_name;
/* Length of java name. */
int java_len;
/* How to print a value of this type. */
enum d_builtin_type_print print;
};
/* The information structure we pass around. */
struct d_info
{
/* The string we are demangling. */
const char *s;
/* The end of the string we are demangling. */
const char *send;
/* The options passed to the demangler. */
int options;
/* The next character in the string to consider. */
const char *n;
/* The array of components. */
struct demangle_component *comps;
/* The index of the next available component. */
int next_comp;
/* The number of available component structures. */
int num_comps;
/* The array of substitutions. */
struct demangle_component **subs;
/* The index of the next substitution. */
int next_sub;
/* The number of available entries in the subs array. */
int num_subs;
/* The last name we saw, for constructors and destructors. */
struct demangle_component *last_name;
/* A running total of the length of large expansions from the
mangled name to the demangled name, such as standard
substitutions and builtin types. */
int expansion;
/* Non-zero if we are parsing an expression. */
int is_expression;
/* Non-zero if we are parsing the type operand of a conversion
operator, but not when in an expression. */
int is_conversion;
/* 1: using new unresolved-name grammar.
-1: using new unresolved-name grammar and saw an unresolved-name.
0: using old unresolved-name grammar. */
int unresolved_name_state;
/* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
the current recursion level. */
unsigned int recursion_level;
};
/* To avoid running past the ending '\0', don't:
- call d_peek_next_char if d_peek_char returned '\0'
- call d_advance with an 'i' that is too large
- call d_check_char(di, '\0')
Everything else is safe. */
#define d_peek_char(di) (*((di)->n))
#ifndef CHECK_DEMANGLER
# define d_peek_next_char(di) ((di)->n[1])
# define d_advance(di, i) ((di)->n += (i))
#endif
#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
#define d_str(di) ((di)->n)
#ifdef CHECK_DEMANGLER
static inline char
d_peek_next_char (const struct d_info *di)
{
if (!di->n[0])
abort ();
return di->n[1];
}
static inline void
d_advance (struct d_info *di, int i)
{
if (i < 0)
abort ();
while (i--)
{
if (!di->n[0])
abort ();
di->n++;
}
}
#endif
/* Functions and arrays in cp-demangle.c which are referenced by
functions in cp-demint.c. */
#ifdef IN_GLIBCPP_V3
#define CP_STATIC_IF_GLIBCPP_V3 static
#else
#define CP_STATIC_IF_GLIBCPP_V3 extern
#endif
#ifndef IN_GLIBCPP_V3
extern const struct demangle_operator_info cplus_demangle_operators[];
#endif
#define D_BUILTIN_TYPE_COUNT (36)
CP_STATIC_IF_GLIBCPP_V3
const struct demangle_builtin_type_info
cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT];
CP_STATIC_IF_GLIBCPP_V3
struct demangle_component *
cplus_demangle_mangled_name (struct d_info *, int);
CP_STATIC_IF_GLIBCPP_V3
struct demangle_component *
cplus_demangle_type (struct d_info *);
extern void
cplus_demangle_init_info (const char *, int, size_t, struct d_info *);
/* cp-demangle.c needs to define this a little differently */
#undef CP_STATIC_IF_GLIBCPP_V3

756
3rdparty/demangler/include/demangle.h vendored Normal file
View File

@@ -0,0 +1,756 @@
/* Defs for interface to demanglers.
Copyright (C) 1992-2023 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License
as published by the Free Software Foundation; either version 2, or
(at your option) any later version.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited
permission to link the compiled version of this file into
combinations with other programs, and to distribute those
combinations without any restriction coming from the use of this
file. (The Library Public License restrictions do apply in other
respects; for example, they cover modification of the file, and
distribution when not linked into a combined executable.)
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#if !defined (DEMANGLE_H)
#define DEMANGLE_H
#include "libiberty.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Options passed to cplus_demangle (in 2nd parameter). */
#define DMGL_NO_OPTS 0 /* For readability... */
#define DMGL_PARAMS (1 << 0) /* Include function args */
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
#define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when
present) after function signature.
It applies only to the toplevel
function type. */
#define DMGL_RET_DROP (1 << 6) /* Suppress printing function return
types, even if present. It applies
only to the toplevel function type.
*/
#define DMGL_AUTO (1 << 8)
#define DMGL_GNU (1 << 9)
#define DMGL_LUCID (1 << 10)
#define DMGL_ARM (1 << 11)
#define DMGL_HP (1 << 12) /* For the HP aCC compiler;
same as ARM except for
template arguments, etc. */
#define DMGL_EDG (1 << 13)
#define DMGL_GNU_V3 (1 << 14)
#define DMGL_GNAT (1 << 15)
#define DMGL_DLANG (1 << 16)
#define DMGL_RUST (1 << 17) /* Rust wraps GNU_V3 style mangling. */
/* If none of these are set, use 'current_demangling_style' as the default. */
#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST)
/* Disable a limit on the depth of recursion in mangled strings.
Note if this limit is disabled then stack exhaustion is possible when
demangling pathologically complicated strings. Bug reports about stack
exhaustion when the option is enabled will be rejected. */
#define DMGL_NO_RECURSE_LIMIT (1 << 18)
/* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as
the maximum depth of recursion allowed. It should be enough for any
real-world mangled name. */
#define DEMANGLE_RECURSION_LIMIT 2048
/* Enumeration of possible demangling styles.
Lucid and ARM styles are still kept logically distinct, even though
they now both behave identically. The resulting style is actual the
union of both. I.E. either style recognizes both "__pt__" and "__rf__"
for operator "->", even though the first is lucid style and the second
is ARM style. (FIXME?) */
extern enum demangling_styles
{
no_demangling = -1,
unknown_demangling = 0,
auto_demangling = DMGL_AUTO,
gnu_demangling = DMGL_GNU,
lucid_demangling = DMGL_LUCID,
arm_demangling = DMGL_ARM,
hp_demangling = DMGL_HP,
edg_demangling = DMGL_EDG,
gnu_v3_demangling = DMGL_GNU_V3,
java_demangling = DMGL_JAVA,
gnat_demangling = DMGL_GNAT,
dlang_demangling = DMGL_DLANG,
rust_demangling = DMGL_RUST
} current_demangling_style;
/* Define string names for the various demangling styles. */
#define NO_DEMANGLING_STYLE_STRING "none"
#define AUTO_DEMANGLING_STYLE_STRING "auto"
#define GNU_DEMANGLING_STYLE_STRING "gnu"
#define LUCID_DEMANGLING_STYLE_STRING "lucid"
#define ARM_DEMANGLING_STYLE_STRING "arm"
#define HP_DEMANGLING_STYLE_STRING "hp"
#define EDG_DEMANGLING_STYLE_STRING "edg"
#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3"
#define JAVA_DEMANGLING_STYLE_STRING "java"
#define GNAT_DEMANGLING_STYLE_STRING "gnat"
#define DLANG_DEMANGLING_STYLE_STRING "dlang"
#define RUST_DEMANGLING_STYLE_STRING "rust"
/* Some macros to test what demangling style is active. */
#define CURRENT_DEMANGLING_STYLE current_demangling_style
#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM)
#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP)
#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG)
#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
#define DLANG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_DLANG)
#define RUST_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_RUST)
/* Provide information about the available demangle styles. This code is
pulled from gdb into libiberty because it is useful to binutils also. */
extern const struct demangler_engine
{
const char *const demangling_style_name;
const enum demangling_styles demangling_style;
const char *const demangling_style_doc;
} libiberty_demanglers[];
extern char *
cplus_demangle (const char *mangled, int options);
/* CCC: Allocate the result on the heap to prevent buffer overruns. */
extern char *
cplus_demangle_opname (const char *opname, int options);
extern const char *
cplus_mangle_opname (const char *opname, int options);
/* Note: This sets global state. FIXME if you care about multi-threading. */
extern void
set_cplus_marker_for_demangling (int ch);
extern enum demangling_styles
cplus_demangle_set_style (enum demangling_styles style);
extern enum demangling_styles
cplus_demangle_name_to_style (const char *name);
/* Callback typedef for allocation-less demangler interfaces. */
typedef void (*demangle_callbackref) (const char *, size_t, void *);
/* V3 ABI demangling entry points, defined in cp-demangle.c. Callback
variants return non-zero on success, zero on error. char* variants
return a string allocated by malloc on success, NULL on error. */
extern int
cplus_demangle_v3_callback (const char *mangled, int options,
demangle_callbackref callback, void *opaque);
extern char*
cplus_demangle_v3 (const char *mangled, int options);
extern int
java_demangle_v3_callback (const char *mangled,
demangle_callbackref callback, void *opaque);
extern char*
java_demangle_v3 (const char *mangled);
char *
ada_demangle (const char *mangled, int options);
extern char *
dlang_demangle (const char *mangled, int options);
extern int
rust_demangle_callback (const char *mangled, int options,
demangle_callbackref callback, void *opaque);
extern char *
rust_demangle (const char *mangled, int options);
enum gnu_v3_ctor_kinds {
gnu_v3_complete_object_ctor = 1,
gnu_v3_base_object_ctor,
gnu_v3_complete_object_allocating_ctor,
/* These are not part of the V3 ABI. Unified constructors are generated
as a speed-for-space optimization when the -fdeclone-ctor-dtor option
is used, and are always internal symbols. */
gnu_v3_unified_ctor,
gnu_v3_object_ctor_group
};
/* Return non-zero iff NAME is the mangled form of a constructor name
in the G++ V3 ABI demangling style. Specifically, return an `enum
gnu_v3_ctor_kinds' value indicating what kind of constructor
it is. */
extern enum gnu_v3_ctor_kinds
is_gnu_v3_mangled_ctor (const char *name);
enum gnu_v3_dtor_kinds {
gnu_v3_deleting_dtor = 1,
gnu_v3_complete_object_dtor,
gnu_v3_base_object_dtor,
/* These are not part of the V3 ABI. Unified destructors are generated
as a speed-for-space optimization when the -fdeclone-ctor-dtor option
is used, and are always internal symbols. */
gnu_v3_unified_dtor,
gnu_v3_object_dtor_group
};
/* Return non-zero iff NAME is the mangled form of a destructor name
in the G++ V3 ABI demangling style. Specifically, return an `enum
gnu_v3_dtor_kinds' value, indicating what kind of destructor
it is. */
extern enum gnu_v3_dtor_kinds
is_gnu_v3_mangled_dtor (const char *name);
/* The V3 demangler works in two passes. The first pass builds a tree
representation of the mangled name, and the second pass turns the
tree representation into a demangled string. Here we define an
interface to permit a caller to build their own tree
representation, which they can pass to the demangler to get a
demangled string. This can be used to canonicalize user input into
something which the demangler might output. It could also be used
by other demanglers in the future. */
/* These are the component types which may be found in the tree. Many
component types have one or two subtrees, referred to as left and
right (a component type with only one subtree puts it in the left
subtree). */
enum demangle_component_type
{
/* A name, with a length and a pointer to a string. */
DEMANGLE_COMPONENT_NAME,
/* A qualified name. The left subtree is a class or namespace or
some such thing, and the right subtree is a name qualified by
that class. */
DEMANGLE_COMPONENT_QUAL_NAME,
/* A local name. The left subtree describes a function, and the
right subtree is a name which is local to that function. */
DEMANGLE_COMPONENT_LOCAL_NAME,
/* A typed name. The left subtree is a name, and the right subtree
describes that name as a function. */
DEMANGLE_COMPONENT_TYPED_NAME,
/* A template. The left subtree is a template name, and the right
subtree is a template argument list. */
DEMANGLE_COMPONENT_TEMPLATE,
/* A template parameter. This holds a number, which is the template
parameter index. */
DEMANGLE_COMPONENT_TEMPLATE_PARAM,
/* A function parameter. This holds a number, which is the index. */
DEMANGLE_COMPONENT_FUNCTION_PARAM,
/* A constructor. This holds a name and the kind of
constructor. */
DEMANGLE_COMPONENT_CTOR,
/* A destructor. This holds a name and the kind of destructor. */
DEMANGLE_COMPONENT_DTOR,
/* A vtable. This has one subtree, the type for which this is a
vtable. */
DEMANGLE_COMPONENT_VTABLE,
/* A VTT structure. This has one subtree, the type for which this
is a VTT. */
DEMANGLE_COMPONENT_VTT,
/* A construction vtable. The left subtree is the type for which
this is a vtable, and the right subtree is the derived type for
which this vtable is built. */
DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
/* A typeinfo structure. This has one subtree, the type for which
this is the tpeinfo structure. */
DEMANGLE_COMPONENT_TYPEINFO,
/* A typeinfo name. This has one subtree, the type for which this
is the typeinfo name. */
DEMANGLE_COMPONENT_TYPEINFO_NAME,
/* A typeinfo function. This has one subtree, the type for which
this is the tpyeinfo function. */
DEMANGLE_COMPONENT_TYPEINFO_FN,
/* A thunk. This has one subtree, the name for which this is a
thunk. */
DEMANGLE_COMPONENT_THUNK,
/* A virtual thunk. This has one subtree, the name for which this
is a virtual thunk. */
DEMANGLE_COMPONENT_VIRTUAL_THUNK,
/* A covariant thunk. This has one subtree, the name for which this
is a covariant thunk. */
DEMANGLE_COMPONENT_COVARIANT_THUNK,
/* A Java class. This has one subtree, the type. */
DEMANGLE_COMPONENT_JAVA_CLASS,
/* A guard variable. This has one subtree, the name for which this
is a guard variable. */
DEMANGLE_COMPONENT_GUARD,
/* The init and wrapper functions for C++11 thread_local variables. */
DEMANGLE_COMPONENT_TLS_INIT,
DEMANGLE_COMPONENT_TLS_WRAPPER,
/* A reference temporary. This has one subtree, the name for which
this is a temporary. */
DEMANGLE_COMPONENT_REFTEMP,
/* A hidden alias. This has one subtree, the encoding for which it
is providing alternative linkage. */
DEMANGLE_COMPONENT_HIDDEN_ALIAS,
/* A standard substitution. This holds the name of the
substitution. */
DEMANGLE_COMPONENT_SUB_STD,
/* The restrict qualifier. The one subtree is the type which is
being qualified. */
DEMANGLE_COMPONENT_RESTRICT,
/* The volatile qualifier. The one subtree is the type which is
being qualified. */
DEMANGLE_COMPONENT_VOLATILE,
/* The const qualifier. The one subtree is the type which is being
qualified. */
DEMANGLE_COMPONENT_CONST,
/* The restrict qualifier modifying a member function. The one
subtree is the type which is being qualified. */
DEMANGLE_COMPONENT_RESTRICT_THIS,
/* The volatile qualifier modifying a member function. The one
subtree is the type which is being qualified. */
DEMANGLE_COMPONENT_VOLATILE_THIS,
/* The const qualifier modifying a member function. The one subtree
is the type which is being qualified. */
DEMANGLE_COMPONENT_CONST_THIS,
/* C++11 A reference modifying a member function. The one subtree is the
type which is being referenced. */
DEMANGLE_COMPONENT_REFERENCE_THIS,
/* C++11: An rvalue reference modifying a member function. The one
subtree is the type which is being referenced. */
DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS,
/* A vendor qualifier. The left subtree is the type which is being
qualified, and the right subtree is the name of the
qualifier. */
DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
/* A pointer. The one subtree is the type which is being pointed
to. */
DEMANGLE_COMPONENT_POINTER,
/* A reference. The one subtree is the type which is being
referenced. */
DEMANGLE_COMPONENT_REFERENCE,
/* C++0x: An rvalue reference. The one subtree is the type which is
being referenced. */
DEMANGLE_COMPONENT_RVALUE_REFERENCE,
/* A complex type. The one subtree is the base type. */
DEMANGLE_COMPONENT_COMPLEX,
/* An imaginary type. The one subtree is the base type. */
DEMANGLE_COMPONENT_IMAGINARY,
/* A builtin type. This holds the builtin type information. */
DEMANGLE_COMPONENT_BUILTIN_TYPE,
/* A vendor's builtin type. This holds the name of the type. */
DEMANGLE_COMPONENT_VENDOR_TYPE,
/* A function type. The left subtree is the return type. The right
subtree is a list of ARGLIST nodes. Either or both may be
NULL. */
DEMANGLE_COMPONENT_FUNCTION_TYPE,
/* An array type. The left subtree is the dimension, which may be
NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an
expression. The right subtree is the element type. */
DEMANGLE_COMPONENT_ARRAY_TYPE,
/* A pointer to member type. The left subtree is the class type,
and the right subtree is the member type. CV-qualifiers appear
on the latter. */
DEMANGLE_COMPONENT_PTRMEM_TYPE,
/* A fixed-point type. */
DEMANGLE_COMPONENT_FIXED_TYPE,
/* A vector type. The left subtree is the number of elements,
the right subtree is the element type. */
DEMANGLE_COMPONENT_VECTOR_TYPE,
/* An argument list. The left subtree is the current argument, and
the right subtree is either NULL or another ARGLIST node. */
DEMANGLE_COMPONENT_ARGLIST,
/* A template argument list. The left subtree is the current
template argument, and the right subtree is either NULL or
another TEMPLATE_ARGLIST node. */
DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
/* A template parameter object (C++20). The left subtree is the
corresponding template argument. */
DEMANGLE_COMPONENT_TPARM_OBJ,
/* An initializer list. The left subtree is either an explicit type or
NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */
DEMANGLE_COMPONENT_INITIALIZER_LIST,
/* An operator. This holds information about a standard
operator. */
DEMANGLE_COMPONENT_OPERATOR,
/* An extended operator. This holds the number of arguments, and
the name of the extended operator. */
DEMANGLE_COMPONENT_EXTENDED_OPERATOR,
/* A typecast, represented as a unary operator. The one subtree is
the type to which the argument should be cast. */
DEMANGLE_COMPONENT_CAST,
/* A conversion operator, represented as a unary operator. The one
subtree is the type to which the argument should be converted
to. */
DEMANGLE_COMPONENT_CONVERSION,
/* A nullary expression. The left subtree is the operator. */
DEMANGLE_COMPONENT_NULLARY,
/* A unary expression. The left subtree is the operator, and the
right subtree is the single argument. */
DEMANGLE_COMPONENT_UNARY,
/* A binary expression. The left subtree is the operator, and the
right subtree is a BINARY_ARGS. */
DEMANGLE_COMPONENT_BINARY,
/* Arguments to a binary expression. The left subtree is the first
argument, and the right subtree is the second argument. */
DEMANGLE_COMPONENT_BINARY_ARGS,
/* A trinary expression. The left subtree is the operator, and the
right subtree is a TRINARY_ARG1. */
DEMANGLE_COMPONENT_TRINARY,
/* Arguments to a trinary expression. The left subtree is the first
argument, and the right subtree is a TRINARY_ARG2. */
DEMANGLE_COMPONENT_TRINARY_ARG1,
/* More arguments to a trinary expression. The left subtree is the
second argument, and the right subtree is the third argument. */
DEMANGLE_COMPONENT_TRINARY_ARG2,
/* A literal. The left subtree is the type, and the right subtree
is the value, represented as a DEMANGLE_COMPONENT_NAME. */
DEMANGLE_COMPONENT_LITERAL,
/* A negative literal. Like LITERAL, but the value is negated.
This is a minor hack: the NAME used for LITERAL points directly
to the mangled string, but since negative numbers are mangled
using 'n' instead of '-', we want a way to indicate a negative
number which involves neither modifying the mangled string nor
allocating a new copy of the literal in memory. */
DEMANGLE_COMPONENT_LITERAL_NEG,
/* A vendor's builtin expression. The left subtree holds the
expression's name, and the right subtree is a argument list. */
DEMANGLE_COMPONENT_VENDOR_EXPR,
/* A libgcj compiled resource. The left subtree is the name of the
resource. */
DEMANGLE_COMPONENT_JAVA_RESOURCE,
/* A name formed by the concatenation of two parts. The left
subtree is the first part and the right subtree the second. */
DEMANGLE_COMPONENT_COMPOUND_NAME,
/* A name formed by a single character. */
DEMANGLE_COMPONENT_CHARACTER,
/* A number. */
DEMANGLE_COMPONENT_NUMBER,
/* A decltype type. */
DEMANGLE_COMPONENT_DECLTYPE,
/* Global constructors keyed to name. */
DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS,
/* Global destructors keyed to name. */
DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS,
/* A lambda closure type. */
DEMANGLE_COMPONENT_LAMBDA,
/* A default argument scope. */
DEMANGLE_COMPONENT_DEFAULT_ARG,
/* An unnamed type. */
DEMANGLE_COMPONENT_UNNAMED_TYPE,
/* A transactional clone. This has one subtree, the encoding for
which it is providing alternative linkage. */
DEMANGLE_COMPONENT_TRANSACTION_CLONE,
/* A non-transactional clone entry point. In the i386/x86_64 abi,
the unmangled symbol of a tm_callable becomes a thunk and the
non-transactional function version is mangled thus. */
DEMANGLE_COMPONENT_NONTRANSACTION_CLONE,
/* A pack expansion. */
DEMANGLE_COMPONENT_PACK_EXPANSION,
/* A name with an ABI tag. */
DEMANGLE_COMPONENT_TAGGED_NAME,
/* A transaction-safe function type. */
DEMANGLE_COMPONENT_TRANSACTION_SAFE,
/* A cloned function. */
DEMANGLE_COMPONENT_CLONE,
DEMANGLE_COMPONENT_NOEXCEPT,
DEMANGLE_COMPONENT_THROW_SPEC,
DEMANGLE_COMPONENT_STRUCTURED_BINDING,
DEMANGLE_COMPONENT_MODULE_NAME,
DEMANGLE_COMPONENT_MODULE_PARTITION,
DEMANGLE_COMPONENT_MODULE_ENTITY,
DEMANGLE_COMPONENT_MODULE_INIT,
DEMANGLE_COMPONENT_TEMPLATE_HEAD,
DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM,
/* A builtin type with argument. This holds the builtin type
information. */
DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
};
/* Types which are only used internally. */
struct demangle_operator_info;
struct demangle_builtin_type_info;
/* A node in the tree representation is an instance of a struct
demangle_component. Note that the field names of the struct are
not well protected against macros defined by the file including
this one. We can fix this if it ever becomes a problem. */
struct demangle_component
{
/* The type of this component. */
enum demangle_component_type type;
/* Guard against recursive component printing.
Initialize to zero. Private to d_print_comp.
All other fields are final after initialization. */
int d_printing;
int d_counting;
union
{
/* For DEMANGLE_COMPONENT_NAME. */
struct
{
/* A pointer to the name (which need not NULL terminated) and
its length. */
const char *s;
int len;
} s_name;
/* For DEMANGLE_COMPONENT_OPERATOR. */
struct
{
/* Operator. */
const struct demangle_operator_info *op;
} s_operator;
/* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
struct
{
/* Number of arguments. */
int args;
/* Name. */
struct demangle_component *name;
} s_extended_operator;
/* For DEMANGLE_COMPONENT_FIXED_TYPE. */
struct
{
/* The length, indicated by a C integer type name. */
struct demangle_component *length;
/* _Accum or _Fract? */
short accum;
/* Saturating or not? */
short sat;
} s_fixed;
/* For DEMANGLE_COMPONENT_CTOR. */
struct
{
/* Kind of constructor. */
enum gnu_v3_ctor_kinds kind;
/* Name. */
struct demangle_component *name;
} s_ctor;
/* For DEMANGLE_COMPONENT_DTOR. */
struct
{
/* Kind of destructor. */
enum gnu_v3_dtor_kinds kind;
/* Name. */
struct demangle_component *name;
} s_dtor;
/* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */
struct
{
/* Builtin type. */
const struct demangle_builtin_type_info *type;
} s_builtin;
/* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. */
struct
{
/* Builtin type. */
const struct demangle_builtin_type_info *type;
short arg;
char suffix;
} s_extended_builtin;
/* For DEMANGLE_COMPONENT_SUB_STD. */
struct
{
/* Standard substitution string. */
const char* string;
/* Length of string. */
int len;
} s_string;
/* For DEMANGLE_COMPONENT_*_PARAM. */
struct
{
/* Parameter index. */
long number;
} s_number;
/* For DEMANGLE_COMPONENT_CHARACTER. */
struct
{
int character;
} s_character;
/* For other types. */
struct
{
/* Left (or only) subtree. */
struct demangle_component *left;
/* Right subtree. */
struct demangle_component *right;
} s_binary;
struct
{
/* subtree, same place as d_left. */
struct demangle_component *sub;
/* integer. */
int num;
} s_unary_num;
} u;
};
/* People building mangled trees are expected to allocate instances of
struct demangle_component themselves. They can then call one of
the following functions to fill them in. */
/* Fill in most component types with a left subtree and a right
subtree. Returns non-zero on success, zero on failure, such as an
unrecognized or inappropriate component type. */
extern int
cplus_demangle_fill_component (struct demangle_component *fill,
enum demangle_component_type,
struct demangle_component *left,
struct demangle_component *right);
/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_name (struct demangle_component *fill,
const char *, int);
/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the
builtin type (e.g., "int", etc.). Returns non-zero on success,
zero if the type is not recognized. */
extern int
cplus_demangle_fill_builtin_type (struct demangle_component *fill,
const char *type_name);
/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the
operator and the number of arguments which it takes (the latter is
used to disambiguate operators which can be both binary and unary,
such as '-'). Returns non-zero on success, zero if the operator is
not recognized. */
extern int
cplus_demangle_fill_operator (struct demangle_component *fill,
const char *opname, int args);
/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the
number of arguments and the name. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_extended_operator (struct demangle_component *fill,
int numargs,
struct demangle_component *nm);
/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_ctor (struct demangle_component *fill,
enum gnu_v3_ctor_kinds kind,
struct demangle_component *name);
/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_dtor (struct demangle_component *fill,
enum gnu_v3_dtor_kinds kind,
struct demangle_component *name);
/* This function translates a mangled name into a struct
demangle_component tree. The first argument is the mangled name.
The second argument is DMGL_* options. This returns a pointer to a
tree on success, or NULL on failure. On success, the third
argument is set to a block of memory allocated by malloc. This
block should be passed to free when the tree is no longer
needed. */
extern struct demangle_component *
cplus_demangle_v3_components (const char *mangled, int options, void **mem);
/* This function takes a struct demangle_component tree and returns
the corresponding demangled string. The first argument is DMGL_*
options. The second is the tree to demangle. The third is a guess
at the length of the demangled string, used to initially allocate
the return buffer. The fourth is a pointer to a size_t. On
success, this function returns a buffer allocated by malloc(), and
sets the size_t pointed to by the fourth argument to the size of
the allocated buffer (not the length of the returned string). On
failure, this function returns NULL, and sets the size_t pointed to
by the fourth argument to 0 for an invalid tree, or to 1 for a
memory allocation error. */
extern char *
cplus_demangle_print (int options,
struct demangle_component *tree,
int estimated_length,
size_t *p_allocated_size);
/* This function takes a struct demangle_component tree and passes back
a demangled string in one or more calls to a callback function.
The first argument is DMGL_* options. The second is the tree to
demangle. The third is a pointer to a callback function; on each call
this receives an element of the demangled string, its length, and an
opaque value. The fourth is the opaque value passed to the callback.
The callback is called once or more to return the full demangled
string. The demangled element string is always nul-terminated, though
its length is also provided for convenience. In contrast to
cplus_demangle_print(), this function does not allocate heap memory
to grow output strings (except perhaps where alloca() is implemented
by malloc()), and so is normally safe for use where the heap has been
corrupted. On success, this function returns 1; on failure, 0. */
extern int
cplus_demangle_print_callback (int options,
struct demangle_component *tree,
demangle_callbackref callback, void *opaque);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DEMANGLE_H */

View File

@@ -1,45 +0,0 @@
/**
* @file include/demangler/demangler.h
* @brief Demangler library.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_DEMANGLERL_H
#define DEMANGLER_DEMANGLERL_H
#include <memory>
#include <string>
#include "demangler/gparser.h"
namespace demangler {
/**
* The grammar parser class - the core of the demangler.
*/
class CDemangler {
cGram *pGram;
cName *pName;
std::string compiler = "gcc";
cGram::errcode errState; /// error state; 0 = everyting is ok
public:
CDemangler(std::string gname, bool i = true);
static std::unique_ptr<CDemangler> createGcc(bool i = true);
static std::unique_ptr<CDemangler> createMs(bool i = true);
static std::unique_ptr<CDemangler> createBorland(bool i = true);
virtual ~CDemangler();
bool isOk();
std::string printError();
void resetError();
void createGrammar(std::string inputfilename, std::string outputname);
cName *demangleToClass(std::string inputName);
std::string demangleToString(std::string inputName);
void setSubAnalyze(bool x);
};
} // namespace demangler
#endif

View File

@@ -1,20 +0,0 @@
/**
* @file include/demangler/demglobal.h
* @brief Global variables in demangler namespace.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_DEMGLOBAL_H
#define DEMANGLER_DEMGLOBAL_H
#include "demangler/igrams.h"
namespace demangler {
extern cGram::igram_t internalGrammarStruct;
extern cIgram_msll* igram_msll;
extern cIgram_gccll* igram_gccll;
} // namespace demangler
#endif

View File

@@ -1,36 +0,0 @@
/**
* @file include/demangler/demtools.h
* @brief Tools and extra functions for demangler.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_DEMTOOLS_H
#define DEMANGLER_DEMTOOLS_H
#include <string>
namespace demangler {
/**
* @brief Structure for date and time.
*/
struct sdate_t {
unsigned int y = 0;
unsigned int m = 0;
unsigned int d = 0;
unsigned int h = 0;
unsigned int min = 0;
unsigned int s = 0;
};
bool fileExists(const std::string &filename);
void initSdate_t(sdate_t &x);
sdate_t genTimeStruct();
void xreplace(std::string &source, const std::string &tobereplaced, const std::string &replacement);
} // namespace demangler
#endif

View File

@@ -1,830 +0,0 @@
/**
* @file include/demangler/gparser.h
* @brief Parser of LL grammar.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_GPARSER_H
#define DEMANGLER_GPARSER_H
#include <map>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
//internal grammars
namespace demangler {
/**
* @brief Class which holds a demangled name.
*/
class cName {
public:
/**
* @brief Enum of types of the mangled types (Determines whether a type is built-in or named).
*/
enum ttype { //type of type
TT_UNKNOWN = 0, //can be used for unknown return type
TT_BUILTIN,
TT_NAME,
TT_NUM,
TT_PEXPR
};
/**
* @brief Enum of types of the mangled names.
*/
enum ntype { //type of the mangled name
NT_FUNCTION = 0,
NT_TEMPLFUNCTION,
NT_OPERATOR,
NT_CONSTRUCTOR,
NT_DESTRUCTOR,
NT_DATA,
NT_VTABLE,
NT_R0,
NT_R1,
NT_R2,
NT_R3,
NT_R4,
NT__A,
NT__B,
NT__C,
NT__D,
NT__E,
NT__F,
NT__G,
NT__H,
NT__I,
NT__J,
NT__K,
NT__L,
NT__M,
NT__N,
NT__O,
NT__P,
NT__Q,
NT__R,
NT__S,
NT__T,
NT__U,
NT__V,
NT__W,
NT__X,
NT__Y,
NT__Z,
NT_CLASS
};
/**
* @brief Enum of operator types.
*/
enum optype { //type of operator
OT_NULL = 0,
OT_NEW,
OT_NEWARR,
OT_DEL,
OT_DELARR,
OT_UPLUS,
OT_UMINUS,
OT_UAND,
OT_UAST,
OT_TILDA,
OT_PLUS,
OT_MINUS,
OT_AST,
OT_DIV,
OT_MOD,
OT_AND,
OT_OR,
OT_EXP,
OT_ASSIGN,
OT_PLUSASS,
OT_MINUSASS,
OT_ASTASS,
OT_DIVASS,
OT_MODASS,
OT_ANDASS,
OT_ORASS,
OT_EXPASS,
OT_LSHIFT,
OT_RSHIFT,
OT_LSHIFTASS,
OT_RSHIFTASS,
OT_EQ,
OT_NEQ,
OT_LT,
OT_GT,
OT_LE,
OT_GE,
OT_NOT,
OT_ANDAND,
OT_OROR,
OT_PLUSPLUS,
OT_MINUSMINUS,
OT_COMMA,
OT_PTAST,
OT_PT,
OT_BRACKETS,
OT_ARR,
OT_QUESTION,
OT_SIZEOFT,
OT_SIZEOFE,
OT_ALIGNOFT,
OT_ALIGNOFE,
OT_CAST
};
/**
* @brief Enum of built-in types.
*/
enum st_type { //standard built-in types
T_VOID = 0,
T_WCHAR,
T_BOOL,
T_CHAR,
T_SCHAR,
T_UCHAR,
T_SHORT,
T_USHORT,
T_INT,
T_UINT,
T_LONG,
T_ULONG,
T_LONGLONG,
T_ULONGLONG,
T_INT128,
T_UINT128,
T_FLOAT,
T_DOUBLE,
T_LONGDOUBLE,
T_FLOAT128,
T_ELLIPSIS,
T_DD,
T_DE,
T_DF,
T_DH,
T_CHAR32,
T_CHAR16,
T_AUTO,
T_NULLPTR
};
/**
* @brief Enum of member function accessibility.
*/
enum memfacc_t { //standard built-in types
MFM_NULL = 0,
MFM_PRIVATE,
MFM_PUBLIC,
MFM_PROTECTED
};
/**
* @brief Enum of function call conventions.
*/
enum fcall_t { //standard built-in types
FCC_NULL = 0,
FCC_CDECL,
FCC_PASCAL,
FCC_FORTRAN,
FCC_THISCALL,
FCC_STDCALL,
FCC_FASTCALL,
FCC_INTERRUPT
};
/**
* @brief Enum of named type classifications. Union, Struct, Class, Enum.
*/
enum mstype_t { //standard built-in types
MST_NULL = 0,
MST_UNION,
MST_STRUCT,
MST_CLASS,
MST_ENUM
};
/**
* @brief Structure of an unqualified name.
* @param un String which holds the name.
* @param tpl Pointer to the the template (vector of types) of this unqualified name. If nullptr, the unqualified name consists only of the string.
*/
struct name_t {
std::string un; //unqualified name
void *tpl = nullptr; //std::vector<type_t>
bool op = false; //is it operator name element?
};
/**
* @brief Structure of a type.
* @param type Type of the type.
* @param b Built-in type. This value is defined only if 'type' is TT_BUILTIN.
* @param n Qualified name of the type. This value is defined only if 'type' is TT_NAME.
* @param is_const Bool value which determines whether the type is const.
* @param is_restrict Bool value which determines whether the type is restrict.
* @param is_volatile Bool value which determines whether the type is volatile.
* @param is_pointer Integer value determining the pointer level of the type.
* @param is_reference Bool value which determines whether the type is a reference.
* @param is_rvalue Bool value which determines whether the type is an R-value.
* @param is_cpair Bool value which determines whether the type is a complex pair.
* @param is_imaginary Bool value which determines whether the type is imaginary.
*/
struct type_t {
ttype type = TT_UNKNOWN; //type of type... builtin or named type
st_type b = T_VOID; //builtin type
void *value = nullptr; //expression value
std::vector<name_t> n; //qualified name of named type
std::string modifiers;
mstype_t mst = MST_NULL;
int num = 0;
bool is_array = false;
std::vector<unsigned int> array_dimensions;
bool is_const = false;
bool is_restrict = false;
bool is_volatile = false;
unsigned int is_pointer = 0;
bool is_reference = false;
bool is_rvalue = false; //r-value reference
bool is_cpair = false; //complex pair
bool is_imaginary = false;
std::string getLlvmType();
private:
std::string llvmIr;
std::string getLlvmTypePrivate();
};
ntype name_type = NT_FUNCTION; //name type
optype operator_type = OT_NULL; //type of operator. it is OT_NULL if function is not an operator
type_t return_type;
type_t special_type; //return value for function or conversion type for operator OT_CAST
std::string modifiers;
memfacc_t member_function_access = MFM_NULL;
fcall_t function_call = FCC_NULL;
bool is_static = false;
bool is_virtual = false;
std::string storage_class;
std::vector<long int> rttibcd;
std::vector<type_t> parameters; //function parameters
std::vector<name_t> name; //qualified name composed of unqualified names
void *tf_tpl = nullptr;
bool last_shown_endtpl = false; //an auxiliary variable which helps to add space between multiple '>' at the end of templates
void deleteparams(std::vector<type_t> & vec);
cName(); //constructor
virtual ~cName(); //mass destruction
void type_t_clear(type_t &x);
void addname(const std::vector<name_t> & inname); //set the function name
void addpar(const std::vector<type_t> & inpar); //set the parameters of the name
void setnametype(ntype x); //set type of the mangled name
void setfcall(fcall_t x); //set type of the function call convention
void setmfacc(memfacc_t x); //set type of the member function access level
ntype getnametype(void); //get type of the mangled name
void setop(optype x); //set operator type
void setret(type_t x); //set return type
void setspec(type_t x); //set special type
void setstatic(); //set name's static flag
void setvirtual(); //set name's virtual flag
void addmodifier(char x); //add a modifier to the name modifier string
void addstcl(char x); //add a modifier to the storage class string
void setmodifiers(std::string x); //set modifiers
void settftpl(void* x); //set template function template
void addrttinum(long int x); //add a RTTI Base Class descriptor num
std::string optypetostr(optype x); //operator type to string
std::string printmodifiers(std::string x, bool space);
std::string printpremodifiers(std::string x, bool space);
std::string printpostmodifiers(std::string x, bool space);
std::string printname(std::vector<name_t> & vec, std::string compiler = "gcc");
std::string printparams(std::vector<type_t> & vec, bool ignorevoid = false, std::string compiler = "gcc");
std::string printpexpr(type_t & x);
/**
* @brief Print the calling convention to a string.
* @param callconv The calling convention to be printed.
* @return String containing calling convention.
*/
std::string printcallingconvention(fcall_t callconv);
std::string printall(std::string compiler = "gcc");
std::string printall_old(bool msvcpp = false);
}; //class cName
/**
* @brief Grammar class. It's member functions allow loading an external grammar and demangling a mangled name using the grammar.
*/
class cGram {
public:
/**
* @brief Global array of semantic action names. Used when building internal LL table from external grammar.
*/
static const char *semactname[];
/**
* @brief Enum of error codes.
*/
enum errcode {
ERROR_OK = 0,
ERROR_FILE,
ERROR_FSM,
ERROR_SYN,
ERROR_MEM,
ERROR_GRAM,
ERROR_LL,
ERROR_UNK
};
/**
* @brief An array of error messages.
*/
static const char *errmsg[];
/**
* @brief Type of a grammar element. It can be either a terminal or a non-terminal.
*/
enum gelemtype {
GE_TERM = 0,
GE_NONTERM
};
/**
* @brief Structure of a grammar element.
* @param type Type of the element (terminal or non-terminal).
* @param nt The name of the non-terminal. Only vylid if type is GE_NONTERM.
* @param t The byte value of the terminal. Only valid if type is GE_TERM.
*/
struct gelem_t {
gelem_t(gelemtype t, char* n, unsigned int i, char c) :
type(t),
nt(n),
ntst(i),
t(c)
{}
gelem_t() {}
gelemtype type = GE_TERM;
char* nt = nullptr;
unsigned int ntst = 0;
char t = 0;
};
/**
* @brief Enum of semantic actions.
*/
enum semact {
//do nothing
SA_NULL = 0,
//set type of name (function, operator, constructor, destructor, data)
SA_SETNAMEF,
SA_SETNAMETF,
SA_SETNAMEO,
SA_SETNAMEC,
SA_SETNAMED,
SA_SETNAMEX,
SA_SETNAMEVT,
//set operator type
SA_SETOPXX,
SA_SETOPNW,
SA_SETOPNA,
SA_SETOPDL,
SA_SETOPDA,
SA_SETOPPS,
SA_SETOPNG,
SA_SETOPAD,
SA_SETOPDE,
SA_SETOPCO,
SA_SETOPPL,
SA_SETOPMI,
SA_SETOPML,
SA_SETOPDV,
SA_SETOPRM,
SA_SETOPAN,
SA_SETOPOR,
SA_SETOPEO,
SA_SETOPASS,
SA_SETOPPLL,
SA_SETOPMII,
SA_SETOPMLL,
SA_SETOPDVV,
SA_SETOPRMM,
SA_SETOPANN,
SA_SETOPORR,
SA_SETOPEOO,
SA_SETOPLS,
SA_SETOPRS,
SA_SETOPLSS,
SA_SETOPRSS,
SA_SETOPEQ,
SA_SETOPNE,
SA_SETOPLT,
SA_SETOPGT,
SA_SETOPLE,
SA_SETOPGE,
SA_SETOPNT,
SA_SETOPAA,
SA_SETOPOO,
SA_SETOPPP,
SA_SETOPMM,
SA_SETOPCM,
SA_SETOPPM,
SA_SETOPPT,
SA_SETOPCL,
SA_SETOPIX,
SA_SETOPQU,
SA_SETOPST,
SA_SETOPSZ,
SA_SETOPAT,
SA_SETOPAZ,
SA_SETOPCV,
//builtin types
SA_SETTYPEV,
SA_SETTYPEW,
SA_SETTYPEB,
SA_SETTYPEC,
SA_SETTYPEA,
SA_SETTYPEH,
SA_SETTYPES,
SA_SETTYPET,
SA_SETTYPEI,
SA_SETTYPEJ,
SA_SETTYPEL,
SA_SETTYPEM,
SA_SETTYPEX,
SA_SETTYPEY,
SA_SETTYPEN,
SA_SETTYPEO,
SA_SETTYPEF,
SA_SETTYPED,
SA_SETTYPEE,
SA_SETTYPEG,
SA_SETTYPEZ,
//parameter modifiers
SA_SETCONST,
SA_SETRESTRICT,
SA_SETVOLATILE,
SA_SETPTR,
SA_SETREF,
SA_SETRVAL,
SA_SETCPAIR,
SA_SETIM,
//substitutions
SA_SUBSTD, //::std::
SA_SUBALC, //::std::allocator
SA_SUBSTR, //::std::basic_string
SA_SUBSTRS, //::std::basic_string<char,::std::char_traits<char>,::std::allocator<char>>
SA_SUBISTR, //::std::basic_istream<char, std::char_traits<char>>
SA_SUBOSTR, //::std::basic_ostream<char, std::char_traits<char>>
SA_SUBIOSTR, //::std::basic_iostream<char, std::char_traits<char>>
//other very important semantic actions
SA_LOADID, //load an unqualified name into the qualified vector of names
SA_LOADSUB, //load a substitution
SA_LOADTSUB, //load a template sub
SA_LOADARR, //load an array dimension
SA_STOREPAR, //store current parameter to vector of parameters
SA_STORETEMPARG, //store current parameter to current vector of template arguments
SA_STORETEMPLATE, //store the whole template into the last name element of last name vector
SA_BEGINTEMPL, //begin a template
SA_SKIPTEMPL, //skip a template
SA_PAR2F, //store current vector of parameters into the function
SA_PAR2RET, //store current parameter to the return value
SA_PAR2SPEC, //store current parameter to the special value
SA_UNQ2F, //future identifiers are added to the function name
SA_UNQ2P, //function identifiers are added to parameter name
//substitution expansion modifiers
SA_SSNEST, //nested sub
SA_STUNQ, //unqualified std:: sub
SA_SSNO, //other sub derived from <name>
SA_TYPE2EXPR, //builtin type is converted to primary expression
SA_EXPRVAL, //load expression value
SA_BEGINPEXPR, //begin a primary expression
SA_STOREPEXPR, //end a primary expression
SA_COPYTERM, //copy the terminal on the input into current_name in substitution analyzer
SA_ADDCHARTONAME, //add current character to current unqualified name
SA_STORENAME, //move current unqualified name into current name vector
SA_REVERSENAME,
SA_SETPRIVATE,
SA_SETPUBLIC,
SA_SETPROTECTED,
SA_SETFCDECL,
SA_SETFPASCAL,
SA_SETFFORTRAN,
SA_SETFTHISCALL,
SA_SETFSTDCALL,
SA_SETFFASTCALL,
SA_SETFINTERRUPT,
SA_SETUNION,
SA_SETSTRUCT,
SA_SETCLASS,
SA_SETENUM,
SA_SETSTATIC,
SA_SETVIRTUAL,
SA_STCLCONST,
SA_STCLVOL,
SA_STCLFAR,
SA_STCLHUGE,
SA_SAVENAMESUB,
SA_LOADNAMESUB,
SA_MSTEMPLPSUB,
SA_SETNAMER0,
SA_SETNAMER1,
SA_SETNAMER2,
SA_SETNAMER3,
SA_SETNAMER4,
SA_SETNAME_A,
SA_SETNAME_B,
SA_SETNAME_C,
SA_SETNAME_D,
SA_SETNAME_E,
SA_SETNAME_F,
SA_SETNAME_G,
SA_SETNAME_H,
SA_SETNAME_I,
SA_SETNAME_J,
SA_SETNAME_K,
SA_SETNAME_L,
SA_SETNAME_M,
SA_SETNAME_N,
SA_SETNAME_O,
SA_SETNAME_P,
SA_SETNAME_Q,
SA_SETNAME_R,
SA_SETNAME_S,
SA_SETNAME_T,
SA_SETNAME_U,
SA_SETNAME_V,
SA_SETNAME_W,
SA_SETNAME_X,
SA_SETNAME_Y,
SA_SETNAME_Z,
SA_TEMPL2TFTPL,
SA_BEGINBSUB,
SA_LOADBSUB,
SA_ADDMCONST,
SA_ADDMVOL,
SA_ADDMFAR,
SA_ADDMHUGE,
SA_LOADMSNUM,
SA_NUMTORTTIBCD,
SA_NUMTOTYPE,
SA_BORLANDNORMALIZEPARNAME,
SA_BORLANDID,
SA_LOADBORLANDSUB,
SA_BORLANDARR,
SA_END
};
/**
* @brief Structure of an element in an internal LL table.
* @param n Rule number. Numbered from 1. 0 is reserved for "no rule", which indicates a syntax error.
* @param s Semantic action to be done when this LL element is used.
*/
struct llelem_t {
llelem_t(unsigned int i, semact ss) :
n(i),
s(ss)
{}
llelem_t() {}
unsigned int n = 0;
semact s = SA_NULL;
};
/**
* @brief Struct used to describe a rule boundaries in an internal LL table.
* @param offset Offset from the start of ruleelements array.
* @param size Number of elements in the current rule.
*/
struct ruleaddr_t {
ruleaddr_t(unsigned int o, unsigned int s) :
offset(o),
size(s)
{}
unsigned int offset = 0;
unsigned int size = 0;
};
/**
* @brief Structure of a grammar rule.
* @param n Number of the rule. Numbered from 1. 0 is reserved for "no rule", which indicates a syntax error.
* @param left The left side of the rule, consisting of only one non-terminal.
* @param right The right side of the rule, which is a sequence of terminals or non-terminals. May be empty.
*/
struct rule_t {
unsigned int n = 0;
gelem_t left;
std::vector<gelem_t> right;
};
/**
* @brief Types of substitution expansion.
*/
enum subtype {
ST_NULL = 0,
ST_STUNQ,
ST_SSNEST,
ST_SSNO
};
/**
* @brief States of the FSM for parsing grammar rules from a file.
*/
enum fsmstate {
S_START = 0, //beginning of a line
S_NT_LEFT, //non-terminal on the left side
S_OP1, //:
S_OP2, //:
S_OP3, //=
S_RIGHT, //right side
S_NT_RIGHT, //non-terminal on the right side
S_T, //terminal on the right side
S_QT, //quoted terminal on the right side
S_QT_ESC, //escape sequence of a quoted terminal
S_IGNORE, //ignore the rest of the line
S_ERROR, //error ocurred
S_NULL //just a NULL terminator for the array of final states
};
/**
* @brief Class for comparing two grammar element structures. Used in std::set of grammar elements.
*/
class comparegelem_c {
public:
/**
* @brief Comparison function for two grammar element structures
* @param t1 First grammar element.
* @param t2 Second grammar element.
*/
bool operator() (const gelem_t t1, const gelem_t t2) const {
//if types don't match, terminal is less than non-terminal
if (t1.type!= t2.type) {
return (t1.type == GE_TERM)?true:false;
}
//for two terminals, compare their byte values
if (t1.type == GE_TERM) {
return t1.t < t2.t;
}
//for two non-terminals, compare the non-terminal name strings
else {
return t1.nt < t2.nt;
}
}
};
/**
* @brief Struct for internal grammar.
*/
struct igram_t {
igram_t(unsigned int tsx, unsigned int rax, unsigned int rex, unsigned int lx, unsigned int ly,
gelem_t r, unsigned char* ts, ruleaddr_t* ra, gelem_t* re, llelem_t** lt) :
terminal_static_x(tsx),
ruleaddrs_x(rax),
ruleelements_x(rex),
llst_x(lx),
llst_y(ly),
root(r),
terminal_static(ts),
ruleaddrs(ra),
ruleelements(re),
llst(lt)
{}
igram_t() {}
//dimensions of the arrays
unsigned int terminal_static_x = 0;
unsigned int ruleaddrs_x = 0;
unsigned int ruleelements_x = 0;
unsigned int llst_x = 0; //first one
unsigned int llst_y = 0; //second one
//root element
gelem_t root;
//the arrays
unsigned char* terminal_static = nullptr; //array of used terminals
ruleaddr_t* ruleaddrs = nullptr; //structures defining offset and size of each rule in the ruleelements table
gelem_t* ruleelements = nullptr; //all elements of all rules
llelem_t** llst = nullptr; //the LL table
};
/**
* @brief The struct variable containing pointers to internal grammar data.
*/
cGram::igram_t internalGrammarStruct;
//FSM for parsing external rules
static const fsmstate fsm_final[];
static const gelem_t T_EOF;
bool internalGrammar = false;
std::string compiler;
/*
* Variables used for generation of new internal grammars
*/
std::string createIGrammar; //if this thing is on, new internal grammar will be generated from external grammar file
unsigned int newIG_terminal_static_x = 0;
std::size_t newIG_ruleaddrs_x = 0;
std::size_t newIG_ruleelements_x = 0;
std::size_t newIG_llst_x = 0;
std::size_t newIG_llst_y = 0;
std::string newIG_root;
std::string newIG_terminal_static;
std::string newIG_ruleaddrs;
std::string newIG_ruleelements;
std::string newIG_llst;
/*
* Variables for parsed external grammar
*/
std::vector<rule_t> rules;
std::map<std::string,bool> empty;
std::map<std::string,std::set<gelem_t,comparegelem_c>> first;
std::map<std::string,std::set<gelem_t,comparegelem_c>> follow;
std::map<unsigned int,std::set<gelem_t,comparegelem_c>> predict;
std::map<std::string,std::map<char,std::pair<unsigned int, semact>>> ll;
std::vector<unsigned char> terminals;
std::vector<std::string> nonterminals;
size_t lex_position = 0; //position in the source file
std::fstream *source = nullptr; //pointer to the input filestream
/*
* methods
*/
errcode loadfile(const std::string filename);
bool is_final(fsmstate s); //is s a final state of fsm?
char getc();
bool eof();
bool lf();
errcode getgrammar(const std::string filename);
bool copyset(std::set<gelem_t,comparegelem_c> & src, std::set<gelem_t,comparegelem_c> & dst);
void genempty();
void genfirst();
bool getempty(std::vector<gelem_t> & src);
std::set<gelem_t,comparegelem_c> getfirst(std::vector<gelem_t> & src);
llelem_t getllpair(std::string nt, unsigned int ntst, unsigned char t);
void genfollow();
void genpredict();
errcode genll();
errcode genconstll();
void genllsem();
errcode analyze(std::string input, cName & pName);
std::string subanalyze(const std::string input, cGram::errcode *err);
semact getsem(const std::string input);
void *getbstpl(cName & pName);
void *getstrtpl(cName & pName);
bool issub(std::string candidate,std::vector<std::string> & vec);
void showsubs(std::vector<std::string> & vec);
long int b36toint(std::string x);
void * copynametpl(void * src);
public:
//constructor
cGram();
//destructor
virtual ~cGram();
errcode initialize(std::string gname, bool i = true);
errcode parse(const std::string filename);
cName *perform(const std::string input, errcode *err);
void demangleClassName(const std::string& input, cName* retvalue, cGram::errcode& err_i);
void showrules();
void showempty();
void showfirst();
void showfollow();
void showpredict();
void showll();
unsigned int isnt(std::vector<std::string> & nonterminals, std::string nonterminal);
unsigned int ist(std::vector<unsigned char> & terminals, unsigned char terminal);
void resetError() {errString = "";}
std::string errString; //string containing last error message
bool errValid = false; //is the gParser valid? false if it has not been properly initialized yet
bool SubAnalyzeEnabled = false; //enable substitution analysis for GCC demangler?
void setSubAnalyze(bool x);
errcode generateIgrammar(const std::string inputfilename, const std::string outputname);
std::string generatedTerminalStatic;
}; //class cGram
} // namespace demangler
#endif

View File

@@ -1,23 +0,0 @@
/**
* @file include/demangler/igrams.h
* @brief Internal grammar list.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_IGRAMS_H
#define DEMANGLER_IGRAMS_H
//[igram] add internal grammar headers here
#include "demangler/stgrammars/borlandll.h"
#include "demangler/stgrammars/gccll.h"
#include "demangler/stgrammars/msll.h"
namespace demangler {
bool initIgram(std::string gname, cGram* gParser);
void deleteIgrams(cGram* gParser);
} // namespace demangler
#endif

View File

@@ -1,25 +0,0 @@
/**
* @file include/demangler/stgrammars/borlandll.h
* @brief Internal LL grammar for demangler.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_STGRAMMARS_BORLANDLL_H
#define DEMANGLER_STGRAMMARS_BORLANDLL_H
#include "demangler/gparser.h"
namespace demangler {
class cIgram_borlandll {
public:
static unsigned char terminal_static[256];
static cGram::llelem_t llst[280][69];
static cGram::ruleaddr_t ruleaddrs[467];
static cGram::gelem_t ruleelements[603];
static cGram::gelem_t root;
cGram::igram_t getInternalGrammar();
};
} // namespace demangler
#endif

View File

@@ -1,25 +0,0 @@
/**
* @file include/demangler/stgrammars/gccll.h
* @brief Internal LL grammar for demangler.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_STGRAMMARS_GCCLL_H
#define DEMANGLER_STGRAMMARS_GCCLL_H
#include "demangler/gparser.h"
namespace demangler {
class cIgram_gccll {
public:
static unsigned char terminal_static[256];
static cGram::llelem_t llst[254][64];
static cGram::ruleaddr_t ruleaddrs[423];
static cGram::gelem_t ruleelements[445];
static cGram::gelem_t root;
cGram::igram_t getInternalGrammar();
};
} // namespace demangler
#endif

View File

@@ -1,26 +0,0 @@
/**
* @file include/demangler/stgrammars/msll.h
* @brief Internal LL grammar for demangler.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#ifndef DEMANGLER_STGRAMMARS_MSLL_H
#define DEMANGLER_STGRAMMARS_MSLL_H
#include "demangler/gparser.h"
namespace demangler {
class cIgram_msll {
public:
static unsigned char terminal_static[256];
static cGram::llelem_t llst[249][68];
static cGram::ruleaddr_t ruleaddrs[534];
static cGram::gelem_t ruleelements[796];
static cGram::gelem_t root;
cGram::igram_t getInternalGrammar();
};
} // namespace demangler
#endif

72
3rdparty/demangler/include/dyn-string.h vendored Normal file
View File

@@ -0,0 +1,72 @@
/* An abstract string datatype.
Copyright (C) 1998-2023 Free Software Foundation, Inc.
Contributed by Mark Mitchell (mark@markmitchell.com).
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
#ifndef DYN_STRING_H
#define DYN_STRING_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dyn_string
{
int allocated; /* The amount of space allocated for the string. */
int length; /* The actual length of the string. */
char *s; /* The string itself, NUL-terminated. */
}* dyn_string_t;
/* The length STR, in bytes, not including the terminating NUL. */
#define dyn_string_length(STR) \
((STR)->length)
/* The NTBS in which the contents of STR are stored. */
#define dyn_string_buf(STR) \
((STR)->s)
/* Compare DS1 to DS2 with strcmp. */
#define dyn_string_compare(DS1, DS2) \
(strcmp ((DS1)->s, (DS2)->s))
extern int dyn_string_init (struct dyn_string *, int);
extern dyn_string_t dyn_string_new (int);
extern void dyn_string_delete (dyn_string_t);
extern char *dyn_string_release (dyn_string_t);
extern dyn_string_t dyn_string_resize (dyn_string_t, int);
extern void dyn_string_clear (dyn_string_t);
extern int dyn_string_copy (dyn_string_t, dyn_string_t);
extern int dyn_string_copy_cstr (dyn_string_t, const char *);
extern int dyn_string_prepend (dyn_string_t, dyn_string_t);
extern int dyn_string_prepend_cstr (dyn_string_t, const char *);
extern int dyn_string_insert (dyn_string_t, int, dyn_string_t);
extern int dyn_string_insert_cstr (dyn_string_t, int, const char *);
extern int dyn_string_insert_char (dyn_string_t, int, int);
extern int dyn_string_append (dyn_string_t, dyn_string_t);
extern int dyn_string_append_cstr (dyn_string_t, const char *);
extern int dyn_string_append_char (dyn_string_t, int);
extern int dyn_string_substring (dyn_string_t, dyn_string_t, int, int);
extern int dyn_string_eq (dyn_string_t, dyn_string_t);
#ifdef __cplusplus
}
#endif
#endif /* !defined (DYN_STRING_H) */

35
3rdparty/demangler/include/environ.h vendored Normal file
View File

@@ -0,0 +1,35 @@
/* Declare the environ system variable.
Copyright (C) 2015-2023 Free Software Foundation, Inc.
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* On OSX, the environ variable can be used directly in the code of an
executable, but cannot be used in the code of a shared library (such as
GCC's liblto_plugin, which links in libiberty code). Instead, the
function _NSGetEnviron can be called to get the address of environ. */
#ifndef HAVE_ENVIRON_DECL
# ifdef __APPLE__
# include <crt_externs.h>
# define environ (*_NSGetEnviron ())
# else
# ifndef environ
extern char **environ;
# endif
# endif
# define HAVE_ENVIRON_DECL
#endif

143
3rdparty/demangler/include/getopt.h vendored Normal file
View File

@@ -0,0 +1,143 @@
/* Declarations for getopt.
Copyright (C) 1989-2023 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if defined (__STDC__) && __STDC__
/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
undefined, we haven't run the autoconf check so provide the
declaration without arguments. If it is 0, we checked and failed
to find the declaration so provide a fully prototyped one. If it
is 1, we found it so don't provide any declaration at all. */
#if !HAVE_DECL_GETOPT
#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in unistd.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else
#ifndef __cplusplus
extern int getopt ();
#endif /* __cplusplus */
#endif
#endif /* !HAVE_DECL_GETOPT */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* getopt.h */

761
3rdparty/demangler/include/libiberty.h vendored Normal file
View File

@@ -0,0 +1,761 @@
/* Function declarations for libiberty.
Copyright (C) 1997-2023 Free Software Foundation, Inc.
Note - certain prototypes declared in this header file are for
functions whoes implementation copyright does not belong to the
FSF. Those prototypes are present in this file for reference
purposes only and their presence in this file should not construed
as an indication of ownership by the FSF of the implementation of
those functions in any way or form whatsoever.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA.
Written by Cygnus Support, 1994.
The libiberty library provides a number of functions which are
missing on some operating systems. We do not declare those here,
to avoid conflicts with the system header files on operating
systems that do support those functions. In this file we only
declare those functions which are specific to libiberty. */
#ifndef LIBIBERTY_H
#define LIBIBERTY_H
#ifdef __cplusplus
extern "C" {
#endif
#include "ansidecl.h"
/* Get a definition for size_t. */
#include <stddef.h>
/* Get a definition for va_list. */
#include <stdarg.h>
#include <stdio.h>
/* If the OS supports it, ensure that the supplied stream is setup to
avoid any multi-threaded locking. Otherwise leave the FILE pointer
unchanged. If the stream is NULL do nothing. */
extern void unlock_stream (FILE *);
/* If the OS supports it, ensure that the standard I/O streams, stdin,
stdout and stderr are setup to avoid any multi-threaded locking.
Otherwise do nothing. */
extern void unlock_std_streams (void);
/* Open and return a FILE pointer. If the OS supports it, ensure that
the stream is setup to avoid any multi-threaded locking. Otherwise
return the FILE pointer unchanged. */
extern FILE *fopen_unlocked (const char *, const char *);
extern FILE *fdopen_unlocked (int, const char *);
extern FILE *freopen_unlocked (const char *, const char *, FILE *);
/* Build an argument vector from a string. Allocates memory using
malloc. Use freeargv to free the vector. */
extern char **buildargv (const char *) ATTRIBUTE_MALLOC;
/* Free a vector returned by buildargv. */
extern void freeargv (char **);
/* Duplicate an argument vector. Allocates memory using malloc. Use
freeargv to free the vector. */
extern char **dupargv (char * const *) ATTRIBUTE_MALLOC;
/* Expand "@file" arguments in argv. */
extern void expandargv (int *, char ***);
/* Write argv to an @-file, inserting necessary quoting. */
extern int writeargv (char * const *, FILE *);
/* Return the number of elements in argv. */
extern int countargv (char * const *);
/* Return the last component of a path name. Note that we can't use a
prototype here because the parameter is declared inconsistently
across different systems, sometimes as "char *" and sometimes as
"const char *" */
/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
undefined, we haven't run the autoconf check so provide the
declaration without arguments. If it is 0, we checked and failed
to find the declaration so provide a fully prototyped one. If it
is 1, we found it so don't provide any declaration at all. */
#if !HAVE_DECL_BASENAME
#if defined (__GNU_LIBRARY__ ) || defined (__linux__) \
|| defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) \
|| defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) \
|| defined (__DragonFly__) || defined (HAVE_DECL_BASENAME)
extern char *basename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
#else
/* Do not allow basename to be used if there is no prototype seen. We
either need to use the above prototype or have one from
autoconf which would result in HAVE_DECL_BASENAME being set. */
#define basename basename_cannot_be_used_without_a_prototype
#endif
#endif
/* A well-defined basename () that is always compiled in. */
extern const char *lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
/* Same, but assumes DOS semantics (drive name, backslash is also a
dir separator) regardless of host. */
extern const char *dos_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
/* Same, but assumes Unix semantics (absolute paths always start with
a slash, only forward slash is accepted as dir separator)
regardless of host. */
extern const char *unix_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
/* A well-defined realpath () that is always compiled in. */
extern char *lrealpath (const char *);
/* Return true when FD file descriptor exists. */
extern int is_valid_fd (int fd);
/* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of
strings. Allocates memory using xmalloc. */
extern char *concat (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
/* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of
strings. Allocates memory using xmalloc. The first argument is
not one of the strings to be concatenated, but if not NULL is a
pointer to be freed after the new string is created, similar to the
way xrealloc works. */
extern char *reconcat (char *, const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
/* Determine the length of concatenating an arbitrary number of
strings. You must pass NULL as the last argument of this function,
to terminate the list of strings. */
extern unsigned long concat_length (const char *, ...) ATTRIBUTE_SENTINEL;
/* Concatenate an arbitrary number of strings into a SUPPLIED area of
memory. You must pass NULL as the last argument of this function,
to terminate the list of strings. The supplied memory is assumed
to be large enough. */
extern char *concat_copy (char *, const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
/* Concatenate an arbitrary number of strings into a GLOBAL area of
memory. You must pass NULL as the last argument of this function,
to terminate the list of strings. The supplied memory is assumed
to be large enough. */
extern char *concat_copy2 (const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
/* This is the global area used by concat_copy2. */
extern char *libiberty_concat_ptr;
/* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of
strings. Allocates memory using alloca. The arguments are
evaluated twice! */
#define ACONCAT(ACONCAT_PARAMS) \
(libiberty_concat_ptr = (char *) alloca (concat_length ACONCAT_PARAMS + 1), \
concat_copy2 ACONCAT_PARAMS)
/* Check whether two file descriptors refer to the same file. */
extern int fdmatch (int fd1, int fd2);
/* Return the position of the first bit set in the argument. */
/* Prototypes vary from system to system, so we only provide a
prototype on systems where we know that we need it. */
#if defined (HAVE_DECL_FFS) && !HAVE_DECL_FFS
extern int ffs(int);
#endif
/* Get the working directory. The result is cached, so don't call
chdir() between calls to getpwd(). */
extern char * getpwd (void);
/* Get the current time. */
/* Prototypes vary from system to system, so we only provide a
prototype on systems where we know that we need it. */
#ifdef __MINGW32__
/* Forward declaration to avoid #include <sys/time.h>. */
struct timeval;
extern int gettimeofday (struct timeval *, void *);
#endif
/* Get the amount of time the process has run, in microseconds. */
extern long get_run_time (void);
/* Generate a relocated path to some installation directory. Allocates
return value using malloc. */
extern char *make_relative_prefix (const char *, const char *,
const char *) ATTRIBUTE_MALLOC;
/* Generate a relocated path to some installation directory without
attempting to follow any soft links. Allocates
return value using malloc. */
extern char *make_relative_prefix_ignore_links (const char *, const char *,
const char *) ATTRIBUTE_MALLOC;
/* Returns a pointer to a directory path suitable for creating temporary
files in. */
extern const char *choose_tmpdir (void) ATTRIBUTE_RETURNS_NONNULL;
/* Choose a temporary directory to use for scratch files. */
extern char *choose_temp_base (void) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
/* Return a temporary file name or NULL if unable to create one. */
extern char *make_temp_file (const char *) ATTRIBUTE_MALLOC;
/* Return a temporary file name with given PREFIX and SUFFIX
or NULL if unable to create one. */
extern char *make_temp_file_with_prefix (const char *, const char *) ATTRIBUTE_MALLOC;
/* Remove a link to a file unless it is special. */
extern int unlink_if_ordinary (const char *);
/* Allocate memory filled with spaces. Allocates using malloc. */
extern const char *spaces (int count);
/* Return the maximum error number for which strerror will return a
string. */
extern int errno_max (void);
/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
"EINVAL"). */
extern const char *strerrno (int);
/* Given the name of an errno value, return the value. */
extern int strtoerrno (const char *);
/* ANSI's strerror(), but more robust. */
extern char *xstrerror (int) ATTRIBUTE_RETURNS_NONNULL;
/* Return the maximum signal number for which strsignal will return a
string. */
extern int signo_max (void);
/* Return a signal message string for a signal number
(e.g., strsignal (SIGHUP) returns something like "Hangup"). */
/* This is commented out as it can conflict with one in system headers.
We still document its existence though. */
/*extern const char *strsignal (int);*/
/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
"SIGHUP"). */
extern const char *strsigno (int);
/* Given the name of a signal, return its number. */
extern int strtosigno (const char *);
/* Register a function to be run by xexit. Returns 0 on success. */
extern int xatexit (void (*fn) (void));
/* Exit, calling all the functions registered with xatexit. */
extern void xexit (int status) ATTRIBUTE_NORETURN;
/* Set the program name used by xmalloc. */
extern void xmalloc_set_program_name (const char *);
/* Report an allocation failure. */
extern void xmalloc_failed (size_t) ATTRIBUTE_NORETURN;
/* Allocate memory without fail. If malloc fails, this will print a
message to stderr (using the name set by xmalloc_set_program_name,
if any) and then call xexit. */
extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1 ATTRIBUTE_WARN_UNUSED_RESULT;
/* Reallocate memory without fail. This works like xmalloc. Note,
realloc type functions are not suitable for attribute malloc since
they may return the same address across multiple calls. */
extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_2 ATTRIBUTE_WARN_UNUSED_RESULT;
/* Allocate memory without fail and set it to zero. This works like
xmalloc. */
extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1_2 ATTRIBUTE_WARN_UNUSED_RESULT;
/* Copy a string into a memory buffer without fail. */
extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT;
/* Copy at most N characters from string into a buffer without fail. */
extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT;
/* Copy an existing memory buffer to a new memory buffer without fail. */
extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT;
/* Physical memory routines. Return values are in BYTES. */
extern double physmem_total (void);
extern double physmem_available (void);
/* Compute the 32-bit CRC of a block of memory. */
extern unsigned int xcrc32 (const unsigned char *, int, unsigned int);
/* These macros provide a K&R/C89/C++-friendly way of allocating structures
with nice encapsulation. The XDELETE*() macros are technically
superfluous, but provided here for symmetry. Using them consistently
makes it easier to update client code to use different allocators such
as new/delete and new[]/delete[]. */
/* Scalar allocators. */
#define XALLOCA(T) ((T *) alloca (sizeof (T)))
#define XNEW(T) ((T *) xmalloc (sizeof (T)))
#define XCNEW(T) ((T *) xcalloc (1, sizeof (T)))
#define XDUP(T, P) ((T *) xmemdup ((P), sizeof (T), sizeof (T)))
#define XDELETE(P) free ((void*) (P))
/* Array allocators. */
#define XALLOCAVEC(T, N) ((T *) alloca (sizeof (T) * (N)))
#define XNEWVEC(T, N) ((T *) xmalloc (sizeof (T) * (N)))
#define XCNEWVEC(T, N) ((T *) xcalloc ((N), sizeof (T)))
#define XDUPVEC(T, P, N) ((T *) xmemdup ((P), sizeof (T) * (N), sizeof (T) * (N)))
#define XRESIZEVEC(T, P, N) ((T *) xrealloc ((void *) (P), sizeof (T) * (N)))
#define XDELETEVEC(P) free ((void*) (P))
/* Allocators for variable-sized structures and raw buffers. */
#define XALLOCAVAR(T, S) ((T *) alloca ((S)))
#define XNEWVAR(T, S) ((T *) xmalloc ((S)))
#define XCNEWVAR(T, S) ((T *) xcalloc (1, (S)))
#define XDUPVAR(T, P, S1, S2) ((T *) xmemdup ((P), (S1), (S2)))
#define XRESIZEVAR(T, P, S) ((T *) xrealloc ((P), (S)))
/* Type-safe obstack allocator. */
#define XOBNEW(O, T) ((T *) obstack_alloc ((O), sizeof (T)))
#define XOBNEWVEC(O, T, N) ((T *) obstack_alloc ((O), sizeof (T) * (N)))
#define XOBNEWVAR(O, T, S) ((T *) obstack_alloc ((O), (S)))
#define XOBFINISH(O, T) ((T) obstack_finish ((O)))
/* hex character manipulation routines */
#define _hex_array_size 256
#define _hex_bad 99
extern const unsigned char _hex_value[_hex_array_size];
extern void hex_init (void);
#define hex_p(c) (hex_value (c) != _hex_bad)
/* If you change this, note well: Some code relies on side effects in
the argument being performed exactly once. */
#define hex_value(c) ((unsigned int) _hex_value[(unsigned char) (c)])
/* Flags for pex_init. These are bits to be or'ed together. */
/* Record subprocess times, if possible. */
#define PEX_RECORD_TIMES 0x1
/* Use pipes for communication between processes, if possible. */
#define PEX_USE_PIPES 0x2
/* Save files used for communication between processes. */
#define PEX_SAVE_TEMPS 0x4
/* Max number of alloca bytes per call before we must switch to malloc.
?? Swiped from gnulib's regex_internal.h header. Is this actually
the case? This number seems arbitrary, though sane.
The OS usually guarantees only one guard page at the bottom of the stack,
and a page size can be as small as 4096 bytes. So we cannot safely
allocate anything larger than 4096 bytes. Also care for the possibility
of a few compiler-allocated temporary stack slots. */
#define MAX_ALLOCA_SIZE 4032
/* Prepare to execute one or more programs, with standard output of
each program fed to standard input of the next.
FLAGS As above.
PNAME The name of the program to report in error messages.
TEMPBASE A base name to use for temporary files; may be NULL to
use a random name.
Returns NULL on error. */
extern struct pex_obj *pex_init (int flags, const char *pname,
const char *tempbase) ATTRIBUTE_RETURNS_NONNULL;
/* Flags for pex_run. These are bits to be or'ed together. */
/* Last program in pipeline. Standard output of program goes to
OUTNAME, or, if OUTNAME is NULL, to standard output of caller. Do
not set this if you want to call pex_read_output. After this is
set, pex_run may no longer be called with the same struct
pex_obj. */
#define PEX_LAST 0x1
/* Search for program in executable search path. */
#define PEX_SEARCH 0x2
/* OUTNAME is a suffix. */
#define PEX_SUFFIX 0x4
/* Send program's standard error to standard output. */
#define PEX_STDERR_TO_STDOUT 0x8
/* Input file should be opened in binary mode. This flag is ignored
on Unix. */
#define PEX_BINARY_INPUT 0x10
/* Output file should be opened in binary mode. This flag is ignored
on Unix. For proper behaviour PEX_BINARY_INPUT and
PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using
PEX_BINARY_OUTPUT should be followed by a call using
PEX_BINARY_INPUT. */
#define PEX_BINARY_OUTPUT 0x20
/* Capture stderr to a pipe. The output can be read by
calling pex_read_err and reading from the returned
FILE object. This flag may be specified only for
the last program in a pipeline.
This flag is supported only on Unix and Windows. */
#define PEX_STDERR_TO_PIPE 0x40
/* Capture stderr in binary mode. This flag is ignored
on Unix. */
#define PEX_BINARY_ERROR 0x80
/* Append stdout to existing file instead of truncating it. */
#define PEX_STDOUT_APPEND 0x100
/* Thes same as PEX_STDOUT_APPEND, but for STDERR. */
#define PEX_STDERR_APPEND 0x200
/* Execute one program. Returns NULL on success. On error returns an
error string (typically just the name of a system call); the error
string is statically allocated.
OBJ Returned by pex_init.
FLAGS As above.
EXECUTABLE The program to execute.
ARGV NULL terminated array of arguments to pass to the program.
OUTNAME Sets the output file name as follows:
PEX_SUFFIX set (OUTNAME may not be NULL):
TEMPBASE parameter to pex_init not NULL:
Output file name is the concatenation of TEMPBASE
and OUTNAME.
TEMPBASE is NULL:
Output file name is a random file name ending in
OUTNAME.
PEX_SUFFIX not set:
OUTNAME not NULL:
Output file name is OUTNAME.
OUTNAME NULL, TEMPBASE not NULL:
Output file name is randomly chosen using
TEMPBASE.
OUTNAME NULL, TEMPBASE NULL:
Output file name is randomly chosen.
If PEX_LAST is not set, the output file name is the
name to use for a temporary file holding stdout, if
any (there will not be a file if PEX_USE_PIPES is set
and the system supports pipes). If a file is used, it
will be removed when no longer needed unless
PEX_SAVE_TEMPS is set.
If PEX_LAST is set, and OUTNAME is not NULL, standard
output is written to the output file name. The file
will not be removed. If PEX_LAST and PEX_SUFFIX are
both set, TEMPBASE may not be NULL.
ERRNAME If not NULL, this is the name of a file to which
standard error is written. If NULL, standard error of
the program is standard error of the caller.
ERR On an error return, *ERR is set to an errno value, or
to 0 if there is no relevant errno.
*/
extern const char *pex_run (struct pex_obj *obj, int flags,
const char *executable, char * const *argv,
const char *outname, const char *errname,
int *err);
/* As for pex_run (), but takes an extra parameter to enable the
environment for the child process to be specified.
ENV The environment for the child process, specified as
an array of character pointers. Each element of the
array should point to a string of the form VAR=VALUE,
with the exception of the last element which must be
a null pointer.
*/
extern const char *pex_run_in_environment (struct pex_obj *obj, int flags,
const char *executable,
char * const *argv,
char * const *env,
const char *outname,
const char *errname, int *err);
/* Return a stream for a temporary file to pass to the first program
in the pipeline as input. The file name is chosen as for pex_run.
pex_run closes the file automatically; don't close it yourself. */
extern FILE *pex_input_file (struct pex_obj *obj, int flags,
const char *in_name);
/* Return a stream for a pipe connected to the standard input of the
first program in the pipeline. You must have passed
`PEX_USE_PIPES' to `pex_init'. Close the returned stream
yourself. */
extern FILE *pex_input_pipe (struct pex_obj *obj, int binary);
/* Read the standard output of the last program to be executed.
pex_run cannot be called after this. BINARY should be non-zero if
the file should be opened in binary mode; this is ignored on Unix.
Returns NULL on error. Don't call fclose on the returned FILE; it
will be closed by pex_free. */
extern FILE *pex_read_output (struct pex_obj *, int binary);
/* Read the standard error of the last program to be executed.
pex_run cannot be called after this. BINARY should be non-zero if
the file should be opened in binary mode; this is ignored on Unix.
Returns NULL on error. Don't call fclose on the returned FILE; it
will be closed by pex_free. */
extern FILE *pex_read_err (struct pex_obj *, int binary);
/* Return exit status of all programs in VECTOR. COUNT indicates the
size of VECTOR. The status codes in the vector are in the order of
the calls to pex_run. Returns 0 on error, 1 on success. */
extern int pex_get_status (struct pex_obj *, int count, int *vector);
/* Return times of all programs in VECTOR. COUNT indicates the size
of VECTOR. struct pex_time is really just struct timeval, but that
is not portable to all systems. Returns 0 on error, 1 on
success. */
struct pex_time
{
unsigned long user_seconds;
unsigned long user_microseconds;
unsigned long system_seconds;
unsigned long system_microseconds;
};
extern int pex_get_times (struct pex_obj *, int count,
struct pex_time *vector);
/* Clean up a pex_obj. If you have not called pex_get_times or
pex_get_status, this will try to kill the subprocesses. */
extern void pex_free (struct pex_obj *);
/* Just execute one program. Return value is as for pex_run.
FLAGS Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT.
EXECUTABLE As for pex_run.
ARGV As for pex_run.
PNAME As for pex_init.
OUTNAME As for pex_run when PEX_LAST is set.
ERRNAME As for pex_run.
STATUS Set to exit status on success.
ERR As for pex_run.
*/
extern const char *pex_one (int flags, const char *executable,
char * const *argv, const char *pname,
const char *outname, const char *errname,
int *status, int *err);
/* pexecute and pwait are the old pexecute interface, still here for
backward compatibility. Don't use these for new code. Instead,
use pex_init/pex_run/pex_get_status/pex_free, or pex_one. */
/* Definitions used by the pexecute routine. */
#define PEXECUTE_FIRST 1
#define PEXECUTE_LAST 2
#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
#define PEXECUTE_SEARCH 4
#define PEXECUTE_VERBOSE 8
/* Execute a program. */
extern int pexecute (const char *, char * const *, const char *,
const char *, char **, char **, int);
/* Wait for pexecute to finish. */
extern int pwait (int, int *, int);
/* Like bsearch, but takes and passes on an argument like qsort_r. */
extern void *bsearch_r (const void *, const void *,
size_t, size_t,
int (*)(const void *, const void *, void *),
void *);
#if defined(HAVE_DECL_ASPRINTF) && !HAVE_DECL_ASPRINTF
/* Like sprintf but provides a pointer to malloc'd storage, which must
be freed by the caller. */
extern int asprintf (char **, const char *, ...) ATTRIBUTE_PRINTF_2;
#endif
/* Like asprintf but allocates memory without fail. This works like
xmalloc. */
extern char *xasprintf (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF_1;
#if defined(HAVE_DECL_VASPRINTF) && !HAVE_DECL_VASPRINTF
/* Like vsprintf but provides a pointer to malloc'd storage, which
must be freed by the caller. */
extern int vasprintf (char **, const char *, va_list) ATTRIBUTE_PRINTF(2,0);
#endif
/* Like vasprintf but allocates memory without fail. This works like
xmalloc. */
extern char *xvasprintf (const char *, va_list) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF(1,0);
#if defined(HAVE_DECL_SNPRINTF) && !HAVE_DECL_SNPRINTF
/* Like sprintf but prints at most N characters. */
extern int snprintf (char *, size_t, const char *, ...) ATTRIBUTE_PRINTF_3;
#endif
#if defined(HAVE_DECL_VSNPRINTF) && !HAVE_DECL_VSNPRINTF
/* Like vsprintf but prints at most N characters. */
extern int vsnprintf (char *, size_t, const char *, va_list) ATTRIBUTE_PRINTF(3,0);
#endif
#if defined (HAVE_DECL_STRNLEN) && !HAVE_DECL_STRNLEN
extern size_t strnlen (const char *, size_t);
#endif
#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP
/* Compare version strings. */
extern int strverscmp (const char *, const char *);
#endif
#if defined(HAVE_DECL_STRTOL) && !HAVE_DECL_STRTOL
extern long int strtol (const char *nptr,
char **endptr, int base);
#endif
#if defined(HAVE_DECL_STRTOUL) && !HAVE_DECL_STRTOUL
extern unsigned long int strtoul (const char *nptr,
char **endptr, int base);
#endif
#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOLL) && !HAVE_DECL_STRTOLL
__extension__
extern long long int strtoll (const char *nptr,
char **endptr, int base);
#endif
#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOULL) && !HAVE_DECL_STRTOULL
__extension__
extern unsigned long long int strtoull (const char *nptr,
char **endptr, int base);
#endif
/* Set the title of a process */
extern void setproctitle (const char *name, ...);
/* Increase stack limit if possible. */
extern void stack_limit_increase (unsigned long);
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
/* Drastically simplified alloca configurator. If we're using GCC,
we use __builtin_alloca; otherwise we use the C alloca. The C
alloca is always available. You can override GCC by defining
USE_C_ALLOCA yourself. The canonical autoconf macro C_ALLOCA is
also set/unset as it is often used to indicate whether code needs
to call alloca(0). */
extern void *C_alloca (size_t) ATTRIBUTE_MALLOC;
#undef alloca
#if GCC_VERSION >= 2000 && !defined USE_C_ALLOCA
# define alloca(x) __builtin_alloca(x)
# undef C_ALLOCA
# define ASTRDUP(X) \
(__extension__ ({ const char *const libiberty_optr = (X); \
const unsigned long libiberty_len = strlen (libiberty_optr) + 1; \
char *const libiberty_nptr = (char *) alloca (libiberty_len); \
(char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len); }))
#else
# define alloca(x) C_alloca(x)
# undef USE_C_ALLOCA
# define USE_C_ALLOCA 1
# undef C_ALLOCA
# define C_ALLOCA 1
extern const char *libiberty_optr;
extern char *libiberty_nptr;
extern unsigned long libiberty_len;
# define ASTRDUP(X) \
(libiberty_optr = (X), \
libiberty_len = strlen (libiberty_optr) + 1, \
libiberty_nptr = (char *) alloca (libiberty_len), \
(char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len))
#endif
#ifdef __cplusplus
}
#endif
#endif /* ! defined (LIBIBERTY_H) */

150
3rdparty/demangler/include/safe-ctype.h vendored Normal file
View File

@@ -0,0 +1,150 @@
/* <ctype.h> replacement macros.
Copyright (C) 2000-2023 Free Software Foundation, Inc.
Contributed by Zack Weinberg <zackw@stanford.edu>.
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* This is a compatible replacement of the standard C library's <ctype.h>
with the following properties:
- Implements all isxxx() macros required by C99.
- Also implements some character classes useful when
parsing C-like languages.
- Does not change behavior depending on the current locale.
- Behaves properly for all values in the range of a signed or
unsigned char.
To avoid conflicts, this header defines the isxxx functions in upper
case, e.g. ISALPHA not isalpha. */
#ifndef SAFE_CTYPE_H
#define SAFE_CTYPE_H
/* Determine host character set. */
#define HOST_CHARSET_UNKNOWN 0
#define HOST_CHARSET_ASCII 1
#define HOST_CHARSET_EBCDIC 2
#if '\n' == 0x0A && ' ' == 0x20 && '0' == 0x30 \
&& 'A' == 0x41 && 'a' == 0x61 && '!' == 0x21
# define HOST_CHARSET HOST_CHARSET_ASCII
#else
# if '\n' == 0x15 && ' ' == 0x40 && '0' == 0xF0 \
&& 'A' == 0xC1 && 'a' == 0x81 && '!' == 0x5A
# define HOST_CHARSET HOST_CHARSET_EBCDIC
# else
# define HOST_CHARSET HOST_CHARSET_UNKNOWN
# endif
#endif
/* Categories. */
enum {
/* In C99 */
_sch_isblank = 0x0001, /* space \t */
_sch_iscntrl = 0x0002, /* nonprinting characters */
_sch_isdigit = 0x0004, /* 0-9 */
_sch_islower = 0x0008, /* a-z */
_sch_isprint = 0x0010, /* any printing character including ' ' */
_sch_ispunct = 0x0020, /* all punctuation */
_sch_isspace = 0x0040, /* space \t \n \r \f \v */
_sch_isupper = 0x0080, /* A-Z */
_sch_isxdigit = 0x0100, /* 0-9A-Fa-f */
/* Extra categories useful to cpplib. */
_sch_isidst = 0x0200, /* A-Za-z_ */
_sch_isvsp = 0x0400, /* \n \r */
_sch_isnvsp = 0x0800, /* space \t \f \v \0 */
/* Combinations of the above. */
_sch_isalpha = _sch_isupper|_sch_islower, /* A-Za-z */
_sch_isalnum = _sch_isalpha|_sch_isdigit, /* A-Za-z0-9 */
_sch_isidnum = _sch_isidst|_sch_isdigit, /* A-Za-z0-9_ */
_sch_isgraph = _sch_isalnum|_sch_ispunct, /* isprint and not space */
_sch_iscppsp = _sch_isvsp|_sch_isnvsp, /* isspace + \0 */
_sch_isbasic = _sch_isprint|_sch_iscppsp /* basic charset of ISO C
(plus ` and @) */
};
/* Character classification. */
extern const unsigned short _sch_istable[256];
#define _sch_test(c, bit) (_sch_istable[(c) & 0xff] & (unsigned short)(bit))
#define ISALPHA(c) _sch_test(c, _sch_isalpha)
#define ISALNUM(c) _sch_test(c, _sch_isalnum)
#define ISBLANK(c) _sch_test(c, _sch_isblank)
#define ISCNTRL(c) _sch_test(c, _sch_iscntrl)
#define ISDIGIT(c) _sch_test(c, _sch_isdigit)
#define ISGRAPH(c) _sch_test(c, _sch_isgraph)
#define ISLOWER(c) _sch_test(c, _sch_islower)
#define ISPRINT(c) _sch_test(c, _sch_isprint)
#define ISPUNCT(c) _sch_test(c, _sch_ispunct)
#define ISSPACE(c) _sch_test(c, _sch_isspace)
#define ISUPPER(c) _sch_test(c, _sch_isupper)
#define ISXDIGIT(c) _sch_test(c, _sch_isxdigit)
#define ISIDNUM(c) _sch_test(c, _sch_isidnum)
#define ISIDST(c) _sch_test(c, _sch_isidst)
#define IS_ISOBASIC(c) _sch_test(c, _sch_isbasic)
#define IS_VSPACE(c) _sch_test(c, _sch_isvsp)
#define IS_NVSPACE(c) _sch_test(c, _sch_isnvsp)
#define IS_SPACE_OR_NUL(c) _sch_test(c, _sch_iscppsp)
/* Character transformation. */
extern const unsigned char _sch_toupper[256];
extern const unsigned char _sch_tolower[256];
#define TOUPPER(c) _sch_toupper[(c) & 0xff]
#define TOLOWER(c) _sch_tolower[(c) & 0xff]
/* Prevent the users of safe-ctype.h from accidently using the routines
from ctype.h. Initially, the approach was to produce an error when
detecting that ctype.h has been included. But this was causing
trouble as ctype.h might get indirectly included as a result of
including another system header (for instance gnulib's stdint.h).
So we include ctype.h here and then immediately redefine its macros. */
#include <ctype.h>
#undef isalpha
#define isalpha(c) do_not_use_isalpha_with_safe_ctype
#undef isalnum
#define isalnum(c) do_not_use_isalnum_with_safe_ctype
#undef iscntrl
#define iscntrl(c) do_not_use_iscntrl_with_safe_ctype
#undef isdigit
#define isdigit(c) do_not_use_isdigit_with_safe_ctype
#undef isgraph
#define isgraph(c) do_not_use_isgraph_with_safe_ctype
#undef islower
#define islower(c) do_not_use_islower_with_safe_ctype
#undef isprint
#define isprint(c) do_not_use_isprint_with_safe_ctype
#undef ispunct
#define ispunct(c) do_not_use_ispunct_with_safe_ctype
#undef isspace
#define isspace(c) do_not_use_isspace_with_safe_ctype
#undef isupper
#define isupper(c) do_not_use_isupper_with_safe_ctype
#undef isxdigit
#define isxdigit(c) do_not_use_isxdigit_with_safe_ctype
#undef toupper
#define toupper(c) do_not_use_toupper_with_safe_ctype
#undef tolower
#define tolower(c) do_not_use_tolower_with_safe_ctype
#endif /* SAFE_CTYPE_H */

View File

@@ -1,17 +0,0 @@
set(DEMANGLER_SOURCES
demangler.cpp
demtools.cpp
gparser.cpp
igrams.cpp
stgrammars/borlandll.cpp
stgrammars/gccll.cpp
stgrammars/msll.cpp
)
add_library(demangler STATIC ${DEMANGLER_SOURCES})
target_include_directories(demangler PUBLIC ${PROJECT_SOURCE_DIR}/include/)
set_property(TARGET demangler PROPERTY CXX_STANDARD 17)
set_property(TARGET demangler PROPERTY CXX_STANDARD_REQUIRED ON)
disable_compiler_warnings_for_target(demangler)

483
3rdparty/demangler/src/alloca.c vendored Normal file
View File

@@ -0,0 +1,483 @@
/* alloca.c -- allocate automatically reclaimed memory
(Mostly) portable public-domain implementation -- D A Gwyn
This implementation of the PWB library alloca function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.
J.Otto Tennant <jot@cray.com> contributed the Cray support.
There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.
The general concept of this implementation is to keep
track of all alloca-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.
As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection. */
/*
@deftypefn Replacement void* alloca (size_t @var{size})
This function allocates memory which will be automatically reclaimed
after the procedure exits. The @libib{} implementation does not free
the memory immediately but will do so eventually during subsequent
calls to this function. Memory is allocated using @code{xmalloc} under
normal circumstances.
The header file @file{alloca-conf.h} can be used in conjunction with the
GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make
available this function. The @code{AC_FUNC_ALLOCA} test requires that
client code use a block of preprocessor code to be safe (see the Autoconf
manual for more); this header incorporates that logic and more, including
the possibility of a GCC built-in function.
@end deftypefn
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <libiberty.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* These variables are used by the ASTRDUP implementation that relies
on C_alloca. */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
const char *libiberty_optr;
char *libiberty_nptr;
unsigned long libiberty_len;
#ifdef __cplusplus
}
#endif /* __cplusplus */
/* If your stack is a linked list of frames, you have to
provide an "address metric" ADDRESS_FUNCTION macro. */
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
static long i00afunc ();
#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
#else
#define ADDRESS_FUNCTION(arg) &(arg)
#endif
#ifndef NULL
#define NULL 0
#endif
/* Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* Direction unknown. */
#endif
#if STACK_DIRECTION != 0
#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
#else /* STACK_DIRECTION == 0; need run-time code. */
static int stack_dir; /* 1 or -1 once known. */
#define STACK_DIR stack_dir
static void
find_stack_direction (void)
{
static char *addr = NULL; /* Address of first `dummy', once known. */
auto char dummy; /* To get stack address. */
if (addr == NULL)
{ /* Initial entry. */
addr = ADDRESS_FUNCTION (dummy);
find_stack_direction (); /* Recurse once. */
}
else
{
/* Second entry. */
if (ADDRESS_FUNCTION (dummy) > addr)
stack_dir = 1; /* Stack grew upward. */
else
stack_dir = -1; /* Stack grew downward. */
}
}
#endif /* STACK_DIRECTION == 0 */
/* An "alloca header" is used to:
(a) chain together all alloca'ed blocks;
(b) keep track of stack depth.
It is very important that sizeof(header) agree with malloc
alignment chunk size. The following default should work okay. */
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr
{
char align[ALIGN_SIZE]; /* To force sizeof(header). */
struct
{
union hdr *next; /* For chaining headers. */
char *deep; /* For stack depth measure. */
} h;
} header;
static header *last_alloca_header = NULL; /* -> last alloca header. */
/* Return a pointer to at least SIZE bytes of storage,
which will be automatically reclaimed upon exit from
the procedure that called alloca. Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32. */
/* @undocumented C_alloca */
void *
C_alloca (size_t size)
{
auto char probe; /* Probes stack depth: */
register char *depth = ADDRESS_FUNCTION (probe);
#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* Unknown growth direction. */
find_stack_direction ();
#endif
/* Reclaim garbage, defined as all alloca'd storage that
was allocated from deeper in the stack than currently. */
{
register header *hp; /* Traverses linked list. */
for (hp = last_alloca_header; hp != NULL;)
if ((STACK_DIR > 0 && hp->h.deep > depth)
|| (STACK_DIR < 0 && hp->h.deep < depth))
{
register header *np = hp->h.next;
free ((void *) hp); /* Collect garbage. */
hp = np; /* -> next header. */
}
else
break; /* Rest are not deeper. */
last_alloca_header = hp; /* -> last valid storage. */
}
if (size == 0)
return NULL; /* No allocation required. */
/* Allocate combined header + user data storage. */
{
register void *new_storage = XNEWVEC (char, sizeof (header) + size);
/* Address of header. */
if (new_storage == 0)
abort();
((header *) new_storage)->h.next = last_alloca_header;
((header *) new_storage)->h.deep = depth;
last_alloca_header = (header *) new_storage;
/* User storage begins just after header. */
return (void *) ((char *) new_storage + sizeof (header));
}
}
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
#ifdef DEBUG_I00AFUNC
#include <stdio.h>
#endif
#ifndef CRAY_STACK
#define CRAY_STACK
#ifndef CRAY2
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
struct stack_control_header
{
long shgrow:32; /* Number of times stack has grown. */
long shaseg:32; /* Size of increments to stack. */
long shhwm:32; /* High water mark of stack. */
long shsize:32; /* Current size of stack (all segments). */
};
/* The stack segment linkage control information occurs at
the high-address end of a stack segment. (The stack
grows from low addresses to high addresses.) The initial
part of the stack segment linkage control information is
0200 (octal) words. This provides for register storage
for the routine which overflows the stack. */
struct stack_segment_linkage
{
long ss[0200]; /* 0200 overflow words. */
long sssize:32; /* Number of words in this segment. */
long ssbase:32; /* Offset to stack base. */
long:32;
long sspseg:32; /* Offset to linkage control of previous
segment of stack. */
long:32;
long sstcpt:32; /* Pointer to task common address block. */
long sscsnm; /* Private control structure number for
microtasking. */
long ssusr1; /* Reserved for user. */
long ssusr2; /* Reserved for user. */
long sstpid; /* Process ID for pid based multi-tasking. */
long ssgvup; /* Pointer to multitasking thread giveup. */
long sscray[7]; /* Reserved for Cray Research. */
long ssa0;
long ssa1;
long ssa2;
long ssa3;
long ssa4;
long ssa5;
long ssa6;
long ssa7;
long sss0;
long sss1;
long sss2;
long sss3;
long sss4;
long sss5;
long sss6;
long sss7;
};
#else /* CRAY2 */
/* The following structure defines the vector of words
returned by the STKSTAT library routine. */
struct stk_stat
{
long now; /* Current total stack size. */
long maxc; /* Amount of contiguous space which would
be required to satisfy the maximum
stack demand to date. */
long high_water; /* Stack high-water mark. */
long overflows; /* Number of stack overflow ($STKOFEN) calls. */
long hits; /* Number of internal buffer hits. */
long extends; /* Number of block extensions. */
long stko_mallocs; /* Block allocations by $STKOFEN. */
long underflows; /* Number of stack underflow calls ($STKRETN). */
long stko_free; /* Number of deallocations by $STKRETN. */
long stkm_free; /* Number of deallocations by $STKMRET. */
long segments; /* Current number of stack segments. */
long maxs; /* Maximum number of stack segments so far. */
long pad_size; /* Stack pad size. */
long current_address; /* Current stack segment address. */
long current_size; /* Current stack segment size. This
number is actually corrupted by STKSTAT to
include the fifteen word trailer area. */
long initial_address; /* Address of initial segment. */
long initial_size; /* Size of initial segment. */
};
/* The following structure describes the data structure which trails
any stack segment. I think that the description in 'asdef' is
out of date. I only describe the parts that I am sure about. */
struct stk_trailer
{
long this_address; /* Address of this block. */
long this_size; /* Size of this block (does not include
this trailer). */
long unknown2;
long unknown3;
long link; /* Address of trailer block of previous
segment. */
long unknown5;
long unknown6;
long unknown7;
long unknown8;
long unknown9;
long unknown10;
long unknown11;
long unknown12;
long unknown13;
long unknown14;
};
#endif /* CRAY2 */
#endif /* not CRAY_STACK */
#ifdef CRAY2
/* Determine a "stack measure" for an arbitrary ADDRESS.
I doubt that "lint" will like this much. */
static long
i00afunc (long *address)
{
struct stk_stat status;
struct stk_trailer *trailer;
long *block, size;
long result = 0;
/* We want to iterate through all of the segments. The first
step is to get the stack status structure. We could do this
more quickly and more directly, perhaps, by referencing the
$LM00 common block, but I know that this works. */
STKSTAT (&status);
/* Set up the iteration. */
trailer = (struct stk_trailer *) (status.current_address
+ status.current_size
- 15);
/* There must be at least one stack segment. Therefore it is
a fatal error if "trailer" is null. */
if (trailer == 0)
abort ();
/* Discard segments that do not contain our argument address. */
while (trailer != 0)
{
block = (long *) trailer->this_address;
size = trailer->this_size;
if (block == 0 || size == 0)
abort ();
trailer = (struct stk_trailer *) trailer->link;
if ((block <= address) && (address < (block + size)))
break;
}
/* Set the result to the offset in this segment and add the sizes
of all predecessor segments. */
result = address - block;
if (trailer == 0)
{
return result;
}
do
{
if (trailer->this_size <= 0)
abort ();
result += trailer->this_size;
trailer = (struct stk_trailer *) trailer->link;
}
while (trailer != 0);
/* We are done. Note that if you present a bogus address (one
not in any segment), you will get a different number back, formed
from subtracting the address of the first block. This is probably
not what you want. */
return (result);
}
#else /* not CRAY2 */
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
Determine the number of the cell within the stack,
given the address of the cell. The purpose of this
routine is to linearize, in some sense, stack addresses
for alloca. */
static long
i00afunc (long address)
{
long stkl = 0;
long size, pseg, this_segment, stack;
long result = 0;
struct stack_segment_linkage *ssptr;
/* Register B67 contains the address of the end of the
current stack segment. If you (as a subprogram) store
your registers on the stack and find that you are past
the contents of B67, you have overflowed the segment.
B67 also points to the stack segment linkage control
area, which is what we are really interested in. */
stkl = CRAY_STACKSEG_END ();
ssptr = (struct stack_segment_linkage *) stkl;
/* If one subtracts 'size' from the end of the segment,
one has the address of the first word of the segment.
If this is not the first segment, 'pseg' will be
nonzero. */
pseg = ssptr->sspseg;
size = ssptr->sssize;
this_segment = stkl - size;
/* It is possible that calling this routine itself caused
a stack overflow. Discard stack segments which do not
contain the target address. */
while (!(this_segment <= address && address <= stkl))
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
#endif
if (pseg == 0)
break;
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
this_segment = stkl - size;
}
result = address - this_segment;
/* If you subtract pseg from the current end of the stack,
you get the address of the previous stack segment's end.
This seems a little convoluted to me, but I'll bet you save
a cycle somewhere. */
while (pseg != 0)
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o\n", pseg, size);
#endif
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
result += size;
}
return (result);
}
#endif /* not CRAY2 */
#endif /* CRAY */

568
3rdparty/demangler/src/argv.c vendored Normal file
View File

@@ -0,0 +1,568 @@
/* Create and destroy argument vectors (argv's)
Copyright (C) 1992-2023 Free Software Foundation, Inc.
Written by Fred Fish @ Cygnus Support
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* Create and destroy argument vectors. An argument vector is simply an
array of string pointers, terminated by a NULL pointer. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ansidecl.h"
#include "libiberty.h"
#include "safe-ctype.h"
/* Routines imported from standard C runtime libraries. */
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef EOS
#define EOS '\0'
#endif
#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
/*
@deftypefn Extension char** dupargv (char * const *@var{vector})
Duplicate an argument vector. Simply scans through @var{vector},
duplicating each argument until the terminating @code{NULL} is found.
Returns a pointer to the argument vector if successful. Returns
@code{NULL} if there is insufficient memory to complete building the
argument vector.
@end deftypefn
*/
char **
dupargv (char * const *argv)
{
int argc;
char **copy;
if (argv == NULL)
return NULL;
/* the vector */
for (argc = 0; argv[argc] != NULL; argc++);
copy = (char **) xmalloc ((argc + 1) * sizeof (char *));
/* the strings */
for (argc = 0; argv[argc] != NULL; argc++)
copy[argc] = xstrdup (argv[argc]);
copy[argc] = NULL;
return copy;
}
/*
@deftypefn Extension void freeargv (char **@var{vector})
Free an argument vector that was built using @code{buildargv}. Simply
scans through @var{vector}, freeing the memory for each argument until
the terminating @code{NULL} is found, and then frees @var{vector}
itself.
@end deftypefn
*/
void freeargv (char **vector)
{
register char **scan;
if (vector != NULL)
{
for (scan = vector; *scan != NULL; scan++)
{
free (*scan);
}
free (vector);
}
}
static void
consume_whitespace (const char **input)
{
while (ISSPACE (**input))
{
(*input)++;
}
}
static int
only_whitespace (const char* input)
{
while (*input != EOS && ISSPACE (*input))
input++;
return (*input == EOS);
}
/*
@deftypefn Extension char** buildargv (char *@var{sp})
Given a pointer to a string, parse the string extracting fields
separated by whitespace and optionally enclosed within either single
or double quotes (which are stripped off), and build a vector of
pointers to copies of the string for each field. The input string
remains unchanged. The last element of the vector is followed by a
@code{NULL} element.
All of the memory for the pointer array and copies of the string
is obtained from @code{xmalloc}. All of the memory can be returned to the
system with the single function call @code{freeargv}, which takes the
returned result of @code{buildargv}, as it's argument.
Returns a pointer to the argument vector if successful. Returns
@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
memory to complete building the argument vector.
If the input is a null string (as opposed to a @code{NULL} pointer),
then buildarg returns an argument vector that has one arg, a null
string.
@end deftypefn
The memory for the argv array is dynamically expanded as necessary.
In order to provide a working buffer for extracting arguments into,
with appropriate stripping of quotes and translation of backslash
sequences, we allocate a working buffer at least as long as the input
string. This ensures that we always have enough space in which to
work, since the extracted arg is never larger than the input string.
The argument vector is always kept terminated with a @code{NULL} arg
pointer, so it can be passed to @code{freeargv} at any time, or
returned, as appropriate.
*/
char **buildargv (const char *input)
{
char *arg;
char *copybuf;
int squote = 0;
int dquote = 0;
int bsquote = 0;
int argc = 0;
int maxargc = 0;
char **argv = NULL;
char **nargv;
if (input != NULL)
{
copybuf = (char *) xmalloc (strlen (input) + 1);
/* Is a do{}while to always execute the loop once. Always return an
argv, even for null strings. See NOTES above, test case below. */
do
{
/* Pick off argv[argc] */
consume_whitespace (&input);
if ((maxargc == 0) || (argc >= (maxargc - 1)))
{
/* argv needs initialization, or expansion */
if (argv == NULL)
{
maxargc = INITIAL_MAXARGC;
nargv = (char **) xmalloc (maxargc * sizeof (char *));
}
else
{
maxargc *= 2;
nargv = (char **) xrealloc (argv, maxargc * sizeof (char *));
}
argv = nargv;
argv[argc] = NULL;
}
/* Begin scanning arg */
arg = copybuf;
while (*input != EOS)
{
if (ISSPACE (*input) && !squote && !dquote && !bsquote)
{
break;
}
else
{
if (bsquote)
{
bsquote = 0;
*arg++ = *input;
}
else if (*input == '\\')
{
bsquote = 1;
}
else if (squote)
{
if (*input == '\'')
{
squote = 0;
}
else
{
*arg++ = *input;
}
}
else if (dquote)
{
if (*input == '"')
{
dquote = 0;
}
else
{
*arg++ = *input;
}
}
else
{
if (*input == '\'')
{
squote = 1;
}
else if (*input == '"')
{
dquote = 1;
}
else
{
*arg++ = *input;
}
}
input++;
}
}
*arg = EOS;
argv[argc] = xstrdup (copybuf);
argc++;
argv[argc] = NULL;
consume_whitespace (&input);
}
while (*input != EOS);
free (copybuf);
}
return (argv);
}
/*
@deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file})
Write each member of ARGV, handling all necessary quoting, to the file
named by FILE, separated by whitespace. Return 0 on success, non-zero
if an error occurred while writing to FILE.
@end deftypefn
*/
int
writeargv (char * const *argv, FILE *f)
{
int status = 0;
if (f == NULL)
return 1;
while (*argv != NULL)
{
const char *arg = *argv;
while (*arg != EOS)
{
char c = *arg;
if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
if (EOF == fputc ('\\', f))
{
status = 1;
goto done;
}
if (EOF == fputc (c, f))
{
status = 1;
goto done;
}
arg++;
}
/* Write out a pair of quotes for an empty argument. */
if (arg == *argv)
if (EOF == fputs ("\"\"", f))
{
status = 1;
goto done;
}
if (EOF == fputc ('\n', f))
{
status = 1;
goto done;
}
argv++;
}
done:
return status;
}
/*
@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
The @var{argcp} and @code{argvp} arguments are pointers to the usual
@code{argc} and @code{argv} arguments to @code{main}. This function
looks for arguments that begin with the character @samp{@@}. Any such
arguments are interpreted as ``response files''. The contents of the
response file are interpreted as additional command line options. In
particular, the file is separated into whitespace-separated strings;
each such string is taken as a command-line option. The new options
are inserted in place of the option naming the response file, and
@code{*argcp} and @code{*argvp} will be updated. If the value of
@code{*argvp} is modified by this function, then the new value has
been dynamically allocated and can be deallocated by the caller with
@code{freeargv}. However, most callers will simply call
@code{expandargv} near the beginning of @code{main} and allow the
operating system to free the memory when the program exits.
@end deftypefn
*/
void
expandargv (int *argcp, char ***argvp)
{
/* The argument we are currently processing. */
int i = 0;
/* To check if ***argvp has been dynamically allocated. */
char ** const original_argv = *argvp;
/* Limit the number of response files that we parse in order
to prevent infinite recursion. */
unsigned int iteration_limit = 2000;
/* Loop over the arguments, handling response files. We always skip
ARGVP[0], as that is the name of the program being run. */
while (++i < *argcp)
{
/* The name of the response file. */
const char *filename;
/* The response file. */
FILE *f;
/* An upper bound on the number of characters in the response
file. */
long pos;
/* The number of characters in the response file, when actually
read. */
size_t len;
/* A dynamically allocated buffer used to hold options read from a
response file. */
char *buffer;
/* Dynamically allocated storage for the options read from the
response file. */
char **file_argv;
/* The number of options read from the response file, if any. */
size_t file_argc;
#ifdef S_ISDIR
struct stat sb;
#endif
/* We are only interested in options of the form "@file". */
filename = (*argvp)[i];
if (filename[0] != '@')
continue;
/* If we have iterated too many times then stop. */
if (-- iteration_limit == 0)
{
fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]);
xexit (1);
}
#ifdef S_ISDIR
if (stat (filename+1, &sb) < 0)
continue;
if (S_ISDIR(sb.st_mode))
{
fprintf (stderr, "%s: error: @-file refers to a directory\n", (*argvp)[0]);
xexit (1);
}
#endif
/* Read the contents of the file. */
f = fopen (++filename, "r");
if (!f)
continue;
if (fseek (f, 0L, SEEK_END) == -1)
goto error;
pos = ftell (f);
if (pos == -1)
goto error;
if (fseek (f, 0L, SEEK_SET) == -1)
goto error;
buffer = (char *) xmalloc (pos * sizeof (char) + 1);
len = fread (buffer, sizeof (char), pos, f);
if (len != (size_t) pos
/* On Windows, fread may return a value smaller than POS,
due to CR/LF->CR translation when reading text files.
That does not in-and-of itself indicate failure. */
&& ferror (f))
{
free (buffer);
goto error;
}
/* Add a NUL terminator. */
buffer[len] = '\0';
/* If the file is empty or contains only whitespace, buildargv would
return a single empty argument. In this context we want no arguments,
instead. */
if (only_whitespace (buffer))
{
file_argv = (char **) xmalloc (sizeof (char *));
file_argv[0] = NULL;
}
else
/* Parse the string. */
file_argv = buildargv (buffer);
/* If *ARGVP is not already dynamically allocated, copy it. */
if (*argvp == original_argv)
*argvp = dupargv (*argvp);
/* Count the number of arguments. */
file_argc = 0;
while (file_argv[file_argc])
++file_argc;
/* Free the original option's memory. */
free ((*argvp)[i]);
/* Now, insert FILE_ARGV into ARGV. The "+1" below handles the
NULL terminator at the end of ARGV. */
*argvp = ((char **)
xrealloc (*argvp,
(*argcp + file_argc + 1) * sizeof (char *)));
memmove (*argvp + i + file_argc, *argvp + i + 1,
(*argcp - i) * sizeof (char *));
memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
/* The original option has been replaced by all the new
options. */
*argcp += file_argc - 1;
/* Free up memory allocated to process the response file. We do
not use freeargv because the individual options in FILE_ARGV
are now in the main ARGV. */
free (file_argv);
free (buffer);
/* Rescan all of the arguments just read to support response
files that include other response files. */
--i;
error:
/* We're all done with the file now. */
fclose (f);
}
}
/*
@deftypefn Extension int countargv (char * const *@var{argv})
Return the number of elements in @var{argv}.
Returns zero if @var{argv} is NULL.
@end deftypefn
*/
int
countargv (char * const *argv)
{
int argc;
if (argv == NULL)
return 0;
for (argc = 0; argv[argc] != NULL; argc++)
continue;
return argc;
}
#ifdef MAIN
/* Simple little test driver. */
static const char *const tests[] =
{
"a simple command line",
"arg 'foo' is single quoted",
"arg \"bar\" is double quoted",
"arg \"foo bar\" has embedded whitespace",
"arg 'Jack said \\'hi\\'' has single quotes",
"arg 'Jack said \\\"hi\\\"' has double quotes",
"a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9",
/* This should be expanded into only one argument. */
"trailing-whitespace ",
"",
NULL
};
int
main (void)
{
char **argv;
const char *const *test;
char **targs;
for (test = tests; *test != NULL; test++)
{
printf ("buildargv(\"%s\")\n", *test);
if ((argv = buildargv (*test)) == NULL)
{
printf ("failed!\n\n");
}
else
{
for (targs = argv; *targs != NULL; targs++)
{
printf ("\t\"%s\"\n", *targs);
}
printf ("\n");
}
freeargv (argv);
}
return 0;
}
#endif /* MAIN */

7326
3rdparty/demangler/src/cp-demangle.c vendored Normal file

File diff suppressed because it is too large Load Diff

5052
3rdparty/demangler/src/cplus-dem.c vendored Normal file

File diff suppressed because it is too large Load Diff

1982
3rdparty/demangler/src/d-demangle.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,131 +0,0 @@
/**
* @file src/demangler/demangler.cpp
* @brief Demangler library.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#include <iostream>
#include <string>
#include "demangler/demangler.h"
namespace demangler {
/**
* @brief Constructor of CDemangler class.
* @param gname Grammar name. If internal grammar is used, internal grammar of this name must exist.
* If external grammar is used file with this name must exist and it used as external grammar.
* @param i Use internal grammar? Default setting is true. If set to false, external grammar is used.
*/
CDemangler::CDemangler(std::string gname, bool i):
pGram(new cGram()),
pName(nullptr),
errState(cGram::ERROR_OK) {
//if gname is empty, pGram will not be initialized (may be used for creating new internal grammars)
if (!gname.empty()) {
errState = pGram->initialize(gname, i);
compiler = gname;
}
}
std::unique_ptr<CDemangler> CDemangler::createGcc(bool i)
{
return std::make_unique<CDemangler>("gcc", i);
}
std::unique_ptr<CDemangler> CDemangler::createMs(bool i)
{
return std::make_unique<CDemangler>("ms", i);
}
std::unique_ptr<CDemangler> CDemangler::createBorland(bool i)
{
return std::make_unique<CDemangler>("borland", i);
}
/**
* @brief Destructor of CDemangler class.
*/
CDemangler::~CDemangler() {
delete pGram;
}
/**
* @brief Check if the error state of demangler is ok. Returns false if an error has ocurred during the last action.
* @return Boolean value determining whether everything is ok.
*/
bool CDemangler::isOk() {
if (errState == cGram::ERROR_OK) {
return true;
}
else {
return false;
}
}
/**
* @brief Returns string describing the last error.
*/
std::string CDemangler::printError() {
if (pGram != nullptr) {
return pGram->errString;
}
else {
return "No grammar class allocated. Cannot get error state.";
}
}
/**
* @brief Reset error state.
*/
void CDemangler::resetError() {
if (pGram != nullptr) {
pGram->resetError();
errState = cGram::ERROR_OK;
}
}
/**
* @brief Function which converts external grammar into internal grammar.
* After using this function the demangler object must not be used for demangling.S
* errState may be set if an error occurs.
* @param inputfilename The name of the file which contains grammar rules.
* @param outputname The name of the output grammar.
*/
void CDemangler::createGrammar(std::string inputfilename, std::string outputname) {
errState = pGram->generateIgrammar(inputfilename, outputname);
}
/**
* @brief Demangle the input string and return the demangled name class. errState may be set if an error occurs.
* @param inputName The name to be demangled.
* @return Pointer to a cName object containing all info anout the demangled name.
*/
cName *CDemangler::demangleToClass(std::string inputName) {
return pGram->perform(inputName,&errState);
}
/**
* @brief Demangle the input string and return the demangled name as a string. errState may be set if an error occurs.
* @param inputName The name to be demangled.
* @return String containing the declaration of the demangled name.
*/
std::string CDemangler::demangleToString(std::string inputName) {
std::string retvalue;
resetError();
pName = pGram->perform(inputName,&errState);
retvalue = pName->printall(compiler);
delete pName;
return retvalue;
}
/**
* @brief Set substitution analysis manually to enabled or disabled.
* @param x Boolean value. True means enable, false means disable.
*/
void CDemangler::setSubAnalyze(bool x) {
pGram->setSubAnalyze(x);
}
} // namespace demangler

View File

@@ -1,82 +0,0 @@
/**
* @file src/demangler/demtools.cpp
* @brief Tools and extra functions for demangler.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/
#include <ctime>
#include <fstream>
#include <sstream>
#include <string>
#include "demangler/demtools.h"
using namespace std;
namespace demangler {
/**
* @brief Function which finds out whether a file exists.
* @param filename Name of the file to be checked.
* @return Boolean value determining whether the file exists or not.
*/
bool fileExists(const std::string &filename) {
ifstream ifile(filename);
return ifile.is_open();
}
/**
* @brief Initializes a sdate_t to default values.
* @param x sdate_t to be initialized..
*/
void initSdate_t(sdate_t &x) {
x.y = 0;
x.m = 0;
x.d = 0;
x.h = 0;
x.min = 0;
x.s = 0;
}
/**
* @brief Get stuct with current date and time.
* @return Struct with current date and time.
*/
sdate_t genTimeStruct() {
sdate_t retvalue;
initSdate_t(retvalue);
time_t t = time(nullptr); // get time now
struct tm * now = localtime( & t );
//year
retvalue.y = now->tm_year + 1900;
//month
retvalue.m = (now->tm_mon + 1);
//day
retvalue.d = now->tm_mday;
//hour
retvalue.h = now->tm_hour;
//minute
retvalue.min = now->tm_min;
//second
retvalue.s = now->tm_sec;
return retvalue;
}
/**
* @brief Replaces strings "tobereplaced" in source with "replacement".
* @param source Source string.
* @param tobereplaced Substring which will be searched for and all of its instances will be replaced.
* @param replacement The replacement string.
*/
void xreplace(string &source, const string &tobereplaced, const string &replacement) {
std::size_t lastfound = 0;
if (tobereplaced != "") {
while (source.find(tobereplaced,lastfound) != source.npos) {
lastfound = source.find(tobereplaced,lastfound);
source.replace(source.find(tobereplaced,lastfound),tobereplaced.length(),replacement);
lastfound += replacement.length();
}
}
}
} // namespace demangler

397
3rdparty/demangler/src/dyn-string.c vendored Normal file
View File

@@ -0,0 +1,397 @@
/* An abstract string datatype.
Copyright (C) 1998-2023 Free Software Foundation, Inc.
Contributed by Mark Mitchell (mark@markmitchell.com).
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file. (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combined
executable.)
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "libiberty.h"
#include "dyn-string.h"
/* Performs in-place initialization of a dyn_string struct. This
function can be used with a dyn_string struct on the stack or
embedded in another object. The contents of of the string itself
are still dynamically allocated. The string initially is capable
of holding at least SPACE characeters, including the terminating
NUL. If SPACE is 0, it will silently be increated to 1.
If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
fails, returns 0. Otherwise returns 1. */
int
dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
{
/* We need at least one byte in which to store the terminating NUL. */
if (space == 0)
space = 1;
#ifdef RETURN_ON_ALLOCATION_FAILURE
ds_struct_ptr->s = (char *) malloc (space);
if (ds_struct_ptr->s == NULL)
return 0;
#else
ds_struct_ptr->s = XNEWVEC (char, space);
#endif
ds_struct_ptr->allocated = space;
ds_struct_ptr->length = 0;
ds_struct_ptr->s[0] = '\0';
return 1;
}
/* Create a new dynamic string capable of holding at least SPACE
characters, including the terminating NUL. If SPACE is 0, it will
be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is
defined and memory allocation fails, returns NULL. Otherwise
returns the newly allocated string. */
dyn_string_t
dyn_string_new (int space)
{
dyn_string_t result;
#ifdef RETURN_ON_ALLOCATION_FAILURE
result = (dyn_string_t) malloc (sizeof (struct dyn_string));
if (result == NULL)
return NULL;
if (!dyn_string_init (result, space))
{
free (result);
return NULL;
}
#else
result = XNEW (struct dyn_string);
dyn_string_init (result, space);
#endif
return result;
}
/* Free the memory used by DS. */
void
dyn_string_delete (dyn_string_t ds)
{
free (ds->s);
free (ds);
}
/* Returns the contents of DS in a buffer allocated with malloc. It
is the caller's responsibility to deallocate the buffer using free.
DS is then set to the empty string. Deletes DS itself. */
char*
dyn_string_release (dyn_string_t ds)
{
/* Store the old buffer. */
char* result = ds->s;
/* The buffer is no longer owned by DS. */
ds->s = NULL;
/* Delete DS. */
free (ds);
/* Return the old buffer. */
return result;
}
/* Increase the capacity of DS so it can hold at least SPACE
characters, plus the terminating NUL. This function will not (at
present) reduce the capacity of DS. Returns DS on success.
If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
operation fails, deletes DS and returns NULL. */
dyn_string_t
dyn_string_resize (dyn_string_t ds, int space)
{
int new_allocated = ds->allocated;
/* Increase SPACE to hold the NUL termination. */
++space;
/* Increase allocation by factors of two. */
while (space > new_allocated)
new_allocated *= 2;
if (new_allocated != ds->allocated)
{
ds->allocated = new_allocated;
/* We actually need more space. */
#ifdef RETURN_ON_ALLOCATION_FAILURE
ds->s = (char *) realloc (ds->s, ds->allocated);
if (ds->s == NULL)
{
free (ds);
return NULL;
}
#else
ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
#endif
}
return ds;
}
/* Sets the contents of DS to the empty string. */
void
dyn_string_clear (dyn_string_t ds)
{
/* A dyn_string always has room for at least the NUL terminator. */
ds->s[0] = '\0';
ds->length = 0;
}
/* Makes the contents of DEST the same as the contents of SRC. DEST
and SRC must be distinct. Returns 1 on success. On failure, if
RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_copy (dyn_string_t dest, dyn_string_t src)
{
if (dest == src)
abort ();
/* Make room in DEST. */
if (dyn_string_resize (dest, src->length) == NULL)
return 0;
/* Copy DEST into SRC. */
strcpy (dest->s, src->s);
/* Update the size of DEST. */
dest->length = src->length;
return 1;
}
/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on
success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
and returns 0. */
int
dyn_string_copy_cstr (dyn_string_t dest, const char *src)
{
int length = strlen (src);
/* Make room in DEST. */
if (dyn_string_resize (dest, length) == NULL)
return 0;
/* Copy DEST into SRC. */
strcpy (dest->s, src);
/* Update the size of DEST. */
dest->length = length;
return 1;
}
/* Inserts SRC at the beginning of DEST. DEST is expanded as
necessary. SRC and DEST must be distinct. Returns 1 on success.
On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
returns 0. */
int
dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
{
return dyn_string_insert (dest, 0, src);
}
/* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
DEST is expanded as necessary. Returns 1 on success. On failure,
if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
{
return dyn_string_insert_cstr (dest, 0, src);
}
/* Inserts SRC into DEST starting at position POS. DEST is expanded
as necessary. SRC and DEST must be distinct. Returns 1 on
success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
and returns 0. */
int
dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
{
int i;
if (src == dest)
abort ();
if (dyn_string_resize (dest, dest->length + src->length) == NULL)
return 0;
/* Make room for the insertion. Be sure to copy the NUL. */
for (i = dest->length; i >= pos; --i)
dest->s[i + src->length] = dest->s[i];
/* Splice in the new stuff. */
strncpy (dest->s + pos, src->s, src->length);
/* Compute the new length. */
dest->length += src->length;
return 1;
}
/* Inserts SRC, a NUL-terminated string, into DEST starting at
position POS. DEST is expanded as necessary. Returns 1 on
success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
and returns 0. */
int
dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
{
int i;
int length = strlen (src);
if (dyn_string_resize (dest, dest->length + length) == NULL)
return 0;
/* Make room for the insertion. Be sure to copy the NUL. */
for (i = dest->length; i >= pos; --i)
dest->s[i + length] = dest->s[i];
/* Splice in the new stuff. */
memcpy (dest->s + pos, src, length);
/* Compute the new length. */
dest->length += length;
return 1;
}
/* Inserts character C into DEST starting at position POS. DEST is
expanded as necessary. Returns 1 on success. On failure,
RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_insert_char (dyn_string_t dest, int pos, int c)
{
int i;
if (dyn_string_resize (dest, dest->length + 1) == NULL)
return 0;
/* Make room for the insertion. Be sure to copy the NUL. */
for (i = dest->length; i >= pos; --i)
dest->s[i + 1] = dest->s[i];
/* Add the new character. */
dest->s[pos] = c;
/* Compute the new length. */
++dest->length;
return 1;
}
/* Append S to DS, resizing DS if necessary. Returns 1 on success.
On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
returns 0. */
int
dyn_string_append (dyn_string_t dest, dyn_string_t s)
{
if (dyn_string_resize (dest, dest->length + s->length) == 0)
return 0;
strcpy (dest->s + dest->length, s->s);
dest->length += s->length;
return 1;
}
/* Append the NUL-terminated string S to DS, resizing DS if necessary.
Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
deletes DEST and returns 0. */
int
dyn_string_append_cstr (dyn_string_t dest, const char *s)
{
int len = strlen (s);
/* The new length is the old length plus the size of our string, plus
one for the null at the end. */
if (dyn_string_resize (dest, dest->length + len) == NULL)
return 0;
strcpy (dest->s + dest->length, s);
dest->length += len;
return 1;
}
/* Appends C to the end of DEST. Returns 1 on success. On failure,
if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_append_char (dyn_string_t dest, int c)
{
/* Make room for the extra character. */
if (dyn_string_resize (dest, dest->length + 1) == NULL)
return 0;
/* Append the character; it will overwrite the old NUL. */
dest->s[dest->length] = c;
/* Add a new NUL at the end. */
dest->s[dest->length + 1] = '\0';
/* Update the length. */
++(dest->length);
return 1;
}
/* Sets the contents of DEST to the substring of SRC starting at START
and ending before END. START must be less than or equal to END,
and both must be between zero and the length of SRC, inclusive.
Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
deletes DEST and returns 0. */
int
dyn_string_substring (dyn_string_t dest, dyn_string_t src,
int start, int end)
{
int i;
int length = end - start;
if (start > end || start > src->length || end > src->length)
abort ();
/* Make room for the substring. */
if (dyn_string_resize (dest, length) == NULL)
return 0;
/* Copy the characters in the substring, */
for (i = length; --i >= 0; )
dest->s[i] = src->s[start + i];
/* NUL-terimate the result. */
dest->s[length] = '\0';
/* Record the length of the substring. */
dest->length = length;
return 1;
}
/* Returns non-zero if DS1 and DS2 have the same contents. */
int
dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
{
/* If DS1 and DS2 have different lengths, they must not be the same. */
if (ds1->length != ds2->length)
return 0;
else
return !strcmp (ds1->s, ds2->s);
}

View File

@@ -1,467 +0,0 @@
<mangled-name> ::= <template-prefix> @ <qualified-name> <sem-unq2f> <function-section> <sem-end>
<template-prefix> ::=
<template-section> ::= % <name-element> $ t <sem-begintempl> <sem-beginbsub> <type> <type-more-template> %
<qualified-name> ::= <name-element> <name-element-more>
<name-element-more> ::=
<name-element-more> ::= @ <name-element> <name-element-more>
<name-element> ::= @ <name-element> #double @ for __linksys__ - ignore that for now and just use qualified name
<name-element> ::= $ <op>
<name-element> ::= <template-section>
<name-element> ::= <name-char> <name-char-more>
<name-char-more> ::= <sem-storename> #no more characters in name, store the name
<name-char-more> ::= <name-char> <name-char-more>
<name-char> ::= <sem-addchartoname> _
<name-char> ::= <sem-addchartoname> a
<name-char> ::= <sem-addchartoname> b
<name-char> ::= <sem-addchartoname> c
<name-char> ::= <sem-addchartoname> d
<name-char> ::= <sem-addchartoname> e
<name-char> ::= <sem-addchartoname> f
<name-char> ::= <sem-addchartoname> g
<name-char> ::= <sem-addchartoname> h
<name-char> ::= <sem-addchartoname> i
<name-char> ::= <sem-addchartoname> j
<name-char> ::= <sem-addchartoname> k
<name-char> ::= <sem-addchartoname> l
<name-char> ::= <sem-addchartoname> m
<name-char> ::= <sem-addchartoname> n
<name-char> ::= <sem-addchartoname> o
<name-char> ::= <sem-addchartoname> p
<name-char> ::= <sem-addchartoname> q
<name-char> ::= <sem-addchartoname> r
<name-char> ::= <sem-addchartoname> s
<name-char> ::= <sem-addchartoname> t
<name-char> ::= <sem-addchartoname> u
<name-char> ::= <sem-addchartoname> v
<name-char> ::= <sem-addchartoname> w
<name-char> ::= <sem-addchartoname> x
<name-char> ::= <sem-addchartoname> y
<name-char> ::= <sem-addchartoname> z
<name-char> ::= <sem-addchartoname> A
<name-char> ::= <sem-addchartoname> B
<name-char> ::= <sem-addchartoname> C
<name-char> ::= <sem-addchartoname> D
<name-char> ::= <sem-addchartoname> E
<name-char> ::= <sem-addchartoname> F
<name-char> ::= <sem-addchartoname> G
<name-char> ::= <sem-addchartoname> H
<name-char> ::= <sem-addchartoname> I
<name-char> ::= <sem-addchartoname> J
<name-char> ::= <sem-addchartoname> K
<name-char> ::= <sem-addchartoname> L
<name-char> ::= <sem-addchartoname> M
<name-char> ::= <sem-addchartoname> N
<name-char> ::= <sem-addchartoname> O
<name-char> ::= <sem-addchartoname> P
<name-char> ::= <sem-addchartoname> Q
<name-char> ::= <sem-addchartoname> R
<name-char> ::= <sem-addchartoname> S
<name-char> ::= <sem-addchartoname> T
<name-char> ::= <sem-addchartoname> U
<name-char> ::= <sem-addchartoname> V
<name-char> ::= <sem-addchartoname> W
<name-char> ::= <sem-addchartoname> X
<name-char> ::= <sem-addchartoname> Y
<name-char> ::= <sem-addchartoname> Z
<name-char> ::= <sem-addchartoname> 0
<name-char> ::= <sem-addchartoname> 1
<name-char> ::= <sem-addchartoname> 2
<name-char> ::= <sem-addchartoname> 3
<name-char> ::= <sem-addchartoname> 4
<name-char> ::= <sem-addchartoname> 5
<name-char> ::= <sem-addchartoname> 6
<name-char> ::= <sem-addchartoname> 7
<name-char> ::= <sem-addchartoname> 8
<name-char> ::= <sem-addchartoname> 9
<function-section> ::= <sem-setnamex>
<function-section> ::= $ <const-vol> q <calling-convention> <parameters>
<const-vol> ::=
<const-vol> ::= <sem-addmconst> x <const-vol>
<const-vol> ::= <sem-addmvol> w <const-vol>
<calling-convention> ::=
<calling-convention> ::= <sem-setfpascal> Q
<calling-convention> ::= q <calling-convention-q>
<calling-convention-q> ::= <sem-setffortran> f
<calling-convention-q> ::= <sem-setfstdcall> s
<calling-convention-q> ::= <sem-setffastcall> r
<calling-convention-q> ::= <sem-setfinterrupt> i
<parameters> ::= <sem-beginbsub> <type> <type-more>
<type-more> ::= <sem-par2f>
<type-more> ::= <sem-storepar> <sem-beginbsub> <type> <type-more>
<type-more-template> ::= <sem-storetemplate>
<type-more-template> ::= <sem-storetemparg> <sem-beginbsub> <type> <type-more-template>
<type> ::= <sem-settypev> v #void
<type> ::= <sem-settypec> c #char
<type> ::= <sem-settypes> s #short int
<type> ::= <sem-settypei> i #int
<type> ::= <sem-settypex> j #__int64
<type> ::= <sem-settypel> l #long int
<type> ::= <sem-settypew> b #wchar_t
<type> ::= <sem-settypef> f #float
<type> ::= <sem-settyped> d #double
<type> ::= <sem-settypee> g #long double
<type> ::= <sem-settypeb> o #bool
<type> ::= z <type-z>
<type> ::= u <type-u>
<type> ::= x <sem-setconst> <type>
<type> ::= p <sem-setptr> <type>
<type> ::= w <sem-setvolatile> <type>
<type> ::= r <sem-setref> <type>
<type> ::= t <typesub>
<type> ::= a <array-number> $ <type>
<array-number> ::= <sem-borlandarr> <number>
<type> ::= <source-name>
<type-z> ::= <sem-settypea> c #signed char
<type-u> ::= <sem-settypeh> c #unsigned char
<type-u> ::= <sem-settypet> s #unsigned short int
<type-u> ::= <sem-settypej> i #unsigned int
<type-u> ::= <sem-settypem> l #unsigned long int
<typesub> ::= <sem-loadborlandsub> 1
<typesub> ::= <sem-loadborlandsub> 2
<typesub> ::= <sem-loadborlandsub> 3
<typesub> ::= <sem-loadborlandsub> 4
<typesub> ::= <sem-loadborlandsub> 5
<typesub> ::= <sem-loadborlandsub> 6
<typesub> ::= <sem-loadborlandsub> 7
<typesub> ::= <sem-loadborlandsub> 8
<typesub> ::= <sem-loadborlandsub> 9
<typesub> ::= <sem-loadborlandsub> a
<typesub> ::= <sem-loadborlandsub> b
<typesub> ::= <sem-loadborlandsub> c
<typesub> ::= <sem-loadborlandsub> d
<typesub> ::= <sem-loadborlandsub> e
<typesub> ::= <sem-loadborlandsub> f
<typesub> ::= <sem-loadborlandsub> g
<typesub> ::= <sem-loadborlandsub> h
<typesub> ::= <sem-loadborlandsub> i
<typesub> ::= <sem-loadborlandsub> j
<typesub> ::= <sem-loadborlandsub> k
<typesub> ::= <sem-loadborlandsub> l
<typesub> ::= <sem-loadborlandsub> m
<typesub> ::= <sem-loadborlandsub> n
<typesub> ::= <sem-loadborlandsub> o
<typesub> ::= <sem-loadborlandsub> p
<typesub> ::= <sem-loadborlandsub> q
<typesub> ::= <sem-loadborlandsub> r
<typesub> ::= <sem-loadborlandsub> s
<typesub> ::= <sem-loadborlandsub> t
<typesub> ::= <sem-loadborlandsub> u
<typesub> ::= <sem-loadborlandsub> v
<typesub> ::= <sem-loadborlandsub> w
<typesub> ::= <sem-loadborlandsub> x
<typesub> ::= <sem-loadborlandsub> y
<typesub> ::= <sem-loadborlandsub> z
<source-name> ::= <source-number>
<source-number> ::= <sem-borlandid> <number> <qualified-name> <sem-unq2p> |
<number> ::= 0
<number> ::= 1
<number> ::= 2
<number> ::= 3
<number> ::= 4
<number> ::= 5
<number> ::= 6
<number> ::= 7
<number> ::= 8
<number> ::= 9
<op> ::= b <op-b>
<op-b> ::= a <op-ba>
<op-ba> ::= d <op-bad>
<op-bad> ::= <sem-setnameo> <sem-setoppl> d #operator +
<op-bad> ::= <sem-setnameo> <sem-setopad> r #operator & (unary)
<op-ba> ::= n <op-ban>
<op-ban> ::= <sem-setnameo> <sem-setopan> d #operator &
<op-ba> ::= r <op-bar>
<op-bar> ::= o <op-baro>
<op-baro> ::= <sem-setnameo> <sem-setoppt> w #operator ->
<op-bar> ::= w <op-barw>
<op-barw> ::= <sem-setnameo> <sem-setoppm> m #operator ->*
<op-ba> ::= s <op-bas>
<op-bas> ::= <sem-setnameo> <sem-setopass> g #operator =
<op-b> ::= c <op-bc>
<op-bc> ::= a <op-bca>
<op-bca> ::= l <op-bcal>
<op-bcal> ::= <sem-setnameo> <sem-setopcl> l #operator ()
<op-bc> ::= m <op-bcm>
<op-bcm> ::= <sem-setnameo> <sem-setopco> p #operator ~
<op-bc> ::= o <op-bco>
<op-bco> ::= m <op-bcom>
<op-bcom> ::= <sem-setnameo> <sem-setopcm> a #operator ,
<op-bc> ::= t <op-bct>
<op-bct> ::= <sem-setnamec> r #constructor
<op-b> ::= d <op-bd>
<op-bd> ::= e <op-bde>
<op-bde> ::= <sem-setnameo> <sem-setopmm> c #operator --
<op-bde> ::= l <op-bdel>
<op-bdel> ::= <sem-setnameo> <sem-setopdl> e #operator delete
<op-bd> ::= i <op-bdi>
<op-bdi> ::= <sem-setnameo> <sem-setopdv> v #operator /
<op-bd> ::= l <op-bdl>
<op-bdl> ::= <sem-setnameo> <sem-setopda> a #operator delete[]
<op-bd> ::= t <op-bdt>
<op-bdt> ::= <sem-setnamed> r #destructor
<op-b> ::= e <op-be>
<op-be> ::= q <op-beq>
<op-beq> ::= <sem-setnameo> <sem-setopeq> l #operator ==
<op-b> ::= g <op-bg>
<op-bg> ::= e <op-bge>
<op-bge> ::= <sem-setnameo> <sem-setopge> q #operator >=
<op-bg> ::= t <op-bgt>
<op-bgt> ::= <sem-setnameo> <sem-setopgt> r #operator >
<op-b> ::= i <op-bi>
<op-bi> ::= n <op-bin>
<op-bin> ::= <sem-setnameo> <sem-setoppp> c #operator ++
<op-bin> ::= <sem-setnameo> <sem-setopde> d #operator * (unary)
<op-b> ::= l <op-bl>
<op-bl> ::= a <op-bla>
<op-bla> ::= n <op-blan>
<op-blan> ::= <sem-setnameo> <sem-setopaa> d #operator &&
<op-bl> ::= e <op-ble>
<op-ble> ::= <sem-setnameo> <sem-setople> q #operator <=
<op-bl> ::= o <op-blo>
<op-blo> ::= <sem-setnameo> <sem-setopoo> r #operator ||
<op-bl> ::= s <op-bls>
<op-bls> ::= <sem-setnameo> <sem-setopls> h #operator <<
<op-bls> ::= <sem-setnameo> <sem-setoplt> s #operator <
<op-b> ::= m <op-bm>
<op-bm> ::= o <op-bmo>
<op-bmo> ::= <sem-setnameo> <sem-setoprm> d #operator %
<op-bm> ::= u <op-bmu>
<op-bmu> ::= <sem-setnameo> <sem-setopml> l #operator *
<op-b> ::= n <op-bn>
<op-bn> ::= e <op-bne>
<op-bne> ::= <sem-setnameo> <sem-setopne> q #operator !=
<op-bne> ::= <sem-setnameo> <sem-setopnw> w #operator new
<op-bn> ::= o <op-bno>
<op-bno> ::= <sem-setnameo> <sem-setopnt> t #operator !
<op-bn> ::= w <op-bnw>
<op-bnw> ::= <sem-setnameo> <sem-setopna> a #operator new[]
<op-b> ::= o <op-bo>
<op-bo> ::= <sem-setnameo> <sem-setopor> r #operator |
<op-b> ::= r <op-br>
<op-br> ::= a <op-bra>
<op-bra> ::= n <op-bran>
<op-bran> ::= <sem-setnameo> <sem-setopann> d #operator &=
<op-br> ::= d <op-brd>
<op-brd> ::= i <op-brdi>
<op-brdi> ::= <sem-setnameo> <sem-setopdvv> v #operator /=
<op-br> ::= l <op-brl>
<op-brl> ::= s <op-brls>
<op-brls> ::= <sem-setnameo> <sem-setoplss> h #operator <<=
<op-br> ::= m <op-brm>
<op-brm> ::= i <op-brmi>
<op-brmi> ::= <sem-setnameo> <sem-setopmii> n #operator -=
<op-brm> ::= o <op-brmo>
<op-brmo> ::= <sem-setnameo> <sem-setoprmm> d #operator %=
<op-brm> ::= u <op-brmu>
<op-brmu> ::= <sem-setnameo> <sem-setopmll> l #operator *=
<op-br> ::= o <op-bro>
<op-bro> ::= <sem-setnameo> <sem-setoporr> r #operator |=
<op-br> ::= p <op-brp>
<op-brp> ::= l <op-brpl>
<op-brpl> ::= <sem-setnameo> <sem-setoppll> u #operator +=
<op-br> ::= r <op-brr>
<op-brr> ::= s <op-brrs>
<op-brrs> ::= <sem-setnameo> <sem-setoprss> h #operator >>=
<op-br> ::= s <op-brs>
<op-brs> ::= <sem-setnameo> <sem-setoprs> h #operator >>
<op-br> ::= x <op-brx>
<op-brx> ::= o <op-brxo>
<op-brxo> ::= <sem-setnameo> <sem-setopeoo> r #operator ^=
<op-b> ::= s <op-bs>
<op-bs> ::= u <op-bsu>
<op-bsu> ::= b <op-bsub>
<op-bsub> ::= <sem-setnameo> <sem-setopmi> #operator -
<op-bsub> ::= <sem-setnameo> <sem-setopix> s #operator []
<op-b> ::= x <op-bx>
<op-bx> ::= o <op-bxo>
<op-bxo> ::= <sem-setnameo> <sem-setopeo> r #operator ^
<sem-addchartoname> ::=
<sem-storename> ::=
<sem-loadid> ::=
<sem-loadarr> ::=
<sem-ssno> ::=
<sem-ssnest> ::=
<sem-stunq> ::=
<sem-loadtsub> ::=
<sem-type2expr> ::=
<sem-exprval> ::=
<sem-beginexpr> ::=
<sem-storeexpr> ::=
<sem-copyexpr> ::=
<sem-storepar> ::=
<sem-begintempl> ::=
<sem-skiptempl> ::=
<sem-storetemparg> ::=
<sem-storetemplate> ::=
<sem-setnametf> ::=
<sem-par2f> ::=
<sem-unq2f> ::=
<sem-unq2p> ::=
<sem-setnamex> ::=
<sem-setnameo> ::=
<sem-par2spec> ::=
<sem-par2ret> ::=
<sem-settypev> ::=
<sem-settypew> ::=
<sem-settypeb> ::=
<sem-settypec> ::=
<sem-settypea> ::=
<sem-settypeh> ::=
<sem-settypes> ::=
<sem-settypet> ::=
<sem-settypei> ::=
<sem-settypej> ::=
<sem-settypel> ::=
<sem-settypem> ::=
<sem-settypex> ::=
<sem-settypey> ::=
<sem-settypen> ::=
<sem-settypeo> ::=
<sem-settypef> ::=
<sem-settyped> ::=
<sem-settypee> ::=
<sem-settypeg> ::=
<sem-settypez> ::=
<sem-setrestrict> ::=
<sem-setvolatile> ::=
<sem-setconst> ::=
<sem-setptr> ::=
<sem-setref> ::=
<sem-setrval> ::=
<sem-setcpair> ::=
<sem-setim> ::=
<sem-substd> ::=
<sem-subalc> ::=
<sem-substr> ::=
<sem-substrs> ::=
<sem-subistr> ::=
<sem-subostr> ::=
<sem-subiostr> ::=
<sem-loadsub> ::=
<sem-setnamec> ::=
<sem-setnamed> ::=
<sem-setopnw> ::=
<sem-setopna> ::=
<sem-setopdl> ::=
<sem-setopda> ::=
<sem-setopps> ::=
<sem-setopng> ::=
<sem-setopad> ::=
<sem-setopde> ::=
<sem-setopco> ::=
<sem-setoppl> ::=
<sem-setopmi> ::=
<sem-setopml> ::=
<sem-setopdv> ::=
<sem-setoprm> ::=
<sem-setopan> ::=
<sem-setopor> ::=
<sem-setopeo> ::=
<sem-setopass> ::=
<sem-setoppll> ::=
<sem-setopmii> ::=
<sem-setopmll> ::=
<sem-setopdvv> ::=
<sem-setoprmm> ::=
<sem-setopann> ::=
<sem-setoporr> ::=
<sem-setopeoo> ::=
<sem-setopls> ::=
<sem-setoprs> ::=
<sem-setoplss> ::=
<sem-setoprss> ::=
<sem-setopeq> ::=
<sem-setopne> ::=
<sem-setoplt> ::=
<sem-setopgt> ::=
<sem-setople> ::=
<sem-setopnt> ::=
<sem-setopaa> ::=
<sem-setopoo> ::=
<sem-setoppp> ::=
<sem-setopmm> ::=
<sem-setopcm> ::=
<sem-setoppm> ::=
<sem-setoppt> ::=
<sem-setopcl> ::=
<sem-setopix> ::=
<sem-setopge> ::=
<sem-setopqu> ::=
<sem-setopst> ::=
<sem-setopsz> ::=
<sem-setopat> ::=
<sem-setopaz> ::=
<sem-setopcv> ::=
<sem-setopxx> ::=
<sem-setnamef> ::=
<sem-setnamevt> ::=
<sem-reversename> ::=
<sem-setprivate> ::=
<sem-setpublic> ::=
<sem-setprotected> ::=
<sem-setfcdecl> ::=
<sem-setfpascal> ::=
<sem-setffortran> ::=
<sem-setfthiscall> ::=
<sem-setfstdcall> ::=
<sem-setffastcall> ::=
<sem-setfinterrupt> ::=
<sem-setunion> ::=
<sem-setstruct> ::=
<sem-setclass> ::=
<sem-setenum> ::=
<sem-setstatic> ::=
<sem-setvirtual> ::=
<sem-stclconst> ::=
<sem-stclvol> ::=
<sem-stclfar> ::=
<sem-stclhuge> ::=
<sem-savenamesub> ::=
<sem-loadnamesub> ::=
<sem-mstemplsub> ::=
<sem-setnamer0> ::=
<sem-setnamer1> ::=
<sem-setnamer2> ::=
<sem-setnamer3> ::=
<sem-setnamer4> ::=
<sem-setname_a> ::=
<sem-setname_b> ::=
<sem-setname_c> ::=
<sem-setname_d> ::=
<sem-setname_e> ::=
<sem-setname_f> ::=
<sem-setname_g> ::=
<sem-setname_h> ::=
<sem-setname_i> ::=
<sem-setname_j> ::=
<sem-setname_k> ::=
<sem-setname_l> ::=
<sem-setname_m> ::=
<sem-setname_n> ::=
<sem-setname_o> ::=
<sem-setname_p> ::=
<sem-setname_q> ::=
<sem-setname_r> ::=
<sem-setname_s> ::=
<sem-setname_t> ::=
<sem-setname_u> ::=
<sem-setname_v> ::=
<sem-setname_w> ::=
<sem-setname_x> ::=
<sem-setname_y> ::=
<sem-setname_z> ::=
<sem-templ2tftpl> ::=
<sem-beginbsub> ::= #begin built-in substitution
<sem-loadbsub> ::=
<sem-addmconst> ::=
<sem-addmvol> ::=
<sem-addmfar> ::=
<sem-addmhuge> ::=
<sem-loadmsnum> ::=
<sem-numtorttibcd> ::=
<sem-numtotype> ::=
<sem-normalizeparname> ::=
<sem-borlandid> ::=
<sem-loadborlandsub> ::=
<sem-borlandarr> ::=
<sem-end> ::=

View File

@@ -1,423 +0,0 @@
<mangled-name> ::= _ <mangled-name2>
<mangled-name2> ::= <mangled-name3> <sem-end>
<mangled-name2> ::= _ <mangled-name3> <sem-end>
<mangled-name3> ::= Z <encoding>
<encoding> ::= <name> <bare-function-type>
<name> ::= <nested-name>
<name> ::= <source-name> <template-args>
<name> ::= S <name-sub> #deciding rule
<name-sub> ::= <sem-ssno> <substitution2-t> <unqualified-name>
<name-sub> ::= <sem-ssno> <substitution2> <template-args>
<template-args> ::= <sem-skiptempl>
<template-args> ::= <sem-begintempl> I <template-arg> <template-arg-more> E
<template-args-nostore> ::= <sem-skiptempl>
<template-args-nostore> ::= <sem-begintempl> I <template-arg-nostore> <template-arg-nostore-more> E
<template-arg-more> ::= <sem-storetemparg> <template-arg> <template-arg-more>
<template-arg-more> ::= <sem-storetemplate>
<template-arg> ::= <type>
<template-arg> ::= <expr-primary>
<template-arg-nostore> ::= <type>
<template-arg-nostore> ::= <expr-primary>
<template-arg-nostore-more> ::= <sem-storetemparg> <template-arg> <template-arg-more>
<template-arg-nostore-more> ::= <sem-templ2tftpl>
<template-param> ::= T <template-param2>
<template-param2> ::= <sem-loadtsub> _
<template-param2> ::= <sem-loadtsub> <number> _ #<unscoped-name> ::= <unqualified-name> #<unscoped-name> ::= St <unqualified-name> # unused, but may be useful in the future
<nested-name> ::= <sem-ssnest> N <CV-qualifiers> <unqualified-name> <unqualified-name-more> E
<prefix> ::=
<prefix> ::= <substitution>
<prefix> ::= <template-param>
<unqualified-function-name> ::= <unqualified-name>
<unqualified-function-name> ::= <ctor-dtor-name> <template-args-nostore>
<unqualified-function-name> ::= <operator-name-setname>
<operator-name-setname> ::= <sem-setnameo> <operator-name> <template-args>
<operator-name-setname> ::= <sem-setnameo> <operator-name-cv>
<unqualified-name> ::= <source-name> <template-args>
<unqualified-name> ::= <substitution> <template-args>
<unqualified-name-more> ::= <unqualified-function-name> <unqualified-name-more>
<unqualified-name-more> ::=
<source-name> ::= <source-number>
<source-number> ::= <sem-loadid> <number>
<number> ::= 0
<number> ::= 1
<number> ::= 2
<number> ::= 3
<number> ::= 4
<number> ::= 5
<number> ::= 6
<number> ::= 7
<number> ::= 8
<number> ::= 9
<ctor-dtor-name> ::= <sem-setnamec> C <ctor>
<ctor> ::= 1 # complete object constructor
<ctor> ::= 2 # base object constructor
<ctor> ::= 3 # complete object allocating constructor
<ctor-dtor-name> ::= <sem-setnamed> D <dtor>
<dtor> ::= 0 # deleting destructor
<dtor> ::= 1 # complete object destructor
<dtor> ::= 2 # base object destructor
<CV-qualifiers> ::= <r> <V> <K>
<r> ::= <sem-setrestrict> r # restrict
<r> ::=
<V> ::= <sem-setvolatile> V # volatile
<V> ::=
<K> ::= <sem-setconst> K # const
<K> ::=
<bare-function-type> ::= <sem-unq2f> <bare-function-type2>
<bare-function-type2> ::= <type> <another-type> <sem-par2f>
<bare-function-type2> ::= <sem-setnamex>
<another-type> ::= <sem-storepar> <type> <another-type>
<another-type> ::=
<type> ::= <type-qualifier> <type2>
<type-qualifier> ::=
<type-qualifier> ::= <sem-setrestrict> r <type-qualifier>
<type-qualifier> ::= <sem-setvolatile> V <type-qualifier>
<type-qualifier> ::= <sem-setconst> K <type-qualifier>
<type-qualifier> ::= <sem-setptr> P <type-qualifier>
<type-qualifier> ::= <sem-setref> R <type-qualifier>
<type-qualifier> ::= <sem-setrval> O <type-qualifier>
<type-qualifier> ::= <sem-setcpair> C <type-qualifier>
<type-qualifier> ::= <sem-setim> G <type-qualifier>
<type2> ::= <template-param>
<type2> ::= <builtin-type>
<type2> ::= <class-enum-type>
<type2> ::= <array-type>
<array-type> ::= A <array-number> _ <type>
<array-number> ::= <sem-loadarr> <number>
<class-enum-type> ::= <name>
<builtin-type> ::= <sem-settypev> v # void
<builtin-type> ::= <sem-settypew> w # wchar_t
<builtin-type> ::= <sem-settypeb> b # bool
<builtin-type> ::= <sem-settypec> c # char
<builtin-type> ::= <sem-settypea> a # signed char
<builtin-type> ::= <sem-settypeh> h # unsigned char
<builtin-type> ::= <sem-settypes> s # short
<builtin-type> ::= <sem-settypet> t # unsigned short
<builtin-type> ::= <sem-settypei> i # int
<builtin-type> ::= <sem-settypej> j # unsigned int
<builtin-type> ::= <sem-settypel> l # long
<builtin-type> ::= <sem-settypem> m # unsigned long
<builtin-type> ::= <sem-settypex> x # long long, __int64
<builtin-type> ::= <sem-settypey> y # unsigned long long, __int64
<builtin-type> ::= <sem-settypen> n # __int128
<builtin-type> ::= <sem-settypeo> o # unsigned __int128
<builtin-type> ::= <sem-settypef> f # float
<builtin-type> ::= <sem-settyped> d # double
<builtin-type> ::= <sem-settypee> e # long double, __float80
<builtin-type> ::= <sem-settypeg> g # __float128
<builtin-type> ::= <sem-settypez> z # ellipsis
<builtin-type> ::= D <builtin-type2>
<builtin-type2> ::= d # IEEE 754r decimal floating point (64 bits)
<builtin-type2> ::= e # IEEE 754r decimal floating point (128 bits)
<builtin-type2> ::= f # IEEE 754r decimal floating point (32 bits)
<builtin-type2> ::= h # IEEE 754r half-precision floating point (16 bits)
<builtin-type2> ::= i # char32_t
<builtin-type2> ::= s # char16_t
<builtin-type2> ::= a # auto (in dependent new-expressions)
<builtin-type2> ::= n # std::nullptr_t (i.e., decltype(nullptr))
<substitution> ::= S <subst>
<subst> ::= <substitution2-t> # separating St
<subst> ::= <substitution2>
<substitution2> ::= <seq-id> _
<substitution2> ::= <sem-loadsub> _
<seq-id> ::= <sem-loadsub> 0
<seq-id> ::= <sem-loadsub> 1
<seq-id> ::= <sem-loadsub> 2
<seq-id> ::= <sem-loadsub> 3
<seq-id> ::= <sem-loadsub> 4
<seq-id> ::= <sem-loadsub> 5
<seq-id> ::= <sem-loadsub> 6
<seq-id> ::= <sem-loadsub> 7
<seq-id> ::= <sem-loadsub> 8
<seq-id> ::= <sem-loadsub> 9
<seq-id> ::= <sem-loadsub> A
<seq-id> ::= <sem-loadsub> B
<seq-id> ::= <sem-loadsub> C
<seq-id> ::= <sem-loadsub> D
<seq-id> ::= <sem-loadsub> E
<seq-id> ::= <sem-loadsub> F
<seq-id> ::= <sem-loadsub> G
<seq-id> ::= <sem-loadsub> H
<seq-id> ::= <sem-loadsub> I
<seq-id> ::= <sem-loadsub> J
<seq-id> ::= <sem-loadsub> K
<seq-id> ::= <sem-loadsub> L
<seq-id> ::= <sem-loadsub> M
<seq-id> ::= <sem-loadsub> N
<seq-id> ::= <sem-loadsub> O
<seq-id> ::= <sem-loadsub> P
<seq-id> ::= <sem-loadsub> Q
<seq-id> ::= <sem-loadsub> R
<seq-id> ::= <sem-loadsub> S
<seq-id> ::= <sem-loadsub> T
<seq-id> ::= <sem-loadsub> U
<seq-id> ::= <sem-loadsub> V
<seq-id> ::= <sem-loadsub> W
<seq-id> ::= <sem-loadsub> X
<seq-id> ::= <sem-loadsub> Y
<seq-id> ::= <sem-loadsub> Z
<substitution2-t> ::= <sem-substd> t # ::std::
<substitution2> ::= <sem-subalc> a # ::std::allocator
<substitution2> ::= <sem-substr> b # ::std::basic_string
<substitution2> ::= <sem-substrs> s # ::std::basic_string<char,::std::char_traits<char>,::std::allocator<char>>
<substitution2> ::= <sem-subistr> i # ::std::basic_istream<char, std::char_traits<char> >
<substitution2> ::= <sem-subostr> o # ::std::basic_ostream<char, std::char_traits<char> >
<substitution2> ::= <sem-subiostr> d # ::std::basic_iostream<char, std::char_traits<char> >
<operator-name> ::= a <operator-name-a>
<operator-name> ::= c <operator-name-c>
<operator-name> ::= d <operator-name-d>
<operator-name> ::= e <operator-name-e>
<operator-name> ::= g <operator-name-g>
<operator-name> ::= i <operator-name-i>
<operator-name> ::= l <operator-name-l>
<operator-name> ::= m <operator-name-m>
<operator-name> ::= n <operator-name-n>
<operator-name> ::= o <operator-name-o>
<operator-name> ::= p <operator-name-p>
<operator-name> ::= q <operator-name-q>
<operator-name> ::= r <operator-name-r>
<operator-name> ::= s <operator-name-s>
<operator-name-a> ::= <sem-setopaa> a # &&
<operator-name-a> ::= <sem-setopad> d # & (unary)
<operator-name-a> ::= <sem-setopan> n # &
<operator-name-a> ::= <sem-setopat> t # alignof (a type)
<operator-name-a> ::= <sem-setopaz> z # alignof (an expression)
<operator-name-a> ::= <sem-setopass> S # =
<operator-name-a> ::= <sem-setopann> N # &=
<operator-name-c> ::= <sem-setopcm> m # ,
<operator-name-c> ::= <sem-setopcl> l # ()
<operator-name-c> ::= <sem-setopco> o # ~
<operator-name-cv> ::= <sem-setopcv> v <type> <sem-par2spec> # (cast)
<operator-name-d> ::= <sem-setopdl> l # delete
<operator-name-d> ::= <sem-setopda> a # delete[]
<operator-name-d> ::= <sem-setopde> e # * (unary)
<operator-name-d> ::= <sem-setopdv> v # /
<operator-name-d> ::= <sem-setopdvv> V # /=
<operator-name-e> ::= <sem-setopeo> o # ^
<operator-name-e> ::= <sem-setopeoo> O # ^=
<operator-name-e> ::= <sem-setopeq> q # ==
<operator-name-g> ::= <sem-setopgt> t # >
<operator-name-g> ::= <sem-setopge> e # >=
<operator-name-i> ::= <sem-setopix> x # []
<operator-name-l> ::= <sem-setopls> s # <<
<operator-name-l> ::= <sem-setoplss> S # <<=
<operator-name-l> ::= <sem-setoplt> t # <
<operator-name-l> ::= <sem-setople> e # <=
<operator-name-m> ::= <sem-setopmi> i # -
<operator-name-m> ::= <sem-setopml> l # *
<operator-name-m> ::= <sem-setopmii> I # -=
<operator-name-m> ::= <sem-setopmll> L # *=
<operator-name-m> ::= <sem-setopmm> m # -- (postfix in <expression> context)
<operator-name-n> ::= <sem-setopnw> w # new
<operator-name-n> ::= <sem-setopna> a # new[]
<operator-name-n> ::= <sem-setopng> g # - (unary)
<operator-name-n> ::= <sem-setopne> e # !=
<operator-name-n> ::= <sem-setopnt> t # !
<operator-name-o> ::= <sem-setopor> r # |
<operator-name-o> ::= <sem-setoporr> R # |=
<operator-name-o> ::= <sem-setopoo> o # ||
<operator-name-p> ::= <sem-setopps> s # + (unary)
<operator-name-p> ::= <sem-setoppl> l # +
<operator-name-p> ::= <sem-setoppll> L # +=
<operator-name-p> ::= <sem-setoppp> p # ++ (postfix in <expression> context)
<operator-name-p> ::= <sem-setoppm> m # ->*
<operator-name-p> ::= <sem-setoppt> t # ->
<operator-name-q> ::= <sem-setopqu> u # ?
<operator-name-r> ::= <sem-setoprm> m # %
<operator-name-r> ::= <sem-setoprmm> M # %=
<operator-name-r> ::= <sem-setoprs> s # >>
<operator-name-r> ::= <sem-setoprss> S # >>=
<operator-name-s> ::= <sem-setopst> t # sizeof (a type)
<operator-name-s> ::= <sem-setopsz> z # sizeof (an expression)
<expr-primary> ::= <sem-beginexpr> L <builtin-type> <sem-type2expr> <expr-number> E <sem-storeexpr>
<expr-number> ::= <sem-exprval> <number>
<sem-addchartoname> ::=
<sem-storename> ::=
<sem-loadid> ::=
<sem-loadarr> ::=
<sem-ssno> ::=
<sem-ssnest> ::=
<sem-stunq> ::=
<sem-loadtsub> ::=
<sem-type2expr> ::=
<sem-exprval> ::=
<sem-beginexpr> ::=
<sem-storeexpr> ::=
<sem-copyexpr> ::=
<sem-storepar> ::=
<sem-begintempl> ::=
<sem-skiptempl> ::=
<sem-storetemparg> ::=
<sem-storetemplate> ::=
<sem-setnametf> ::=
<sem-par2f> ::=
<sem-unq2f> ::=
<sem-unq2p> ::=
<sem-setnamex> ::=
<sem-setnameo> ::=
<sem-par2spec> ::=
<sem-par2ret> ::=
<sem-settypev> ::=
<sem-settypew> ::=
<sem-settypeb> ::=
<sem-settypec> ::=
<sem-settypea> ::=
<sem-settypeh> ::=
<sem-settypes> ::=
<sem-settypet> ::=
<sem-settypei> ::=
<sem-settypej> ::=
<sem-settypel> ::=
<sem-settypem> ::=
<sem-settypex> ::=
<sem-settypey> ::=
<sem-settypen> ::=
<sem-settypeo> ::=
<sem-settypef> ::=
<sem-settyped> ::=
<sem-settypee> ::=
<sem-settypeg> ::=
<sem-settypez> ::=
<sem-setrestrict> ::=
<sem-setvolatile> ::=
<sem-setconst> ::=
<sem-setptr> ::=
<sem-setref> ::=
<sem-setrval> ::=
<sem-setcpair> ::=
<sem-setim> ::=
<sem-substd> ::=
<sem-subalc> ::=
<sem-substr> ::=
<sem-substrs> ::=
<sem-subistr> ::=
<sem-subostr> ::=
<sem-subiostr> ::=
<sem-loadsub> ::=
<sem-setnamec> ::=
<sem-setnamed> ::=
<sem-setopnw> ::=
<sem-setopna> ::=
<sem-setopdl> ::=
<sem-setopda> ::=
<sem-setopps> ::=
<sem-setopng> ::=
<sem-setopad> ::=
<sem-setopde> ::=
<sem-setopco> ::=
<sem-setoppl> ::=
<sem-setopmi> ::=
<sem-setopml> ::=
<sem-setopdv> ::=
<sem-setoprm> ::=
<sem-setopan> ::=
<sem-setopor> ::=
<sem-setopeo> ::=
<sem-setopass> ::=
<sem-setoppll> ::=
<sem-setopmii> ::=
<sem-setopmll> ::=
<sem-setopdvv> ::=
<sem-setoprmm> ::=
<sem-setopann> ::=
<sem-setoporr> ::=
<sem-setopeoo> ::=
<sem-setopls> ::=
<sem-setoprs> ::=
<sem-setoplss> ::=
<sem-setoprss> ::=
<sem-setopeq> ::=
<sem-setopne> ::=
<sem-setoplt> ::=
<sem-setopgt> ::=
<sem-setople> ::=
<sem-setopnt> ::=
<sem-setopaa> ::=
<sem-setopoo> ::=
<sem-setoppp> ::=
<sem-setopmm> ::=
<sem-setopcm> ::=
<sem-setoppm> ::=
<sem-setoppt> ::=
<sem-setopcl> ::=
<sem-setopix> ::=
<sem-setopge> ::=
<sem-setopqu> ::=
<sem-setopst> ::=
<sem-setopsz> ::=
<sem-setopat> ::=
<sem-setopaz> ::=
<sem-setopcv> ::=
<sem-setopxx> ::=
<sem-setnamef> ::=
<sem-setnamevt> ::=
<sem-reversename> ::=
<sem-setprivate> ::=
<sem-setpublic> ::=
<sem-setprotected> ::=
<sem-setfcdecl> ::=
<sem-setfpascal> ::=
<sem-setffortran> ::=
<sem-setfthiscall> ::=
<sem-setfstdcall> ::=
<sem-setffastcall> ::=
<sem-setfinterrupt> ::=
<sem-setunion> ::=
<sem-setstruct> ::=
<sem-setclass> ::=
<sem-setenum> ::=
<sem-setstatic> ::=
<sem-setvirtual> ::=
<sem-stclconst> ::=
<sem-stclvol> ::=
<sem-stclfar> ::=
<sem-stclhuge> ::=
<sem-savenamesub> ::=
<sem-loadnamesub> ::=
<sem-mstemplsub> ::=
<sem-setnamer0> ::=
<sem-setnamer1> ::=
<sem-setnamer2> ::=
<sem-setnamer3> ::=
<sem-setnamer4> ::=
<sem-setname_a> ::=
<sem-setname_b> ::=
<sem-setname_c> ::=
<sem-setname_d> ::=
<sem-setname_e> ::=
<sem-setname_f> ::=
<sem-setname_g> ::=
<sem-setname_h> ::=
<sem-setname_i> ::=
<sem-setname_j> ::=
<sem-setname_k> ::=
<sem-setname_l> ::=
<sem-setname_m> ::=
<sem-setname_n> ::=
<sem-setname_o> ::=
<sem-setname_p> ::=
<sem-setname_q> ::=
<sem-setname_r> ::=
<sem-setname_s> ::=
<sem-setname_t> ::=
<sem-setname_u> ::=
<sem-setname_v> ::=
<sem-setname_w> ::=
<sem-setname_x> ::=
<sem-setname_y> ::=
<sem-setname_z> ::=
<sem-templ2tftpl> ::=
<sem-beginbsub> ::= #begin built-in substitution
<sem-loadbsub> ::=
<sem-addmconst> ::=
<sem-addmvol> ::=
<sem-addmfar> ::=
<sem-addmhuge> ::=
<sem-loadmsnum> ::=
<sem-numtorttibcd> ::=
<sem-numtotype> ::=
<sem-normalizeparname> ::=
<sem-borlandid> ::=
<sem-loadborlandsub> ::=
<sem-borlandarr> ::=
<sem-end> ::=

View File

@@ -1,534 +0,0 @@
<mangled-name> ::= ? <mangled-name-2>
<mangled-name-2> ::= ? <mangled-name-qs>
<mangled-name-qs> ::= _ <mangled-name-qssub>
<mangled-name-qs> ::= 0 <name-cover> <sem-setnamec> <sem-unq2f> <modif> <const-vol> <calling-conv> @ <parameters> <terma> Z <sem-end>
<mangled-name-qs> ::= 1 <name-cover> <sem-setnamed> <sem-unq2f> <modif> <const-vol> <calling-conv> @ <parameters> <terma>Z <sem-end>
<mangled-name-qs> ::= <sem-setnameo> <optype> <name-cover> <sem-unq2f> <mangled-name-data>
<optype> ::= <sem-setopdl> 3
<optype> ::= <sem-setopix> A
<optype> ::= <sem-setopcl> R
<optype> ::= <sem-setoppt> C
<optype> ::= <sem-setoppp> E
<optype> ::= <sem-setopmm> F
<optype> ::= <sem-setopnw> 2
<optype> ::= <sem-setopde> D
<optype> ::= <sem-setopad> I
<optype> ::= <sem-setopps> H
<optype> ::= <sem-setopng> G
<optype> ::= <sem-setopnt> 7
<optype> ::= <sem-setopco> S
<optype> ::= <sem-setoppm> J
<optype> ::= <sem-setopdv> K
<optype> ::= <sem-setoprm> L
<optype> ::= <sem-setopls> 6
<optype> ::= <sem-setoprs> 5
<optype> ::= <sem-setoplt> M
<optype> ::= <sem-setopgt> O
<optype> ::= <sem-setople> N
<optype> ::= <sem-setopge> P
<optype> ::= <sem-setopeq> 8
<optype> ::= <sem-setopne> 9
<optype> ::= <sem-setopor> U
<optype> ::= <sem-setopeo> T
<optype> ::= <sem-setopaa> V
<optype> ::= <sem-setopoo> W
<optype> ::= <sem-setopass> 4
<optype> ::= <sem-setopmll> X
<optype> ::= <sem-setoppll> Y
<optype> ::= <sem-setopmii> Z
<optype> ::= <sem-setopcm> Q
<optype> ::= <sem-setopcv> B
<optype_> ::= <sem-setopna> U
<optype_> ::= <sem-setopda> V
<optype_> ::= <sem-setopdvv> 0
<optype_> ::= <sem-setoprmm> 1
<optype_> ::= <sem-setoprss> 2
<optype_> ::= <sem-setoplss> 3
<optype_> ::= <sem-setopann> 4
<optype_> ::= <sem-setoporr> 5
<optype_> ::= <sem-setopeoo> 6
<terma> ::=
<terma> ::= @
<mangled-name-qssub> ::= 7 <name-cover> <sem-setnamevt> <sem-unq2f> <mangled-name-data>
<mangled-name-qssub> ::= R <mangled-name-qssub-r>
<mangled-name-qssub-r> ::= <r-num> <name-cover> <sem-unq2f> 8 <sem-end>
<mangled-name-qssub-r> ::= <sem-setnamer4> 4 <name-cover> <sem-unq2f> <mangled-name-data>
<mangled-name-qssub-r> ::= <sem-setnamer1> 1 <sem-loadmsnum> <msnum> <sem-numtorttibcd> <sem-loadmsnum> <msnum> <sem-numtorttibcd> <sem-loadmsnum> <msnum> <sem-numtorttibcd> <sem-loadmsnum> <msnum> <sem-numtorttibcd> <name-cover> <sem-unq2f> <terma> 8 <sem-end>
<mangled-name-qssub-r> ::= <sem-setnamer0> 0 <storage-return> <type> <sem-par2ret> @ 8 <sem-end>
<r-num> ::= <sem-setnamer2> 2
<r-num> ::= <sem-setnamer3> 3
<mangled-name-qssub> ::= <sem-setnameo> <optype_> <name-cover> <sem-unq2f> <mangled-name-data>
<mangled-name-qssub> ::= <qssub> <name-cover> <sem-unq2f> <mangled-name-data>
<qssub> ::= <sem-setname_a> A
<qssub> ::= <sem-setname_b> B
<qssub> ::= <sem-setname_d> D
<qssub> ::= <sem-setname_e> E
<qssub> ::= <sem-setname_f> F
<qssub> ::= <sem-setname_g> G
<qssub> ::= <sem-setname_h> H
<qssub> ::= <sem-setname_i> I
<qssub> ::= <sem-setname_j> J
<qssub> ::= <sem-setname_k> K
<qssub> ::= <sem-setname_l> L
<qssub> ::= <sem-setname_m> M
<qssub> ::= <sem-setname_n> N
<qssub> ::= <sem-setname_o> O
<qssub> ::= <sem-setname_q> Q
<qssub> ::= <sem-setname_s> S
<qssub> ::= <sem-setname_t> T
<qssub> ::= <sem-setname_x> X
<qssub> ::= <sem-setname_y> Y
<storage-return> ::=
<storage-return> ::= ? <storage-return-2>
<storage-return-2> ::= A
<storage-return-2> ::= <sem-setconst> B
<storage-return-2> ::= <sem-setvol> C
<storage-return-2> ::= <sem-setconst> <sem-setvol> D
<mangled-name-qs> ::= <name-cover-qs> <sem-unq2f> <mangled-name-data>
<mangled-name-2> ::= <name-cover-noqs> <sem-unq2f> <mangled-name-data>
<mangled-name-data> ::= <data-object> <sem-end>
<mangled-name-data> ::= <modif> <const-vol> <calling-conv> <storage-return> <type> <sem-par2ret> <parameters> <terma> Z <sem-end>
<mangled-name-data> ::= <near-far> <calling-conv> <storage-return> <type> <sem-par2ret> <parameters> <terma> Z <sem-end>
<data-object> ::= 6 <storage-class> <terma>
<data-object> ::= 3 <sem-setnamex> <type> <sem-par2ret> <storage-class> #global object
<data-object> ::= 2 <sem-setnamex> <sem-setpublic> <sem-setstatic> <type> <sem-par2ret> <storage-class> #static class member object
<data-object> ::= 1 <sem-setnamex> <sem-setprotected> <sem-setstatic> <type> <sem-par2ret> <storage-class> #static class member object
<data-object> ::= 0 <sem-setnamex> <sem-setprivate> <sem-setstatic> <type> <sem-par2ret> <storage-class> #static class member object
<msnum> ::= ?
<msnum> ::= 0
<msnum> ::= 1
<msnum> ::= 2
<msnum> ::= 3
<msnum> ::= 4
<msnum> ::= 5
<msnum> ::= 6
<msnum> ::= 7
<msnum> ::= 8
<msnum> ::= 9
<msnum> ::= A
<msnum> ::= B
<msnum> ::= C
<msnum> ::= D
<msnum> ::= E
<msnum> ::= F
<msnum> ::= G
<msnum> ::= H
<msnum> ::= I
<msnum> ::= J
<msnum> ::= K
<msnum> ::= L
<msnum> ::= M
<msnum> ::= N
<msnum> ::= O
<msnum> ::= P
<storage-class> ::= Q1@ #member pointers, member function pointers
<storage-class> ::= A #near
<storage-class> ::= <sem-stclconst> B #const
<storage-class> ::= <sem-stclvol> C #volatile
<storage-class> ::= <sem-stclconst> <sem-stclvol> D #const volatile
<storage-class> ::= <sem-stclfar> E #far
<storage-class> ::= <sem-stclconst> <sem-stclfar> F #const far
<storage-class> ::= <sem-stclvol> <sem-stclfar> G #volatile far
<storage-class> ::= <sem-stclconst> <sem-stclvol> <sem-stclfar> H #const volatile far
<storage-class> ::= <sem-stclhuge> I #huge
<modif> ::= <sem-setprivate> A #private default
<modif> ::= <sem-setprivate> B #private far
<modif> ::= <sem-setprivate> <sem-setstatic> C #private static
<modif> ::= <sem-setprivate> <sem-setstatic> D #private static far
<modif> ::= <sem-setprivate> <sem-setvirtual> E #private virtual
<modif> ::= <sem-setprivate> <sem-setvirtual> F #private virtual far
<modif> ::= <sem-setprotected> I #protected default
<modif> ::= <sem-setprotected> J #protected far
<modif> ::= <sem-setprotected> <sem-setstatic> K #protected static
<modif> ::= <sem-setprotected> <sem-setstatic> L #protected static far
<modif> ::= <sem-setprotected> <sem-setvirtual> M #protected virtual
<modif> ::= <sem-setprotected> <sem-setvirtual> N #protected virtual far
<modif> ::= <sem-setpublic> Q #public default
<modif> ::= <sem-setpublic> R #public far
<modif> ::= <sem-setpublic> <sem-setstatic> S #public static
<modif> ::= <sem-setpublic> <sem-setstatic> T #public static far
<modif> ::= <sem-setpublic> <sem-setvirtual> U #public virtual
<modif> ::= <sem-setpublic> <sem-setvirtual> V #public virtual far
<const-vol-e> ::=
<const-vol-e> ::= <const-vol>
<const-vol> ::= A #default
<const-vol> ::= <sem-addmconst> B #const
<const-vol> ::= <sem-addmvol> C #volatile
<const-vol> ::= <sem-addmconst> <sem-addmvol> D #const volatile
<calling-conv> ::= <sem-setfcdecl> A #__cdecl
<calling-conv> ::= <sem-setfpascal> C #__pascal
<calling-conv> ::= <sem-setfthiscall> E #__thiscall
<calling-conv> ::= <sem-setfstdcall> G #__stdcall
<calling-conv> ::= <sem-setffastcall> I #__fastcall
<name-cover-qs> ::= <name-qs> @ <namespace-x> @
<name-cover-noqs> ::= <name-element-noqs> <namespace-x> @
<name-cover> ::= <name-element> <namespace-x> @
<name-cover> ::= @
<name-element> ::= <name> @
<name-element> ::= <name-sub>
<name-element-noqs> ::= <name-noqs> @
<name-element-noqs> ::= <name-sub>
<name-sub> ::= <sem-loadnamesub> 0
<name-sub> ::= <sem-loadnamesub> 1
<name-sub> ::= <sem-loadnamesub> 2
<name-sub> ::= <sem-loadnamesub> 3
<name-sub> ::= <sem-loadnamesub> 4
<name-sub> ::= <sem-loadnamesub> 5
<name-sub> ::= <sem-loadnamesub> 6
<name-sub> ::= <sem-loadnamesub> 7
<name-sub> ::= <sem-loadnamesub> 8
<name-sub> ::= <sem-loadnamesub> 9
<name-elemental> ::= <name-char-first> <name-char-more>
<template-header> ::= <name-elemental> @
<template-header> ::= ? <template-op>
<template-op> ::= <sem-setnameo> <optype>
<template-op> ::= <sem-setnameo> _ <optype_>
<name-qs> ::= $ <template-header> <sem-begintempl> <sem-mstemplsub> <template-arg> <template-arg-more> <sem-savenamesub>
<name-noqs> ::= <name-elemental> <sem-savenamesub>
<name> ::= ? <name-qs>
<name> ::= <name-noqs>
<name-char-more> ::= <name-char> <name-char-more>
<name-char-more> ::= <name-char-first> <name-char-more>
<name-char-more> ::= <sem-storename>
<namespace-x> ::= <sem-reversename>
<namespace-x> ::= <name-element> <namespace-x>
<template-arg-more> ::= <sem-storetemplate>
<template-arg-more> ::= <sem-storetemparg> <template-arg> <template-arg-more>
<template-arg> ::= <type>
<parameters> ::= <parameter> <parameter-more>
<parameter> ::= <type>
<parameter-more> ::= <sem-storepar> <parameter> <parameter-more>
<parameter-more> ::= <sem-par2f>
<near-far> ::= Y #near
<near-far> ::= Z #far
<name-char-first> ::= <sem-addchartoname> _
<name-char-first> ::= <sem-addchartoname> a
<name-char-first> ::= <sem-addchartoname> b
<name-char-first> ::= <sem-addchartoname> c
<name-char-first> ::= <sem-addchartoname> d
<name-char-first> ::= <sem-addchartoname> e
<name-char-first> ::= <sem-addchartoname> f
<name-char-first> ::= <sem-addchartoname> g
<name-char-first> ::= <sem-addchartoname> h
<name-char-first> ::= <sem-addchartoname> i
<name-char-first> ::= <sem-addchartoname> j
<name-char-first> ::= <sem-addchartoname> k
<name-char-first> ::= <sem-addchartoname> l
<name-char-first> ::= <sem-addchartoname> m
<name-char-first> ::= <sem-addchartoname> n
<name-char-first> ::= <sem-addchartoname> o
<name-char-first> ::= <sem-addchartoname> p
<name-char-first> ::= <sem-addchartoname> q
<name-char-first> ::= <sem-addchartoname> r
<name-char-first> ::= <sem-addchartoname> s
<name-char-first> ::= <sem-addchartoname> t
<name-char-first> ::= <sem-addchartoname> u
<name-char-first> ::= <sem-addchartoname> v
<name-char-first> ::= <sem-addchartoname> w
<name-char-first> ::= <sem-addchartoname> x
<name-char-first> ::= <sem-addchartoname> y
<name-char-first> ::= <sem-addchartoname> z
<name-char-first> ::= <sem-addchartoname> A
<name-char-first> ::= <sem-addchartoname> B
<name-char-first> ::= <sem-addchartoname> C
<name-char-first> ::= <sem-addchartoname> D
<name-char-first> ::= <sem-addchartoname> E
<name-char-first> ::= <sem-addchartoname> F
<name-char-first> ::= <sem-addchartoname> G
<name-char-first> ::= <sem-addchartoname> H
<name-char-first> ::= <sem-addchartoname> I
<name-char-first> ::= <sem-addchartoname> J
<name-char-first> ::= <sem-addchartoname> K
<name-char-first> ::= <sem-addchartoname> L
<name-char-first> ::= <sem-addchartoname> M
<name-char-first> ::= <sem-addchartoname> N
<name-char-first> ::= <sem-addchartoname> O
<name-char-first> ::= <sem-addchartoname> P
<name-char-first> ::= <sem-addchartoname> Q
<name-char-first> ::= <sem-addchartoname> R
<name-char-first> ::= <sem-addchartoname> S
<name-char-first> ::= <sem-addchartoname> T
<name-char-first> ::= <sem-addchartoname> U
<name-char-first> ::= <sem-addchartoname> V
<name-char-first> ::= <sem-addchartoname> W
<name-char-first> ::= <sem-addchartoname> X
<name-char-first> ::= <sem-addchartoname> Y
<name-char-first> ::= <sem-addchartoname> Z
<name-char> ::= <sem-addchartoname> 0
<name-char> ::= <sem-addchartoname> 1
<name-char> ::= <sem-addchartoname> 2
<name-char> ::= <sem-addchartoname> 3
<name-char> ::= <sem-addchartoname> 4
<name-char> ::= <sem-addchartoname> 5
<name-char> ::= <sem-addchartoname> 6
<name-char> ::= <sem-addchartoname> 7
<name-char> ::= <sem-addchartoname> 8
<name-char> ::= <sem-addchartoname> 9
<name-char> ::= <sem-addchartoname> $
<type> ::= <typesub>
<type> ::= _ <sem-beginbsub> <type_>
<type> ::= $ <type-ds>
<type-ds> ::= $ <type-dsds>
<type-ds> ::= 0 <sem-loadmsnum> <msnum> <sem-numtotype>
<type-dsds> ::= C <dsds-modifier> <type>
<dsds-modifier> ::= A
<dsds-modifier> ::= <sem-setconst> B
<dsds-modifier> ::= <sem-setvolatile> C
<dsds-modifier> ::= <sem-setvolatile> <sem-setconst> D
<dsds-modifier> ::= E
<dsds-modifier> ::= F
<dsds-modifier> ::= <sem-setvolatile> G
<dsds-modifier> ::= <sem-setvolatile> <sem-setconst> H
<dsds-modifier> ::= I
<dsds-modifier> ::= <sem-setconst> J
<dsds-modifier> ::= <sem-setvolatile> K
<dsds-modifier> ::= <sem-setvolatile> <sem-setconst> L
<typesub> ::= <sem-loadbsub> 0
<typesub> ::= <sem-loadbsub> 1
<typesub> ::= <sem-loadbsub> 2
<typesub> ::= <sem-loadbsub> 3
<typesub> ::= <sem-loadbsub> 4
<typesub> ::= <sem-loadbsub> 5
<typesub> ::= <sem-loadbsub> 6
<typesub> ::= <sem-loadbsub> 7
<typesub> ::= <sem-loadbsub> 8
<typesub> ::= <sem-loadbsub> 9
<type> ::= <sem-settypev> X #void
<type> ::= <sem-settypec> D #char
<type> ::= <sem-settypea> C #signed char
<type> ::= <sem-settypeh> E #unsigned char
<type> ::= <sem-settypes> F #short int
<type> ::= <sem-settypet> G #unsigned short int
<type> ::= <sem-settypei> H #int
<type> ::= <sem-settypej> I #unsigned int
<type> ::= <sem-settypel> J #long int
<type> ::= <sem-settypem> K #unsigned long int
<type> ::= <sem-settypef> M #float
<type> ::= <sem-settyped> N #double
<type> ::= <sem-settypee> O #long double (64-bit precision)
<type> ::= T <sem-beginbsub> <type-t>
<type> ::= U <sem-beginbsub> <type-u>
<type> ::= V <sem-beginbsub> <sem-setclass> <name-cover> <sem-unq2p> #class
<type> ::= W <sem-beginbsub> <type-w>
<type-t> ::= <sem-setunion> <name-cover> <sem-unq2p> #union
<type-u> ::= <sem-setstruct> <name-cover> <sem-unq2p> #struct
<type-w> ::= 4 <sem-setenum> <name-cover> <sem-unq2p> #enum
<type> ::= P <e> <sem-beginbsub> <type-pe> <type>
<type> ::= Q <e> <sem-beginbsub> <type-qe> <type>
<type> ::= R <e> <sem-beginbsub> <type-re> <type>
<type> ::= S <e> <sem-beginbsub> <type-se> <type>
<type> ::= A <e> <sem-beginbsub> <type-ae> <type>
<type-pe> ::= <sem-setptr> A #X *
<type-pe> ::= <sem-setptr> <sem-setconst> B #const X *
<type-pe> ::= <sem-setptr> <sem-setvolatile> C #volatile X *
<type-pe> ::= <sem-setptr> <sem-setvolatile> <sem-setconst> D #const volatile X *
<type-qe> ::= <sem-setptr> A #X * const
<type-qe> ::= <sem-setptr> <sem-setconst> B #const X * const
<type-qe> ::= <sem-setptr> <sem-setvolatile> C #volatile X *
<type-qe> ::= <sem-setptr> <sem-setvolatile> <sem-setconst> D #const volatile X *
<type-re> ::= A #X * volatile
<type-se> ::= A #X * const volatile
<type-pe> ::= IA #X * __restrict
<type-ae> ::= <sem-setref> A #X &
<type-ae> ::= <sem-setref> <sem-setconst> B #const X &
<type-ae> ::= <sem-setref> <sem-setvolatile> C #volatile X &
<type-ae> ::= <sem-setref> <sem-setvolatile> <sem-setconst> D #const volatile X &
<type-pa> ::= #X[] (as global object)
<type_> ::= <sem-settypeb> N #bool
<type_> ::= <sem-settypex> J #long long (__int64)
<type_> ::= <sem-settypey> K #unsigned long long (unsigned __int64)
<type_> ::= <sem-settypew> W #wchar_t
<type_> ::= T #long double (80-bit precision Intel compiler)
<type_> ::= Z #long double (80-bit precision Symantec/Digital Mars compiler)
<e> ::= E
<e> ::=
<sem-addchartoname> ::=
<sem-storename> ::=
<sem-loadid> ::=
<sem-loadarr> ::=
<sem-ssno> ::=
<sem-ssnest> ::=
<sem-stunq> ::=
<sem-loadtsub> ::=
<sem-type2expr> ::=
<sem-exprval> ::=
<sem-beginexpr> ::=
<sem-storeexpr> ::=
<sem-copyexpr> ::=
<sem-storepar> ::=
<sem-begintempl> ::=
<sem-skiptempl> ::=
<sem-storetemparg> ::=
<sem-storetemplate> ::=
<sem-setnametf> ::=
<sem-par2f> ::=
<sem-unq2f> ::=
<sem-unq2p> ::=
<sem-setnamex> ::=
<sem-setnameo> ::=
<sem-par2spec> ::=
<sem-par2ret> ::=
<sem-settypev> ::=
<sem-settypew> ::=
<sem-settypeb> ::=
<sem-settypec> ::=
<sem-settypea> ::=
<sem-settypeh> ::=
<sem-settypes> ::=
<sem-settypet> ::=
<sem-settypei> ::=
<sem-settypej> ::=
<sem-settypel> ::=
<sem-settypem> ::=
<sem-settypex> ::=
<sem-settypey> ::=
<sem-settypen> ::=
<sem-settypeo> ::=
<sem-settypef> ::=
<sem-settyped> ::=
<sem-settypee> ::=
<sem-settypeg> ::=
<sem-settypez> ::=
<sem-setrestrict> ::=
<sem-setvolatile> ::=
<sem-setconst> ::=
<sem-setptr> ::=
<sem-setref> ::=
<sem-setrval> ::=
<sem-setcpair> ::=
<sem-setim> ::=
<sem-substd> ::=
<sem-subalc> ::=
<sem-substr> ::=
<sem-substrs> ::=
<sem-subistr> ::=
<sem-subostr> ::=
<sem-subiostr> ::=
<sem-loadsub> ::=
<sem-setnamec> ::=
<sem-setnamed> ::=
<sem-setopnw> ::=
<sem-setopna> ::=
<sem-setopdl> ::=
<sem-setopda> ::=
<sem-setopps> ::=
<sem-setopng> ::=
<sem-setopad> ::=
<sem-setopde> ::=
<sem-setopco> ::=
<sem-setoppl> ::=
<sem-setopmi> ::=
<sem-setopml> ::=
<sem-setopdv> ::=
<sem-setoprm> ::=
<sem-setopan> ::=
<sem-setopor> ::=
<sem-setopeo> ::=
<sem-setopass> ::=
<sem-setoppll> ::=
<sem-setopmii> ::=
<sem-setopmll> ::=
<sem-setopdvv> ::=
<sem-setoprmm> ::=
<sem-setopann> ::=
<sem-setoporr> ::=
<sem-setopeoo> ::=
<sem-setopls> ::=
<sem-setoprs> ::=
<sem-setoplss> ::=
<sem-setoprss> ::=
<sem-setopeq> ::=
<sem-setopne> ::=
<sem-setoplt> ::=
<sem-setopgt> ::=
<sem-setople> ::=
<sem-setopnt> ::=
<sem-setopaa> ::=
<sem-setopoo> ::=
<sem-setoppp> ::=
<sem-setopmm> ::=
<sem-setopcm> ::=
<sem-setoppm> ::=
<sem-setoppt> ::=
<sem-setopcl> ::=
<sem-setopix> ::=
<sem-setopge> ::=
<sem-setopqu> ::=
<sem-setopst> ::=
<sem-setopsz> ::=
<sem-setopat> ::=
<sem-setopaz> ::=
<sem-setopcv> ::=
<sem-setopxx> ::=
<sem-setnamef> ::=
<sem-setnamevt> ::=
<sem-reversename> ::=
<sem-setprivate> ::=
<sem-setpublic> ::=
<sem-setprotected> ::=
<sem-setfcdecl> ::=
<sem-setfpascal> ::=
<sem-setffortran> ::=
<sem-setfthiscall> ::=
<sem-setfstdcall> ::=
<sem-setffastcall> ::=
<sem-setfinterrupt> ::=
<sem-setunion> ::=
<sem-setstruct> ::=
<sem-setclass> ::=
<sem-setenum> ::=
<sem-setstatic> ::=
<sem-setvirtual> ::=
<sem-stclconst> ::=
<sem-stclvol> ::=
<sem-stclfar> ::=
<sem-stclhuge> ::=
<sem-savenamesub> ::=
<sem-loadnamesub> ::=
<sem-mstemplsub> ::=
<sem-setnamer0> ::=
<sem-setnamer1> ::=
<sem-setnamer2> ::=
<sem-setnamer3> ::=
<sem-setnamer4> ::=
<sem-setname_a> ::=
<sem-setname_b> ::=
<sem-setname_c> ::=
<sem-setname_d> ::=
<sem-setname_e> ::=
<sem-setname_f> ::=
<sem-setname_g> ::=
<sem-setname_h> ::=
<sem-setname_i> ::=
<sem-setname_j> ::=
<sem-setname_k> ::=
<sem-setname_l> ::=
<sem-setname_m> ::=
<sem-setname_n> ::=
<sem-setname_o> ::=
<sem-setname_p> ::=
<sem-setname_q> ::=
<sem-setname_r> ::=
<sem-setname_s> ::=
<sem-setname_t> ::=
<sem-setname_u> ::=
<sem-setname_v> ::=
<sem-setname_w> ::=
<sem-setname_x> ::=
<sem-setname_y> ::=
<sem-setname_z> ::=
<sem-templ2tftpl> ::=
<sem-beginbsub> ::= #begin built-in substitution
<sem-loadbsub> ::=
<sem-addmconst> ::=
<sem-addmvol> ::=
<sem-addmfar> ::=
<sem-addmhuge> ::=
<sem-loadmsnum> ::=
<sem-numtorttibcd> ::=
<sem-numtotype> ::=
<sem-normalizeparname> ::=
<sem-borlandid> ::=
<sem-loadborlandsub> ::=
<sem-borlandarr> ::=
<sem-end> ::=

1051
3rdparty/demangler/src/getopt.c vendored Normal file

File diff suppressed because it is too large Load Diff

179
3rdparty/demangler/src/getopt1.c vendored Normal file
View File

@@ -0,0 +1,179 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987-2023 Free Software Foundation, Inc.
NOTE: This source is derived from an old version taken from the GNU C
Library (glibc).
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
#include "getopt.h"
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (int argc, char *const *argv, const char *options,
const struct option *long_options, int *opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (int argc, char *const *argv, const char *options,
const struct option *long_options, int *opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int
main (int argc, char **argv)
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

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