mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
318 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22413b8e7f | ||
|
|
1b50057764 | ||
|
|
9e15058634 | ||
|
|
2a81a7af9e | ||
|
|
6d3d5ebdc5 | ||
|
|
7d63a9e51c | ||
|
|
56a2b3b5ad | ||
|
|
f46f788d80 | ||
|
|
a044b7cf6e | ||
|
|
8afd29e1a2 | ||
|
|
d89b051e6d | ||
|
|
47cf69d2b3 | ||
|
|
35c3c912e7 | ||
|
|
67c5f0229b | ||
|
|
5dcc79555d | ||
|
|
82f741e1dc | ||
|
|
ab21d22514 | ||
|
|
0a599e7337 | ||
|
|
f77bf1ec6b | ||
|
|
ed4fbb4f5a | ||
|
|
f963291970 | ||
|
|
2c3abe33d5 | ||
|
|
0fd7e1d7c2 | ||
|
|
1e23e7efc4 | ||
|
|
46d5d24fcd | ||
|
|
3276c0db9c | ||
|
|
1bdd53a6c5 | ||
|
|
1f2d9ab4e5 | ||
|
|
0806ca442a | ||
|
|
e3a666bfe4 | ||
|
|
6b2dc7a68c | ||
|
|
18c492d9da | ||
|
|
6065caaf19 | ||
|
|
bb4c456f35 | ||
|
|
078a10dcdb | ||
|
|
a8a0c5c0bf | ||
|
|
1a95bd3088 | ||
|
|
cf157fd2d7 | ||
|
|
35ada362d4 | ||
|
|
444b110411 | ||
|
|
1b82fac70e | ||
|
|
dafca1e264 | ||
|
|
69de95df8b | ||
|
|
ca9f64a08b | ||
|
|
3b3e35beb7 | ||
|
|
c087fc430b | ||
|
|
d1a4733939 | ||
|
|
5845109b75 | ||
|
|
7dd2ebdf49 | ||
|
|
3e78322ea4 | ||
|
|
8d6633fcf9 | ||
|
|
1c1f67c091 | ||
|
|
324b1464e4 | ||
|
|
1e9a248a0c | ||
|
|
4319094b02 | ||
|
|
60abebb3a5 | ||
|
|
62f20a4809 | ||
|
|
924326460c | ||
|
|
bba85dc08f | ||
|
|
68678ac4ec | ||
|
|
7f9f383324 | ||
|
|
1239c94fba | ||
|
|
2ab24bbf28 | ||
|
|
a304959933 | ||
|
|
5f0bc729d7 | ||
|
|
e2421bf3c6 | ||
|
|
9b4b21887f | ||
|
|
cc9eaef477 | ||
|
|
c1eecb3512 | ||
|
|
58a26dbca4 | ||
|
|
d06700276f | ||
|
|
ab5b622d70 | ||
|
|
60e21e2530 | ||
|
|
a694c1bd26 | ||
|
|
84d16802a3 | ||
|
|
02fda478ea | ||
|
|
31dcda05b7 | ||
|
|
5479ab1b8a | ||
|
|
cc9c0f9b12 | ||
|
|
aa5a94df5a | ||
|
|
d9b7f413ff | ||
|
|
6c3cf12df6 | ||
|
|
13e0546f56 | ||
|
|
c01dc20284 | ||
|
|
3faf22256e | ||
|
|
ac4d827a9c | ||
|
|
95201409e3 | ||
|
|
89cd474278 | ||
|
|
fc715d58f0 | ||
|
|
217e1c8fae | ||
|
|
5486eed151 | ||
|
|
d1721360ff | ||
|
|
0a0f99dd1b | ||
|
|
eb5ea6f64e | ||
|
|
1d449e9675 | ||
|
|
c82671fce4 | ||
|
|
4c267c4206 | ||
|
|
158e67cf6d | ||
|
|
1afff1a064 | ||
|
|
904874d959 | ||
|
|
d33168d31f | ||
|
|
2b7c4ae438 | ||
|
|
6483565d47 | ||
|
|
11704f7f0c | ||
|
|
8d3f4fac23 | ||
|
|
93b18412f5 | ||
|
|
d9c5f22d1e | ||
|
|
d12ef2b17c | ||
|
|
e8e0b97f6d | ||
|
|
f50083e47a | ||
|
|
461ee350c2 | ||
|
|
0cf4b76876 | ||
|
|
4e1979427d | ||
|
|
110426ac9f | ||
|
|
4565a62634 | ||
|
|
f75da73fca | ||
|
|
5c83edb7b2 | ||
|
|
bb1162f6cc | ||
|
|
a4d2332f9c | ||
|
|
4963ea9b11 | ||
|
|
11caae46c1 | ||
|
|
bfaad9f9bf | ||
|
|
0792ceb21a | ||
|
|
2886f825aa | ||
|
|
22c9b70ca3 | ||
|
|
6dbbebeafb | ||
|
|
f54eeca1fd | ||
|
|
7d6f74083b | ||
|
|
28e4b10fda | ||
|
|
b8405ef7a6 | ||
|
|
d178bb3904 | ||
|
|
1ea512655a | ||
|
|
90463a4a6c | ||
|
|
f340b5ebd0 | ||
|
|
ab2d18ebf0 | ||
|
|
8d3bb1ad80 | ||
|
|
ed3405b5a9 | ||
|
|
904d6b9c78 | ||
|
|
edcd1d0f9f | ||
|
|
a8ce6a9f0e | ||
|
|
42e4a47bfc | ||
|
|
e423fd10c6 | ||
|
|
f73a9e89f6 | ||
|
|
48de49b85d | ||
|
|
da1ee3a3b9 | ||
|
|
79dbc272b8 | ||
|
|
c83cca1d87 | ||
|
|
44b50bee26 | ||
|
|
87b03fdc28 | ||
|
|
b43e05a8fc | ||
|
|
67d7744f7f | ||
|
|
27fb7dc26e | ||
|
|
04168a0359 | ||
|
|
1131db784f | ||
|
|
517fba3686 | ||
|
|
64e17fce3f | ||
|
|
518728ca36 | ||
|
|
d1a7430f80 | ||
|
|
973c522756 | ||
|
|
5536342f9d | ||
|
|
d9ddab1a33 | ||
|
|
c915aac1fa | ||
|
|
a3c2a4db5f | ||
|
|
aebebf5115 | ||
|
|
9a50218400 | ||
|
|
fd5a652270 | ||
|
|
c647a30aa9 | ||
|
|
40d5c78573 | ||
|
|
fe2a9fc2cd | ||
|
|
83f9add68b | ||
|
|
ffe8d16df4 | ||
|
|
31b5672870 | ||
|
|
777fc444ae | ||
|
|
cd5c961dc4 | ||
|
|
c2ea8c4eab | ||
|
|
d6507a945b | ||
|
|
f1abee5d0b | ||
|
|
e4dccc237c | ||
|
|
92d8c740d4 | ||
|
|
b6eddade00 | ||
|
|
04fdd09d1e | ||
|
|
69574aecc6 | ||
|
|
c72d98d4cd | ||
|
|
4f405adea9 | ||
|
|
5217ec375d | ||
|
|
10b264b9ec | ||
|
|
dc741e95bd | ||
|
|
a1ca0a9a02 | ||
|
|
c076c50b68 | ||
|
|
c688db8f08 | ||
|
|
469053de9b | ||
|
|
185b85f86a | ||
|
|
11096a520e | ||
|
|
07fd035aa2 | ||
|
|
6bedcd768f | ||
|
|
0c949db506 | ||
|
|
4c5253c0f5 | ||
|
|
325133e54c | ||
|
|
4113ac574d | ||
|
|
2d6c687913 | ||
|
|
f9fbecc783 | ||
|
|
c5ceba35b6 | ||
|
|
c7a53703b1 | ||
|
|
2151ffcb6a | ||
|
|
e25cb92041 | ||
|
|
c3ed4faec1 | ||
|
|
01de02677f | ||
|
|
6c44e985b1 | ||
|
|
31026e420d | ||
|
|
f2523bdf9f | ||
|
|
5c4d814b63 | ||
|
|
752f479483 | ||
|
|
3a53144bdb | ||
|
|
b0940094f0 | ||
|
|
92904994ef | ||
|
|
112d02eaf5 | ||
|
|
deb8e5bf18 | ||
|
|
fe3eab5815 | ||
|
|
72034da6ac | ||
|
|
2106c353d9 | ||
|
|
27b681bb4c | ||
|
|
ad3e66f903 | ||
|
|
3f7190e884 | ||
|
|
e2fd09df88 | ||
|
|
ebc3923b35 | ||
|
|
30e7de7555 | ||
|
|
15dfc0496e | ||
|
|
3a55653c3e | ||
|
|
1df2fdff3e | ||
|
|
dd16ff5021 | ||
|
|
2633bc4d59 | ||
|
|
e7a8c2b037 | ||
|
|
e292c0986f | ||
|
|
2320330b6a | ||
|
|
8cd12852ce | ||
|
|
51019dc456 | ||
|
|
5a35afadd7 | ||
|
|
63e516ebfe | ||
|
|
7086060724 | ||
|
|
93e4bd8215 | ||
|
|
85fc04598b | ||
|
|
36d4f2602f | ||
|
|
129be9dfe4 | ||
|
|
ed9b82097d | ||
|
|
2fea312187 | ||
|
|
c6b8df0588 | ||
|
|
40cd0d898f | ||
|
|
d6e57f3867 | ||
|
|
c3a5b13301 | ||
|
|
1c7b1d7ff9 | ||
|
|
a1ac86934e | ||
|
|
b0026ff59f | ||
|
|
a5a8a1a06b | ||
|
|
132431b7c8 | ||
|
|
e045d4a0ff | ||
|
|
a41be51385 | ||
|
|
acb0829d81 | ||
|
|
02e0d2acde | ||
|
|
6b6993cc24 | ||
|
|
3af50632d1 | ||
|
|
cd7cb18274 | ||
|
|
7a99ed3c8e | ||
|
|
7d0eaf9a05 | ||
|
|
0b59b930a3 | ||
|
|
5dc015c0a3 | ||
|
|
edd39dfe08 | ||
|
|
f5320e201e | ||
|
|
37569d1526 | ||
|
|
1efeab4078 | ||
|
|
2bff3579e5 | ||
|
|
2fa85c56c2 | ||
|
|
ded55635c1 | ||
|
|
c9b8874eb6 | ||
|
|
9172a1a6f8 | ||
|
|
b2ac7afbcb | ||
|
|
dcfd663c19 | ||
|
|
225f057a5c | ||
|
|
0017e33023 | ||
|
|
76ced16f9e | ||
|
|
245937eb85 | ||
|
|
3a72328d55 | ||
|
|
06bc0300c0 | ||
|
|
98dcf40967 | ||
|
|
6b61ffbb63 | ||
|
|
dd7eef723a | ||
|
|
328275cd45 | ||
|
|
a4f1431bcc | ||
|
|
473df8dad4 | ||
|
|
042959958e | ||
|
|
cd4de28b9e | ||
|
|
24a87c3fee | ||
|
|
17567b960f | ||
|
|
7a3d22ecdf | ||
|
|
7e5016fdab | ||
|
|
47606400fa | ||
|
|
d6076a6107 | ||
|
|
95c57462cc | ||
|
|
48a1ec3531 | ||
|
|
9da3bccca2 | ||
|
|
a1a92920b2 | ||
|
|
b6b775e44e | ||
|
|
5ea46ac076 | ||
|
|
ab008bf5d0 | ||
|
|
54782cbf70 | ||
|
|
3c7cff99f4 | ||
|
|
f326e8775f | ||
|
|
a2a711b1b3 | ||
|
|
dfb857b68f | ||
|
|
ad64d88e7b | ||
|
|
cbd207d3f4 | ||
|
|
4bf8b23204 | ||
|
|
951780b43d | ||
|
|
84fe413635 | ||
|
|
17aaa31362 | ||
|
|
f943bdad98 | ||
|
|
09b2b6f949 | ||
|
|
c46902c0f5 | ||
|
|
c0dce9f64b |
2
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
@@ -18,6 +18,8 @@ body:
|
||||
|
||||
Please make an effort to make sure your issue isn't already reported.
|
||||
|
||||
Please make sure your game is verified using the built-in game verifier.
|
||||
|
||||
Do not create issues involving software piracy of BIOS or ISO files, our rules specifically prohibit this and your issue will be closed.
|
||||
|
||||
### Please Avoid Issues Pertaining to the Following:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@@ -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:
|
||||
|
||||
8
.github/workflows/cron_publish_flatpak.yml
vendored
8
.github/workflows/cron_publish_flatpak.yml
vendored
@@ -23,12 +23,18 @@ jobs:
|
||||
FLATHUB_RELEASE=$(curl -L -s https://flathub.org/api/v2/appstream/net.pcsx2.PCSX2 | jq -r '.releases | max_by(.version) | .version')
|
||||
echo "Latest PCSX2 release is: '${PCSX2_RELEASE}'"
|
||||
echo "Latest Flathub release is: '${FLATHUB_RELEASE}'"
|
||||
PCSX2_RELEASE=$(echo $PCSX2_RELEASE | sed 's/[^0-9]*//g')
|
||||
FLATHUB_RELEASE=$(echo $FLATHUB_RELEASE | sed 's/[^0-9]*//g')
|
||||
echo "PCSX2_RELEASE=${PCSX2_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||
echo "FLATHUB_RELEASE=${FLATHUB_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build:
|
||||
needs: check
|
||||
if: needs.check.outputs.FLATHUB_RELEASE < needs.check.outputs.PCSX2_RELEASE
|
||||
# outputs are automatically compared as strings. This doesn't work in our favour
|
||||
# Use fromJson() to convert them to proper integers...
|
||||
# see: https://github.com/github/docs/pull/25870
|
||||
# and: https://github.com/orgs/community/discussions/57480
|
||||
#if: fromJson(needs.check.outputs.FLATHUB_RELEASE) < fromJson(needs.check.outputs.PCSX2_RELEASE)
|
||||
name: "Build and publish Flatpak"
|
||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||
with:
|
||||
|
||||
@@ -17,7 +17,7 @@ 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"
|
||||
|
||||
@@ -19,11 +19,12 @@ 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."
|
||||
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||
body: "Weekly automatic update of SDL Controller DB"
|
||||
reviewers: lightningterror
|
||||
body: "Weekly automatic update of SDL Controller DB."
|
||||
branch: update-controller-db
|
||||
delete-branch: true
|
||||
|
||||
6
.github/workflows/linux_build_flatpak.yml
vendored
6
.github/workflows/linux_build_flatpak.yml
vendored
@@ -94,12 +94,6 @@ jobs:
|
||||
cd bin/resources
|
||||
wget "${{ inputs.patchesUrl }}/patches.zip"
|
||||
|
||||
- name: Generate AppStream XML
|
||||
run: |
|
||||
./.github/workflows/scripts/linux/generate-metainfo.sh .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
|
||||
cat .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
|
||||
# flatpak-builder-lint appstream .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
|
||||
|
||||
- name: Validate manifest
|
||||
run: |
|
||||
flatpak-builder-lint manifest .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
|
||||
|
||||
10
.github/workflows/linux_build_qt.yml
vendored
10
.github/workflows/linux_build_qt.yml
vendored
@@ -58,16 +58,10 @@ jobs:
|
||||
CCACHE_MAXSIZE: 100M
|
||||
|
||||
steps:
|
||||
# Work around https://github.com/actions/runner-images/issues/8659
|
||||
- name: Remove GCC 13 from runner image
|
||||
shell: bash
|
||||
run: |
|
||||
sudo rm -f /etc/apt/sources.list.d/ubuntu-toolchain-r-ubuntu-test-jammy.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --allow-downgrades 'libc6=2.35-0ubuntu*' 'libc6-dev=2.35-0ubuntu*' libstdc++6=12.3.0-1ubuntu1~22.04 libgcc-s1=12.3.0-1ubuntu1~22.04
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# actions/checkout elides tags, fetch them primarily for releases
|
||||
- name: Fetch Tags
|
||||
|
||||
@@ -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
|
||||
|
||||
PATH=/usr/lib/qt6/bin:$PATH "$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_base_translation.sh"
|
||||
PATH=/usr/bin/python3:$PATH "$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_glyph_ranges.py"
|
||||
PATH=/usr/bin/python3:$PATH "$SCRIPTDIR/../../../../tools/generate_fullscreen_ui_translation_strings.py"
|
||||
PATH=/usr/bin/python3:$PATH "$SCRIPTDIR/../../../../tools/generate_update_fa_glyph_ranges.py"
|
||||
|
||||
25
.github/workflows/scripts/linux/appimage-qt.sh
vendored
25
.github/workflows/scripts/linux/appimage-qt.sh
vendored
@@ -63,9 +63,9 @@ declare -a REMOVE_LIBS=(
|
||||
|
||||
set -e
|
||||
|
||||
LINUXDEPLOY=./linuxdeploy-x86_64.AppImage
|
||||
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
APPIMAGETOOL=./appimagetool-x86_64.AppImage
|
||||
LINUXDEPLOY=./linuxdeploy-x86_64
|
||||
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64
|
||||
APPIMAGETOOL=./appimagetool-x86_64
|
||||
PATCHELF=patchelf
|
||||
|
||||
if [ ! -f "$LINUXDEPLOY" ]; then
|
||||
@@ -78,8 +78,11 @@ if [ ! -f "$LINUXDEPLOY_PLUGIN_QT" ]; then
|
||||
chmod +x "$LINUXDEPLOY_PLUGIN_QT"
|
||||
fi
|
||||
|
||||
# Using go-appimage
|
||||
# Backported from https://github.com/stenzek/duckstation/pull/3251
|
||||
if [ ! -f "$APPIMAGETOOL" ]; then
|
||||
"$PCSX2DIR/tools/retry.sh" wget -O "$APPIMAGETOOL" https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
APPIMAGETOOLURL=$(wget -q https://api.github.com/repos/probonopd/go-appimage/releases -O - | sed 's/[()",{} ]/\n/g' | grep -o 'https.*continuous.*tool.*86_64.*mage$' | head -1)
|
||||
"$PCSX2DIR/tools/retry.sh" wget -O "$APPIMAGETOOL" "$APPIMAGETOOLURL"
|
||||
chmod +x "$APPIMAGETOOL"
|
||||
fi
|
||||
|
||||
@@ -199,6 +202,16 @@ for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
|
||||
done
|
||||
|
||||
echo "Generating AppImage..."
|
||||
rm -f "$NAME.AppImage"
|
||||
$APPIMAGETOOL -v "$OUTDIR" "$NAME.AppImage"
|
||||
GIT_VERSION=$(git tag --points-at HEAD)
|
||||
|
||||
if [[ "${GIT_VERSION}" == "" ]]; then
|
||||
# In the odd event that we run this script before the release gets tagged.
|
||||
GIT_VERSION=$(git describe --tags)
|
||||
if [[ "${GIT_VERSION}" == "" ]]; then
|
||||
GIT_VERSION=$(git rev-parse HEAD)
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f "$NAME.AppImage"
|
||||
ARCH=x86_64 VERSION="${GIT_VERSION}" "$APPIMAGETOOL" -s "$OUTDIR" && mv ./*.AppImage "$NAME.AppImage"
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ LIBJPEG=9f
|
||||
LIBPNG=1.6.43
|
||||
LIBWEBP=1.4.0
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
SDL=SDL2-2.30.5
|
||||
QT=6.7.2
|
||||
SDL=SDL2-2.30.8
|
||||
QT=6.8.0
|
||||
ZSTD=1.5.6
|
||||
|
||||
SHADERC=2024.1
|
||||
@@ -37,21 +37,21 @@ fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.
|
||||
6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c libpng-$LIBPNG.tar.xz
|
||||
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
f374f3fa29c37dfcc20822d4a7d7dc57e58924d1a5f2ad511bfab4c8193de63b $SDL.tar.gz
|
||||
380c295ea76b9bd72d90075793971c8bcb232ba0a69a9b14da4ae8f603350058 $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 ../../
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://libsdl.org/release/SDL2-2.30.5.tar.gz",
|
||||
"sha256": "f374f3fa29c37dfcc20822d4a7d7dc57e58924d1a5f2ad511bfab4c8193de63b"
|
||||
"url": "https://libsdl.org/release/SDL2-2.30.8.tar.gz",
|
||||
"sha256": "380c295ea76b9bd72d90075793971c8bcb232ba0a69a9b14da4ae8f603350058"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"add-extensions": {
|
||||
"org.freedesktop.Platform.ffmpeg-full": {
|
||||
"directory": "lib/ffmpeg",
|
||||
"version": "22.08",
|
||||
"version": "23.08",
|
||||
"add-ld-path": ".",
|
||||
"autodownload": true
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
"-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld",
|
||||
"-DUSE_LINKED_FFMPEG=ON",
|
||||
"-DDISABLE_ADVANCE_SIMD=TRUE"
|
||||
]
|
||||
]
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
@@ -63,8 +63,10 @@
|
||||
"cp -a bin \"${FLATPAK_DEST}\"",
|
||||
"install -Dm644 \"${FLATPAK_BUILDER_BUILDDIR}/bin/resources/icons/AppIconLarge.png\" \"${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/net.pcsx2.PCSX2.png\"",
|
||||
"install -Dm644 \"${FLATPAK_BUILDER_BUILDDIR}/.github/workflows/scripts/linux/pcsx2-qt.desktop\" \"${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop\"",
|
||||
"desktop-file-edit --set-key=Icon --set-value=net.pcsx2.PCSX2 \"${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop\"",
|
||||
"install -Dm644 \"${FLATPAK_BUILDER_BUILDDIR}/.github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml\" \"${FLATPAK_DEST}/share/metainfo/net.pcsx2.PCSX2.metainfo.xml\"",
|
||||
"desktop-file-edit --set-key=Icon --set-value=net.pcsx2.PCSX2 \"${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop\"",
|
||||
"${FLATPAK_BUILDER_BUILDDIR}/.github/workflows/scripts/linux/generate-metainfo.sh \"${FLATPAK_BUILDER_BUILDDIR}/net.pcsx2.PCSX2.metainfo.xml\"",
|
||||
"cat \"${FLATPAK_BUILDER_BUILDDIR}/net.pcsx2.PCSX2.metainfo.xml\"",
|
||||
"install -Dm644 \"${FLATPAK_BUILDER_BUILDDIR}/net.pcsx2.PCSX2.metainfo.xml\" \"${FLATPAK_DEST}/share/metainfo/net.pcsx2.PCSX2.metainfo.xml\"",
|
||||
"mkdir -p \"${FLATPAK_DEST}/lib/ffmpeg\""
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,33 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uses the AppStream standard https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html -->
|
||||
<component type="desktop">
|
||||
<id>net.pcsx2.PCSX2</id>
|
||||
<launchable type="desktop-id">net.pcsx2.PCSX2.desktop</launchable>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0</project_license>
|
||||
<project_license>GPL-3.0+</project_license>
|
||||
<name>PCSX2</name>
|
||||
<developer_name>PCSX2</developer_name>
|
||||
<summary>PlayStation 2 Emulator</summary>
|
||||
<description>
|
||||
<p>PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.</p>
|
||||
<p>PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers, and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.</p>
|
||||
<p>PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.</p>
|
||||
</description>
|
||||
<url type="homepage">https://pcsx2.net/</url>
|
||||
<url type="bugtracker">https://github.com/PCSX2/pcsx2/issues</url>
|
||||
<url type="donation">https://github.com/sponsors/PCSX2</url>
|
||||
<url type="faq">https://pcsx2.net/docs/</url>
|
||||
<url type="help">https://discord.com/invite/TCz3t9k</url>
|
||||
<url type="help">https://pcsx2.net/discord</url>
|
||||
<url type="translate">https://crowdin.com/project/pcsx2-emulator</url>
|
||||
<url type="vcs-browser">https://github.com/PCSX2/pcsx2</url>
|
||||
<url type="contact">https://mastodon.social/@PCSX2</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot1.png</image>
|
||||
<image>
|
||||
https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot1.png
|
||||
</image>
|
||||
<caption>
|
||||
The main PCSX2 Qt interface
|
||||
</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot2.png</image>
|
||||
<image>
|
||||
https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot2.png
|
||||
</image>
|
||||
<caption>
|
||||
PCSX2 running a game
|
||||
</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<update_contact>stenzek_AT_gmail.com</update_contact>
|
||||
<update_contact>pcsx2_AT_pcsx2.net</update_contact>
|
||||
<releases>
|
||||
<release version="@GIT_VERSION@" date="@GIT_DATE@" />
|
||||
</releases>
|
||||
|
||||
@@ -40,15 +40,15 @@ fi
|
||||
|
||||
FREETYPE=2.13.2
|
||||
HARFBUZZ=8.3.1
|
||||
SDL=SDL2-2.30.3
|
||||
ZSTD=1.5.5
|
||||
SDL=SDL2-2.30.8
|
||||
ZSTD=1.5.6
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.43
|
||||
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
|
||||
@@ -76,19 +76,19 @@ 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
|
||||
380c295ea76b9bd72d90075793971c8bcb232ba0a69a9b14da4ae8f603350058 $SDL.tar.gz
|
||||
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c libpng-$LIBPNG.tar.xz
|
||||
2a499607df669e40258e53d0ade8035ba4ec0175244869d1025d460562aa09b4 libwebp-$LIBWEBP.tar.gz
|
||||
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
|
||||
|
||||
@@ -22,7 +22,7 @@ fi
|
||||
|
||||
FREETYPE=2.13.2
|
||||
HARFBUZZ=8.3.1
|
||||
SDL=SDL2-2.30.5
|
||||
SDL=SDL2-2.30.8
|
||||
ZSTD=1.5.6
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.43
|
||||
@@ -56,7 +56,7 @@ CMAKE_COMMON=(
|
||||
cat > SHASUMS <<EOF
|
||||
12991c4e55c506dd7f9b765933e62fd2be2e06d421505d7950a132e4f1bb484d freetype-$FREETYPE.tar.xz
|
||||
19a54fe9596f7a47c502549fce8e8a10978c697203774008cc173f8360b19a9a harfbuzz-$HARFBUZZ.tar.gz
|
||||
f374f3fa29c37dfcc20822d4a7d7dc57e58924d1a5f2ad511bfab4c8193de63b $SDL.tar.gz
|
||||
380c295ea76b9bd72d90075793971c8bcb232ba0a69a9b14da4ae8f603350058 $SDL.tar.gz
|
||||
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c libpng-$LIBPNG.tar.xz
|
||||
|
||||
@@ -47,13 +47,13 @@ set HARFBUZZ=8.3.1
|
||||
set LIBJPEG=9f
|
||||
set LIBPNG=1643
|
||||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.7.0
|
||||
set QTMINOR=6.7
|
||||
set SDL=SDL2-2.30.2
|
||||
set WEBP=1.3.2
|
||||
set QT=6.8.0
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.8
|
||||
set WEBP=1.4.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
set ZSTD=1.5.5
|
||||
set ZSTD=1.5.6
|
||||
|
||||
set SHADERC=2024.1
|
||||
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -64,16 +64,17 @@ call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip b2bc56184ae37324bc4829fde7d3f9e6916866ad711ee85792e457547c9fd127 || 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" 2a499607df669e40258e53d0ade8035ba4ec0175244869d1025d460562aa09b4 || 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" c5d78a9e0346c6695f03df8ba25e5e111a1e23c8aefa8372a1c5a0dd79acaf10 || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 3027fb990cb66436b5476b9dd17cd58f23b55a42eb1c1bcf9c7d78bca3ad7d63 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" f30065289517847d721467827ee446a5f606f6d1c750e166cbfb0ed5bf066c5e || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 882d1db58d35155bd92e4ed92b485d7d713b6aff0d7cf78655de0b414a980689 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 93a31892ca8a4f38464e923328788ce3da881d82016fe18fa1ed12dd43ce486c || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 102ca62fa682c0d3e700ba89069fd3b6663b9f0c2890b058e97998b6e8971fb3 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" abe2921dffcb25d39d270454810b211a9f47be3e5e802bc45e7d058f286a325e || 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" c5c8daa1d40dabc51790c62a5b86af2b36dfc4e1a738ff10dc4a46ea4e68ee51 || 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
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
|
||||
@@ -108,6 +109,7 @@ ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Building libjpeg...
|
||||
rmdir /S /Q "jpeg-%LIBJPEG%"
|
||||
%SEVENZIP% x "jpegsr%LIBJPEG%.zip" || goto error
|
||||
cd "jpeg-%LIBJPEG%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\libjpeg-cmake.patch" || goto error
|
||||
@@ -155,8 +157,9 @@ cd .. || goto error
|
||||
|
||||
echo Building Zstandard...
|
||||
rmdir /S /Q "zstd-%ZSTD%"
|
||||
%SEVENZIP% x "-x^!zstd-1.5.5\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||
cd "zstd-%ZSTD%"
|
||||
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
|
||||
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
|
||||
@@ -45,9 +45,9 @@ set HARFBUZZ=8.3.1
|
||||
set LIBJPEG=9f
|
||||
set LIBPNG=1643
|
||||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.7.2
|
||||
set QTMINOR=6.7
|
||||
set SDL=SDL2-2.30.5
|
||||
set QT=6.8.0
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.8
|
||||
set WEBP=1.4.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
@@ -64,12 +64,12 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
|
||||
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" 688d3da2bf7e887d0ba8e0f81c926119f85029544f4f6da8dea96db70f9d28e3 || 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" abe2921dffcb25d39d270454810b211a9f47be3e5e802bc45e7d058f286a325e || 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
|
||||
@@ -154,7 +154,7 @@ cd .. || goto error
|
||||
|
||||
echo Building Zstandard...
|
||||
rmdir /S /Q "zstd-%ZSTD%"
|
||||
%SEVENZIP% x "-x^!zstd-1.5.6\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||
cd "zstd-%ZSTD%"
|
||||
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -63,6 +63,7 @@ oprofile_data/
|
||||
*.kdev4
|
||||
/.kdev4*
|
||||
|
||||
# Resources and docs in /bin are tracked
|
||||
/bin/**/*.dll
|
||||
/bin/**/*.dmp
|
||||
/bin/**/*.exp
|
||||
@@ -93,6 +94,9 @@ oprofile_data/
|
||||
/bin/portable.ini
|
||||
/bin/portable.txt
|
||||
|
||||
# Resources and docs copied from /bin
|
||||
/bin-arm64
|
||||
|
||||
# Manually added by user.
|
||||
/bin/resources/patches.zip
|
||||
|
||||
@@ -115,3 +119,4 @@ oprofile_data/
|
||||
CMakeSettings.json
|
||||
/ci-artifacts/
|
||||
/out/
|
||||
/.cache/
|
||||
|
||||
41
3rdparty/ccc/CMakeLists.txt
vendored
Normal file
41
3rdparty/ccc/CMakeLists.txt
vendored
Normal 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
37
3rdparty/ccc/README.md
vendored
Normal 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
75
3rdparty/ccc/ccc.vcxproj
vendored
Normal 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
111
3rdparty/ccc/ccc.vcxproj.filters
vendored
Normal 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
562
3rdparty/ccc/src/ccc/ast.cpp
vendored
Normal 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
377
3rdparty/ccc/src/ccc/ast.h
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
125
3rdparty/ccc/src/ccc/elf.cpp
vendored
Normal file
125
3rdparty/ccc/src/ccc/elf.cpp
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
// 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 §ion;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
Result<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 CCC_FAILURE("No ELF segment for address range 0x%x to 0x%x.", address, end_address);
|
||||
}
|
||||
|
||||
Result<void> ElfFile::copy_virtual(u8* dest, u32 address, u32 size) const
|
||||
{
|
||||
Result<std::span<const u8>> block = get_virtual(address, size);
|
||||
CCC_RETURN_IF_ERROR(block);
|
||||
|
||||
memcpy(dest, block->data(), size);
|
||||
|
||||
return Result<void>();
|
||||
}
|
||||
|
||||
}
|
||||
156
3rdparty/ccc/src/ccc/elf.h
vendored
Normal file
156
3rdparty/ccc/src/ccc/elf.h
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// 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.
|
||||
Result<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.
|
||||
Result<void> 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>
|
||||
Result<T> get_object_virtual(u32 address) const
|
||||
{
|
||||
Result<std::span<const u8>> result = get_virtual(address, sizeof(T));
|
||||
CCC_RETURN_IF_ERROR(result);
|
||||
|
||||
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>
|
||||
Result<std::span<const T>> get_array_virtual(u32 address, u32 element_count) const
|
||||
{
|
||||
Result<std::span<const u8>> result = get_virtual(address, element_count * sizeof(T));
|
||||
CCC_RETURN_IF_ERROR(result);
|
||||
|
||||
return std::span<const T>((T*) result->data(), (T*) (result->data() + result->size()));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
213
3rdparty/ccc/src/ccc/elf_symtab.cpp
vendored
Normal file
213
3rdparty/ccc/src/ccc/elf_symtab.cpp
vendored
Normal 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
20
3rdparty/ccc/src/ccc/elf_symtab.h
vendored
Normal 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
95
3rdparty/ccc/src/ccc/importer_flags.cpp
vendored
Normal 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
39
3rdparty/ccc/src/ccc/importer_flags.h
vendored
Normal 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
349
3rdparty/ccc/src/ccc/mdebug_analysis.cpp
vendored
Normal 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
99
3rdparty/ccc/src/ccc/mdebug_analysis.h
vendored
Normal 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
668
3rdparty/ccc/src/ccc/mdebug_importer.cpp
vendored
Normal 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
31
3rdparty/ccc/src/ccc/mdebug_importer.h
vendored
Normal 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
474
3rdparty/ccc/src/ccc/mdebug_section.cpp
vendored
Normal 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
176
3rdparty/ccc/src/ccc/mdebug_section.h
vendored
Normal 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
220
3rdparty/ccc/src/ccc/mdebug_symbols.cpp
vendored
Normal 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
32
3rdparty/ccc/src/ccc/mdebug_symbols.h
vendored
Normal 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
191
3rdparty/ccc/src/ccc/sndll.cpp
vendored
Normal 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
55
3rdparty/ccc/src/ccc/sndll.h
vendored
Normal 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
835
3rdparty/ccc/src/ccc/stabs.cpp
vendored
Normal 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
379
3rdparty/ccc/src/ccc/stabs.h
vendored
Normal 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
834
3rdparty/ccc/src/ccc/stabs_to_ast.cpp
vendored
Normal 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
29
3rdparty/ccc/src/ccc/stabs_to_ast.h
vendored
Normal 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
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
721
3rdparty/ccc/src/ccc/symbol_database.h
vendored
Normal 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;
|
||||
|
||||
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
114
3rdparty/ccc/src/ccc/symbol_file.cpp
vendored
Normal 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
62
3rdparty/ccc/src/ccc/symbol_file.h
vendored
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
283
3rdparty/ccc/src/ccc/symbol_table.cpp
vendored
Normal file
283
3rdparty/ccc/src/ccc/symbol_table.cpp
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
// 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,
|
||||
std::string module_name,
|
||||
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
|
||||
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), *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>();
|
||||
}
|
||||
|
||||
}
|
||||
163
3rdparty/ccc/src/ccc/symbol_table.h
vendored
Normal file
163
3rdparty/ccc/src/ccc/symbol_table.h
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
// 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,
|
||||
std::string module_name,
|
||||
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
|
||||
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
173
3rdparty/ccc/src/ccc/util.cpp
vendored
Normal 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
312
3rdparty/ccc/src/ccc/util.h
vendored
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
15
3rdparty/cpuinfo/cpuinfo.vcxproj
vendored
15
3rdparty/cpuinfo/cpuinfo.vcxproj
vendored
@@ -30,13 +30,16 @@
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\cache.c">
|
||||
<ClCompile Include="src\arm\cache.c">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\uarch.c">
|
||||
<ClCompile Include="src\arm\uarch.c">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\init.c">
|
||||
<ClCompile Include="src\arm\windows\init-by-logical-sys-info.c">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\arm\windows\init.c">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="deps\clog\src\clog.c" />
|
||||
@@ -78,13 +81,13 @@
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\api.h">
|
||||
<ClInclude Include="src\arm\api.h">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\midr.h">
|
||||
<ClInclude Include="src\arm\midr.h">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\api.h">
|
||||
<ClInclude Include="src\arm\windows\windows-arm-init.h">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="deps\clog\include\clog.h" />
|
||||
|
||||
15
3rdparty/cpuinfo/cpuinfo.vcxproj.filters
vendored
15
3rdparty/cpuinfo/cpuinfo.vcxproj.filters
vendored
@@ -63,13 +63,16 @@
|
||||
<ClCompile Include="deps\clog\src\clog.c">
|
||||
<Filter>clog</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\cache.c">
|
||||
<ClCompile Include="src\arm\cache.c">
|
||||
<Filter>arm</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\uarch.c">
|
||||
<ClCompile Include="src\arm\uarch.c">
|
||||
<Filter>arm</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\init.c">
|
||||
<ClCompile Include="src\arm\windows\init.c">
|
||||
<Filter>arm\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\arm\windows\init-by-logical-sys-info.c">
|
||||
<Filter>arm\windows</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@@ -99,13 +102,13 @@
|
||||
<ClInclude Include="deps\clog\include\clog.h">
|
||||
<Filter>clog</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\api.h">
|
||||
<ClInclude Include="src\arm\api.h">
|
||||
<Filter>arm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\midr.h">
|
||||
<ClInclude Include="src\arm\midr.h">
|
||||
<Filter>arm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\api.h">
|
||||
<ClInclude Include="src\arm\windows\windows-arm-init.h">
|
||||
<Filter>arm\windows</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
27
3rdparty/demangler/CMakeLists.txt
vendored
27
3rdparty/demangler/CMakeLists.txt
vendored
@@ -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})
|
||||
|
||||
340
3rdparty/demangler/DemanglerLicenseGPL.txt
vendored
Normal file
340
3rdparty/demangler/DemanglerLicenseGPL.txt
vendored
Normal 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.
|
||||
482
3rdparty/demangler/DemanglerLicenseLGPL.txt
vendored
Normal file
482
3rdparty/demangler/DemanglerLicenseLGPL.txt
vendored
Normal 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
33
3rdparty/demangler/README
vendored
Normal 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
40
3rdparty/demangler/copy_demangler_files.sh
vendored
Executable 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/"
|
||||
45
3rdparty/demangler/demangler.vcxproj
vendored
45
3rdparty/demangler/demangler.vcxproj
vendored
@@ -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" />
|
||||
|
||||
97
3rdparty/demangler/demangler.vcxproj.filters
vendored
97
3rdparty/demangler/demangler.vcxproj.filters
vendored
@@ -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
354
3rdparty/demangler/include/ansidecl.h
vendored
Normal 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
201
3rdparty/demangler/include/cp-demangle.h
vendored
Normal 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
756
3rdparty/demangler/include/demangle.h
vendored
Normal 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 */
|
||||
45
3rdparty/demangler/include/demangler/demangler.h
vendored
45
3rdparty/demangler/include/demangler/demangler.h
vendored
@@ -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
|
||||
20
3rdparty/demangler/include/demangler/demglobal.h
vendored
20
3rdparty/demangler/include/demangler/demglobal.h
vendored
@@ -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
|
||||
36
3rdparty/demangler/include/demangler/demtools.h
vendored
36
3rdparty/demangler/include/demangler/demtools.h
vendored
@@ -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
|
||||
830
3rdparty/demangler/include/demangler/gparser.h
vendored
830
3rdparty/demangler/include/demangler/gparser.h
vendored
@@ -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
|
||||
23
3rdparty/demangler/include/demangler/igrams.h
vendored
23
3rdparty/demangler/include/demangler/igrams.h
vendored
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
72
3rdparty/demangler/include/dyn-string.h
vendored
Normal 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
35
3rdparty/demangler/include/environ.h
vendored
Normal 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
143
3rdparty/demangler/include/getopt.h
vendored
Normal 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
761
3rdparty/demangler/include/libiberty.h
vendored
Normal 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
150
3rdparty/demangler/include/safe-ctype.h
vendored
Normal 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 */
|
||||
17
3rdparty/demangler/src/CMakeLists.txt
vendored
17
3rdparty/demangler/src/CMakeLists.txt
vendored
@@ -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
483
3rdparty/demangler/src/alloca.c
vendored
Normal 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
568
3rdparty/demangler/src/argv.c
vendored
Normal 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
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
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
1982
3rdparty/demangler/src/d-demangle.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
131
3rdparty/demangler/src/demangler.cpp
vendored
131
3rdparty/demangler/src/demangler.cpp
vendored
@@ -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
|
||||
82
3rdparty/demangler/src/demtools.cpp
vendored
82
3rdparty/demangler/src/demtools.cpp
vendored
@@ -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
397
3rdparty/demangler/src/dyn-string.c
vendored
Normal 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);
|
||||
}
|
||||
467
3rdparty/demangler/src/extgrammars/gramatika-borland
vendored
467
3rdparty/demangler/src/extgrammars/gramatika-borland
vendored
@@ -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> ::=
|
||||
423
3rdparty/demangler/src/extgrammars/gramatika-gcc
vendored
423
3rdparty/demangler/src/extgrammars/gramatika-gcc
vendored
@@ -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> ::=
|
||||
534
3rdparty/demangler/src/extgrammars/gramatika-ms
vendored
534
3rdparty/demangler/src/extgrammars/gramatika-ms
vendored
@@ -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
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
179
3rdparty/demangler/src/getopt1.c
vendored
Normal 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 */
|
||||
6131
3rdparty/demangler/src/gparser.cpp
vendored
6131
3rdparty/demangler/src/gparser.cpp
vendored
File diff suppressed because it is too large
Load Diff
91
3rdparty/demangler/src/igrams.cpp
vendored
91
3rdparty/demangler/src/igrams.cpp
vendored
@@ -1,91 +0,0 @@
|
||||
/**
|
||||
* @file src/demangler/igrams.cpp
|
||||
* @brief Internal grammar list.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "demangler/demglobal.h"
|
||||
#include "demangler/igrams.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace demangler {
|
||||
|
||||
/**
|
||||
* @brief Classes containing internal grammar.
|
||||
*/
|
||||
cIgram_msll* igram_msll = nullptr; //Microsoft Visual C++
|
||||
cIgram_gccll* igram_gccll = nullptr; //GCC
|
||||
cIgram_borlandll* igram_borlandll = nullptr; //Borland
|
||||
|
||||
//[igram] add pointers to internal grammars here
|
||||
|
||||
/**
|
||||
* @brief Function which allocates an internal grammar class and sets the internal grammar structure.
|
||||
* @param gname Grammar name. The particular internal grammar is selected using this name.
|
||||
* @param gParser Pointer to a cGram to send pointers to newly allocated grammar to.
|
||||
* @return Was the initialisation successful?
|
||||
* @retval false Grammar with the specified name was not found.
|
||||
*/
|
||||
bool initIgram(string gname, cGram* gParser) {
|
||||
bool retvalue = false;
|
||||
|
||||
//Microsoft Visual C++ (msll)
|
||||
if (gname == "ms") {
|
||||
igram_msll = new cIgram_msll;
|
||||
gParser->internalGrammarStruct = igram_msll->getInternalGrammar();
|
||||
return true;
|
||||
}
|
||||
//GCC (gccll)
|
||||
else if (gname == "gcc") {
|
||||
igram_gccll = new cIgram_gccll;
|
||||
gParser->internalGrammarStruct = igram_gccll->getInternalGrammar();
|
||||
return true;
|
||||
}
|
||||
//Borland (borlandll)
|
||||
else if (gname == "borland") {
|
||||
igram_borlandll = new cIgram_borlandll;
|
||||
gParser->internalGrammarStruct = igram_borlandll->getInternalGrammar();
|
||||
return true;
|
||||
}
|
||||
|
||||
//[igram] add allocation of internal grammars here
|
||||
|
||||
return retvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function which deallocates all used internal grammar classes.
|
||||
* @param gParser Pointer to a cGram to clean internal grammars from.
|
||||
*/
|
||||
void deleteIgrams(cGram* gParser) {
|
||||
|
||||
//first, delete the dynamically allocated internal llst if there is any
|
||||
if (gParser->internalGrammarStruct.llst != nullptr) {
|
||||
free(gParser->internalGrammarStruct.llst);
|
||||
gParser->internalGrammarStruct.llst = nullptr;
|
||||
}
|
||||
|
||||
//dealocate all internal grammars here...
|
||||
if (igram_msll != nullptr) {
|
||||
delete igram_msll;
|
||||
igram_msll = nullptr;
|
||||
}
|
||||
|
||||
if (igram_gccll != nullptr) {
|
||||
delete igram_gccll;
|
||||
igram_gccll = nullptr;
|
||||
}
|
||||
|
||||
if (igram_borlandll != nullptr) {
|
||||
delete igram_borlandll;
|
||||
igram_borlandll = nullptr;
|
||||
}
|
||||
|
||||
//[igram] add deallocation of internal grammars here
|
||||
|
||||
}
|
||||
|
||||
} // namespace demangler
|
||||
1604
3rdparty/demangler/src/rust-demangle.c
vendored
Normal file
1604
3rdparty/demangler/src/rust-demangle.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
254
3rdparty/demangler/src/safe-ctype.c
vendored
Normal file
254
3rdparty/demangler/src/safe-ctype.c
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/* <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. */
|
||||
|
||||
/*
|
||||
|
||||
@defvr Extension HOST_CHARSET
|
||||
This macro indicates the basic character set and encoding used by the
|
||||
host: more precisely, the encoding used for character constants in
|
||||
preprocessor @samp{#if} statements (the C "execution character set").
|
||||
It is defined by @file{safe-ctype.h}, and will be an integer constant
|
||||
with one of the following values:
|
||||
|
||||
@ftable @code
|
||||
@item HOST_CHARSET_UNKNOWN
|
||||
The host character set is unknown - that is, not one of the next two
|
||||
possibilities.
|
||||
|
||||
@item HOST_CHARSET_ASCII
|
||||
The host character set is ASCII.
|
||||
|
||||
@item HOST_CHARSET_EBCDIC
|
||||
The host character set is some variant of EBCDIC. (Only one of the
|
||||
nineteen EBCDIC varying characters is tested; exercise caution.)
|
||||
@end ftable
|
||||
@end defvr
|
||||
|
||||
@deffn Extension ISALPHA (@var{c})
|
||||
@deffnx Extension ISALNUM (@var{c})
|
||||
@deffnx Extension ISBLANK (@var{c})
|
||||
@deffnx Extension ISCNTRL (@var{c})
|
||||
@deffnx Extension ISDIGIT (@var{c})
|
||||
@deffnx Extension ISGRAPH (@var{c})
|
||||
@deffnx Extension ISLOWER (@var{c})
|
||||
@deffnx Extension ISPRINT (@var{c})
|
||||
@deffnx Extension ISPUNCT (@var{c})
|
||||
@deffnx Extension ISSPACE (@var{c})
|
||||
@deffnx Extension ISUPPER (@var{c})
|
||||
@deffnx Extension ISXDIGIT (@var{c})
|
||||
|
||||
These twelve macros are defined by @file{safe-ctype.h}. Each has the
|
||||
same meaning as the corresponding macro (with name in lowercase)
|
||||
defined by the standard header @file{ctype.h}. For example,
|
||||
@code{ISALPHA} returns true for alphabetic characters and false for
|
||||
others. However, there are two differences between these macros and
|
||||
those provided by @file{ctype.h}:
|
||||
|
||||
@itemize @bullet
|
||||
@item These macros are guaranteed to have well-defined behavior for all
|
||||
values representable by @code{signed char} and @code{unsigned char}, and
|
||||
for @code{EOF}.
|
||||
|
||||
@item These macros ignore the current locale; they are true for these
|
||||
fixed sets of characters:
|
||||
@multitable {@code{XDIGIT}} {yada yada yada yada yada yada yada yada}
|
||||
@item @code{ALPHA} @tab @kbd{A-Za-z}
|
||||
@item @code{ALNUM} @tab @kbd{A-Za-z0-9}
|
||||
@item @code{BLANK} @tab @kbd{space tab}
|
||||
@item @code{CNTRL} @tab @code{!PRINT}
|
||||
@item @code{DIGIT} @tab @kbd{0-9}
|
||||
@item @code{GRAPH} @tab @code{ALNUM || PUNCT}
|
||||
@item @code{LOWER} @tab @kbd{a-z}
|
||||
@item @code{PRINT} @tab @code{GRAPH ||} @kbd{space}
|
||||
@item @code{PUNCT} @tab @kbd{`~!@@#$%^&*()_-=+[@{]@}\|;:'",<.>/?}
|
||||
@item @code{SPACE} @tab @kbd{space tab \n \r \f \v}
|
||||
@item @code{UPPER} @tab @kbd{A-Z}
|
||||
@item @code{XDIGIT} @tab @kbd{0-9A-Fa-f}
|
||||
@end multitable
|
||||
|
||||
Note that, if the host character set is ASCII or a superset thereof,
|
||||
all these macros will return false for all values of @code{char} outside
|
||||
the range of 7-bit ASCII. In particular, both ISPRINT and ISCNTRL return
|
||||
false for characters with numeric values from 128 to 255.
|
||||
@end itemize
|
||||
@end deffn
|
||||
|
||||
@deffn Extension ISIDNUM (@var{c})
|
||||
@deffnx Extension ISIDST (@var{c})
|
||||
@deffnx Extension IS_VSPACE (@var{c})
|
||||
@deffnx Extension IS_NVSPACE (@var{c})
|
||||
@deffnx Extension IS_SPACE_OR_NUL (@var{c})
|
||||
@deffnx Extension IS_ISOBASIC (@var{c})
|
||||
These six macros are defined by @file{safe-ctype.h} and provide
|
||||
additional character classes which are useful when doing lexical
|
||||
analysis of C or similar languages. They are true for the following
|
||||
sets of characters:
|
||||
|
||||
@multitable {@code{SPACE_OR_NUL}} {yada yada yada yada yada yada yada yada}
|
||||
@item @code{IDNUM} @tab @kbd{A-Za-z0-9_}
|
||||
@item @code{IDST} @tab @kbd{A-Za-z_}
|
||||
@item @code{VSPACE} @tab @kbd{\r \n}
|
||||
@item @code{NVSPACE} @tab @kbd{space tab \f \v \0}
|
||||
@item @code{SPACE_OR_NUL} @tab @code{VSPACE || NVSPACE}
|
||||
@item @code{ISOBASIC} @tab @code{VSPACE || NVSPACE || PRINT}
|
||||
@end multitable
|
||||
@end deffn
|
||||
|
||||
*/
|
||||
|
||||
#include "ansidecl.h"
|
||||
#include <safe-ctype.h>
|
||||
#include <stdio.h> /* for EOF */
|
||||
|
||||
#if EOF != -1
|
||||
#error "<safe-ctype.h> requires EOF == -1"
|
||||
#endif
|
||||
|
||||
/* Shorthand */
|
||||
#define bl _sch_isblank
|
||||
#define cn _sch_iscntrl
|
||||
#define di _sch_isdigit
|
||||
#define is _sch_isidst
|
||||
#define lo _sch_islower
|
||||
#define nv _sch_isnvsp
|
||||
#define pn _sch_ispunct
|
||||
#define pr _sch_isprint
|
||||
#define sp _sch_isspace
|
||||
#define up _sch_isupper
|
||||
#define vs _sch_isvsp
|
||||
#define xd _sch_isxdigit
|
||||
|
||||
/* Masks. */
|
||||
#define L (const unsigned short) (lo|is |pr) /* lower case letter */
|
||||
#define XL (const unsigned short) (lo|is|xd|pr) /* lowercase hex digit */
|
||||
#define U (const unsigned short) (up|is |pr) /* upper case letter */
|
||||
#define XU (const unsigned short) (up|is|xd|pr) /* uppercase hex digit */
|
||||
#define D (const unsigned short) (di |xd|pr) /* decimal digit */
|
||||
#define P (const unsigned short) (pn |pr) /* punctuation */
|
||||
#define _ (const unsigned short) (pn|is |pr) /* underscore */
|
||||
|
||||
#define C (const unsigned short) ( cn) /* control character */
|
||||
#define Z (const unsigned short) (nv |cn) /* NUL */
|
||||
#define M (const unsigned short) (nv|sp |cn) /* cursor movement: \f \v */
|
||||
#define V (const unsigned short) (vs|sp |cn) /* vertical space: \r \n */
|
||||
#define T (const unsigned short) (nv|sp|bl|cn) /* tab */
|
||||
#define S (const unsigned short) (nv|sp|bl|pr) /* space */
|
||||
|
||||
/* Are we ASCII? */
|
||||
#if HOST_CHARSET == HOST_CHARSET_ASCII
|
||||
|
||||
const unsigned short _sch_istable[256] =
|
||||
{
|
||||
Z, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */
|
||||
C, T, V, M, M, V, C, C, /* BS HT LF VT FF CR SO SI */
|
||||
C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
|
||||
C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */
|
||||
S, P, P, P, P, P, P, P, /* SP ! " # $ % & ' */
|
||||
P, P, P, P, P, P, P, P, /* ( ) * + , - . / */
|
||||
D, D, D, D, D, D, D, D, /* 0 1 2 3 4 5 6 7 */
|
||||
D, D, P, P, P, P, P, P, /* 8 9 : ; < = > ? */
|
||||
P, XU, XU, XU, XU, XU, XU, U, /* @ A B C D E F G */
|
||||
U, U, U, U, U, U, U, U, /* H I J K L M N O */
|
||||
U, U, U, U, U, U, U, U, /* P Q R S T U V W */
|
||||
U, U, U, P, P, P, P, _, /* X Y Z [ \ ] ^ _ */
|
||||
P, XL, XL, XL, XL, XL, XL, L, /* ` a b c d e f g */
|
||||
L, L, L, L, L, L, L, L, /* h i j k l m n o */
|
||||
L, L, L, L, L, L, L, L, /* p q r s t u v w */
|
||||
L, L, L, P, P, P, P, C, /* x y z { | } ~ DEL */
|
||||
|
||||
/* high half of unsigned char is locale-specific, so all tests are
|
||||
false in "C" locale */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
const unsigned char _sch_tolower[256] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64,
|
||||
|
||||
'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',
|
||||
|
||||
91, 92, 93, 94, 95, 96,
|
||||
|
||||
'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',
|
||||
|
||||
123,124,125,126,127,
|
||||
|
||||
128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
|
||||
144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
|
||||
160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175,
|
||||
176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191,
|
||||
|
||||
192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
|
||||
208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
|
||||
224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
|
||||
240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255,
|
||||
};
|
||||
|
||||
const unsigned char _sch_toupper[256] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64,
|
||||
|
||||
'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',
|
||||
|
||||
91, 92, 93, 94, 95, 96,
|
||||
|
||||
'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',
|
||||
|
||||
123,124,125,126,127,
|
||||
|
||||
128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
|
||||
144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
|
||||
160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175,
|
||||
176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191,
|
||||
|
||||
192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
|
||||
208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
|
||||
224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
|
||||
240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255,
|
||||
};
|
||||
|
||||
#else
|
||||
# if HOST_CHARSET == HOST_CHARSET_EBCDIC
|
||||
#error "FIXME: write tables for EBCDIC"
|
||||
# else
|
||||
#error "Unrecognized host character set"
|
||||
# endif
|
||||
#endif
|
||||
6245
3rdparty/demangler/src/stgrammars/borlandll.cpp
vendored
6245
3rdparty/demangler/src/stgrammars/borlandll.cpp
vendored
File diff suppressed because it is too large
Load Diff
5166
3rdparty/demangler/src/stgrammars/gccll.cpp
vendored
5166
3rdparty/demangler/src/stgrammars/gccll.cpp
vendored
File diff suppressed because it is too large
Load Diff
5449
3rdparty/demangler/src/stgrammars/msll.cpp
vendored
5449
3rdparty/demangler/src/stgrammars/msll.cpp
vendored
File diff suppressed because it is too large
Load Diff
52
3rdparty/demangler/src/xexit.c
vendored
Normal file
52
3rdparty/demangler/src/xexit.c
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/* xexit.c -- Run any exit handlers, then exit.
|
||||
Copyright (C) 1994-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. */
|
||||
|
||||
/*
|
||||
|
||||
@deftypefn Replacement void xexit (int @var{code})
|
||||
|
||||
Terminates the program. If any functions have been registered with
|
||||
the @code{xatexit} replacement function, they will be called first.
|
||||
Termination is handled via the system's normal @code{exit} call.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "libiberty.h"
|
||||
|
||||
|
||||
/* This variable is set by xatexit if it is called. This way, xmalloc
|
||||
doesn't drag xatexit into the link. */
|
||||
void (*_xexit_cleanup) (void);
|
||||
|
||||
void
|
||||
xexit (int code)
|
||||
{
|
||||
if (_xexit_cleanup != NULL)
|
||||
(*_xexit_cleanup) ();
|
||||
exit (code);
|
||||
}
|
||||
186
3rdparty/demangler/src/xmalloc.c
vendored
Normal file
186
3rdparty/demangler/src/xmalloc.c
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
/* memory allocation routines with error checking.
|
||||
Copyright (C) 1989-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. */
|
||||
|
||||
/*
|
||||
|
||||
@deftypefn Replacement void* xmalloc (size_t)
|
||||
|
||||
Allocate memory without fail. If @code{malloc} fails, this will print
|
||||
a message to @code{stderr} (using the name set by
|
||||
@code{xmalloc_set_program_name},
|
||||
if any) and then call @code{xexit}. Note that it is therefore safe for
|
||||
a program to contain @code{#define malloc xmalloc} in its source.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Replacement void* xrealloc (void *@var{ptr}, size_t @var{size})
|
||||
Reallocate memory without fail. This routine functions like @code{realloc},
|
||||
but will behave the same as @code{xmalloc} if memory cannot be found.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Replacement void* xcalloc (size_t @var{nelem}, size_t @var{elsize})
|
||||
|
||||
Allocate memory without fail, and set it to zero. This routine functions
|
||||
like @code{calloc}, but will behave the same as @code{xmalloc} if memory
|
||||
cannot be found.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Replacement void xmalloc_set_program_name (const char *@var{name})
|
||||
|
||||
You can use this to set the name of the program used by
|
||||
@code{xmalloc_failed} when printing a failure message.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Replacement void xmalloc_failed (size_t)
|
||||
|
||||
This function is not meant to be called by client code, and is listed
|
||||
here for completeness only. If any of the allocation routines fail, this
|
||||
function will be called to print an error message and terminate execution.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "ansidecl.h"
|
||||
#include "libiberty.h"
|
||||
#include "environ.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if VMS
|
||||
#include <stdlib.h>
|
||||
#include <unixlib.h>
|
||||
#else
|
||||
/* For systems with larger pointers than ints, these must be declared. */
|
||||
# if HAVE_STDLIB_H && HAVE_UNISTD_H && HAVE_DECL_MALLOC \
|
||||
&& HAVE_DECL_REALLOC && HAVE_DECL_CALLOC && HAVE_DECL_SBRK
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
# else
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif /* __cplusplus */
|
||||
void *malloc (size_t);
|
||||
void *realloc (void *, size_t);
|
||||
void *calloc (size_t, size_t);
|
||||
#ifdef HAVE_SBRK
|
||||
void *sbrk (ptrdiff_t);
|
||||
#endif
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif /* __cplusplus */
|
||||
# endif /* HAVE_STDLIB_H ... */
|
||||
#endif /* VMS */
|
||||
|
||||
/* The program name if set. */
|
||||
static const char *name = "";
|
||||
|
||||
#ifdef HAVE_SBRK
|
||||
/* The initial sbrk, set when the program name is set. Not used for win32
|
||||
ports other than cygwin32. */
|
||||
static char *first_break = NULL;
|
||||
#endif /* HAVE_SBRK */
|
||||
|
||||
void
|
||||
xmalloc_set_program_name (const char *s)
|
||||
{
|
||||
name = s;
|
||||
#ifdef HAVE_SBRK
|
||||
/* Win32 ports other than cygwin32 don't have brk() */
|
||||
if (first_break == NULL)
|
||||
first_break = (char *) sbrk (0);
|
||||
#endif /* HAVE_SBRK */
|
||||
}
|
||||
|
||||
void
|
||||
xmalloc_failed (size_t size)
|
||||
{
|
||||
#ifdef HAVE_SBRK
|
||||
size_t allocated;
|
||||
|
||||
if (first_break != NULL)
|
||||
allocated = (char *) sbrk (0) - first_break;
|
||||
else
|
||||
allocated = (char *) sbrk (0) - (char *) &environ;
|
||||
fprintf (stderr,
|
||||
"\n%s%sout of memory allocating %lu bytes after a total of %lu bytes\n",
|
||||
name, *name ? ": " : "",
|
||||
(unsigned long) size, (unsigned long) allocated);
|
||||
#else /* HAVE_SBRK */
|
||||
fprintf (stderr,
|
||||
"\n%s%sout of memory allocating %lu bytes\n",
|
||||
name, *name ? ": " : "",
|
||||
(unsigned long) size);
|
||||
#endif /* HAVE_SBRK */
|
||||
xexit (1);
|
||||
}
|
||||
|
||||
void *
|
||||
xmalloc (size_t size)
|
||||
{
|
||||
void *newmem;
|
||||
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
newmem = malloc (size);
|
||||
if (!newmem)
|
||||
xmalloc_failed (size);
|
||||
|
||||
return (newmem);
|
||||
}
|
||||
|
||||
void *
|
||||
xcalloc (size_t nelem, size_t elsize)
|
||||
{
|
||||
void *newmem;
|
||||
|
||||
if (nelem == 0 || elsize == 0)
|
||||
nelem = elsize = 1;
|
||||
|
||||
newmem = calloc (nelem, elsize);
|
||||
if (!newmem)
|
||||
xmalloc_failed (nelem * elsize);
|
||||
|
||||
return (newmem);
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc (void *oldmem, size_t size)
|
||||
{
|
||||
void *newmem;
|
||||
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
if (!oldmem)
|
||||
newmem = malloc (size);
|
||||
else
|
||||
newmem = realloc (oldmem, size);
|
||||
if (!newmem)
|
||||
xmalloc_failed (size);
|
||||
|
||||
return (newmem);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user