summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/windows/docker.sh1
-rw-r--r--.ci/scripts/windows/install-vulkan-sdk.ps133
-rw-r--r--.ci/templates/build-msvc.yml9
-rw-r--r--.github/workflows/android-build.yml1
-rw-r--r--.github/workflows/verify.yml30
-rw-r--r--.gitmodules2
-rw-r--r--CMakeLists.txt21
-rw-r--r--externals/CMakeLists.txt6
m---------externals/Vulkan-Headers0
m---------externals/VulkanMemoryAllocator0
-rw-r--r--externals/demangle/ItaniumDemangle.cpp171
-rw-r--r--externals/demangle/llvm/Demangle/Demangle.h37
-rw-r--r--externals/demangle/llvm/Demangle/DemangleConfig.h4
-rw-r--r--externals/demangle/llvm/Demangle/ItaniumDemangle.h3888
-rw-r--r--externals/demangle/llvm/Demangle/ItaniumNodes.def96
-rw-r--r--externals/demangle/llvm/Demangle/StringView.h32
-rw-r--r--externals/demangle/llvm/Demangle/StringViewExtras.h39
-rw-r--r--externals/demangle/llvm/Demangle/Utility.h208
m---------externals/vma/VulkanMemoryAllocator0
-rw-r--r--src/android/app/src/main/AndroidManifest.xml2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt16
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt114
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeSetting.kt5
-rw-r--r--src/android/app/src/main/jni/native.cpp2
-rw-r--r--src/android/app/src/main/res/values/strings.xml4
-rw-r--r--src/audio_core/device/device_session.cpp6
-rw-r--r--src/audio_core/renderer/command/data_source/decode.cpp21
-rw-r--r--src/audio_core/renderer/command/effect/aux_.cpp82
-rw-r--r--src/common/demangle.cpp2
-rw-r--r--src/common/detached_tasks.cpp4
-rw-r--r--src/common/page_table.cpp1
-rw-r--r--src/common/page_table.h1
-rw-r--r--src/common/scratch_buffer.h17
-rw-r--r--src/common/settings.cpp5
-rw-r--r--src/common/socket_types.h17
-rw-r--r--src/common/time_zone.cpp47
-rw-r--r--src/core/CMakeLists.txt19
-rw-r--r--src/core/arm/arm_interface.cpp2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h6
-rw-r--r--src/core/arm/dynarmic/dynarmic_exclusive_monitor.h5
-rw-r--r--src/core/core.cpp8
-rw-r--r--src/core/core.h3
-rw-r--r--src/core/core_timing.cpp3
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/debugger/gdbstub.cpp4
-rw-r--r--src/core/file_sys/content_archive.cpp39
-rw-r--r--src/core/hle/kernel/k_code_memory.cpp17
-rw-r--r--src/core/hle/kernel/k_page_table.h41
-rw-r--r--src/core/hle/kernel/k_process.cpp2
-rw-r--r--src/core/hle/kernel/k_process.h10
-rw-r--r--src/core/hle/kernel/k_server_session.cpp165
-rw-r--r--src/core/hle/kernel/k_shared_memory.cpp6
-rw-r--r--src/core/hle/kernel/k_thread.cpp4
-rw-r--r--src/core/hle/kernel/k_thread_local_page.cpp10
-rw-r--r--src/core/hle/kernel/kernel.cpp6
-rw-r--r--src/core/hle/kernel/message_buffer.h612
-rw-r--r--src/core/hle/kernel/physical_core.cpp8
-rw-r--r--src/core/hle/kernel/svc/svc_cache.cpp2
-rw-r--r--src/core/hle/kernel/svc/svc_code_memory.cpp14
-rw-r--r--src/core/hle/kernel/svc/svc_device_address_space.cpp6
-rw-r--r--src/core/hle/kernel/svc/svc_info.cpp16
-rw-r--r--src/core/hle/kernel/svc/svc_memory.cpp33
-rw-r--r--src/core/hle/kernel/svc/svc_physical_memory.cpp14
-rw-r--r--src/core/hle/kernel/svc/svc_process.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_process_memory.cpp34
-rw-r--r--src/core/hle/kernel/svc/svc_query_memory.cpp2
-rw-r--r--src/core/hle/kernel/svc/svc_shared_memory.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_thread.cpp2
-rw-r--r--src/core/hle/kernel/svc/svc_transfer_memory.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp4
-rw-r--r--src/core/hle/service/hle_ipc.cpp32
-rw-r--r--src/core/hle/service/ldr/ldr.cpp20
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.cpp2
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.h2
-rw-r--r--src/core/hle/service/nfc/common/device.cpp3
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp135
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h34
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp18
-rw-r--r--src/core/hle/service/nfc/nfc_result.h3
-rw-r--r--src/core/hle/service/nifm/nifm.cpp1
-rw-r--r--src/core/hle/service/nifm/nifm.h7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp4
-rw-r--r--src/core/hle/service/sockets/bsd.cpp120
-rw-r--r--src/core/hle/service/sockets/bsd.h13
-rw-r--r--src/core/hle/service/sockets/nsd.cpp75
-rw-r--r--src/core/hle/service/sockets/nsd.h5
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp388
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h3
-rw-r--r--src/core/hle/service/sockets/sockets.h33
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp114
-rw-r--r--src/core/hle/service/sockets/sockets_translate.h17
-rw-r--r--src/core/hle/service/ssl/ssl.cpp353
-rw-r--r--src/core/hle/service/ssl/ssl_backend.h45
-rw-r--r--src/core/hle/service/ssl/ssl_backend_none.cpp16
-rw-r--r--src/core/hle/service/ssl/ssl_backend_openssl.cpp351
-rw-r--r--src/core/hle/service/ssl/ssl_backend_schannel.cpp544
-rw-r--r--src/core/hle/service/ssl/ssl_backend_securetransport.cpp222
-rw-r--r--src/core/internal_network/network.cpp286
-rw-r--r--src/core/internal_network/network.h36
-rw-r--r--src/core/internal_network/socket_proxy.cpp23
-rw-r--r--src/core/internal_network/socket_proxy.h12
-rw-r--r--src/core/internal_network/sockets.h19
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp2
-rw-r--r--src/core/loader/kip.cpp2
-rw-r--r--src/core/loader/loader.h2
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nso.cpp2
-rw-r--r--src/core/memory.cpp62
-rw-r--r--src/core/memory.h212
-rw-r--r--src/core/memory/cheat_engine.cpp2
-rw-r--r--src/core/reporter.cpp4
-rw-r--r--src/input_common/drivers/sdl_driver.cpp46
-rw-r--r--src/input_common/drivers/sdl_driver.h7
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h17
-rw-r--r--src/video_core/buffer_cache/buffer_cache_base.h2
-rw-r--r--src/video_core/dma_pusher.cpp26
-rw-r--r--src/video_core/engines/engine_upload.cpp28
-rw-r--r--src/video_core/engines/kepler_compute.cpp1
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/engines/maxwell_dma.cpp87
-rw-r--r--src/video_core/engines/sw_blitter/blitter.cpp29
-rw-r--r--src/video_core/memory_manager.cpp30
-rw-r--r--src/video_core/memory_manager.h18
-rw-r--r--src/video_core/renderer_base.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp33
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp6
-rw-r--r--src/video_core/texture_cache/texture_cache.h24
-rw-r--r--src/video_core/texture_cache/util.cpp26
-rw-r--r--src/video_core/texture_cache/util.h3
-rw-r--r--src/video_core/vulkan_common/vma.cpp (renamed from externals/vma/vma.cpp)0
-rw-r--r--src/web_service/announce_room_json.cpp10
-rw-r--r--src/yuzu/game_list_worker.cpp2
140 files changed, 6564 insertions, 3168 deletions
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh
index 0be3613aa..45f75c874 100755
--- a/.ci/scripts/windows/docker.sh
+++ b/.ci/scripts/windows/docker.sh
@@ -56,7 +56,6 @@ for i in package/*.exe; do
56 x86_64-w64-mingw32-strip "${i}" 56 x86_64-w64-mingw32-strip "${i}"
57done 57done
58 58
59pip3 install pefile
60python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/" 59python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/"
61 60
62# copy FFmpeg libraries 61# copy FFmpeg libraries
diff --git a/.ci/scripts/windows/install-vulkan-sdk.ps1 b/.ci/scripts/windows/install-vulkan-sdk.ps1
new file mode 100644
index 000000000..de218d90a
--- /dev/null
+++ b/.ci/scripts/windows/install-vulkan-sdk.ps1
@@ -0,0 +1,33 @@
1# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2# SPDX-License-Identifier: GPL-3.0-or-later
3
4$ErrorActionPreference = "Stop"
5
6$VulkanSDKVer = "1.3.250.1"
7$ExeFile = "VulkanSDK-$VulkanSDKVer-Installer.exe"
8$Uri = "https://sdk.lunarg.com/sdk/download/$VulkanSDKVer/windows/$ExeFile"
9$Destination = "./$ExeFile"
10
11echo "Downloading Vulkan SDK $VulkanSDKVer from $Uri"
12$WebClient = New-Object System.Net.WebClient
13$WebClient.DownloadFile($Uri, $Destination)
14echo "Finished downloading $ExeFile"
15
16$VULKAN_SDK = "C:/VulkanSDK/$VulkanSDKVer"
17$Arguments = "--root `"$VULKAN_SDK`" --accept-licenses --default-answer --confirm-command install"
18
19echo "Installing Vulkan SDK $VulkanSDKVer"
20$InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -Wait -ArgumentList $Arguments
21$ExitCode = $InstallProcess.ExitCode
22
23if ($ExitCode -ne 0) {
24 echo "Error installing Vulkan SDK $VulkanSDKVer (Error: $ExitCode)"
25 Exit $ExitCode
26}
27
28echo "Finished installing Vulkan SDK $VulkanSDKVer"
29
30if ("$env:GITHUB_ACTIONS" -eq "true") {
31 echo "VULKAN_SDK=$VULKAN_SDK" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
32 echo "$VULKAN_SDK/Bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
33}
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml
index ceb7e0c32..1e259df05 100644
--- a/.ci/templates/build-msvc.yml
+++ b/.ci/templates/build-msvc.yml
@@ -7,9 +7,12 @@ parameters:
7 version: '' 7 version: ''
8 8
9steps: 9steps:
10- script: choco install vulkan-sdk 10- task: Powershell@2
11 displayName: 'Install vulkan-sdk' 11 displayName: 'Install Vulkan SDK'
12- script: refreshenv && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd .. 12 inputs:
13 targetType: 'filePath'
14 filePath: './.ci/scripts/windows/install-vulkan-sdk.ps1'
15- script: refreshenv && glslangValidator --version && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
13 displayName: 'Configure CMake' 16 displayName: 'Configure CMake'
14- task: MSBuild@1 17- task: MSBuild@1
15 displayName: 'Build' 18 displayName: 'Build'
diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml
index e639e965a..5893f860e 100644
--- a/.github/workflows/android-build.yml
+++ b/.github/workflows/android-build.yml
@@ -10,6 +10,7 @@ on:
10jobs: 10jobs:
11 android: 11 android:
12 runs-on: ubuntu-latest 12 runs-on: ubuntu-latest
13 if: ${{ github.repository == 'yuzu-emu/yuzu-android' }}
13 steps: 14 steps:
14 - uses: actions/checkout@v3 15 - uses: actions/checkout@v3
15 with: 16 with:
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index b5d338199..cbe6b0fbd 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -73,6 +73,10 @@ jobs:
73 needs: format 73 needs: format
74 runs-on: windows-2022 74 runs-on: windows-2022
75 steps: 75 steps:
76 - uses: actions/checkout@v3
77 with:
78 submodules: recursive
79 fetch-depth: 0
76 - name: Set up cache 80 - name: Set up cache
77 uses: actions/cache@v3 81 uses: actions/cache@v3
78 with: 82 with:
@@ -81,22 +85,22 @@ jobs:
81 restore-keys: | 85 restore-keys: |
82 ${{ runner.os }}-msvc- 86 ${{ runner.os }}-msvc-
83 - name: Install dependencies 87 - name: Install dependencies
84 # due to how chocolatey works, only cmd.exe is supported here 88 shell: pwsh
85 shell: cmd
86 run: | 89 run: |
87 choco install vulkan-sdk wget 90 $ErrorActionPreference = "Stop"
88 call refreshenv 91 $BuildCacheVer = "v0.28.4"
89 wget https://github.com/mbitsnbites/buildcache/releases/download/v0.27.6/buildcache-windows.zip 92 $File = "buildcache-windows.zip"
90 7z x buildcache-windows.zip 93 $Uri = "https://github.com/mbitsnbites/buildcache/releases/download/$BuildCacheVer/$File"
91 copy buildcache\bin\buildcache.exe C:\ProgramData\chocolatey\bin 94 $WebClient = New-Object System.Net.WebClient
92 rmdir buildcache 95 $WebClient.DownloadFile($Uri, $File)
93 echo %PATH% >> %GITHUB_PATH% 96 7z x $File
97 $CurrentDir = Convert-Path .
98 echo "$CurrentDir/buildcache/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
99 - name: Install Vulkan SDK
100 shell: pwsh
101 run: .\.ci\scripts\windows\install-vulkan-sdk.ps1
94 - name: Set up MSVC 102 - name: Set up MSVC
95 uses: ilammy/msvc-dev-cmd@v1 103 uses: ilammy/msvc-dev-cmd@v1
96 - uses: actions/checkout@v3
97 with:
98 submodules: recursive
99 fetch-depth: 0
100 - name: Configure 104 - name: Configure
101 env: 105 env:
102 CC: cl.exe 106 CC: cl.exe
diff --git a/.gitmodules b/.gitmodules
index 9f96b70be..361f4845b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -56,5 +56,5 @@
56 path = externals/nx_tzdb/tzdb_to_nx 56 path = externals/nx_tzdb/tzdb_to_nx
57 url = https://github.com/lat9nq/tzdb_to_nx.git 57 url = https://github.com/lat9nq/tzdb_to_nx.git
58[submodule "VulkanMemoryAllocator"] 58[submodule "VulkanMemoryAllocator"]
59 path = externals/vma/VulkanMemoryAllocator 59 path = externals/VulkanMemoryAllocator
60 url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git 60 url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 26e93b038..00d540f1f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,18 @@ option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
63 63
64CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF) 64CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
65 65
66set(DEFAULT_ENABLE_OPENSSL ON)
67if (ANDROID OR WIN32 OR APPLE)
68 # - Windows defaults to the Schannel backend.
69 # - macOS defaults to the SecureTransport backend.
70 # - Android currently has no SSL backend as the NDK doesn't include any SSL
71 # library; a proper 'native' backend would have to go through Java.
72 # But you can force builds for those platforms to use OpenSSL if you have
73 # your own copy of it.
74 set(DEFAULT_ENABLE_OPENSSL OFF)
75endif()
76option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
77
66# On Android, fetch and compile libcxx before doing anything else 78# On Android, fetch and compile libcxx before doing anything else
67if (ANDROID) 79if (ANDROID)
68 set(CMAKE_SKIP_INSTALL_RULES ON) 80 set(CMAKE_SKIP_INSTALL_RULES ON)
@@ -277,15 +289,16 @@ find_package(Boost 1.79.0 REQUIRED context)
277find_package(enet 1.3 MODULE) 289find_package(enet 1.3 MODULE)
278find_package(fmt 9 REQUIRED) 290find_package(fmt 9 REQUIRED)
279find_package(inih 52 MODULE COMPONENTS INIReader) 291find_package(inih 52 MODULE COMPONENTS INIReader)
280find_package(LLVM MODULE COMPONENTS Demangle) 292find_package(LLVM 17 MODULE COMPONENTS Demangle)
281find_package(lz4 REQUIRED) 293find_package(lz4 REQUIRED)
282find_package(nlohmann_json 3.8 REQUIRED) 294find_package(nlohmann_json 3.8 REQUIRED)
283find_package(Opus 1.3 MODULE) 295find_package(Opus 1.3 MODULE)
296find_package(VulkanMemoryAllocator CONFIG)
284find_package(ZLIB 1.2 REQUIRED) 297find_package(ZLIB 1.2 REQUIRED)
285find_package(zstd 1.5 REQUIRED) 298find_package(zstd 1.5 REQUIRED)
286 299
287if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS) 300if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
288 find_package(Vulkan 1.3.246 REQUIRED) 301 find_package(Vulkan 1.3.256 REQUIRED)
289endif() 302endif()
290 303
291if (ENABLE_LIBUSB) 304if (ENABLE_LIBUSB)
@@ -322,6 +335,10 @@ if (MINGW)
322 find_library(MSWSOCK_LIBRARY mswsock REQUIRED) 335 find_library(MSWSOCK_LIBRARY mswsock REQUIRED)
323endif() 336endif()
324 337
338if(ENABLE_OPENSSL)
339 find_package(OpenSSL 1.1.1 REQUIRED)
340endif()
341
325# Please consider this as a stub 342# Please consider this as a stub
326if(ENABLE_QT6 AND Qt6_LOCATION) 343if(ENABLE_QT6 AND Qt6_LOCATION)
327 list(APPEND CMAKE_PREFIX_PATH "${Qt6_LOCATION}") 344 list(APPEND CMAKE_PREFIX_PATH "${Qt6_LOCATION}")
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 4ff588851..1f7cd598e 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -144,9 +144,9 @@ endif()
144add_subdirectory(nx_tzdb) 144add_subdirectory(nx_tzdb)
145 145
146# VMA 146# VMA
147add_library(vma vma/vma.cpp) 147if (NOT TARGET GPUOpen::VulkanMemoryAllocator)
148target_include_directories(vma PUBLIC ./vma/VulkanMemoryAllocator/include) 148 add_subdirectory(VulkanMemoryAllocator)
149target_link_libraries(vma PRIVATE Vulkan::Headers) 149endif()
150 150
151if (NOT TARGET LLVM::Demangle) 151if (NOT TARGET LLVM::Demangle)
152 add_library(demangle demangle/ItaniumDemangle.cpp) 152 add_library(demangle demangle/ItaniumDemangle.cpp)
diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers
Subproject 63af1cf1ee906ba4dcd5a324bdd0201d4f4bfd1 Subproject ed857118e243fdc0f3a100f00ac9919e874cfe6
diff --git a/externals/VulkanMemoryAllocator b/externals/VulkanMemoryAllocator
new file mode 160000
Subproject 9b0fc3e7b02afe97895eb3e945fe800c3a7485a
diff --git a/externals/demangle/ItaniumDemangle.cpp b/externals/demangle/ItaniumDemangle.cpp
index b055a2fd7..47dd5d301 100644
--- a/externals/demangle/ItaniumDemangle.cpp
+++ b/externals/demangle/ItaniumDemangle.cpp
@@ -20,9 +20,7 @@
20#include <cstdlib> 20#include <cstdlib>
21#include <cstring> 21#include <cstring>
22#include <functional> 22#include <functional>
23#include <numeric>
24#include <utility> 23#include <utility>
25#include <vector>
26 24
27using namespace llvm; 25using namespace llvm;
28using namespace llvm::itanium_demangle; 26using namespace llvm::itanium_demangle;
@@ -81,8 +79,8 @@ struct DumpVisitor {
81 } 79 }
82 80
83 void printStr(const char *S) { fprintf(stderr, "%s", S); } 81 void printStr(const char *S) { fprintf(stderr, "%s", S); }
84 void print(StringView SV) { 82 void print(std::string_view SV) {
85 fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); 83 fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.data());
86 } 84 }
87 void print(const Node *N) { 85 void print(const Node *N) {
88 if (N) 86 if (N)
@@ -90,14 +88,6 @@ struct DumpVisitor {
90 else 88 else
91 printStr("<null>"); 89 printStr("<null>");
92 } 90 }
93 void print(NodeOrString NS) {
94 if (NS.isNode())
95 print(NS.asNode());
96 else if (NS.isString())
97 print(NS.asString());
98 else
99 printStr("NodeOrString()");
100 }
101 void print(NodeArray A) { 91 void print(NodeArray A) {
102 ++Depth; 92 ++Depth;
103 printStr("{"); 93 printStr("{");
@@ -116,13 +106,11 @@ struct DumpVisitor {
116 // Overload used when T is exactly 'bool', not merely convertible to 'bool'. 106 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
117 void print(bool B) { printStr(B ? "true" : "false"); } 107 void print(bool B) { printStr(B ? "true" : "false"); }
118 108
119 template <class T> 109 template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) {
120 typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
121 fprintf(stderr, "%llu", (unsigned long long)N); 110 fprintf(stderr, "%llu", (unsigned long long)N);
122 } 111 }
123 112
124 template <class T> 113 template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) {
125 typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
126 fprintf(stderr, "%lld", (long long)N); 114 fprintf(stderr, "%lld", (long long)N);
127 } 115 }
128 116
@@ -185,6 +173,50 @@ struct DumpVisitor {
185 return printStr("TemplateParamKind::Template"); 173 return printStr("TemplateParamKind::Template");
186 } 174 }
187 } 175 }
176 void print(Node::Prec P) {
177 switch (P) {
178 case Node::Prec::Primary:
179 return printStr("Node::Prec::Primary");
180 case Node::Prec::Postfix:
181 return printStr("Node::Prec::Postfix");
182 case Node::Prec::Unary:
183 return printStr("Node::Prec::Unary");
184 case Node::Prec::Cast:
185 return printStr("Node::Prec::Cast");
186 case Node::Prec::PtrMem:
187 return printStr("Node::Prec::PtrMem");
188 case Node::Prec::Multiplicative:
189 return printStr("Node::Prec::Multiplicative");
190 case Node::Prec::Additive:
191 return printStr("Node::Prec::Additive");
192 case Node::Prec::Shift:
193 return printStr("Node::Prec::Shift");
194 case Node::Prec::Spaceship:
195 return printStr("Node::Prec::Spaceship");
196 case Node::Prec::Relational:
197 return printStr("Node::Prec::Relational");
198 case Node::Prec::Equality:
199 return printStr("Node::Prec::Equality");
200 case Node::Prec::And:
201 return printStr("Node::Prec::And");
202 case Node::Prec::Xor:
203 return printStr("Node::Prec::Xor");
204 case Node::Prec::Ior:
205 return printStr("Node::Prec::Ior");
206 case Node::Prec::AndIf:
207 return printStr("Node::Prec::AndIf");
208 case Node::Prec::OrIf:
209 return printStr("Node::Prec::OrIf");
210 case Node::Prec::Conditional:
211 return printStr("Node::Prec::Conditional");
212 case Node::Prec::Assign:
213 return printStr("Node::Prec::Assign");
214 case Node::Prec::Comma:
215 return printStr("Node::Prec::Comma");
216 case Node::Prec::Default:
217 return printStr("Node::Prec::Default");
218 }
219 }
188 220
189 void newLine() { 221 void newLine() {
190 printStr("\n"); 222 printStr("\n");
@@ -334,36 +366,21 @@ public:
334 366
335using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; 367using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
336 368
337char *llvm::itaniumDemangle(const char *MangledName, char *Buf, 369char *llvm::itaniumDemangle(std::string_view MangledName) {
338 size_t *N, int *Status) { 370 if (MangledName.empty())
339 if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
340 if (Status)
341 *Status = demangle_invalid_args;
342 return nullptr; 371 return nullptr;
343 }
344
345 int InternalStatus = demangle_success;
346 Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
347 OutputStream S;
348 372
373 Demangler Parser(MangledName.data(),
374 MangledName.data() + MangledName.length());
349 Node *AST = Parser.parse(); 375 Node *AST = Parser.parse();
376 if (!AST)
377 return nullptr;
350 378
351 if (AST == nullptr) 379 OutputBuffer OB;
352 InternalStatus = demangle_invalid_mangled_name; 380 assert(Parser.ForwardTemplateRefs.empty());
353 else if (!initializeOutputStream(Buf, N, S, 1024)) 381 AST->print(OB);
354 InternalStatus = demangle_memory_alloc_failure; 382 OB += '\0';
355 else { 383 return OB.getBuffer();
356 assert(Parser.ForwardTemplateRefs.empty());
357 AST->print(S);
358 S += '\0';
359 if (N != nullptr)
360 *N = S.getCurrentPosition();
361 Buf = S.getBuffer();
362 }
363
364 if (Status)
365 *Status = InternalStatus;
366 return InternalStatus == demangle_success ? Buf : nullptr;
367} 384}
368 385
369ItaniumPartialDemangler::ItaniumPartialDemangler() 386ItaniumPartialDemangler::ItaniumPartialDemangler()
@@ -396,14 +413,12 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
396} 413}
397 414
398static char *printNode(const Node *RootNode, char *Buf, size_t *N) { 415static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
399 OutputStream S; 416 OutputBuffer OB(Buf, N);
400 if (!initializeOutputStream(Buf, N, S, 128)) 417 RootNode->print(OB);
401 return nullptr; 418 OB += '\0';
402 RootNode->print(S);
403 S += '\0';
404 if (N != nullptr) 419 if (N != nullptr)
405 *N = S.getCurrentPosition(); 420 *N = OB.getCurrentPosition();
406 return S.getBuffer(); 421 return OB.getBuffer();
407} 422}
408 423
409char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { 424char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
@@ -417,8 +432,8 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
417 case Node::KAbiTagAttr: 432 case Node::KAbiTagAttr:
418 Name = static_cast<const AbiTagAttr *>(Name)->Base; 433 Name = static_cast<const AbiTagAttr *>(Name)->Base;
419 continue; 434 continue;
420 case Node::KStdQualifiedName: 435 case Node::KModuleEntity:
421 Name = static_cast<const StdQualifiedName *>(Name)->Child; 436 Name = static_cast<const ModuleEntity *>(Name)->Name;
422 continue; 437 continue;
423 case Node::KNestedName: 438 case Node::KNestedName:
424 Name = static_cast<const NestedName *>(Name)->Name; 439 Name = static_cast<const NestedName *>(Name)->Name;
@@ -441,9 +456,7 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
441 return nullptr; 456 return nullptr;
442 const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); 457 const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
443 458
444 OutputStream S; 459 OutputBuffer OB(Buf, N);
445 if (!initializeOutputStream(Buf, N, S, 128))
446 return nullptr;
447 460
448 KeepGoingLocalFunction: 461 KeepGoingLocalFunction:
449 while (true) { 462 while (true) {
@@ -458,27 +471,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
458 break; 471 break;
459 } 472 }
460 473
474 if (Name->getKind() == Node::KModuleEntity)
475 Name = static_cast<const ModuleEntity *>(Name)->Name;
476
461 switch (Name->getKind()) { 477 switch (Name->getKind()) {
462 case Node::KStdQualifiedName:
463 S += "std";
464 break;
465 case Node::KNestedName: 478 case Node::KNestedName:
466 static_cast<const NestedName *>(Name)->Qual->print(S); 479 static_cast<const NestedName *>(Name)->Qual->print(OB);
467 break; 480 break;
468 case Node::KLocalName: { 481 case Node::KLocalName: {
469 auto *LN = static_cast<const LocalName *>(Name); 482 auto *LN = static_cast<const LocalName *>(Name);
470 LN->Encoding->print(S); 483 LN->Encoding->print(OB);
471 S += "::"; 484 OB += "::";
472 Name = LN->Entity; 485 Name = LN->Entity;
473 goto KeepGoingLocalFunction; 486 goto KeepGoingLocalFunction;
474 } 487 }
475 default: 488 default:
476 break; 489 break;
477 } 490 }
478 S += '\0'; 491 OB += '\0';
479 if (N != nullptr) 492 if (N != nullptr)
480 *N = S.getCurrentPosition(); 493 *N = OB.getCurrentPosition();
481 return S.getBuffer(); 494 return OB.getBuffer();
482} 495}
483 496
484char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { 497char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
@@ -494,17 +507,15 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
494 return nullptr; 507 return nullptr;
495 NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); 508 NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
496 509
497 OutputStream S; 510 OutputBuffer OB(Buf, N);
498 if (!initializeOutputStream(Buf, N, S, 128))
499 return nullptr;
500 511
501 S += '('; 512 OB += '(';
502 Params.printWithComma(S); 513 Params.printWithComma(OB);
503 S += ')'; 514 OB += ')';
504 S += '\0'; 515 OB += '\0';
505 if (N != nullptr) 516 if (N != nullptr)
506 *N = S.getCurrentPosition(); 517 *N = OB.getCurrentPosition();
507 return S.getBuffer(); 518 return OB.getBuffer();
508} 519}
509 520
510char *ItaniumPartialDemangler::getFunctionReturnType( 521char *ItaniumPartialDemangler::getFunctionReturnType(
@@ -512,18 +523,16 @@ char *ItaniumPartialDemangler::getFunctionReturnType(
512 if (!isFunction()) 523 if (!isFunction())
513 return nullptr; 524 return nullptr;
514 525
515 OutputStream S; 526 OutputBuffer OB(Buf, N);
516 if (!initializeOutputStream(Buf, N, S, 128))
517 return nullptr;
518 527
519 if (const Node *Ret = 528 if (const Node *Ret =
520 static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) 529 static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
521 Ret->print(S); 530 Ret->print(OB);
522 531
523 S += '\0'; 532 OB += '\0';
524 if (N != nullptr) 533 if (N != nullptr)
525 *N = S.getCurrentPosition(); 534 *N = OB.getCurrentPosition();
526 return S.getBuffer(); 535 return OB.getBuffer();
527} 536}
528 537
529char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { 538char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
@@ -563,8 +572,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
563 case Node::KNestedName: 572 case Node::KNestedName:
564 N = static_cast<const NestedName *>(N)->Name; 573 N = static_cast<const NestedName *>(N)->Name;
565 break; 574 break;
566 case Node::KStdQualifiedName: 575 case Node::KModuleEntity:
567 N = static_cast<const StdQualifiedName *>(N)->Child; 576 N = static_cast<const ModuleEntity *>(N)->Name;
568 break; 577 break;
569 } 578 }
570 } 579 }
diff --git a/externals/demangle/llvm/Demangle/Demangle.h b/externals/demangle/llvm/Demangle/Demangle.h
index 5b673e4e1..1552a501a 100644
--- a/externals/demangle/llvm/Demangle/Demangle.h
+++ b/externals/demangle/llvm/Demangle/Demangle.h
@@ -12,6 +12,7 @@
12 12
13#include <cstddef> 13#include <cstddef>
14#include <string> 14#include <string>
15#include <string_view>
15 16
16namespace llvm { 17namespace llvm {
17/// This is a llvm local version of __cxa_demangle. Other than the name and 18/// This is a llvm local version of __cxa_demangle. Other than the name and
@@ -29,9 +30,10 @@ enum : int {
29 demangle_success = 0, 30 demangle_success = 0,
30}; 31};
31 32
32char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, 33/// Returns a non-NULL pointer to a NUL-terminated C style string
33 int *status); 34/// that should be explicitly freed, if successful. Otherwise, may return
34 35/// nullptr if mangled_name is not a valid mangling or is nullptr.
36char *itaniumDemangle(std::string_view mangled_name);
35 37
36enum MSDemangleFlags { 38enum MSDemangleFlags {
37 MSDF_None = 0, 39 MSDF_None = 0,
@@ -40,10 +42,34 @@ enum MSDemangleFlags {
40 MSDF_NoCallingConvention = 1 << 2, 42 MSDF_NoCallingConvention = 1 << 2,
41 MSDF_NoReturnType = 1 << 3, 43 MSDF_NoReturnType = 1 << 3,
42 MSDF_NoMemberType = 1 << 4, 44 MSDF_NoMemberType = 1 << 4,
45 MSDF_NoVariableType = 1 << 5,
43}; 46};
44char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n, 47
48/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
49/// Returns a pointer to the start of a null-terminated demangled string on
50/// success, or nullptr on error.
51/// If n_read is non-null and demangling was successful, it receives how many
52/// bytes of the input string were consumed.
53/// status receives one of the demangle_ enum entries above if it's not nullptr.
54/// Flags controls various details of the demangled representation.
55char *microsoftDemangle(std::string_view mangled_name, size_t *n_read,
45 int *status, MSDemangleFlags Flags = MSDF_None); 56 int *status, MSDemangleFlags Flags = MSDF_None);
46 57
58// Demangles a Rust v0 mangled symbol.
59char *rustDemangle(std::string_view MangledName);
60
61// Demangles a D mangled symbol.
62char *dlangDemangle(std::string_view MangledName);
63
64/// Attempt to demangle a string using different demangling schemes.
65/// The function uses heuristics to determine which demangling scheme to use.
66/// \param MangledName - reference to string to demangle.
67/// \returns - the demangled string, or a copy of the input string if no
68/// demangling occurred.
69std::string demangle(std::string_view MangledName);
70
71bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result);
72
47/// "Partial" demangler. This supports demangling a string into an AST 73/// "Partial" demangler. This supports demangling a string into an AST
48/// (typically an intermediate stage in itaniumDemangle) and querying certain 74/// (typically an intermediate stage in itaniumDemangle) and querying certain
49/// properties or partially printing the demangled name. 75/// properties or partially printing the demangled name.
@@ -59,7 +85,7 @@ struct ItaniumPartialDemangler {
59 bool partialDemangle(const char *MangledName); 85 bool partialDemangle(const char *MangledName);
60 86
61 /// Just print the entire mangled name into Buf. Buf and N behave like the 87 /// Just print the entire mangled name into Buf. Buf and N behave like the
62 /// second and third parameters to itaniumDemangle. 88 /// second and third parameters to __cxa_demangle.
63 char *finishDemangle(char *Buf, size_t *N) const; 89 char *finishDemangle(char *Buf, size_t *N) const;
64 90
65 /// Get the base name of a function. This doesn't include trailing template 91 /// Get the base name of a function. This doesn't include trailing template
@@ -95,6 +121,7 @@ struct ItaniumPartialDemangler {
95 bool isSpecialName() const; 121 bool isSpecialName() const;
96 122
97 ~ItaniumPartialDemangler(); 123 ~ItaniumPartialDemangler();
124
98private: 125private:
99 void *RootNode; 126 void *RootNode;
100 void *Context; 127 void *Context;
diff --git a/externals/demangle/llvm/Demangle/DemangleConfig.h b/externals/demangle/llvm/Demangle/DemangleConfig.h
index a8aef9df1..c7f86d766 100644
--- a/externals/demangle/llvm/Demangle/DemangleConfig.h
+++ b/externals/demangle/llvm/Demangle/DemangleConfig.h
@@ -13,8 +13,8 @@
13// 13//
14//===----------------------------------------------------------------------===// 14//===----------------------------------------------------------------------===//
15 15
16#ifndef LLVM_DEMANGLE_COMPILER_H 16#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H
17#define LLVM_DEMANGLE_COMPILER_H 17#define LLVM_DEMANGLE_DEMANGLECONFIG_H
18 18
19#ifndef __has_feature 19#ifndef __has_feature
20#define __has_feature(x) 0 20#define __has_feature(x) 0
diff --git a/externals/demangle/llvm/Demangle/ItaniumDemangle.h b/externals/demangle/llvm/Demangle/ItaniumDemangle.h
index 64b35c142..0dc3d7337 100644
--- a/externals/demangle/llvm/Demangle/ItaniumDemangle.h
+++ b/externals/demangle/llvm/Demangle/ItaniumDemangle.h
@@ -1,5 +1,5 @@
1//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===// 1//===--- ItaniumDemangle.h -----------*- mode:c++;eval:(read-only-mode) -*-===//
2// 2// Do not edit! See README.txt.
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information. 4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-FileCopyrightText: Part of the LLVM Project 5// SPDX-FileCopyrightText: Part of the LLVM Project
@@ -7,144 +7,220 @@
7// 7//
8//===----------------------------------------------------------------------===// 8//===----------------------------------------------------------------------===//
9// 9//
10// Generic itanium demangler library. This file has two byte-per-byte identical 10// Generic itanium demangler library.
11// copies in the source tree, one in libcxxabi, and the other in llvm. 11// There are two copies of this file in the source tree. The one under
12// libcxxabi is the original and the one under llvm is the copy. Use
13// cp-to-llvm.sh to update the copy. See README.txt for more details.
12// 14//
13//===----------------------------------------------------------------------===// 15//===----------------------------------------------------------------------===//
14 16
15#ifndef DEMANGLE_ITANIUMDEMANGLE_H 17#ifndef DEMANGLE_ITANIUMDEMANGLE_H
16#define DEMANGLE_ITANIUMDEMANGLE_H 18#define DEMANGLE_ITANIUMDEMANGLE_H
17 19
18// FIXME: (possibly) incomplete list of features that clang mangles that this
19// file does not yet support:
20// - C++ modules TS
21
22#include "DemangleConfig.h" 20#include "DemangleConfig.h"
23#include "StringView.h" 21#include "StringViewExtras.h"
24#include "Utility.h" 22#include "Utility.h"
23#include <algorithm>
25#include <cassert> 24#include <cassert>
26#include <cctype> 25#include <cctype>
27#include <cstdio> 26#include <cstdio>
28#include <cstdlib> 27#include <cstdlib>
29#include <cstring> 28#include <cstring>
30#include <numeric> 29#include <limits>
30#include <new>
31#include <string_view>
32#include <type_traits>
31#include <utility> 33#include <utility>
32 34
33#define FOR_EACH_NODE_KIND(X) \
34 X(NodeArrayNode) \
35 X(DotSuffix) \
36 X(VendorExtQualType) \
37 X(QualType) \
38 X(ConversionOperatorType) \
39 X(PostfixQualifiedType) \
40 X(ElaboratedTypeSpefType) \
41 X(NameType) \
42 X(AbiTagAttr) \
43 X(EnableIfAttr) \
44 X(ObjCProtoName) \
45 X(PointerType) \
46 X(ReferenceType) \
47 X(PointerToMemberType) \
48 X(ArrayType) \
49 X(FunctionType) \
50 X(NoexceptSpec) \
51 X(DynamicExceptionSpec) \
52 X(FunctionEncoding) \
53 X(LiteralOperator) \
54 X(SpecialName) \
55 X(CtorVtableSpecialName) \
56 X(QualifiedName) \
57 X(NestedName) \
58 X(LocalName) \
59 X(VectorType) \
60 X(PixelVectorType) \
61 X(SyntheticTemplateParamName) \
62 X(TypeTemplateParamDecl) \
63 X(NonTypeTemplateParamDecl) \
64 X(TemplateTemplateParamDecl) \
65 X(TemplateParamPackDecl) \
66 X(ParameterPack) \
67 X(TemplateArgumentPack) \
68 X(ParameterPackExpansion) \
69 X(TemplateArgs) \
70 X(ForwardTemplateReference) \
71 X(NameWithTemplateArgs) \
72 X(GlobalQualifiedName) \
73 X(StdQualifiedName) \
74 X(ExpandedSpecialSubstitution) \
75 X(SpecialSubstitution) \
76 X(CtorDtorName) \
77 X(DtorName) \
78 X(UnnamedTypeName) \
79 X(ClosureTypeName) \
80 X(StructuredBindingName) \
81 X(BinaryExpr) \
82 X(ArraySubscriptExpr) \
83 X(PostfixExpr) \
84 X(ConditionalExpr) \
85 X(MemberExpr) \
86 X(EnclosingExpr) \
87 X(CastExpr) \
88 X(SizeofParamPackExpr) \
89 X(CallExpr) \
90 X(NewExpr) \
91 X(DeleteExpr) \
92 X(PrefixExpr) \
93 X(FunctionParam) \
94 X(ConversionExpr) \
95 X(InitListExpr) \
96 X(FoldExpr) \
97 X(ThrowExpr) \
98 X(UUIDOfExpr) \
99 X(BoolExpr) \
100 X(StringLiteral) \
101 X(LambdaExpr) \
102 X(IntegerCastExpr) \
103 X(IntegerLiteral) \
104 X(FloatLiteral) \
105 X(DoubleLiteral) \
106 X(LongDoubleLiteral) \
107 X(BracedExpr) \
108 X(BracedRangeExpr)
109
110DEMANGLE_NAMESPACE_BEGIN 35DEMANGLE_NAMESPACE_BEGIN
111 36
37template <class T, size_t N> class PODSmallVector {
38 static_assert(std::is_pod<T>::value,
39 "T is required to be a plain old data type");
40
41 T *First = nullptr;
42 T *Last = nullptr;
43 T *Cap = nullptr;
44 T Inline[N] = {0};
45
46 bool isInline() const { return First == Inline; }
47
48 void clearInline() {
49 First = Inline;
50 Last = Inline;
51 Cap = Inline + N;
52 }
53
54 void reserve(size_t NewCap) {
55 size_t S = size();
56 if (isInline()) {
57 auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T)));
58 if (Tmp == nullptr)
59 std::terminate();
60 std::copy(First, Last, Tmp);
61 First = Tmp;
62 } else {
63 First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T)));
64 if (First == nullptr)
65 std::terminate();
66 }
67 Last = First + S;
68 Cap = First + NewCap;
69 }
70
71public:
72 PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
73
74 PODSmallVector(const PODSmallVector &) = delete;
75 PODSmallVector &operator=(const PODSmallVector &) = delete;
76
77 PODSmallVector(PODSmallVector &&Other) : PODSmallVector() {
78 if (Other.isInline()) {
79 std::copy(Other.begin(), Other.end(), First);
80 Last = First + Other.size();
81 Other.clear();
82 return;
83 }
84
85 First = Other.First;
86 Last = Other.Last;
87 Cap = Other.Cap;
88 Other.clearInline();
89 }
90
91 PODSmallVector &operator=(PODSmallVector &&Other) {
92 if (Other.isInline()) {
93 if (!isInline()) {
94 std::free(First);
95 clearInline();
96 }
97 std::copy(Other.begin(), Other.end(), First);
98 Last = First + Other.size();
99 Other.clear();
100 return *this;
101 }
102
103 if (isInline()) {
104 First = Other.First;
105 Last = Other.Last;
106 Cap = Other.Cap;
107 Other.clearInline();
108 return *this;
109 }
110
111 std::swap(First, Other.First);
112 std::swap(Last, Other.Last);
113 std::swap(Cap, Other.Cap);
114 Other.clear();
115 return *this;
116 }
117
118 // NOLINTNEXTLINE(readability-identifier-naming)
119 void push_back(const T &Elem) {
120 if (Last == Cap)
121 reserve(size() * 2);
122 *Last++ = Elem;
123 }
124
125 // NOLINTNEXTLINE(readability-identifier-naming)
126 void pop_back() {
127 assert(Last != First && "Popping empty vector!");
128 --Last;
129 }
130
131 void dropBack(size_t Index) {
132 assert(Index <= size() && "dropBack() can't expand!");
133 Last = First + Index;
134 }
135
136 T *begin() { return First; }
137 T *end() { return Last; }
138
139 bool empty() const { return First == Last; }
140 size_t size() const { return static_cast<size_t>(Last - First); }
141 T &back() {
142 assert(Last != First && "Calling back() on empty vector!");
143 return *(Last - 1);
144 }
145 T &operator[](size_t Index) {
146 assert(Index < size() && "Invalid access!");
147 return *(begin() + Index);
148 }
149 void clear() { Last = First; }
150
151 ~PODSmallVector() {
152 if (!isInline())
153 std::free(First);
154 }
155};
156
112// Base class of all AST nodes. The AST is built by the parser, then is 157// Base class of all AST nodes. The AST is built by the parser, then is
113// traversed by the printLeft/Right functions to produce a demangled string. 158// traversed by the printLeft/Right functions to produce a demangled string.
114class Node { 159class Node {
115public: 160public:
116 enum Kind : unsigned char { 161 enum Kind : unsigned char {
117#define ENUMERATOR(NodeKind) K ## NodeKind, 162#define NODE(NodeKind) K##NodeKind,
118 FOR_EACH_NODE_KIND(ENUMERATOR) 163#include "ItaniumNodes.def"
119#undef ENUMERATOR
120 }; 164 };
121 165
122 /// Three-way bool to track a cached value. Unknown is possible if this node 166 /// Three-way bool to track a cached value. Unknown is possible if this node
123 /// has an unexpanded parameter pack below it that may affect this cache. 167 /// has an unexpanded parameter pack below it that may affect this cache.
124 enum class Cache : unsigned char { Yes, No, Unknown, }; 168 enum class Cache : unsigned char { Yes, No, Unknown, };
125 169
170 /// Operator precedence for expression nodes. Used to determine required
171 /// parens in expression emission.
172 enum class Prec {
173 Primary,
174 Postfix,
175 Unary,
176 Cast,
177 PtrMem,
178 Multiplicative,
179 Additive,
180 Shift,
181 Spaceship,
182 Relational,
183 Equality,
184 And,
185 Xor,
186 Ior,
187 AndIf,
188 OrIf,
189 Conditional,
190 Assign,
191 Comma,
192 Default,
193 };
194
126private: 195private:
127 Kind K; 196 Kind K;
128 197
198 Prec Precedence : 6;
199
129 // FIXME: Make these protected. 200 // FIXME: Make these protected.
130public: 201public:
131 /// Tracks if this node has a component on its right side, in which case we 202 /// Tracks if this node has a component on its right side, in which case we
132 /// need to call printRight. 203 /// need to call printRight.
133 Cache RHSComponentCache; 204 Cache RHSComponentCache : 2;
134 205
135 /// Track if this node is a (possibly qualified) array type. This can affect 206 /// Track if this node is a (possibly qualified) array type. This can affect
136 /// how we format the output string. 207 /// how we format the output string.
137 Cache ArrayCache; 208 Cache ArrayCache : 2;
138 209
139 /// Track if this node is a (possibly qualified) function type. This can 210 /// Track if this node is a (possibly qualified) function type. This can
140 /// affect how we format the output string. 211 /// affect how we format the output string.
141 Cache FunctionCache; 212 Cache FunctionCache : 2;
142 213
143public: 214public:
144 Node(Kind K_, Cache RHSComponentCache_ = Cache::No, 215 Node(Kind K_, Prec Precedence_ = Prec::Primary,
145 Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) 216 Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No,
146 : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), 217 Cache FunctionCache_ = Cache::No)
147 FunctionCache(FunctionCache_) {} 218 : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_),
219 ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {}
220 Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No,
221 Cache FunctionCache_ = Cache::No)
222 : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_,
223 FunctionCache_) {}
148 224
149 /// Visit the most-derived object corresponding to this object. 225 /// Visit the most-derived object corresponding to this object.
150 template<typename Fn> void visit(Fn F) const; 226 template<typename Fn> void visit(Fn F) const;
@@ -155,52 +231,65 @@ public:
155 // would construct an equivalent node. 231 // would construct an equivalent node.
156 //template<typename Fn> void match(Fn F) const; 232 //template<typename Fn> void match(Fn F) const;
157 233
158 bool hasRHSComponent(OutputStream &S) const { 234 bool hasRHSComponent(OutputBuffer &OB) const {
159 if (RHSComponentCache != Cache::Unknown) 235 if (RHSComponentCache != Cache::Unknown)
160 return RHSComponentCache == Cache::Yes; 236 return RHSComponentCache == Cache::Yes;
161 return hasRHSComponentSlow(S); 237 return hasRHSComponentSlow(OB);
162 } 238 }
163 239
164 bool hasArray(OutputStream &S) const { 240 bool hasArray(OutputBuffer &OB) const {
165 if (ArrayCache != Cache::Unknown) 241 if (ArrayCache != Cache::Unknown)
166 return ArrayCache == Cache::Yes; 242 return ArrayCache == Cache::Yes;
167 return hasArraySlow(S); 243 return hasArraySlow(OB);
168 } 244 }
169 245
170 bool hasFunction(OutputStream &S) const { 246 bool hasFunction(OutputBuffer &OB) const {
171 if (FunctionCache != Cache::Unknown) 247 if (FunctionCache != Cache::Unknown)
172 return FunctionCache == Cache::Yes; 248 return FunctionCache == Cache::Yes;
173 return hasFunctionSlow(S); 249 return hasFunctionSlow(OB);
174 } 250 }
175 251
176 Kind getKind() const { return K; } 252 Kind getKind() const { return K; }
177 253
178 virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } 254 Prec getPrecedence() const { return Precedence; }
179 virtual bool hasArraySlow(OutputStream &) const { return false; } 255
180 virtual bool hasFunctionSlow(OutputStream &) const { return false; } 256 virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; }
257 virtual bool hasArraySlow(OutputBuffer &) const { return false; }
258 virtual bool hasFunctionSlow(OutputBuffer &) const { return false; }
181 259
182 // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to 260 // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to
183 // get at a node that actually represents some concrete syntax. 261 // get at a node that actually represents some concrete syntax.
184 virtual const Node *getSyntaxNode(OutputStream &) const { 262 virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; }
185 return this; 263
186 } 264 // Print this node as an expression operand, surrounding it in parentheses if
187 265 // its precedence is [Strictly] weaker than P.
188 void print(OutputStream &S) const { 266 void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default,
189 printLeft(S); 267 bool StrictlyWorse = false) const {
268 bool Paren =
269 unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse);
270 if (Paren)
271 OB.printOpen();
272 print(OB);
273 if (Paren)
274 OB.printClose();
275 }
276
277 void print(OutputBuffer &OB) const {
278 printLeft(OB);
190 if (RHSComponentCache != Cache::No) 279 if (RHSComponentCache != Cache::No)
191 printRight(S); 280 printRight(OB);
192 } 281 }
193 282
194 // Print the "left" side of this Node into OutputStream. 283 // Print the "left" side of this Node into OutputBuffer.
195 virtual void printLeft(OutputStream &) const = 0; 284 virtual void printLeft(OutputBuffer &) const = 0;
196 285
197 // Print the "right". This distinction is necessary to represent C++ types 286 // Print the "right". This distinction is necessary to represent C++ types
198 // that appear on the RHS of their subtype, such as arrays or functions. 287 // that appear on the RHS of their subtype, such as arrays or functions.
199 // Since most types don't have such a component, provide a default 288 // Since most types don't have such a component, provide a default
200 // implementation. 289 // implementation.
201 virtual void printRight(OutputStream &) const {} 290 virtual void printRight(OutputBuffer &) const {}
202 291
203 virtual StringView getBaseName() const { return StringView(); } 292 virtual std::string_view getBaseName() const { return {}; }
204 293
205 // Silence compiler warnings, this dtor will never be called. 294 // Silence compiler warnings, this dtor will never be called.
206 virtual ~Node() = default; 295 virtual ~Node() = default;
@@ -227,19 +316,19 @@ public:
227 316
228 Node *operator[](size_t Idx) const { return Elements[Idx]; } 317 Node *operator[](size_t Idx) const { return Elements[Idx]; }
229 318
230 void printWithComma(OutputStream &S) const { 319 void printWithComma(OutputBuffer &OB) const {
231 bool FirstElement = true; 320 bool FirstElement = true;
232 for (size_t Idx = 0; Idx != NumElements; ++Idx) { 321 for (size_t Idx = 0; Idx != NumElements; ++Idx) {
233 size_t BeforeComma = S.getCurrentPosition(); 322 size_t BeforeComma = OB.getCurrentPosition();
234 if (!FirstElement) 323 if (!FirstElement)
235 S += ", "; 324 OB += ", ";
236 size_t AfterComma = S.getCurrentPosition(); 325 size_t AfterComma = OB.getCurrentPosition();
237 Elements[Idx]->print(S); 326 Elements[Idx]->printAsOperand(OB, Node::Prec::Comma);
238 327
239 // Elements[Idx] is an empty parameter pack expansion, we should erase the 328 // Elements[Idx] is an empty parameter pack expansion, we should erase the
240 // comma we just printed. 329 // comma we just printed.
241 if (AfterComma == S.getCurrentPosition()) { 330 if (AfterComma == OB.getCurrentPosition()) {
242 S.setCurrentPosition(BeforeComma); 331 OB.setCurrentPosition(BeforeComma);
243 continue; 332 continue;
244 } 333 }
245 334
@@ -254,43 +343,48 @@ struct NodeArrayNode : Node {
254 343
255 template<typename Fn> void match(Fn F) const { F(Array); } 344 template<typename Fn> void match(Fn F) const { F(Array); }
256 345
257 void printLeft(OutputStream &S) const override { 346 void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); }
258 Array.printWithComma(S);
259 }
260}; 347};
261 348
262class DotSuffix final : public Node { 349class DotSuffix final : public Node {
263 const Node *Prefix; 350 const Node *Prefix;
264 const StringView Suffix; 351 const std::string_view Suffix;
265 352
266public: 353public:
267 DotSuffix(const Node *Prefix_, StringView Suffix_) 354 DotSuffix(const Node *Prefix_, std::string_view Suffix_)
268 : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} 355 : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {}
269 356
270 template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); } 357 template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); }
271 358
272 void printLeft(OutputStream &s) const override { 359 void printLeft(OutputBuffer &OB) const override {
273 Prefix->print(s); 360 Prefix->print(OB);
274 s += " ("; 361 OB += " (";
275 s += Suffix; 362 OB += Suffix;
276 s += ")"; 363 OB += ")";
277 } 364 }
278}; 365};
279 366
280class VendorExtQualType final : public Node { 367class VendorExtQualType final : public Node {
281 const Node *Ty; 368 const Node *Ty;
282 StringView Ext; 369 std::string_view Ext;
370 const Node *TA;
283 371
284public: 372public:
285 VendorExtQualType(const Node *Ty_, StringView Ext_) 373 VendorExtQualType(const Node *Ty_, std::string_view Ext_, const Node *TA_)
286 : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} 374 : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {}
375
376 const Node *getTy() const { return Ty; }
377 std::string_view getExt() const { return Ext; }
378 const Node *getTA() const { return TA; }
287 379
288 template<typename Fn> void match(Fn F) const { F(Ty, Ext); } 380 template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); }
289 381
290 void printLeft(OutputStream &S) const override { 382 void printLeft(OutputBuffer &OB) const override {
291 Ty->print(S); 383 Ty->print(OB);
292 S += " "; 384 OB += " ";
293 S += Ext; 385 OB += Ext;
386 if (TA != nullptr)
387 TA->print(OB);
294 } 388 }
295}; 389};
296 390
@@ -316,13 +410,13 @@ protected:
316 const Qualifiers Quals; 410 const Qualifiers Quals;
317 const Node *Child; 411 const Node *Child;
318 412
319 void printQuals(OutputStream &S) const { 413 void printQuals(OutputBuffer &OB) const {
320 if (Quals & QualConst) 414 if (Quals & QualConst)
321 S += " const"; 415 OB += " const";
322 if (Quals & QualVolatile) 416 if (Quals & QualVolatile)
323 S += " volatile"; 417 OB += " volatile";
324 if (Quals & QualRestrict) 418 if (Quals & QualRestrict)
325 S += " restrict"; 419 OB += " restrict";
326 } 420 }
327 421
328public: 422public:
@@ -331,24 +425,27 @@ public:
331 Child_->ArrayCache, Child_->FunctionCache), 425 Child_->ArrayCache, Child_->FunctionCache),
332 Quals(Quals_), Child(Child_) {} 426 Quals(Quals_), Child(Child_) {}
333 427
428 Qualifiers getQuals() const { return Quals; }
429 const Node *getChild() const { return Child; }
430
334 template<typename Fn> void match(Fn F) const { F(Child, Quals); } 431 template<typename Fn> void match(Fn F) const { F(Child, Quals); }
335 432
336 bool hasRHSComponentSlow(OutputStream &S) const override { 433 bool hasRHSComponentSlow(OutputBuffer &OB) const override {
337 return Child->hasRHSComponent(S); 434 return Child->hasRHSComponent(OB);
338 } 435 }
339 bool hasArraySlow(OutputStream &S) const override { 436 bool hasArraySlow(OutputBuffer &OB) const override {
340 return Child->hasArray(S); 437 return Child->hasArray(OB);
341 } 438 }
342 bool hasFunctionSlow(OutputStream &S) const override { 439 bool hasFunctionSlow(OutputBuffer &OB) const override {
343 return Child->hasFunction(S); 440 return Child->hasFunction(OB);
344 } 441 }
345 442
346 void printLeft(OutputStream &S) const override { 443 void printLeft(OutputBuffer &OB) const override {
347 Child->printLeft(S); 444 Child->printLeft(OB);
348 printQuals(S); 445 printQuals(OB);
349 } 446 }
350 447
351 void printRight(OutputStream &S) const override { Child->printRight(S); } 448 void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
352}; 449};
353 450
354class ConversionOperatorType final : public Node { 451class ConversionOperatorType final : public Node {
@@ -360,74 +457,96 @@ public:
360 457
361 template<typename Fn> void match(Fn F) const { F(Ty); } 458 template<typename Fn> void match(Fn F) const { F(Ty); }
362 459
363 void printLeft(OutputStream &S) const override { 460 void printLeft(OutputBuffer &OB) const override {
364 S += "operator "; 461 OB += "operator ";
365 Ty->print(S); 462 Ty->print(OB);
366 } 463 }
367}; 464};
368 465
369class PostfixQualifiedType final : public Node { 466class PostfixQualifiedType final : public Node {
370 const Node *Ty; 467 const Node *Ty;
371 const StringView Postfix; 468 const std::string_view Postfix;
372 469
373public: 470public:
374 PostfixQualifiedType(Node *Ty_, StringView Postfix_) 471 PostfixQualifiedType(const Node *Ty_, std::string_view Postfix_)
375 : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} 472 : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
376 473
377 template<typename Fn> void match(Fn F) const { F(Ty, Postfix); } 474 template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
378 475
379 void printLeft(OutputStream &s) const override { 476 void printLeft(OutputBuffer &OB) const override {
380 Ty->printLeft(s); 477 Ty->printLeft(OB);
381 s += Postfix; 478 OB += Postfix;
382 } 479 }
383}; 480};
384 481
385class NameType final : public Node { 482class NameType final : public Node {
386 const StringView Name; 483 const std::string_view Name;
387 484
388public: 485public:
389 NameType(StringView Name_) : Node(KNameType), Name(Name_) {} 486 NameType(std::string_view Name_) : Node(KNameType), Name(Name_) {}
390 487
391 template<typename Fn> void match(Fn F) const { F(Name); } 488 template<typename Fn> void match(Fn F) const { F(Name); }
392 489
393 StringView getName() const { return Name; } 490 std::string_view getName() const { return Name; }
394 StringView getBaseName() const override { return Name; } 491 std::string_view getBaseName() const override { return Name; }
492
493 void printLeft(OutputBuffer &OB) const override { OB += Name; }
494};
495
496class BitIntType final : public Node {
497 const Node *Size;
498 bool Signed;
499
500public:
501 BitIntType(const Node *Size_, bool Signed_)
502 : Node(KBitIntType), Size(Size_), Signed(Signed_) {}
503
504 template <typename Fn> void match(Fn F) const { F(Size, Signed); }
395 505
396 void printLeft(OutputStream &s) const override { s += Name; } 506 void printLeft(OutputBuffer &OB) const override {
507 if (!Signed)
508 OB += "unsigned ";
509 OB += "_BitInt";
510 OB.printOpen();
511 Size->printAsOperand(OB);
512 OB.printClose();
513 }
397}; 514};
398 515
399class ElaboratedTypeSpefType : public Node { 516class ElaboratedTypeSpefType : public Node {
400 StringView Kind; 517 std::string_view Kind;
401 Node *Child; 518 Node *Child;
402public: 519public:
403 ElaboratedTypeSpefType(StringView Kind_, Node *Child_) 520 ElaboratedTypeSpefType(std::string_view Kind_, Node *Child_)
404 : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} 521 : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {}
405 522
406 template<typename Fn> void match(Fn F) const { F(Kind, Child); } 523 template<typename Fn> void match(Fn F) const { F(Kind, Child); }
407 524
408 void printLeft(OutputStream &S) const override { 525 void printLeft(OutputBuffer &OB) const override {
409 S += Kind; 526 OB += Kind;
410 S += ' '; 527 OB += ' ';
411 Child->print(S); 528 Child->print(OB);
412 } 529 }
413}; 530};
414 531
415struct AbiTagAttr : Node { 532struct AbiTagAttr : Node {
416 Node *Base; 533 Node *Base;
417 StringView Tag; 534 std::string_view Tag;
418 535
419 AbiTagAttr(Node* Base_, StringView Tag_) 536 AbiTagAttr(Node *Base_, std::string_view Tag_)
420 : Node(KAbiTagAttr, Base_->RHSComponentCache, 537 : Node(KAbiTagAttr, Base_->RHSComponentCache, Base_->ArrayCache,
421 Base_->ArrayCache, Base_->FunctionCache), 538 Base_->FunctionCache),
422 Base(Base_), Tag(Tag_) {} 539 Base(Base_), Tag(Tag_) {}
423 540
424 template<typename Fn> void match(Fn F) const { F(Base, Tag); } 541 template<typename Fn> void match(Fn F) const { F(Base, Tag); }
425 542
426 void printLeft(OutputStream &S) const override { 543 std::string_view getBaseName() const override { return Base->getBaseName(); }
427 Base->printLeft(S); 544
428 S += "[abi:"; 545 void printLeft(OutputBuffer &OB) const override {
429 S += Tag; 546 Base->printLeft(OB);
430 S += "]"; 547 OB += "[abi:";
548 OB += Tag;
549 OB += "]";
431 } 550 }
432}; 551};
433 552
@@ -439,21 +558,21 @@ public:
439 558
440 template<typename Fn> void match(Fn F) const { F(Conditions); } 559 template<typename Fn> void match(Fn F) const { F(Conditions); }
441 560
442 void printLeft(OutputStream &S) const override { 561 void printLeft(OutputBuffer &OB) const override {
443 S += " [enable_if:"; 562 OB += " [enable_if:";
444 Conditions.printWithComma(S); 563 Conditions.printWithComma(OB);
445 S += ']'; 564 OB += ']';
446 } 565 }
447}; 566};
448 567
449class ObjCProtoName : public Node { 568class ObjCProtoName : public Node {
450 const Node *Ty; 569 const Node *Ty;
451 StringView Protocol; 570 std::string_view Protocol;
452 571
453 friend class PointerType; 572 friend class PointerType;
454 573
455public: 574public:
456 ObjCProtoName(const Node *Ty_, StringView Protocol_) 575 ObjCProtoName(const Node *Ty_, std::string_view Protocol_)
457 : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} 576 : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
458 577
459 template<typename Fn> void match(Fn F) const { F(Ty, Protocol); } 578 template<typename Fn> void match(Fn F) const { F(Ty, Protocol); }
@@ -463,11 +582,11 @@ public:
463 static_cast<const NameType *>(Ty)->getName() == "objc_object"; 582 static_cast<const NameType *>(Ty)->getName() == "objc_object";
464 } 583 }
465 584
466 void printLeft(OutputStream &S) const override { 585 void printLeft(OutputBuffer &OB) const override {
467 Ty->print(S); 586 Ty->print(OB);
468 S += "<"; 587 OB += "<";
469 S += Protocol; 588 OB += Protocol;
470 S += ">"; 589 OB += ">";
471 } 590 }
472}; 591};
473 592
@@ -479,36 +598,38 @@ public:
479 : Node(KPointerType, Pointee_->RHSComponentCache), 598 : Node(KPointerType, Pointee_->RHSComponentCache),
480 Pointee(Pointee_) {} 599 Pointee(Pointee_) {}
481 600
601 const Node *getPointee() const { return Pointee; }
602
482 template<typename Fn> void match(Fn F) const { F(Pointee); } 603 template<typename Fn> void match(Fn F) const { F(Pointee); }
483 604
484 bool hasRHSComponentSlow(OutputStream &S) const override { 605 bool hasRHSComponentSlow(OutputBuffer &OB) const override {
485 return Pointee->hasRHSComponent(S); 606 return Pointee->hasRHSComponent(OB);
486 } 607 }
487 608
488 void printLeft(OutputStream &s) const override { 609 void printLeft(OutputBuffer &OB) const override {
489 // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. 610 // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
490 if (Pointee->getKind() != KObjCProtoName || 611 if (Pointee->getKind() != KObjCProtoName ||
491 !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { 612 !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
492 Pointee->printLeft(s); 613 Pointee->printLeft(OB);
493 if (Pointee->hasArray(s)) 614 if (Pointee->hasArray(OB))
494 s += " "; 615 OB += " ";
495 if (Pointee->hasArray(s) || Pointee->hasFunction(s)) 616 if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
496 s += "("; 617 OB += "(";
497 s += "*"; 618 OB += "*";
498 } else { 619 } else {
499 const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); 620 const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
500 s += "id<"; 621 OB += "id<";
501 s += objcProto->Protocol; 622 OB += objcProto->Protocol;
502 s += ">"; 623 OB += ">";
503 } 624 }
504 } 625 }
505 626
506 void printRight(OutputStream &s) const override { 627 void printRight(OutputBuffer &OB) const override {
507 if (Pointee->getKind() != KObjCProtoName || 628 if (Pointee->getKind() != KObjCProtoName ||
508 !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { 629 !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
509 if (Pointee->hasArray(s) || Pointee->hasFunction(s)) 630 if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
510 s += ")"; 631 OB += ")";
511 Pointee->printRight(s); 632 Pointee->printRight(OB);
512 } 633 }
513 } 634 }
514}; 635};
@@ -528,15 +649,30 @@ class ReferenceType : public Node {
528 // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The 649 // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The
529 // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any 650 // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any
530 // other combination collapses to a lvalue ref. 651 // other combination collapses to a lvalue ref.
531 std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const { 652 //
653 // A combination of a TemplateForwardReference and a back-ref Substitution
654 // from an ill-formed string may have created a cycle; use cycle detection to
655 // avoid looping forever.
656 std::pair<ReferenceKind, const Node *> collapse(OutputBuffer &OB) const {
532 auto SoFar = std::make_pair(RK, Pointee); 657 auto SoFar = std::make_pair(RK, Pointee);
658 // Track the chain of nodes for the Floyd's 'tortoise and hare'
659 // cycle-detection algorithm, since getSyntaxNode(S) is impure
660 PODSmallVector<const Node *, 8> Prev;
533 for (;;) { 661 for (;;) {
534 const Node *SN = SoFar.second->getSyntaxNode(S); 662 const Node *SN = SoFar.second->getSyntaxNode(OB);
535 if (SN->getKind() != KReferenceType) 663 if (SN->getKind() != KReferenceType)
536 break; 664 break;
537 auto *RT = static_cast<const ReferenceType *>(SN); 665 auto *RT = static_cast<const ReferenceType *>(SN);
538 SoFar.second = RT->Pointee; 666 SoFar.second = RT->Pointee;
539 SoFar.first = std::min(SoFar.first, RT->RK); 667 SoFar.first = std::min(SoFar.first, RT->RK);
668
669 // The middle of Prev is the 'slow' pointer moving at half speed
670 Prev.push_back(SoFar.second);
671 if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) {
672 // Cycle detected
673 SoFar.second = nullptr;
674 break;
675 }
540 } 676 }
541 return SoFar; 677 return SoFar;
542 } 678 }
@@ -548,31 +684,35 @@ public:
548 684
549 template<typename Fn> void match(Fn F) const { F(Pointee, RK); } 685 template<typename Fn> void match(Fn F) const { F(Pointee, RK); }
550 686
551 bool hasRHSComponentSlow(OutputStream &S) const override { 687 bool hasRHSComponentSlow(OutputBuffer &OB) const override {
552 return Pointee->hasRHSComponent(S); 688 return Pointee->hasRHSComponent(OB);
553 } 689 }
554 690
555 void printLeft(OutputStream &s) const override { 691 void printLeft(OutputBuffer &OB) const override {
556 if (Printing) 692 if (Printing)
557 return; 693 return;
558 SwapAndRestore<bool> SavePrinting(Printing, true); 694 ScopedOverride<bool> SavePrinting(Printing, true);
559 std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); 695 std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
560 Collapsed.second->printLeft(s); 696 if (!Collapsed.second)
561 if (Collapsed.second->hasArray(s)) 697 return;
562 s += " "; 698 Collapsed.second->printLeft(OB);
563 if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) 699 if (Collapsed.second->hasArray(OB))
564 s += "("; 700 OB += " ";
701 if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
702 OB += "(";
565 703
566 s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); 704 OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
567 } 705 }
568 void printRight(OutputStream &s) const override { 706 void printRight(OutputBuffer &OB) const override {
569 if (Printing) 707 if (Printing)
570 return; 708 return;
571 SwapAndRestore<bool> SavePrinting(Printing, true); 709 ScopedOverride<bool> SavePrinting(Printing, true);
572 std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); 710 std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
573 if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) 711 if (!Collapsed.second)
574 s += ")"; 712 return;
575 Collapsed.second->printRight(s); 713 if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
714 OB += ")";
715 Collapsed.second->printRight(OB);
576 } 716 }
577}; 717};
578 718
@@ -587,69 +727,33 @@ public:
587 727
588 template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); } 728 template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); }
589 729
590 bool hasRHSComponentSlow(OutputStream &S) const override { 730 bool hasRHSComponentSlow(OutputBuffer &OB) const override {
591 return MemberType->hasRHSComponent(S); 731 return MemberType->hasRHSComponent(OB);
592 } 732 }
593 733
594 void printLeft(OutputStream &s) const override { 734 void printLeft(OutputBuffer &OB) const override {
595 MemberType->printLeft(s); 735 MemberType->printLeft(OB);
596 if (MemberType->hasArray(s) || MemberType->hasFunction(s)) 736 if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
597 s += "("; 737 OB += "(";
598 else 738 else
599 s += " "; 739 OB += " ";
600 ClassType->print(s); 740 ClassType->print(OB);
601 s += "::*"; 741 OB += "::*";
602 }
603
604 void printRight(OutputStream &s) const override {
605 if (MemberType->hasArray(s) || MemberType->hasFunction(s))
606 s += ")";
607 MemberType->printRight(s);
608 }
609};
610
611class NodeOrString {
612 const void *First;
613 const void *Second;
614
615public:
616 /* implicit */ NodeOrString(StringView Str) {
617 const char *FirstChar = Str.begin();
618 const char *SecondChar = Str.end();
619 if (SecondChar == nullptr) {
620 assert(FirstChar == SecondChar);
621 ++FirstChar, ++SecondChar;
622 }
623 First = static_cast<const void *>(FirstChar);
624 Second = static_cast<const void *>(SecondChar);
625 } 742 }
626 743
627 /* implicit */ NodeOrString(Node *N) 744 void printRight(OutputBuffer &OB) const override {
628 : First(static_cast<const void *>(N)), Second(nullptr) {} 745 if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
629 NodeOrString() : First(nullptr), Second(nullptr) {} 746 OB += ")";
630 747 MemberType->printRight(OB);
631 bool isString() const { return Second && First; }
632 bool isNode() const { return First && !Second; }
633 bool isEmpty() const { return !First && !Second; }
634
635 StringView asString() const {
636 assert(isString());
637 return StringView(static_cast<const char *>(First),
638 static_cast<const char *>(Second));
639 }
640
641 const Node *asNode() const {
642 assert(isNode());
643 return static_cast<const Node *>(First);
644 } 748 }
645}; 749};
646 750
647class ArrayType final : public Node { 751class ArrayType final : public Node {
648 const Node *Base; 752 const Node *Base;
649 NodeOrString Dimension; 753 Node *Dimension;
650 754
651public: 755public:
652 ArrayType(const Node *Base_, NodeOrString Dimension_) 756 ArrayType(const Node *Base_, Node *Dimension_)
653 : Node(KArrayType, 757 : Node(KArrayType,
654 /*RHSComponentCache=*/Cache::Yes, 758 /*RHSComponentCache=*/Cache::Yes,
655 /*ArrayCache=*/Cache::Yes), 759 /*ArrayCache=*/Cache::Yes),
@@ -657,21 +761,19 @@ public:
657 761
658 template<typename Fn> void match(Fn F) const { F(Base, Dimension); } 762 template<typename Fn> void match(Fn F) const { F(Base, Dimension); }
659 763
660 bool hasRHSComponentSlow(OutputStream &) const override { return true; } 764 bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
661 bool hasArraySlow(OutputStream &) const override { return true; } 765 bool hasArraySlow(OutputBuffer &) const override { return true; }
662 766
663 void printLeft(OutputStream &S) const override { Base->printLeft(S); } 767 void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
664 768
665 void printRight(OutputStream &S) const override { 769 void printRight(OutputBuffer &OB) const override {
666 if (S.back() != ']') 770 if (OB.back() != ']')
667 S += " "; 771 OB += " ";
668 S += "["; 772 OB += "[";
669 if (Dimension.isString()) 773 if (Dimension)
670 S += Dimension.asString(); 774 Dimension->print(OB);
671 else if (Dimension.isNode()) 775 OB += "]";
672 Dimension.asNode()->print(S); 776 Base->printRight(OB);
673 S += "]";
674 Base->printRight(S);
675 } 777 }
676}; 778};
677 779
@@ -695,8 +797,8 @@ public:
695 F(Ret, Params, CVQuals, RefQual, ExceptionSpec); 797 F(Ret, Params, CVQuals, RefQual, ExceptionSpec);
696 } 798 }
697 799
698 bool hasRHSComponentSlow(OutputStream &) const override { return true; } 800 bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
699 bool hasFunctionSlow(OutputStream &) const override { return true; } 801 bool hasFunctionSlow(OutputBuffer &) const override { return true; }
700 802
701 // Handle C++'s ... quirky decl grammar by using the left & right 803 // Handle C++'s ... quirky decl grammar by using the left & right
702 // distinction. Consider: 804 // distinction. Consider:
@@ -705,32 +807,32 @@ public:
705 // that takes a char and returns an int. If we're trying to print f, start 807 // that takes a char and returns an int. If we're trying to print f, start
706 // by printing out the return types's left, then print our parameters, then 808 // by printing out the return types's left, then print our parameters, then
707 // finally print right of the return type. 809 // finally print right of the return type.
708 void printLeft(OutputStream &S) const override { 810 void printLeft(OutputBuffer &OB) const override {
709 Ret->printLeft(S); 811 Ret->printLeft(OB);
710 S += " "; 812 OB += " ";
711 } 813 }
712 814
713 void printRight(OutputStream &S) const override { 815 void printRight(OutputBuffer &OB) const override {
714 S += "("; 816 OB.printOpen();
715 Params.printWithComma(S); 817 Params.printWithComma(OB);
716 S += ")"; 818 OB.printClose();
717 Ret->printRight(S); 819 Ret->printRight(OB);
718 820
719 if (CVQuals & QualConst) 821 if (CVQuals & QualConst)
720 S += " const"; 822 OB += " const";
721 if (CVQuals & QualVolatile) 823 if (CVQuals & QualVolatile)
722 S += " volatile"; 824 OB += " volatile";
723 if (CVQuals & QualRestrict) 825 if (CVQuals & QualRestrict)
724 S += " restrict"; 826 OB += " restrict";
725 827
726 if (RefQual == FrefQualLValue) 828 if (RefQual == FrefQualLValue)
727 S += " &"; 829 OB += " &";
728 else if (RefQual == FrefQualRValue) 830 else if (RefQual == FrefQualRValue)
729 S += " &&"; 831 OB += " &&";
730 832
731 if (ExceptionSpec != nullptr) { 833 if (ExceptionSpec != nullptr) {
732 S += ' '; 834 OB += ' ';
733 ExceptionSpec->print(S); 835 ExceptionSpec->print(OB);
734 } 836 }
735 } 837 }
736}; 838};
@@ -742,10 +844,11 @@ public:
742 844
743 template<typename Fn> void match(Fn F) const { F(E); } 845 template<typename Fn> void match(Fn F) const { F(E); }
744 846
745 void printLeft(OutputStream &S) const override { 847 void printLeft(OutputBuffer &OB) const override {
746 S += "noexcept("; 848 OB += "noexcept";
747 E->print(S); 849 OB.printOpen();
748 S += ")"; 850 E->printAsOperand(OB);
851 OB.printClose();
749 } 852 }
750}; 853};
751 854
@@ -757,10 +860,11 @@ public:
757 860
758 template<typename Fn> void match(Fn F) const { F(Types); } 861 template<typename Fn> void match(Fn F) const { F(Types); }
759 862
760 void printLeft(OutputStream &S) const override { 863 void printLeft(OutputBuffer &OB) const override {
761 S += "throw("; 864 OB += "throw";
762 Types.printWithComma(S); 865 OB.printOpen();
763 S += ')'; 866 Types.printWithComma(OB);
867 OB.printClose();
764 } 868 }
765}; 869};
766 870
@@ -791,41 +895,41 @@ public:
791 NodeArray getParams() const { return Params; } 895 NodeArray getParams() const { return Params; }
792 const Node *getReturnType() const { return Ret; } 896 const Node *getReturnType() const { return Ret; }
793 897
794 bool hasRHSComponentSlow(OutputStream &) const override { return true; } 898 bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
795 bool hasFunctionSlow(OutputStream &) const override { return true; } 899 bool hasFunctionSlow(OutputBuffer &) const override { return true; }
796 900
797 const Node *getName() const { return Name; } 901 const Node *getName() const { return Name; }
798 902
799 void printLeft(OutputStream &S) const override { 903 void printLeft(OutputBuffer &OB) const override {
800 if (Ret) { 904 if (Ret) {
801 Ret->printLeft(S); 905 Ret->printLeft(OB);
802 if (!Ret->hasRHSComponent(S)) 906 if (!Ret->hasRHSComponent(OB))
803 S += " "; 907 OB += " ";
804 } 908 }
805 Name->print(S); 909 Name->print(OB);
806 } 910 }
807 911
808 void printRight(OutputStream &S) const override { 912 void printRight(OutputBuffer &OB) const override {
809 S += "("; 913 OB.printOpen();
810 Params.printWithComma(S); 914 Params.printWithComma(OB);
811 S += ")"; 915 OB.printClose();
812 if (Ret) 916 if (Ret)
813 Ret->printRight(S); 917 Ret->printRight(OB);
814 918
815 if (CVQuals & QualConst) 919 if (CVQuals & QualConst)
816 S += " const"; 920 OB += " const";
817 if (CVQuals & QualVolatile) 921 if (CVQuals & QualVolatile)
818 S += " volatile"; 922 OB += " volatile";
819 if (CVQuals & QualRestrict) 923 if (CVQuals & QualRestrict)
820 S += " restrict"; 924 OB += " restrict";
821 925
822 if (RefQual == FrefQualLValue) 926 if (RefQual == FrefQualLValue)
823 S += " &"; 927 OB += " &";
824 else if (RefQual == FrefQualRValue) 928 else if (RefQual == FrefQualRValue)
825 S += " &&"; 929 OB += " &&";
826 930
827 if (Attrs != nullptr) 931 if (Attrs != nullptr)
828 Attrs->print(S); 932 Attrs->print(OB);
829 } 933 }
830}; 934};
831 935
@@ -838,25 +942,25 @@ public:
838 942
839 template<typename Fn> void match(Fn F) const { F(OpName); } 943 template<typename Fn> void match(Fn F) const { F(OpName); }
840 944
841 void printLeft(OutputStream &S) const override { 945 void printLeft(OutputBuffer &OB) const override {
842 S += "operator\"\" "; 946 OB += "operator\"\" ";
843 OpName->print(S); 947 OpName->print(OB);
844 } 948 }
845}; 949};
846 950
847class SpecialName final : public Node { 951class SpecialName final : public Node {
848 const StringView Special; 952 const std::string_view Special;
849 const Node *Child; 953 const Node *Child;
850 954
851public: 955public:
852 SpecialName(StringView Special_, const Node *Child_) 956 SpecialName(std::string_view Special_, const Node *Child_)
853 : Node(KSpecialName), Special(Special_), Child(Child_) {} 957 : Node(KSpecialName), Special(Special_), Child(Child_) {}
854 958
855 template<typename Fn> void match(Fn F) const { F(Special, Child); } 959 template<typename Fn> void match(Fn F) const { F(Special, Child); }
856 960
857 void printLeft(OutputStream &S) const override { 961 void printLeft(OutputBuffer &OB) const override {
858 S += Special; 962 OB += Special;
859 Child->print(S); 963 Child->print(OB);
860 } 964 }
861}; 965};
862 966
@@ -871,11 +975,11 @@ public:
871 975
872 template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); } 976 template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); }
873 977
874 void printLeft(OutputStream &S) const override { 978 void printLeft(OutputBuffer &OB) const override {
875 S += "construction vtable for "; 979 OB += "construction vtable for ";
876 FirstType->print(S); 980 FirstType->print(OB);
877 S += "-in-"; 981 OB += "-in-";
878 SecondType->print(S); 982 SecondType->print(OB);
879 } 983 }
880}; 984};
881 985
@@ -888,12 +992,52 @@ struct NestedName : Node {
888 992
889 template<typename Fn> void match(Fn F) const { F(Qual, Name); } 993 template<typename Fn> void match(Fn F) const { F(Qual, Name); }
890 994
891 StringView getBaseName() const override { return Name->getBaseName(); } 995 std::string_view getBaseName() const override { return Name->getBaseName(); }
996
997 void printLeft(OutputBuffer &OB) const override {
998 Qual->print(OB);
999 OB += "::";
1000 Name->print(OB);
1001 }
1002};
1003
1004struct ModuleName : Node {
1005 ModuleName *Parent;
1006 Node *Name;
1007 bool IsPartition;
1008
1009 ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false)
1010 : Node(KModuleName), Parent(Parent_), Name(Name_),
1011 IsPartition(IsPartition_) {}
1012
1013 template <typename Fn> void match(Fn F) const {
1014 F(Parent, Name, IsPartition);
1015 }
1016
1017 void printLeft(OutputBuffer &OB) const override {
1018 if (Parent)
1019 Parent->print(OB);
1020 if (Parent || IsPartition)
1021 OB += IsPartition ? ':' : '.';
1022 Name->print(OB);
1023 }
1024};
1025
1026struct ModuleEntity : Node {
1027 ModuleName *Module;
1028 Node *Name;
1029
1030 ModuleEntity(ModuleName *Module_, Node *Name_)
1031 : Node(KModuleEntity), Module(Module_), Name(Name_) {}
1032
1033 template <typename Fn> void match(Fn F) const { F(Module, Name); }
1034
1035 std::string_view getBaseName() const override { return Name->getBaseName(); }
892 1036
893 void printLeft(OutputStream &S) const override { 1037 void printLeft(OutputBuffer &OB) const override {
894 Qual->print(S); 1038 Name->print(OB);
895 S += "::"; 1039 OB += '@';
896 Name->print(S); 1040 Module->print(OB);
897 } 1041 }
898}; 1042};
899 1043
@@ -906,10 +1050,10 @@ struct LocalName : Node {
906 1050
907 template<typename Fn> void match(Fn F) const { F(Encoding, Entity); } 1051 template<typename Fn> void match(Fn F) const { F(Encoding, Entity); }
908 1052
909 void printLeft(OutputStream &S) const override { 1053 void printLeft(OutputBuffer &OB) const override {
910 Encoding->print(S); 1054 Encoding->print(OB);
911 S += "::"; 1055 OB += "::";
912 Entity->print(S); 1056 Entity->print(OB);
913 } 1057 }
914}; 1058};
915 1059
@@ -924,51 +1068,66 @@ public:
924 1068
925 template<typename Fn> void match(Fn F) const { F(Qualifier, Name); } 1069 template<typename Fn> void match(Fn F) const { F(Qualifier, Name); }
926 1070
927 StringView getBaseName() const override { return Name->getBaseName(); } 1071 std::string_view getBaseName() const override { return Name->getBaseName(); }
928 1072
929 void printLeft(OutputStream &S) const override { 1073 void printLeft(OutputBuffer &OB) const override {
930 Qualifier->print(S); 1074 Qualifier->print(OB);
931 S += "::"; 1075 OB += "::";
932 Name->print(S); 1076 Name->print(OB);
933 } 1077 }
934}; 1078};
935 1079
936class VectorType final : public Node { 1080class VectorType final : public Node {
937 const Node *BaseType; 1081 const Node *BaseType;
938 const NodeOrString Dimension; 1082 const Node *Dimension;
939 1083
940public: 1084public:
941 VectorType(const Node *BaseType_, NodeOrString Dimension_) 1085 VectorType(const Node *BaseType_, const Node *Dimension_)
942 : Node(KVectorType), BaseType(BaseType_), 1086 : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {}
943 Dimension(Dimension_) {} 1087
1088 const Node *getBaseType() const { return BaseType; }
1089 const Node *getDimension() const { return Dimension; }
944 1090
945 template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } 1091 template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }
946 1092
947 void printLeft(OutputStream &S) const override { 1093 void printLeft(OutputBuffer &OB) const override {
948 BaseType->print(S); 1094 BaseType->print(OB);
949 S += " vector["; 1095 OB += " vector[";
950 if (Dimension.isNode()) 1096 if (Dimension)
951 Dimension.asNode()->print(S); 1097 Dimension->print(OB);
952 else if (Dimension.isString()) 1098 OB += "]";
953 S += Dimension.asString();
954 S += "]";
955 } 1099 }
956}; 1100};
957 1101
958class PixelVectorType final : public Node { 1102class PixelVectorType final : public Node {
959 const NodeOrString Dimension; 1103 const Node *Dimension;
960 1104
961public: 1105public:
962 PixelVectorType(NodeOrString Dimension_) 1106 PixelVectorType(const Node *Dimension_)
963 : Node(KPixelVectorType), Dimension(Dimension_) {} 1107 : Node(KPixelVectorType), Dimension(Dimension_) {}
964 1108
965 template<typename Fn> void match(Fn F) const { F(Dimension); } 1109 template<typename Fn> void match(Fn F) const { F(Dimension); }
966 1110
967 void printLeft(OutputStream &S) const override { 1111 void printLeft(OutputBuffer &OB) const override {
968 // FIXME: This should demangle as "vector pixel". 1112 // FIXME: This should demangle as "vector pixel".
969 S += "pixel vector["; 1113 OB += "pixel vector[";
970 S += Dimension.asString(); 1114 Dimension->print(OB);
971 S += "]"; 1115 OB += "]";
1116 }
1117};
1118
1119class BinaryFPType final : public Node {
1120 const Node *Dimension;
1121
1122public:
1123 BinaryFPType(const Node *Dimension_)
1124 : Node(KBinaryFPType), Dimension(Dimension_) {}
1125
1126 template<typename Fn> void match(Fn F) const { F(Dimension); }
1127
1128 void printLeft(OutputBuffer &OB) const override {
1129 OB += "_Float";
1130 Dimension->print(OB);
972 } 1131 }
973}; 1132};
974 1133
@@ -990,20 +1149,20 @@ public:
990 1149
991 template<typename Fn> void match(Fn F) const { F(Kind, Index); } 1150 template<typename Fn> void match(Fn F) const { F(Kind, Index); }
992 1151
993 void printLeft(OutputStream &S) const override { 1152 void printLeft(OutputBuffer &OB) const override {
994 switch (Kind) { 1153 switch (Kind) {
995 case TemplateParamKind::Type: 1154 case TemplateParamKind::Type:
996 S += "$T"; 1155 OB += "$T";
997 break; 1156 break;
998 case TemplateParamKind::NonType: 1157 case TemplateParamKind::NonType:
999 S += "$N"; 1158 OB += "$N";
1000 break; 1159 break;
1001 case TemplateParamKind::Template: 1160 case TemplateParamKind::Template:
1002 S += "$TT"; 1161 OB += "$TT";
1003 break; 1162 break;
1004 } 1163 }
1005 if (Index > 0) 1164 if (Index > 0)
1006 S << Index - 1; 1165 OB << Index - 1;
1007 } 1166 }
1008}; 1167};
1009 1168
@@ -1017,13 +1176,9 @@ public:
1017 1176
1018 template<typename Fn> void match(Fn F) const { F(Name); } 1177 template<typename Fn> void match(Fn F) const { F(Name); }
1019 1178
1020 void printLeft(OutputStream &S) const override { 1179 void printLeft(OutputBuffer &OB) const override { OB += "typename "; }
1021 S += "typename ";
1022 }
1023 1180
1024 void printRight(OutputStream &S) const override { 1181 void printRight(OutputBuffer &OB) const override { Name->print(OB); }
1025 Name->print(S);
1026 }
1027}; 1182};
1028 1183
1029/// A non-type template parameter declaration, 'int N'. 1184/// A non-type template parameter declaration, 'int N'.
@@ -1037,15 +1192,15 @@ public:
1037 1192
1038 template<typename Fn> void match(Fn F) const { F(Name, Type); } 1193 template<typename Fn> void match(Fn F) const { F(Name, Type); }
1039 1194
1040 void printLeft(OutputStream &S) const override { 1195 void printLeft(OutputBuffer &OB) const override {
1041 Type->printLeft(S); 1196 Type->printLeft(OB);
1042 if (!Type->hasRHSComponent(S)) 1197 if (!Type->hasRHSComponent(OB))
1043 S += " "; 1198 OB += " ";
1044 } 1199 }
1045 1200
1046 void printRight(OutputStream &S) const override { 1201 void printRight(OutputBuffer &OB) const override {
1047 Name->print(S); 1202 Name->print(OB);
1048 Type->printRight(S); 1203 Type->printRight(OB);
1049 } 1204 }
1050}; 1205};
1051 1206
@@ -1062,15 +1217,14 @@ public:
1062 1217
1063 template<typename Fn> void match(Fn F) const { F(Name, Params); } 1218 template<typename Fn> void match(Fn F) const { F(Name, Params); }
1064 1219
1065 void printLeft(OutputStream &S) const override { 1220 void printLeft(OutputBuffer &OB) const override {
1066 S += "template<"; 1221 ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
1067 Params.printWithComma(S); 1222 OB += "template<";
1068 S += "> typename "; 1223 Params.printWithComma(OB);
1224 OB += "> typename ";
1069 } 1225 }
1070 1226
1071 void printRight(OutputStream &S) const override { 1227 void printRight(OutputBuffer &OB) const override { Name->print(OB); }
1072 Name->print(S);
1073 }
1074}; 1228};
1075 1229
1076/// A template parameter pack declaration, 'typename ...T'. 1230/// A template parameter pack declaration, 'typename ...T'.
@@ -1083,14 +1237,12 @@ public:
1083 1237
1084 template<typename Fn> void match(Fn F) const { F(Param); } 1238 template<typename Fn> void match(Fn F) const { F(Param); }
1085 1239
1086 void printLeft(OutputStream &S) const override { 1240 void printLeft(OutputBuffer &OB) const override {
1087 Param->printLeft(S); 1241 Param->printLeft(OB);
1088 S += "..."; 1242 OB += "...";
1089 } 1243 }
1090 1244
1091 void printRight(OutputStream &S) const override { 1245 void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
1092 Param->printRight(S);
1093 }
1094}; 1246};
1095 1247
1096/// An unexpanded parameter pack (either in the expression or type context). If 1248/// An unexpanded parameter pack (either in the expression or type context). If
@@ -1104,11 +1256,12 @@ public:
1104class ParameterPack final : public Node { 1256class ParameterPack final : public Node {
1105 NodeArray Data; 1257 NodeArray Data;
1106 1258
1107 // Setup OutputStream for a pack expansion unless we're already expanding one. 1259 // Setup OutputBuffer for a pack expansion, unless we're already expanding
1108 void initializePackExpansion(OutputStream &S) const { 1260 // one.
1109 if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) { 1261 void initializePackExpansion(OutputBuffer &OB) const {
1110 S.CurrentPackMax = static_cast<unsigned>(Data.size()); 1262 if (OB.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
1111 S.CurrentPackIndex = 0; 1263 OB.CurrentPackMax = static_cast<unsigned>(Data.size());
1264 OB.CurrentPackIndex = 0;
1112 } 1265 }
1113 } 1266 }
1114 1267
@@ -1131,38 +1284,38 @@ public:
1131 1284
1132 template<typename Fn> void match(Fn F) const { F(Data); } 1285 template<typename Fn> void match(Fn F) const { F(Data); }
1133 1286
1134 bool hasRHSComponentSlow(OutputStream &S) const override { 1287 bool hasRHSComponentSlow(OutputBuffer &OB) const override {
1135 initializePackExpansion(S); 1288 initializePackExpansion(OB);
1136 size_t Idx = S.CurrentPackIndex; 1289 size_t Idx = OB.CurrentPackIndex;
1137 return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); 1290 return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB);
1138 } 1291 }
1139 bool hasArraySlow(OutputStream &S) const override { 1292 bool hasArraySlow(OutputBuffer &OB) const override {
1140 initializePackExpansion(S); 1293 initializePackExpansion(OB);
1141 size_t Idx = S.CurrentPackIndex; 1294 size_t Idx = OB.CurrentPackIndex;
1142 return Idx < Data.size() && Data[Idx]->hasArray(S); 1295 return Idx < Data.size() && Data[Idx]->hasArray(OB);
1143 } 1296 }
1144 bool hasFunctionSlow(OutputStream &S) const override { 1297 bool hasFunctionSlow(OutputBuffer &OB) const override {
1145 initializePackExpansion(S); 1298 initializePackExpansion(OB);
1146 size_t Idx = S.CurrentPackIndex; 1299 size_t Idx = OB.CurrentPackIndex;
1147 return Idx < Data.size() && Data[Idx]->hasFunction(S); 1300 return Idx < Data.size() && Data[Idx]->hasFunction(OB);
1148 } 1301 }
1149 const Node *getSyntaxNode(OutputStream &S) const override { 1302 const Node *getSyntaxNode(OutputBuffer &OB) const override {
1150 initializePackExpansion(S); 1303 initializePackExpansion(OB);
1151 size_t Idx = S.CurrentPackIndex; 1304 size_t Idx = OB.CurrentPackIndex;
1152 return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; 1305 return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this;
1153 } 1306 }
1154 1307
1155 void printLeft(OutputStream &S) const override { 1308 void printLeft(OutputBuffer &OB) const override {
1156 initializePackExpansion(S); 1309 initializePackExpansion(OB);
1157 size_t Idx = S.CurrentPackIndex; 1310 size_t Idx = OB.CurrentPackIndex;
1158 if (Idx < Data.size()) 1311 if (Idx < Data.size())
1159 Data[Idx]->printLeft(S); 1312 Data[Idx]->printLeft(OB);
1160 } 1313 }
1161 void printRight(OutputStream &S) const override { 1314 void printRight(OutputBuffer &OB) const override {
1162 initializePackExpansion(S); 1315 initializePackExpansion(OB);
1163 size_t Idx = S.CurrentPackIndex; 1316 size_t Idx = OB.CurrentPackIndex;
1164 if (Idx < Data.size()) 1317 if (Idx < Data.size())
1165 Data[Idx]->printRight(S); 1318 Data[Idx]->printRight(OB);
1166 } 1319 }
1167}; 1320};
1168 1321
@@ -1181,8 +1334,8 @@ public:
1181 1334
1182 NodeArray getElements() const { return Elements; } 1335 NodeArray getElements() const { return Elements; }
1183 1336
1184 void printLeft(OutputStream &S) const override { 1337 void printLeft(OutputBuffer &OB) const override {
1185 Elements.printWithComma(S); 1338 Elements.printWithComma(OB);
1186 } 1339 }
1187}; 1340};
1188 1341
@@ -1199,35 +1352,35 @@ public:
1199 1352
1200 const Node *getChild() const { return Child; } 1353 const Node *getChild() const { return Child; }
1201 1354
1202 void printLeft(OutputStream &S) const override { 1355 void printLeft(OutputBuffer &OB) const override {
1203 constexpr unsigned Max = std::numeric_limits<unsigned>::max(); 1356 constexpr unsigned Max = std::numeric_limits<unsigned>::max();
1204 SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max); 1357 ScopedOverride<unsigned> SavePackIdx(OB.CurrentPackIndex, Max);
1205 SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max); 1358 ScopedOverride<unsigned> SavePackMax(OB.CurrentPackMax, Max);
1206 size_t StreamPos = S.getCurrentPosition(); 1359 size_t StreamPos = OB.getCurrentPosition();
1207 1360
1208 // Print the first element in the pack. If Child contains a ParameterPack, 1361 // Print the first element in the pack. If Child contains a ParameterPack,
1209 // it will set up S.CurrentPackMax and print the first element. 1362 // it will set up S.CurrentPackMax and print the first element.
1210 Child->print(S); 1363 Child->print(OB);
1211 1364
1212 // No ParameterPack was found in Child. This can occur if we've found a pack 1365 // No ParameterPack was found in Child. This can occur if we've found a pack
1213 // expansion on a <function-param>. 1366 // expansion on a <function-param>.
1214 if (S.CurrentPackMax == Max) { 1367 if (OB.CurrentPackMax == Max) {
1215 S += "..."; 1368 OB += "...";
1216 return; 1369 return;
1217 } 1370 }
1218 1371
1219 // We found a ParameterPack, but it has no elements. Erase whatever we may 1372 // We found a ParameterPack, but it has no elements. Erase whatever we may
1220 // of printed. 1373 // of printed.
1221 if (S.CurrentPackMax == 0) { 1374 if (OB.CurrentPackMax == 0) {
1222 S.setCurrentPosition(StreamPos); 1375 OB.setCurrentPosition(StreamPos);
1223 return; 1376 return;
1224 } 1377 }
1225 1378
1226 // Else, iterate through the rest of the elements in the pack. 1379 // Else, iterate through the rest of the elements in the pack.
1227 for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { 1380 for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) {
1228 S += ", "; 1381 OB += ", ";
1229 S.CurrentPackIndex = I; 1382 OB.CurrentPackIndex = I;
1230 Child->print(S); 1383 Child->print(OB);
1231 } 1384 }
1232 } 1385 }
1233}; 1386};
@@ -1242,12 +1395,11 @@ public:
1242 1395
1243 NodeArray getParams() { return Params; } 1396 NodeArray getParams() { return Params; }
1244 1397
1245 void printLeft(OutputStream &S) const override { 1398 void printLeft(OutputBuffer &OB) const override {
1246 S += "<"; 1399 ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
1247 Params.printWithComma(S); 1400 OB += "<";
1248 if (S.back() == '>') 1401 Params.printWithComma(OB);
1249 S += " "; 1402 OB += ">";
1250 S += ">";
1251 } 1403 }
1252}; 1404};
1253 1405
@@ -1289,42 +1441,42 @@ struct ForwardTemplateReference : Node {
1289 // special handling. 1441 // special handling.
1290 template<typename Fn> void match(Fn F) const = delete; 1442 template<typename Fn> void match(Fn F) const = delete;
1291 1443
1292 bool hasRHSComponentSlow(OutputStream &S) const override { 1444 bool hasRHSComponentSlow(OutputBuffer &OB) const override {
1293 if (Printing) 1445 if (Printing)
1294 return false; 1446 return false;
1295 SwapAndRestore<bool> SavePrinting(Printing, true); 1447 ScopedOverride<bool> SavePrinting(Printing, true);
1296 return Ref->hasRHSComponent(S); 1448 return Ref->hasRHSComponent(OB);
1297 } 1449 }
1298 bool hasArraySlow(OutputStream &S) const override { 1450 bool hasArraySlow(OutputBuffer &OB) const override {
1299 if (Printing) 1451 if (Printing)
1300 return false; 1452 return false;
1301 SwapAndRestore<bool> SavePrinting(Printing, true); 1453 ScopedOverride<bool> SavePrinting(Printing, true);
1302 return Ref->hasArray(S); 1454 return Ref->hasArray(OB);
1303 } 1455 }
1304 bool hasFunctionSlow(OutputStream &S) const override { 1456 bool hasFunctionSlow(OutputBuffer &OB) const override {
1305 if (Printing) 1457 if (Printing)
1306 return false; 1458 return false;
1307 SwapAndRestore<bool> SavePrinting(Printing, true); 1459 ScopedOverride<bool> SavePrinting(Printing, true);
1308 return Ref->hasFunction(S); 1460 return Ref->hasFunction(OB);
1309 } 1461 }
1310 const Node *getSyntaxNode(OutputStream &S) const override { 1462 const Node *getSyntaxNode(OutputBuffer &OB) const override {
1311 if (Printing) 1463 if (Printing)
1312 return this; 1464 return this;
1313 SwapAndRestore<bool> SavePrinting(Printing, true); 1465 ScopedOverride<bool> SavePrinting(Printing, true);
1314 return Ref->getSyntaxNode(S); 1466 return Ref->getSyntaxNode(OB);
1315 } 1467 }
1316 1468
1317 void printLeft(OutputStream &S) const override { 1469 void printLeft(OutputBuffer &OB) const override {
1318 if (Printing) 1470 if (Printing)
1319 return; 1471 return;
1320 SwapAndRestore<bool> SavePrinting(Printing, true); 1472 ScopedOverride<bool> SavePrinting(Printing, true);
1321 Ref->printLeft(S); 1473 Ref->printLeft(OB);
1322 } 1474 }
1323 void printRight(OutputStream &S) const override { 1475 void printRight(OutputBuffer &OB) const override {
1324 if (Printing) 1476 if (Printing)
1325 return; 1477 return;
1326 SwapAndRestore<bool> SavePrinting(Printing, true); 1478 ScopedOverride<bool> SavePrinting(Printing, true);
1327 Ref->printRight(S); 1479 Ref->printRight(OB);
1328 } 1480 }
1329}; 1481};
1330 1482
@@ -1338,11 +1490,11 @@ struct NameWithTemplateArgs : Node {
1338 1490
1339 template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); } 1491 template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); }
1340 1492
1341 StringView getBaseName() const override { return Name->getBaseName(); } 1493 std::string_view getBaseName() const override { return Name->getBaseName(); }
1342 1494
1343 void printLeft(OutputStream &S) const override { 1495 void printLeft(OutputBuffer &OB) const override {
1344 Name->print(S); 1496 Name->print(OB);
1345 TemplateArgs->print(S); 1497 TemplateArgs->print(OB);
1346 } 1498 }
1347}; 1499};
1348 1500
@@ -1355,26 +1507,11 @@ public:
1355 1507
1356 template<typename Fn> void match(Fn F) const { F(Child); } 1508 template<typename Fn> void match(Fn F) const { F(Child); }
1357 1509
1358 StringView getBaseName() const override { return Child->getBaseName(); } 1510 std::string_view getBaseName() const override { return Child->getBaseName(); }
1359 1511
1360 void printLeft(OutputStream &S) const override { 1512 void printLeft(OutputBuffer &OB) const override {
1361 S += "::"; 1513 OB += "::";
1362 Child->print(S); 1514 Child->print(OB);
1363 }
1364};
1365
1366struct StdQualifiedName : Node {
1367 Node *Child;
1368
1369 StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
1370
1371 template<typename Fn> void match(Fn F) const { F(Child); }
1372
1373 StringView getBaseName() const override { return Child->getBaseName(); }
1374
1375 void printLeft(OutputStream &S) const override {
1376 S += "std::";
1377 Child->print(S);
1378 } 1515 }
1379}; 1516};
1380 1517
@@ -1387,109 +1524,81 @@ enum class SpecialSubKind {
1387 iostream, 1524 iostream,
1388}; 1525};
1389 1526
1390class ExpandedSpecialSubstitution final : public Node { 1527class SpecialSubstitution;
1528class ExpandedSpecialSubstitution : public Node {
1529protected:
1391 SpecialSubKind SSK; 1530 SpecialSubKind SSK;
1392 1531
1532 ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_)
1533 : Node(K_), SSK(SSK_) {}
1393public: 1534public:
1394 ExpandedSpecialSubstitution(SpecialSubKind SSK_) 1535 ExpandedSpecialSubstitution(SpecialSubKind SSK_)
1395 : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} 1536 : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {}
1537 inline ExpandedSpecialSubstitution(SpecialSubstitution const *);
1396 1538
1397 template<typename Fn> void match(Fn F) const { F(SSK); } 1539 template<typename Fn> void match(Fn F) const { F(SSK); }
1398 1540
1399 StringView getBaseName() const override { 1541protected:
1542 bool isInstantiation() const {
1543 return unsigned(SSK) >= unsigned(SpecialSubKind::string);
1544 }
1545
1546 std::string_view getBaseName() const override {
1400 switch (SSK) { 1547 switch (SSK) {
1401 case SpecialSubKind::allocator: 1548 case SpecialSubKind::allocator:
1402 return StringView("allocator"); 1549 return {"allocator"};
1403 case SpecialSubKind::basic_string: 1550 case SpecialSubKind::basic_string:
1404 return StringView("basic_string"); 1551 return {"basic_string"};
1405 case SpecialSubKind::string: 1552 case SpecialSubKind::string:
1406 return StringView("basic_string"); 1553 return {"basic_string"};
1407 case SpecialSubKind::istream: 1554 case SpecialSubKind::istream:
1408 return StringView("basic_istream"); 1555 return {"basic_istream"};
1409 case SpecialSubKind::ostream: 1556 case SpecialSubKind::ostream:
1410 return StringView("basic_ostream"); 1557 return {"basic_ostream"};
1411 case SpecialSubKind::iostream: 1558 case SpecialSubKind::iostream:
1412 return StringView("basic_iostream"); 1559 return {"basic_iostream"};
1413 } 1560 }
1414 DEMANGLE_UNREACHABLE; 1561 DEMANGLE_UNREACHABLE;
1415 } 1562 }
1416 1563
1417 void printLeft(OutputStream &S) const override { 1564private:
1418 switch (SSK) { 1565 void printLeft(OutputBuffer &OB) const override {
1419 case SpecialSubKind::allocator: 1566 OB << "std::" << getBaseName();
1420 S += "std::allocator"; 1567 if (isInstantiation()) {
1421 break; 1568 OB << "<char, std::char_traits<char>";
1422 case SpecialSubKind::basic_string: 1569 if (SSK == SpecialSubKind::string)
1423 S += "std::basic_string"; 1570 OB << ", std::allocator<char>";
1424 break; 1571 OB << ">";
1425 case SpecialSubKind::string:
1426 S += "std::basic_string<char, std::char_traits<char>, "
1427 "std::allocator<char> >";
1428 break;
1429 case SpecialSubKind::istream:
1430 S += "std::basic_istream<char, std::char_traits<char> >";
1431 break;
1432 case SpecialSubKind::ostream:
1433 S += "std::basic_ostream<char, std::char_traits<char> >";
1434 break;
1435 case SpecialSubKind::iostream:
1436 S += "std::basic_iostream<char, std::char_traits<char> >";
1437 break;
1438 } 1572 }
1439 } 1573 }
1440}; 1574};
1441 1575
1442class SpecialSubstitution final : public Node { 1576class SpecialSubstitution final : public ExpandedSpecialSubstitution {
1443public: 1577public:
1444 SpecialSubKind SSK;
1445
1446 SpecialSubstitution(SpecialSubKind SSK_) 1578 SpecialSubstitution(SpecialSubKind SSK_)
1447 : Node(KSpecialSubstitution), SSK(SSK_) {} 1579 : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {}
1448 1580
1449 template<typename Fn> void match(Fn F) const { F(SSK); } 1581 template<typename Fn> void match(Fn F) const { F(SSK); }
1450 1582
1451 StringView getBaseName() const override { 1583 std::string_view getBaseName() const override {
1452 switch (SSK) { 1584 std::string_view SV = ExpandedSpecialSubstitution::getBaseName();
1453 case SpecialSubKind::allocator: 1585 if (isInstantiation()) {
1454 return StringView("allocator"); 1586 // The instantiations are typedefs that drop the "basic_" prefix.
1455 case SpecialSubKind::basic_string: 1587 assert(llvm::itanium_demangle::starts_with(SV, "basic_"));
1456 return StringView("basic_string"); 1588 SV.remove_prefix(sizeof("basic_") - 1);
1457 case SpecialSubKind::string:
1458 return StringView("string");
1459 case SpecialSubKind::istream:
1460 return StringView("istream");
1461 case SpecialSubKind::ostream:
1462 return StringView("ostream");
1463 case SpecialSubKind::iostream:
1464 return StringView("iostream");
1465 } 1589 }
1466 DEMANGLE_UNREACHABLE; 1590 return SV;
1467 } 1591 }
1468 1592
1469 void printLeft(OutputStream &S) const override { 1593 void printLeft(OutputBuffer &OB) const override {
1470 switch (SSK) { 1594 OB << "std::" << getBaseName();
1471 case SpecialSubKind::allocator:
1472 S += "std::allocator";
1473 break;
1474 case SpecialSubKind::basic_string:
1475 S += "std::basic_string";
1476 break;
1477 case SpecialSubKind::string:
1478 S += "std::string";
1479 break;
1480 case SpecialSubKind::istream:
1481 S += "std::istream";
1482 break;
1483 case SpecialSubKind::ostream:
1484 S += "std::ostream";
1485 break;
1486 case SpecialSubKind::iostream:
1487 S += "std::iostream";
1488 break;
1489 }
1490 } 1595 }
1491}; 1596};
1492 1597
1598inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution(
1599 SpecialSubstitution const *SS)
1600 : ExpandedSpecialSubstitution(SS->SSK) {}
1601
1493class CtorDtorName final : public Node { 1602class CtorDtorName final : public Node {
1494 const Node *Basename; 1603 const Node *Basename;
1495 const bool IsDtor; 1604 const bool IsDtor;
@@ -1502,10 +1611,10 @@ public:
1502 1611
1503 template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); } 1612 template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
1504 1613
1505 void printLeft(OutputStream &S) const override { 1614 void printLeft(OutputBuffer &OB) const override {
1506 if (IsDtor) 1615 if (IsDtor)
1507 S += "~"; 1616 OB += "~";
1508 S += Basename->getBaseName(); 1617 OB += Basename->getBaseName();
1509 } 1618 }
1510}; 1619};
1511 1620
@@ -1517,35 +1626,36 @@ public:
1517 1626
1518 template<typename Fn> void match(Fn F) const { F(Base); } 1627 template<typename Fn> void match(Fn F) const { F(Base); }
1519 1628
1520 void printLeft(OutputStream &S) const override { 1629 void printLeft(OutputBuffer &OB) const override {
1521 S += "~"; 1630 OB += "~";
1522 Base->printLeft(S); 1631 Base->printLeft(OB);
1523 } 1632 }
1524}; 1633};
1525 1634
1526class UnnamedTypeName : public Node { 1635class UnnamedTypeName : public Node {
1527 const StringView Count; 1636 const std::string_view Count;
1528 1637
1529public: 1638public:
1530 UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} 1639 UnnamedTypeName(std::string_view Count_)
1640 : Node(KUnnamedTypeName), Count(Count_) {}
1531 1641
1532 template<typename Fn> void match(Fn F) const { F(Count); } 1642 template<typename Fn> void match(Fn F) const { F(Count); }
1533 1643
1534 void printLeft(OutputStream &S) const override { 1644 void printLeft(OutputBuffer &OB) const override {
1535 S += "'unnamed"; 1645 OB += "'unnamed";
1536 S += Count; 1646 OB += Count;
1537 S += "\'"; 1647 OB += "\'";
1538 } 1648 }
1539}; 1649};
1540 1650
1541class ClosureTypeName : public Node { 1651class ClosureTypeName : public Node {
1542 NodeArray TemplateParams; 1652 NodeArray TemplateParams;
1543 NodeArray Params; 1653 NodeArray Params;
1544 StringView Count; 1654 std::string_view Count;
1545 1655
1546public: 1656public:
1547 ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, 1657 ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
1548 StringView Count_) 1658 std::string_view Count_)
1549 : Node(KClosureTypeName), TemplateParams(TemplateParams_), 1659 : Node(KClosureTypeName), TemplateParams(TemplateParams_),
1550 Params(Params_), Count(Count_) {} 1660 Params(Params_), Count(Count_) {}
1551 1661
@@ -1553,22 +1663,23 @@ public:
1553 F(TemplateParams, Params, Count); 1663 F(TemplateParams, Params, Count);
1554 } 1664 }
1555 1665
1556 void printDeclarator(OutputStream &S) const { 1666 void printDeclarator(OutputBuffer &OB) const {
1557 if (!TemplateParams.empty()) { 1667 if (!TemplateParams.empty()) {
1558 S += "<"; 1668 ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
1559 TemplateParams.printWithComma(S); 1669 OB += "<";
1560 S += ">"; 1670 TemplateParams.printWithComma(OB);
1671 OB += ">";
1561 } 1672 }
1562 S += "("; 1673 OB.printOpen();
1563 Params.printWithComma(S); 1674 Params.printWithComma(OB);
1564 S += ")"; 1675 OB.printClose();
1565 } 1676 }
1566 1677
1567 void printLeft(OutputStream &S) const override { 1678 void printLeft(OutputBuffer &OB) const override {
1568 S += "\'lambda"; 1679 OB += "\'lambda";
1569 S += Count; 1680 OB += Count;
1570 S += "\'"; 1681 OB += "\'";
1571 printDeclarator(S); 1682 printDeclarator(OB);
1572 } 1683 }
1573}; 1684};
1574 1685
@@ -1580,10 +1691,10 @@ public:
1580 1691
1581 template<typename Fn> void match(Fn F) const { F(Bindings); } 1692 template<typename Fn> void match(Fn F) const { F(Bindings); }
1582 1693
1583 void printLeft(OutputStream &S) const override { 1694 void printLeft(OutputBuffer &OB) const override {
1584 S += '['; 1695 OB.printOpen('[');
1585 Bindings.printWithComma(S); 1696 Bindings.printWithComma(OB);
1586 S += ']'; 1697 OB.printClose(']');
1587 } 1698 }
1588}; 1699};
1589 1700
@@ -1591,32 +1702,35 @@ public:
1591 1702
1592class BinaryExpr : public Node { 1703class BinaryExpr : public Node {
1593 const Node *LHS; 1704 const Node *LHS;
1594 const StringView InfixOperator; 1705 const std::string_view InfixOperator;
1595 const Node *RHS; 1706 const Node *RHS;
1596 1707
1597public: 1708public:
1598 BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) 1709 BinaryExpr(const Node *LHS_, std::string_view InfixOperator_,
1599 : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { 1710 const Node *RHS_, Prec Prec_)
1600 } 1711 : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_),
1601 1712 RHS(RHS_) {}
1602 template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); } 1713
1603 1714 template <typename Fn> void match(Fn F) const {
1604 void printLeft(OutputStream &S) const override { 1715 F(LHS, InfixOperator, RHS, getPrecedence());
1605 // might be a template argument expression, then we need to disambiguate 1716 }
1606 // with parens. 1717
1607 if (InfixOperator == ">") 1718 void printLeft(OutputBuffer &OB) const override {
1608 S += "("; 1719 bool ParenAll = OB.isGtInsideTemplateArgs() &&
1609 1720 (InfixOperator == ">" || InfixOperator == ">>");
1610 S += "("; 1721 if (ParenAll)
1611 LHS->print(S); 1722 OB.printOpen();
1612 S += ") "; 1723 // Assignment is right associative, with special LHS precedence.
1613 S += InfixOperator; 1724 bool IsAssign = getPrecedence() == Prec::Assign;
1614 S += " ("; 1725 LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign);
1615 RHS->print(S); 1726 // No space before comma operator
1616 S += ")"; 1727 if (!(InfixOperator == ","))
1617 1728 OB += " ";
1618 if (InfixOperator == ">") 1729 OB += InfixOperator;
1619 S += ")"; 1730 OB += " ";
1731 RHS->printAsOperand(OB, getPrecedence(), IsAssign);
1732 if (ParenAll)
1733 OB.printClose();
1620 } 1734 }
1621}; 1735};
1622 1736
@@ -1625,35 +1739,36 @@ class ArraySubscriptExpr : public Node {
1625 const Node *Op2; 1739 const Node *Op2;
1626 1740
1627public: 1741public:
1628 ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) 1742 ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_)
1629 : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} 1743 : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {}
1630 1744
1631 template<typename Fn> void match(Fn F) const { F(Op1, Op2); } 1745 template <typename Fn> void match(Fn F) const {
1746 F(Op1, Op2, getPrecedence());
1747 }
1632 1748
1633 void printLeft(OutputStream &S) const override { 1749 void printLeft(OutputBuffer &OB) const override {
1634 S += "("; 1750 Op1->printAsOperand(OB, getPrecedence());
1635 Op1->print(S); 1751 OB.printOpen('[');
1636 S += ")["; 1752 Op2->printAsOperand(OB);
1637 Op2->print(S); 1753 OB.printClose(']');
1638 S += "]";
1639 } 1754 }
1640}; 1755};
1641 1756
1642class PostfixExpr : public Node { 1757class PostfixExpr : public Node {
1643 const Node *Child; 1758 const Node *Child;
1644 const StringView Operator; 1759 const std::string_view Operator;
1645 1760
1646public: 1761public:
1647 PostfixExpr(const Node *Child_, StringView Operator_) 1762 PostfixExpr(const Node *Child_, std::string_view Operator_, Prec Prec_)
1648 : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} 1763 : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {}
1649 1764
1650 template<typename Fn> void match(Fn F) const { F(Child, Operator); } 1765 template <typename Fn> void match(Fn F) const {
1766 F(Child, Operator, getPrecedence());
1767 }
1651 1768
1652 void printLeft(OutputStream &S) const override { 1769 void printLeft(OutputBuffer &OB) const override {
1653 S += "("; 1770 Child->printAsOperand(OB, getPrecedence(), true);
1654 Child->print(S); 1771 OB += Operator;
1655 S += ")";
1656 S += Operator;
1657 } 1772 }
1658}; 1773};
1659 1774
@@ -1663,78 +1778,128 @@ class ConditionalExpr : public Node {
1663 const Node *Else; 1778 const Node *Else;
1664 1779
1665public: 1780public:
1666 ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) 1781 ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_,
1667 : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} 1782 Prec Prec_)
1783 : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {}
1668 1784
1669 template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); } 1785 template <typename Fn> void match(Fn F) const {
1786 F(Cond, Then, Else, getPrecedence());
1787 }
1670 1788
1671 void printLeft(OutputStream &S) const override { 1789 void printLeft(OutputBuffer &OB) const override {
1672 S += "("; 1790 Cond->printAsOperand(OB, getPrecedence());
1673 Cond->print(S); 1791 OB += " ? ";
1674 S += ") ? ("; 1792 Then->printAsOperand(OB);
1675 Then->print(S); 1793 OB += " : ";
1676 S += ") : ("; 1794 Else->printAsOperand(OB, Prec::Assign, true);
1677 Else->print(S);
1678 S += ")";
1679 } 1795 }
1680}; 1796};
1681 1797
1682class MemberExpr : public Node { 1798class MemberExpr : public Node {
1683 const Node *LHS; 1799 const Node *LHS;
1684 const StringView Kind; 1800 const std::string_view Kind;
1685 const Node *RHS; 1801 const Node *RHS;
1686 1802
1687public: 1803public:
1688 MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) 1804 MemberExpr(const Node *LHS_, std::string_view Kind_, const Node *RHS_,
1689 : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} 1805 Prec Prec_)
1806 : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
1807
1808 template <typename Fn> void match(Fn F) const {
1809 F(LHS, Kind, RHS, getPrecedence());
1810 }
1811
1812 void printLeft(OutputBuffer &OB) const override {
1813 LHS->printAsOperand(OB, getPrecedence(), true);
1814 OB += Kind;
1815 RHS->printAsOperand(OB, getPrecedence(), false);
1816 }
1817};
1818
1819class SubobjectExpr : public Node {
1820 const Node *Type;
1821 const Node *SubExpr;
1822 std::string_view Offset;
1823 NodeArray UnionSelectors;
1824 bool OnePastTheEnd;
1690 1825
1691 template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); } 1826public:
1827 SubobjectExpr(const Node *Type_, const Node *SubExpr_,
1828 std::string_view Offset_, NodeArray UnionSelectors_,
1829 bool OnePastTheEnd_)
1830 : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_),
1831 UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {}
1692 1832
1693 void printLeft(OutputStream &S) const override { 1833 template<typename Fn> void match(Fn F) const {
1694 LHS->print(S); 1834 F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd);
1695 S += Kind; 1835 }
1696 RHS->print(S); 1836
1837 void printLeft(OutputBuffer &OB) const override {
1838 SubExpr->print(OB);
1839 OB += ".<";
1840 Type->print(OB);
1841 OB += " at offset ";
1842 if (Offset.empty()) {
1843 OB += "0";
1844 } else if (Offset[0] == 'n') {
1845 OB += "-";
1846 OB += std::string_view(Offset.data() + 1, Offset.size() - 1);
1847 } else {
1848 OB += Offset;
1849 }
1850 OB += ">";
1697 } 1851 }
1698}; 1852};
1699 1853
1700class EnclosingExpr : public Node { 1854class EnclosingExpr : public Node {
1701 const StringView Prefix; 1855 const std::string_view Prefix;
1702 const Node *Infix; 1856 const Node *Infix;
1703 const StringView Postfix; 1857 const std::string_view Postfix;
1704 1858
1705public: 1859public:
1706 EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) 1860 EnclosingExpr(std::string_view Prefix_, const Node *Infix_,
1707 : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), 1861 Prec Prec_ = Prec::Primary)
1708 Postfix(Postfix_) {} 1862 : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {}
1709 1863
1710 template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); } 1864 template <typename Fn> void match(Fn F) const {
1865 F(Prefix, Infix, getPrecedence());
1866 }
1711 1867
1712 void printLeft(OutputStream &S) const override { 1868 void printLeft(OutputBuffer &OB) const override {
1713 S += Prefix; 1869 OB += Prefix;
1714 Infix->print(S); 1870 OB.printOpen();
1715 S += Postfix; 1871 Infix->print(OB);
1872 OB.printClose();
1873 OB += Postfix;
1716 } 1874 }
1717}; 1875};
1718 1876
1719class CastExpr : public Node { 1877class CastExpr : public Node {
1720 // cast_kind<to>(from) 1878 // cast_kind<to>(from)
1721 const StringView CastKind; 1879 const std::string_view CastKind;
1722 const Node *To; 1880 const Node *To;
1723 const Node *From; 1881 const Node *From;
1724 1882
1725public: 1883public:
1726 CastExpr(StringView CastKind_, const Node *To_, const Node *From_) 1884 CastExpr(std::string_view CastKind_, const Node *To_, const Node *From_,
1727 : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} 1885 Prec Prec_)
1886 : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {}
1728 1887
1729 template<typename Fn> void match(Fn F) const { F(CastKind, To, From); } 1888 template <typename Fn> void match(Fn F) const {
1889 F(CastKind, To, From, getPrecedence());
1890 }
1730 1891
1731 void printLeft(OutputStream &S) const override { 1892 void printLeft(OutputBuffer &OB) const override {
1732 S += CastKind; 1893 OB += CastKind;
1733 S += "<"; 1894 {
1734 To->printLeft(S); 1895 ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
1735 S += ">("; 1896 OB += "<";
1736 From->printLeft(S); 1897 To->printLeft(OB);
1737 S += ")"; 1898 OB += ">";
1899 }
1900 OB.printOpen();
1901 From->printAsOperand(OB);
1902 OB.printClose();
1738 } 1903 }
1739}; 1904};
1740 1905
@@ -1747,11 +1912,12 @@ public:
1747 1912
1748 template<typename Fn> void match(Fn F) const { F(Pack); } 1913 template<typename Fn> void match(Fn F) const { F(Pack); }
1749 1914
1750 void printLeft(OutputStream &S) const override { 1915 void printLeft(OutputBuffer &OB) const override {
1751 S += "sizeof...("; 1916 OB += "sizeof...";
1917 OB.printOpen();
1752 ParameterPackExpansion PPE(Pack); 1918 ParameterPackExpansion PPE(Pack);
1753 PPE.printLeft(S); 1919 PPE.printLeft(OB);
1754 S += ")"; 1920 OB.printClose();
1755 } 1921 }
1756}; 1922};
1757 1923
@@ -1760,16 +1926,18 @@ class CallExpr : public Node {
1760 NodeArray Args; 1926 NodeArray Args;
1761 1927
1762public: 1928public:
1763 CallExpr(const Node *Callee_, NodeArray Args_) 1929 CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_)
1764 : Node(KCallExpr), Callee(Callee_), Args(Args_) {} 1930 : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {}
1765 1931
1766 template<typename Fn> void match(Fn F) const { F(Callee, Args); } 1932 template <typename Fn> void match(Fn F) const {
1933 F(Callee, Args, getPrecedence());
1934 }
1767 1935
1768 void printLeft(OutputStream &S) const override { 1936 void printLeft(OutputBuffer &OB) const override {
1769 Callee->print(S); 1937 Callee->print(OB);
1770 S += "("; 1938 OB.printOpen();
1771 Args.printWithComma(S); 1939 Args.printWithComma(OB);
1772 S += ")"; 1940 OB.printClose();
1773 } 1941 }
1774}; 1942};
1775 1943
@@ -1782,33 +1950,32 @@ class NewExpr : public Node {
1782 bool IsArray; // new[] ? 1950 bool IsArray; // new[] ?
1783public: 1951public:
1784 NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, 1952 NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
1785 bool IsArray_) 1953 bool IsArray_, Prec Prec_)
1786 : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), 1954 : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_),
1787 IsGlobal(IsGlobal_), IsArray(IsArray_) {} 1955 InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
1788 1956
1789 template<typename Fn> void match(Fn F) const { 1957 template<typename Fn> void match(Fn F) const {
1790 F(ExprList, Type, InitList, IsGlobal, IsArray); 1958 F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence());
1791 } 1959 }
1792 1960
1793 void printLeft(OutputStream &S) const override { 1961 void printLeft(OutputBuffer &OB) const override {
1794 if (IsGlobal) 1962 if (IsGlobal)
1795 S += "::operator "; 1963 OB += "::";
1796 S += "new"; 1964 OB += "new";
1797 if (IsArray) 1965 if (IsArray)
1798 S += "[]"; 1966 OB += "[]";
1799 S += ' ';
1800 if (!ExprList.empty()) { 1967 if (!ExprList.empty()) {
1801 S += "("; 1968 OB.printOpen();
1802 ExprList.printWithComma(S); 1969 ExprList.printWithComma(OB);
1803 S += ")"; 1970 OB.printClose();
1804 } 1971 }
1805 Type->print(S); 1972 OB += " ";
1973 Type->print(OB);
1806 if (!InitList.empty()) { 1974 if (!InitList.empty()) {
1807 S += "("; 1975 OB.printOpen();
1808 InitList.printWithComma(S); 1976 InitList.printWithComma(OB);
1809 S += ")"; 1977 OB.printClose();
1810 } 1978 }
1811
1812 } 1979 }
1813}; 1980};
1814 1981
@@ -1818,50 +1985,55 @@ class DeleteExpr : public Node {
1818 bool IsArray; 1985 bool IsArray;
1819 1986
1820public: 1987public:
1821 DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) 1988 DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_)
1822 : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} 1989 : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_),
1990 IsArray(IsArray_) {}
1823 1991
1824 template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); } 1992 template <typename Fn> void match(Fn F) const {
1993 F(Op, IsGlobal, IsArray, getPrecedence());
1994 }
1825 1995
1826 void printLeft(OutputStream &S) const override { 1996 void printLeft(OutputBuffer &OB) const override {
1827 if (IsGlobal) 1997 if (IsGlobal)
1828 S += "::"; 1998 OB += "::";
1829 S += "delete"; 1999 OB += "delete";
1830 if (IsArray) 2000 if (IsArray)
1831 S += "[] "; 2001 OB += "[]";
1832 Op->print(S); 2002 OB += ' ';
2003 Op->print(OB);
1833 } 2004 }
1834}; 2005};
1835 2006
1836class PrefixExpr : public Node { 2007class PrefixExpr : public Node {
1837 StringView Prefix; 2008 std::string_view Prefix;
1838 Node *Child; 2009 Node *Child;
1839 2010
1840public: 2011public:
1841 PrefixExpr(StringView Prefix_, Node *Child_) 2012 PrefixExpr(std::string_view Prefix_, Node *Child_, Prec Prec_)
1842 : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} 2013 : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {}
1843 2014
1844 template<typename Fn> void match(Fn F) const { F(Prefix, Child); } 2015 template <typename Fn> void match(Fn F) const {
2016 F(Prefix, Child, getPrecedence());
2017 }
1845 2018
1846 void printLeft(OutputStream &S) const override { 2019 void printLeft(OutputBuffer &OB) const override {
1847 S += Prefix; 2020 OB += Prefix;
1848 S += "("; 2021 Child->printAsOperand(OB, getPrecedence());
1849 Child->print(S);
1850 S += ")";
1851 } 2022 }
1852}; 2023};
1853 2024
1854class FunctionParam : public Node { 2025class FunctionParam : public Node {
1855 StringView Number; 2026 std::string_view Number;
1856 2027
1857public: 2028public:
1858 FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} 2029 FunctionParam(std::string_view Number_)
2030 : Node(KFunctionParam), Number(Number_) {}
1859 2031
1860 template<typename Fn> void match(Fn F) const { F(Number); } 2032 template<typename Fn> void match(Fn F) const { F(Number); }
1861 2033
1862 void printLeft(OutputStream &S) const override { 2034 void printLeft(OutputBuffer &OB) const override {
1863 S += "fp"; 2035 OB += "fp";
1864 S += Number; 2036 OB += Number;
1865 } 2037 }
1866}; 2038};
1867 2039
@@ -1870,17 +2042,45 @@ class ConversionExpr : public Node {
1870 NodeArray Expressions; 2042 NodeArray Expressions;
1871 2043
1872public: 2044public:
1873 ConversionExpr(const Node *Type_, NodeArray Expressions_) 2045 ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_)
1874 : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} 2046 : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {}
2047
2048 template <typename Fn> void match(Fn F) const {
2049 F(Type, Expressions, getPrecedence());
2050 }
2051
2052 void printLeft(OutputBuffer &OB) const override {
2053 OB.printOpen();
2054 Type->print(OB);
2055 OB.printClose();
2056 OB.printOpen();
2057 Expressions.printWithComma(OB);
2058 OB.printClose();
2059 }
2060};
2061
2062class PointerToMemberConversionExpr : public Node {
2063 const Node *Type;
2064 const Node *SubExpr;
2065 std::string_view Offset;
2066
2067public:
2068 PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_,
2069 std::string_view Offset_, Prec Prec_)
2070 : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_),
2071 SubExpr(SubExpr_), Offset(Offset_) {}
1875 2072
1876 template<typename Fn> void match(Fn F) const { F(Type, Expressions); } 2073 template <typename Fn> void match(Fn F) const {
2074 F(Type, SubExpr, Offset, getPrecedence());
2075 }
1877 2076
1878 void printLeft(OutputStream &S) const override { 2077 void printLeft(OutputBuffer &OB) const override {
1879 S += "("; 2078 OB.printOpen();
1880 Type->print(S); 2079 Type->print(OB);
1881 S += ")("; 2080 OB.printClose();
1882 Expressions.printWithComma(S); 2081 OB.printOpen();
1883 S += ")"; 2082 SubExpr->print(OB);
2083 OB.printClose();
1884 } 2084 }
1885}; 2085};
1886 2086
@@ -1893,12 +2093,12 @@ public:
1893 2093
1894 template<typename Fn> void match(Fn F) const { F(Ty, Inits); } 2094 template<typename Fn> void match(Fn F) const { F(Ty, Inits); }
1895 2095
1896 void printLeft(OutputStream &S) const override { 2096 void printLeft(OutputBuffer &OB) const override {
1897 if (Ty) 2097 if (Ty)
1898 Ty->print(S); 2098 Ty->print(OB);
1899 S += '{'; 2099 OB += '{';
1900 Inits.printWithComma(S); 2100 Inits.printWithComma(OB);
1901 S += '}'; 2101 OB += '}';
1902 } 2102 }
1903}; 2103};
1904 2104
@@ -1912,18 +2112,18 @@ public:
1912 2112
1913 template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); } 2113 template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); }
1914 2114
1915 void printLeft(OutputStream &S) const override { 2115 void printLeft(OutputBuffer &OB) const override {
1916 if (IsArray) { 2116 if (IsArray) {
1917 S += '['; 2117 OB += '[';
1918 Elem->print(S); 2118 Elem->print(OB);
1919 S += ']'; 2119 OB += ']';
1920 } else { 2120 } else {
1921 S += '.'; 2121 OB += '.';
1922 Elem->print(S); 2122 Elem->print(OB);
1923 } 2123 }
1924 if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) 2124 if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
1925 S += " = "; 2125 OB += " = ";
1926 Init->print(S); 2126 Init->print(OB);
1927 } 2127 }
1928}; 2128};
1929 2129
@@ -1937,25 +2137,25 @@ public:
1937 2137
1938 template<typename Fn> void match(Fn F) const { F(First, Last, Init); } 2138 template<typename Fn> void match(Fn F) const { F(First, Last, Init); }
1939 2139
1940 void printLeft(OutputStream &S) const override { 2140 void printLeft(OutputBuffer &OB) const override {
1941 S += '['; 2141 OB += '[';
1942 First->print(S); 2142 First->print(OB);
1943 S += " ... "; 2143 OB += " ... ";
1944 Last->print(S); 2144 Last->print(OB);
1945 S += ']'; 2145 OB += ']';
1946 if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) 2146 if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
1947 S += " = "; 2147 OB += " = ";
1948 Init->print(S); 2148 Init->print(OB);
1949 } 2149 }
1950}; 2150};
1951 2151
1952class FoldExpr : public Node { 2152class FoldExpr : public Node {
1953 const Node *Pack, *Init; 2153 const Node *Pack, *Init;
1954 StringView OperatorName; 2154 std::string_view OperatorName;
1955 bool IsLeftFold; 2155 bool IsLeftFold;
1956 2156
1957public: 2157public:
1958 FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, 2158 FoldExpr(bool IsLeftFold_, std::string_view OperatorName_, const Node *Pack_,
1959 const Node *Init_) 2159 const Node *Init_)
1960 : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), 2160 : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_),
1961 IsLeftFold(IsLeftFold_) {} 2161 IsLeftFold(IsLeftFold_) {}
@@ -1964,43 +2164,35 @@ public:
1964 F(IsLeftFold, OperatorName, Pack, Init); 2164 F(IsLeftFold, OperatorName, Pack, Init);
1965 } 2165 }
1966 2166
1967 void printLeft(OutputStream &S) const override { 2167 void printLeft(OutputBuffer &OB) const override {
1968 auto PrintPack = [&] { 2168 auto PrintPack = [&] {
1969 S += '('; 2169 OB.printOpen();
1970 ParameterPackExpansion(Pack).print(S); 2170 ParameterPackExpansion(Pack).print(OB);
1971 S += ')'; 2171 OB.printClose();
1972 }; 2172 };
1973 2173
1974 S += '('; 2174 OB.printOpen();
1975 2175 // Either '[init op ]... op pack' or 'pack op ...[ op init]'
1976 if (IsLeftFold) { 2176 // Refactored to '[(init|pack) op ]...[ op (pack|init)]'
1977 // init op ... op pack 2177 // Fold expr operands are cast-expressions
1978 if (Init != nullptr) { 2178 if (!IsLeftFold || Init != nullptr) {
1979 Init->print(S); 2179 // '(init|pack) op '
1980 S += ' '; 2180 if (IsLeftFold)
1981 S += OperatorName; 2181 Init->printAsOperand(OB, Prec::Cast, true);
1982 S += ' '; 2182 else
1983 } 2183 PrintPack();
1984 // ... op pack 2184 OB << " " << OperatorName << " ";
1985 S += "... "; 2185 }
1986 S += OperatorName; 2186 OB << "...";
1987 S += ' '; 2187 if (IsLeftFold || Init != nullptr) {
1988 PrintPack(); 2188 // ' op (init|pack)'
1989 } else { // !IsLeftFold 2189 OB << " " << OperatorName << " ";
1990 // pack op ... 2190 if (IsLeftFold)
1991 PrintPack(); 2191 PrintPack();
1992 S += ' '; 2192 else
1993 S += OperatorName; 2193 Init->printAsOperand(OB, Prec::Cast, true);
1994 S += " ...";
1995 // pack op ... op init
1996 if (Init != nullptr) {
1997 S += ' ';
1998 S += OperatorName;
1999 S += ' ';
2000 Init->print(S);
2001 }
2002 } 2194 }
2003 S += ')'; 2195 OB.printClose();
2004 } 2196 }
2005}; 2197};
2006 2198
@@ -2012,24 +2204,9 @@ public:
2012 2204
2013 template<typename Fn> void match(Fn F) const { F(Op); } 2205 template<typename Fn> void match(Fn F) const { F(Op); }
2014 2206
2015 void printLeft(OutputStream &S) const override { 2207 void printLeft(OutputBuffer &OB) const override {
2016 S += "throw "; 2208 OB += "throw ";
2017 Op->print(S); 2209 Op->print(OB);
2018 }
2019};
2020
2021// MSVC __uuidof extension, generated by clang in -fms-extensions mode.
2022class UUIDOfExpr : public Node {
2023 Node *Operand;
2024public:
2025 UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {}
2026
2027 template<typename Fn> void match(Fn F) const { F(Operand); }
2028
2029 void printLeft(OutputStream &S) const override {
2030 S << "__uuidof(";
2031 Operand->print(S);
2032 S << ")";
2033 } 2210 }
2034}; 2211};
2035 2212
@@ -2041,8 +2218,8 @@ public:
2041 2218
2042 template<typename Fn> void match(Fn F) const { F(Value); } 2219 template<typename Fn> void match(Fn F) const { F(Value); }
2043 2220
2044 void printLeft(OutputStream &S) const override { 2221 void printLeft(OutputBuffer &OB) const override {
2045 S += Value ? StringView("true") : StringView("false"); 2222 OB += Value ? std::string_view("true") : std::string_view("false");
2046 } 2223 }
2047}; 2224};
2048 2225
@@ -2054,10 +2231,10 @@ public:
2054 2231
2055 template<typename Fn> void match(Fn F) const { F(Type); } 2232 template<typename Fn> void match(Fn F) const { F(Type); }
2056 2233
2057 void printLeft(OutputStream &S) const override { 2234 void printLeft(OutputBuffer &OB) const override {
2058 S += "\"<"; 2235 OB += "\"<";
2059 Type->print(S); 2236 Type->print(OB);
2060 S += ">\""; 2237 OB += ">\"";
2061 } 2238 }
2062}; 2239};
2063 2240
@@ -2069,58 +2246,61 @@ public:
2069 2246
2070 template<typename Fn> void match(Fn F) const { F(Type); } 2247 template<typename Fn> void match(Fn F) const { F(Type); }
2071 2248
2072 void printLeft(OutputStream &S) const override { 2249 void printLeft(OutputBuffer &OB) const override {
2073 S += "[]"; 2250 OB += "[]";
2074 if (Type->getKind() == KClosureTypeName) 2251 if (Type->getKind() == KClosureTypeName)
2075 static_cast<const ClosureTypeName *>(Type)->printDeclarator(S); 2252 static_cast<const ClosureTypeName *>(Type)->printDeclarator(OB);
2076 S += "{...}"; 2253 OB += "{...}";
2077 } 2254 }
2078}; 2255};
2079 2256
2080class IntegerCastExpr : public Node { 2257class EnumLiteral : public Node {
2081 // ty(integer) 2258 // ty(integer)
2082 const Node *Ty; 2259 const Node *Ty;
2083 StringView Integer; 2260 std::string_view Integer;
2084 2261
2085public: 2262public:
2086 IntegerCastExpr(const Node *Ty_, StringView Integer_) 2263 EnumLiteral(const Node *Ty_, std::string_view Integer_)
2087 : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {} 2264 : Node(KEnumLiteral), Ty(Ty_), Integer(Integer_) {}
2088 2265
2089 template<typename Fn> void match(Fn F) const { F(Ty, Integer); } 2266 template<typename Fn> void match(Fn F) const { F(Ty, Integer); }
2090 2267
2091 void printLeft(OutputStream &S) const override { 2268 void printLeft(OutputBuffer &OB) const override {
2092 S += "("; 2269 OB.printOpen();
2093 Ty->print(S); 2270 Ty->print(OB);
2094 S += ")"; 2271 OB.printClose();
2095 S += Integer; 2272
2273 if (Integer[0] == 'n')
2274 OB << '-' << std::string_view(Integer.data() + 1, Integer.size() - 1);
2275 else
2276 OB << Integer;
2096 } 2277 }
2097}; 2278};
2098 2279
2099class IntegerLiteral : public Node { 2280class IntegerLiteral : public Node {
2100 StringView Type; 2281 std::string_view Type;
2101 StringView Value; 2282 std::string_view Value;
2102 2283
2103public: 2284public:
2104 IntegerLiteral(StringView Type_, StringView Value_) 2285 IntegerLiteral(std::string_view Type_, std::string_view Value_)
2105 : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} 2286 : Node(KIntegerLiteral), Type(Type_), Value(Value_) {}
2106 2287
2107 template<typename Fn> void match(Fn F) const { F(Type, Value); } 2288 template<typename Fn> void match(Fn F) const { F(Type, Value); }
2108 2289
2109 void printLeft(OutputStream &S) const override { 2290 void printLeft(OutputBuffer &OB) const override {
2110 if (Type.size() > 3) { 2291 if (Type.size() > 3) {
2111 S += "("; 2292 OB.printOpen();
2112 S += Type; 2293 OB += Type;
2113 S += ")"; 2294 OB.printClose();
2114 } 2295 }
2115 2296
2116 if (Value[0] == 'n') { 2297 if (Value[0] == 'n')
2117 S += "-"; 2298 OB << '-' << std::string_view(Value.data() + 1, Value.size() - 1);
2118 S += Value.dropFront(1); 2299 else
2119 } else 2300 OB += Value;
2120 S += Value;
2121 2301
2122 if (Type.size() <= 3) 2302 if (Type.size() <= 3)
2123 S += Type; 2303 OB += Type;
2124 } 2304 }
2125}; 2305};
2126 2306
@@ -2139,29 +2319,26 @@ constexpr Node::Kind getFloatLiteralKind(long double *) {
2139} 2319}
2140 2320
2141template <class Float> class FloatLiteralImpl : public Node { 2321template <class Float> class FloatLiteralImpl : public Node {
2142 const StringView Contents; 2322 const std::string_view Contents;
2143 2323
2144 static constexpr Kind KindForClass = 2324 static constexpr Kind KindForClass =
2145 float_literal_impl::getFloatLiteralKind((Float *)nullptr); 2325 float_literal_impl::getFloatLiteralKind((Float *)nullptr);
2146 2326
2147public: 2327public:
2148 FloatLiteralImpl(StringView Contents_) 2328 FloatLiteralImpl(std::string_view Contents_)
2149 : Node(KindForClass), Contents(Contents_) {} 2329 : Node(KindForClass), Contents(Contents_) {}
2150 2330
2151 template<typename Fn> void match(Fn F) const { F(Contents); } 2331 template<typename Fn> void match(Fn F) const { F(Contents); }
2152 2332
2153 void printLeft(OutputStream &s) const override { 2333 void printLeft(OutputBuffer &OB) const override {
2154 const char *first = Contents.begin();
2155 const char *last = Contents.end() + 1;
2156
2157 const size_t N = FloatData<Float>::mangled_size; 2334 const size_t N = FloatData<Float>::mangled_size;
2158 if (static_cast<std::size_t>(last - first) > N) { 2335 if (Contents.size() >= N) {
2159 last = first + N;
2160 union { 2336 union {
2161 Float value; 2337 Float value;
2162 char buf[sizeof(Float)]; 2338 char buf[sizeof(Float)];
2163 }; 2339 };
2164 const char *t = first; 2340 const char *t = Contents.data();
2341 const char *last = t + N;
2165 char *e = buf; 2342 char *e = buf;
2166 for (; t != last; ++t, ++e) { 2343 for (; t != last; ++t, ++e) {
2167 unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') 2344 unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
@@ -2176,7 +2353,7 @@ public:
2176#endif 2353#endif
2177 char num[FloatData<Float>::max_demangled_size] = {0}; 2354 char num[FloatData<Float>::max_demangled_size] = {0};
2178 int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); 2355 int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);
2179 s += StringView(num, num + n); 2356 OB += std::string_view(num, n);
2180 } 2357 }
2181 } 2358 }
2182}; 2359};
@@ -2190,143 +2367,22 @@ using LongDoubleLiteral = FloatLiteralImpl<long double>;
2190template<typename Fn> 2367template<typename Fn>
2191void Node::visit(Fn F) const { 2368void Node::visit(Fn F) const {
2192 switch (K) { 2369 switch (K) {
2193#define CASE(X) case K ## X: return F(static_cast<const X*>(this)); 2370#define NODE(X) \
2194 FOR_EACH_NODE_KIND(CASE) 2371 case K##X: \
2195#undef CASE 2372 return F(static_cast<const X *>(this));
2373#include "ItaniumNodes.def"
2196 } 2374 }
2197 assert(0 && "unknown mangling node kind"); 2375 assert(0 && "unknown mangling node kind");
2198} 2376}
2199 2377
2200/// Determine the kind of a node from its type. 2378/// Determine the kind of a node from its type.
2201template<typename NodeT> struct NodeKind; 2379template<typename NodeT> struct NodeKind;
2202#define SPECIALIZATION(X) \ 2380#define NODE(X) \
2203 template<> struct NodeKind<X> { \ 2381 template <> struct NodeKind<X> { \
2204 static constexpr Node::Kind Kind = Node::K##X; \ 2382 static constexpr Node::Kind Kind = Node::K##X; \
2205 static constexpr const char *name() { return #X; } \ 2383 static constexpr const char *name() { return #X; } \
2206 }; 2384 };
2207FOR_EACH_NODE_KIND(SPECIALIZATION) 2385#include "ItaniumNodes.def"
2208#undef SPECIALIZATION
2209
2210#undef FOR_EACH_NODE_KIND
2211
2212template <class T, size_t N>
2213class PODSmallVector {
2214 static_assert(std::is_pod<T>::value,
2215 "T is required to be a plain old data type");
2216
2217 T* First;
2218 T* Last;
2219 T* Cap;
2220 T Inline[N];
2221
2222 bool isInline() const { return First == Inline; }
2223
2224 void clearInline() {
2225 First = Inline;
2226 Last = Inline;
2227 Cap = Inline + N;
2228 }
2229
2230 void reserve(size_t NewCap) {
2231 size_t S = size();
2232 if (isInline()) {
2233 auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
2234 if (Tmp == nullptr)
2235 std::terminate();
2236 std::copy(First, Last, Tmp);
2237 First = Tmp;
2238 } else {
2239 First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
2240 if (First == nullptr)
2241 std::terminate();
2242 }
2243 Last = First + S;
2244 Cap = First + NewCap;
2245 }
2246
2247public:
2248 PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
2249
2250 PODSmallVector(const PODSmallVector&) = delete;
2251 PODSmallVector& operator=(const PODSmallVector&) = delete;
2252
2253 PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
2254 if (Other.isInline()) {
2255 std::copy(Other.begin(), Other.end(), First);
2256 Last = First + Other.size();
2257 Other.clear();
2258 return;
2259 }
2260
2261 First = Other.First;
2262 Last = Other.Last;
2263 Cap = Other.Cap;
2264 Other.clearInline();
2265 }
2266
2267 PODSmallVector& operator=(PODSmallVector&& Other) {
2268 if (Other.isInline()) {
2269 if (!isInline()) {
2270 std::free(First);
2271 clearInline();
2272 }
2273 std::copy(Other.begin(), Other.end(), First);
2274 Last = First + Other.size();
2275 Other.clear();
2276 return *this;
2277 }
2278
2279 if (isInline()) {
2280 First = Other.First;
2281 Last = Other.Last;
2282 Cap = Other.Cap;
2283 Other.clearInline();
2284 return *this;
2285 }
2286
2287 std::swap(First, Other.First);
2288 std::swap(Last, Other.Last);
2289 std::swap(Cap, Other.Cap);
2290 Other.clear();
2291 return *this;
2292 }
2293
2294 void push_back(const T& Elem) {
2295 if (Last == Cap)
2296 reserve(size() * 2);
2297 *Last++ = Elem;
2298 }
2299
2300 void pop_back() {
2301 assert(Last != First && "Popping empty vector!");
2302 --Last;
2303 }
2304
2305 void dropBack(size_t Index) {
2306 assert(Index <= size() && "dropBack() can't expand!");
2307 Last = First + Index;
2308 }
2309
2310 T* begin() { return First; }
2311 T* end() { return Last; }
2312
2313 bool empty() const { return First == Last; }
2314 size_t size() const { return static_cast<size_t>(Last - First); }
2315 T& back() {
2316 assert(Last != First && "Calling back() on empty vector!");
2317 return *(Last - 1);
2318 }
2319 T& operator[](size_t Index) {
2320 assert(Index < size() && "Invalid access!");
2321 return *(begin() + Index);
2322 }
2323 void clear() { Last = First; }
2324
2325 ~PODSmallVector() {
2326 if (!isInline())
2327 std::free(First);
2328 }
2329};
2330 2386
2331template <typename Derived, typename Alloc> struct AbstractManglingParser { 2387template <typename Derived, typename Alloc> struct AbstractManglingParser {
2332 const char *First; 2388 const char *First;
@@ -2350,9 +2406,9 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
2350 TemplateParamList Params; 2406 TemplateParamList Params;
2351 2407
2352 public: 2408 public:
2353 ScopedTemplateParamList(AbstractManglingParser *Parser) 2409 ScopedTemplateParamList(AbstractManglingParser *TheParser)
2354 : Parser(Parser), 2410 : Parser(TheParser),
2355 OldNumTemplateParamLists(Parser->TemplateParams.size()) { 2411 OldNumTemplateParamLists(TheParser->TemplateParams.size()) {
2356 Parser->TemplateParams.push_back(&Params); 2412 Parser->TemplateParams.push_back(&Params);
2357 } 2413 }
2358 ~ScopedTemplateParamList() { 2414 ~ScopedTemplateParamList() {
@@ -2424,8 +2480,9 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
2424 return res; 2480 return res;
2425 } 2481 }
2426 2482
2427 bool consumeIf(StringView S) { 2483 bool consumeIf(std::string_view S) {
2428 if (StringView(First, Last).startsWith(S)) { 2484 if (llvm::itanium_demangle::starts_with(
2485 std::string_view(First, Last - First), S)) {
2429 First += S.size(); 2486 First += S.size();
2430 return true; 2487 return true;
2431 } 2488 }
@@ -2442,7 +2499,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
2442 2499
2443 char consume() { return First != Last ? *First++ : '\0'; } 2500 char consume() { return First != Last ? *First++ : '\0'; }
2444 2501
2445 char look(unsigned Lookahead = 0) { 2502 char look(unsigned Lookahead = 0) const {
2446 if (static_cast<size_t>(Last - First) <= Lookahead) 2503 if (static_cast<size_t>(Last - First) <= Lookahead)
2447 return '\0'; 2504 return '\0';
2448 return First[Lookahead]; 2505 return First[Lookahead];
@@ -2450,10 +2507,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
2450 2507
2451 size_t numLeft() const { return static_cast<size_t>(Last - First); } 2508 size_t numLeft() const { return static_cast<size_t>(Last - First); }
2452 2509
2453 StringView parseNumber(bool AllowNegative = false); 2510 std::string_view parseNumber(bool AllowNegative = false);
2454 Qualifiers parseCVQualifiers(); 2511 Qualifiers parseCVQualifiers();
2455 bool parsePositiveInteger(size_t *Out); 2512 bool parsePositiveInteger(size_t *Out);
2456 StringView parseBareSourceName(); 2513 std::string_view parseBareSourceName();
2457 2514
2458 bool parseSeqId(size_t *Out); 2515 bool parseSeqId(size_t *Out);
2459 Node *parseSubstitution(); 2516 Node *parseSubstitution();
@@ -2464,16 +2521,17 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
2464 2521
2465 /// Parse the <expr> production. 2522 /// Parse the <expr> production.
2466 Node *parseExpr(); 2523 Node *parseExpr();
2467 Node *parsePrefixExpr(StringView Kind); 2524 Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec);
2468 Node *parseBinaryExpr(StringView Kind); 2525 Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec);
2469 Node *parseIntegerLiteral(StringView Lit); 2526 Node *parseIntegerLiteral(std::string_view Lit);
2470 Node *parseExprPrimary(); 2527 Node *parseExprPrimary();
2471 template <class Float> Node *parseFloatingLiteral(); 2528 template <class Float> Node *parseFloatingLiteral();
2472 Node *parseFunctionParam(); 2529 Node *parseFunctionParam();
2473 Node *parseNewExpr();
2474 Node *parseConversionExpr(); 2530 Node *parseConversionExpr();
2475 Node *parseBracedExpr(); 2531 Node *parseBracedExpr();
2476 Node *parseFoldExpr(); 2532 Node *parseFoldExpr();
2533 Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
2534 Node *parseSubobjectExpr();
2477 2535
2478 /// Parse the <type> production. 2536 /// Parse the <type> production.
2479 Node *parseType(); 2537 Node *parseType();
@@ -2520,17 +2578,81 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
2520 Node *parseName(NameState *State = nullptr); 2578 Node *parseName(NameState *State = nullptr);
2521 Node *parseLocalName(NameState *State); 2579 Node *parseLocalName(NameState *State);
2522 Node *parseOperatorName(NameState *State); 2580 Node *parseOperatorName(NameState *State);
2523 Node *parseUnqualifiedName(NameState *State); 2581 bool parseModuleNameOpt(ModuleName *&Module);
2582 Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module);
2524 Node *parseUnnamedTypeName(NameState *State); 2583 Node *parseUnnamedTypeName(NameState *State);
2525 Node *parseSourceName(NameState *State); 2584 Node *parseSourceName(NameState *State);
2526 Node *parseUnscopedName(NameState *State); 2585 Node *parseUnscopedName(NameState *State, bool *isSubstName);
2527 Node *parseNestedName(NameState *State); 2586 Node *parseNestedName(NameState *State);
2528 Node *parseCtorDtorName(Node *&SoFar, NameState *State); 2587 Node *parseCtorDtorName(Node *&SoFar, NameState *State);
2529 2588
2530 Node *parseAbiTags(Node *N); 2589 Node *parseAbiTags(Node *N);
2531 2590
2591 struct OperatorInfo {
2592 enum OIKind : unsigned char {
2593 Prefix, // Prefix unary: @ expr
2594 Postfix, // Postfix unary: expr @
2595 Binary, // Binary: lhs @ rhs
2596 Array, // Array index: lhs [ rhs ]
2597 Member, // Member access: lhs @ rhs
2598 New, // New
2599 Del, // Delete
2600 Call, // Function call: expr (expr*)
2601 CCast, // C cast: (type)expr
2602 Conditional, // Conditional: expr ? expr : expr
2603 NameOnly, // Overload only, not allowed in expression.
2604 // Below do not have operator names
2605 NamedCast, // Named cast, @<type>(expr)
2606 OfIdOp, // alignof, sizeof, typeid
2607
2608 Unnameable = NamedCast,
2609 };
2610 char Enc[2]; // Encoding
2611 OIKind Kind; // Kind of operator
2612 bool Flag : 1; // Entry-specific flag
2613 Node::Prec Prec : 7; // Precedence
2614 const char *Name; // Spelling
2615
2616 public:
2617 constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P,
2618 const char *N)
2619 : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {}
2620
2621 public:
2622 bool operator<(const OperatorInfo &Other) const {
2623 return *this < Other.Enc;
2624 }
2625 bool operator<(const char *Peek) const {
2626 return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]);
2627 }
2628 bool operator==(const char *Peek) const {
2629 return Enc[0] == Peek[0] && Enc[1] == Peek[1];
2630 }
2631 bool operator!=(const char *Peek) const { return !this->operator==(Peek); }
2632
2633 public:
2634 std::string_view getSymbol() const {
2635 std::string_view Res = Name;
2636 if (Kind < Unnameable) {
2637 assert(llvm::itanium_demangle::starts_with(Res, "operator") &&
2638 "operator name does not start with 'operator'");
2639 Res.remove_prefix(sizeof("operator") - 1);
2640 if (llvm::itanium_demangle::starts_with(Res, ' '))
2641 Res.remove_prefix(1);
2642 }
2643 return Res;
2644 }
2645 std::string_view getName() const { return Name; }
2646 OIKind getKind() const { return Kind; }
2647 bool getFlag() const { return Flag; }
2648 Node::Prec getPrecedence() const { return Prec; }
2649 };
2650 static const OperatorInfo Ops[];
2651 static const size_t NumOps;
2652 const OperatorInfo *parseOperatorEncoding();
2653
2532 /// Parse the <unresolved-name> production. 2654 /// Parse the <unresolved-name> production.
2533 Node *parseUnresolvedName(); 2655 Node *parseUnresolvedName(bool Global);
2534 Node *parseSimpleId(); 2656 Node *parseSimpleId();
2535 Node *parseBaseUnresolvedName(); 2657 Node *parseBaseUnresolvedName();
2536 Node *parseUnresolvedType(); 2658 Node *parseUnresolvedType();
@@ -2551,41 +2673,35 @@ const char* parse_discriminator(const char* first, const char* last);
2551// ::= <substitution> 2673// ::= <substitution>
2552template <typename Derived, typename Alloc> 2674template <typename Derived, typename Alloc>
2553Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) { 2675Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) {
2554 consumeIf('L'); // extension
2555
2556 if (look() == 'N') 2676 if (look() == 'N')
2557 return getDerived().parseNestedName(State); 2677 return getDerived().parseNestedName(State);
2558 if (look() == 'Z') 2678 if (look() == 'Z')
2559 return getDerived().parseLocalName(State); 2679 return getDerived().parseLocalName(State);
2560 2680
2561 // ::= <unscoped-template-name> <template-args> 2681 Node *Result = nullptr;
2562 if (look() == 'S' && look(1) != 't') { 2682 bool IsSubst = false;
2563 Node *S = getDerived().parseSubstitution();
2564 if (S == nullptr)
2565 return nullptr;
2566 if (look() != 'I')
2567 return nullptr;
2568 Node *TA = getDerived().parseTemplateArgs(State != nullptr);
2569 if (TA == nullptr)
2570 return nullptr;
2571 if (State) State->EndsWithTemplateArgs = true;
2572 return make<NameWithTemplateArgs>(S, TA);
2573 }
2574 2683
2575 Node *N = getDerived().parseUnscopedName(State); 2684 Result = getDerived().parseUnscopedName(State, &IsSubst);
2576 if (N == nullptr) 2685 if (!Result)
2577 return nullptr; 2686 return nullptr;
2578 // ::= <unscoped-template-name> <template-args> 2687
2579 if (look() == 'I') { 2688 if (look() == 'I') {
2580 Subs.push_back(N); 2689 // ::= <unscoped-template-name> <template-args>
2690 if (!IsSubst)
2691 // An unscoped-template-name is substitutable.
2692 Subs.push_back(Result);
2581 Node *TA = getDerived().parseTemplateArgs(State != nullptr); 2693 Node *TA = getDerived().parseTemplateArgs(State != nullptr);
2582 if (TA == nullptr) 2694 if (TA == nullptr)
2583 return nullptr; 2695 return nullptr;
2584 if (State) State->EndsWithTemplateArgs = true; 2696 if (State)
2585 return make<NameWithTemplateArgs>(N, TA); 2697 State->EndsWithTemplateArgs = true;
2698 Result = make<NameWithTemplateArgs>(Result, TA);
2699 } else if (IsSubst) {
2700 // The substitution case must be followed by <template-args>.
2701 return nullptr;
2586 } 2702 }
2587 // ::= <unscoped-name> 2703
2588 return N; 2704 return Result;
2589} 2705}
2590 2706
2591// <local-name> := Z <function encoding> E <entity name> [<discriminator>] 2707// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
@@ -2626,34 +2742,63 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
2626 2742
2627// <unscoped-name> ::= <unqualified-name> 2743// <unscoped-name> ::= <unqualified-name>
2628// ::= St <unqualified-name> # ::std:: 2744// ::= St <unqualified-name> # ::std::
2629// extension ::= StL<unqualified-name> 2745// [*] extension
2630template <typename Derived, typename Alloc> 2746template <typename Derived, typename Alloc>
2631Node * 2747Node *
2632AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) { 2748AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
2633 if (consumeIf("StL") || consumeIf("St")) { 2749 bool *IsSubst) {
2634 Node *R = getDerived().parseUnqualifiedName(State); 2750
2635 if (R == nullptr) 2751 Node *Std = nullptr;
2752 if (consumeIf("St")) {
2753 Std = make<NameType>("std");
2754 if (Std == nullptr)
2636 return nullptr; 2755 return nullptr;
2637 return make<StdQualifiedName>(R);
2638 } 2756 }
2639 return getDerived().parseUnqualifiedName(State); 2757
2758 Node *Res = nullptr;
2759 ModuleName *Module = nullptr;
2760 if (look() == 'S') {
2761 Node *S = getDerived().parseSubstitution();
2762 if (!S)
2763 return nullptr;
2764 if (S->getKind() == Node::KModuleName)
2765 Module = static_cast<ModuleName *>(S);
2766 else if (IsSubst && Std == nullptr) {
2767 Res = S;
2768 *IsSubst = true;
2769 } else {
2770 return nullptr;
2771 }
2772 }
2773
2774 if (Res == nullptr || Std != nullptr) {
2775 Res = getDerived().parseUnqualifiedName(State, Std, Module);
2776 }
2777
2778 return Res;
2640} 2779}
2641 2780
2642// <unqualified-name> ::= <operator-name> [abi-tags] 2781// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
2643// ::= <ctor-dtor-name> 2782// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
2644// ::= <source-name> 2783// ::= [<module-name>] L? <source-name> [<abi-tags>]
2645// ::= <unnamed-type-name> 2784// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
2646// ::= DC <source-name>+ E # structured binding declaration 2785// # structured binding declaration
2786// ::= [<module-name>] L? DC <source-name>+ E
2647template <typename Derived, typename Alloc> 2787template <typename Derived, typename Alloc>
2648Node * 2788Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
2649AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) { 2789 NameState *State, Node *Scope, ModuleName *Module) {
2650 // <ctor-dtor-name>s are special-cased in parseNestedName(). 2790 if (getDerived().parseModuleNameOpt(Module))
2791 return nullptr;
2792
2793 consumeIf('L');
2794
2651 Node *Result; 2795 Node *Result;
2652 if (look() == 'U') 2796 if (look() >= '1' && look() <= '9') {
2653 Result = getDerived().parseUnnamedTypeName(State);
2654 else if (look() >= '1' && look() <= '9')
2655 Result = getDerived().parseSourceName(State); 2797 Result = getDerived().parseSourceName(State);
2656 else if (consumeIf("DC")) { 2798 } else if (look() == 'U') {
2799 Result = getDerived().parseUnnamedTypeName(State);
2800 } else if (consumeIf("DC")) {
2801 // Structured binding
2657 size_t BindingsBegin = Names.size(); 2802 size_t BindingsBegin = Names.size();
2658 do { 2803 do {
2659 Node *Binding = getDerived().parseSourceName(State); 2804 Node *Binding = getDerived().parseSourceName(State);
@@ -2662,13 +2807,46 @@ AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) {
2662 Names.push_back(Binding); 2807 Names.push_back(Binding);
2663 } while (!consumeIf('E')); 2808 } while (!consumeIf('E'));
2664 Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin)); 2809 Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
2665 } else 2810 } else if (look() == 'C' || look() == 'D') {
2811 // A <ctor-dtor-name>.
2812 if (Scope == nullptr || Module != nullptr)
2813 return nullptr;
2814 Result = getDerived().parseCtorDtorName(Scope, State);
2815 } else {
2666 Result = getDerived().parseOperatorName(State); 2816 Result = getDerived().parseOperatorName(State);
2817 }
2818
2819 if (Result != nullptr && Module != nullptr)
2820 Result = make<ModuleEntity>(Module, Result);
2667 if (Result != nullptr) 2821 if (Result != nullptr)
2668 Result = getDerived().parseAbiTags(Result); 2822 Result = getDerived().parseAbiTags(Result);
2823 if (Result != nullptr && Scope != nullptr)
2824 Result = make<NestedName>(Scope, Result);
2825
2669 return Result; 2826 return Result;
2670} 2827}
2671 2828
2829// <module-name> ::= <module-subname>
2830// ::= <module-name> <module-subname>
2831// ::= <substitution> # passed in by caller
2832// <module-subname> ::= W <source-name>
2833// ::= W P <source-name>
2834template <typename Derived, typename Alloc>
2835bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
2836 ModuleName *&Module) {
2837 while (consumeIf('W')) {
2838 bool IsPartition = consumeIf('P');
2839 Node *Sub = getDerived().parseSourceName(nullptr);
2840 if (!Sub)
2841 return true;
2842 Module =
2843 static_cast<ModuleName *>(make<ModuleName>(Module, Sub, IsPartition));
2844 Subs.push_back(Module);
2845 }
2846
2847 return false;
2848}
2849
2672// <unnamed-type-name> ::= Ut [<nonnegative number>] _ 2850// <unnamed-type-name> ::= Ut [<nonnegative number>] _
2673// ::= <closure-type-name> 2851// ::= <closure-type-name>
2674// 2852//
@@ -2684,19 +2862,19 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
2684 TemplateParams.clear(); 2862 TemplateParams.clear();
2685 2863
2686 if (consumeIf("Ut")) { 2864 if (consumeIf("Ut")) {
2687 StringView Count = parseNumber(); 2865 std::string_view Count = parseNumber();
2688 if (!consumeIf('_')) 2866 if (!consumeIf('_'))
2689 return nullptr; 2867 return nullptr;
2690 return make<UnnamedTypeName>(Count); 2868 return make<UnnamedTypeName>(Count);
2691 } 2869 }
2692 if (consumeIf("Ul")) { 2870 if (consumeIf("Ul")) {
2693 SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel, 2871 ScopedOverride<size_t> SwapParams(ParsingLambdaParamsAtLevel,
2694 TemplateParams.size()); 2872 TemplateParams.size());
2695 ScopedTemplateParamList LambdaTemplateParams(this); 2873 ScopedTemplateParamList LambdaTemplateParams(this);
2696 2874
2697 size_t ParamsBegin = Names.size(); 2875 size_t ParamsBegin = Names.size();
2698 while (look() == 'T' && 2876 while (look() == 'T' &&
2699 StringView("yptn").find(look(1)) != StringView::npos) { 2877 std::string_view("yptn").find(look(1)) != std::string_view::npos) {
2700 Node *T = parseTemplateParamDecl(); 2878 Node *T = parseTemplateParamDecl();
2701 if (!T) 2879 if (!T)
2702 return nullptr; 2880 return nullptr;
@@ -2739,7 +2917,7 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
2739 } 2917 }
2740 NodeArray Params = popTrailingNodeArray(ParamsBegin); 2918 NodeArray Params = popTrailingNodeArray(ParamsBegin);
2741 2919
2742 StringView Count = parseNumber(); 2920 std::string_view Count = parseNumber();
2743 if (!consumeIf('_')) 2921 if (!consumeIf('_'))
2744 return nullptr; 2922 return nullptr;
2745 return make<ClosureTypeName>(TempParams, Params, Count); 2923 return make<ClosureTypeName>(TempParams, Params, Count);
@@ -2761,104 +2939,138 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
2761 return nullptr; 2939 return nullptr;
2762 if (numLeft() < Length || Length == 0) 2940 if (numLeft() < Length || Length == 0)
2763 return nullptr; 2941 return nullptr;
2764 StringView Name(First, First + Length); 2942 std::string_view Name(First, Length);
2765 First += Length; 2943 First += Length;
2766 if (Name.startsWith("_GLOBAL__N")) 2944 if (llvm::itanium_demangle::starts_with(Name, "_GLOBAL__N"))
2767 return make<NameType>("(anonymous namespace)"); 2945 return make<NameType>("(anonymous namespace)");
2768 return make<NameType>(Name); 2946 return make<NameType>(Name);
2769} 2947}
2770 2948
2771// <operator-name> ::= aa # && 2949// Operator encodings
2772// ::= ad # & (unary) 2950template <typename Derived, typename Alloc>
2773// ::= an # & 2951const typename AbstractManglingParser<
2774// ::= aN # &= 2952 Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived,
2775// ::= aS # = 2953 Alloc>::Ops[] = {
2776// ::= cl # () 2954 // Keep ordered by encoding
2777// ::= cm # , 2955 {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="},
2778// ::= co # ~ 2956 {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="},
2779// ::= cv <type> # (cast) 2957 {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"},
2780// ::= da # delete[] 2958 {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"},
2781// ::= de # * (unary) 2959 {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"},
2782// ::= dl # delete 2960 {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "},
2783// ::= dv # / 2961 {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary,
2784// ::= dV # /= 2962 "operator co_await"},
2785// ::= eo # ^ 2963 {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
2786// ::= eO # ^= 2964 {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
2787// ::= eq # == 2965 {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
2788// ::= ge # >= 2966 {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
2789// ::= gt # > 2967 {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
2790// ::= ix # [] 2968 {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
2791// ::= le # <= 2969 {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
2970 {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
2971 "operator delete[]"},
2972 {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"},
2973 {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"},
2974 {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary,
2975 "operator delete"},
2976 {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
2977 "operator.*"},
2978 {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix,
2979 "operator."},
2980 {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"},
2981 {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="},
2982 {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"},
2983 {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="},
2984 {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="},
2985 {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"},
2986 {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"},
2987 {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="},
2988 {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="},
2989 {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"},
2990 {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"},
2991 {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="},
2992 {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="},
2993 {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"},
2994 {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
2995 "operator*"},
2996 {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"},
2997 {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary,
2998 "operator new[]"},
2999 {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="},
3000 {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"},
3001 {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"},
3002 {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"},
3003 {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="},
3004 {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"},
3005 {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"},
3006 {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="},
3007 {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"},
3008 {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
3009 "operator->*"},
3010 {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"},
3011 {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"},
3012 {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix,
3013 "operator->"},
3014 {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional,
3015 "operator?"},
3016 {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="},
3017 {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="},
3018 {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix,
3019 "reinterpret_cast"},
3020 {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
3021 "operator%"},
3022 {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"},
3023 {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"},
3024 {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"},
3025 {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "},
3026 {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "},
3027 {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix,
3028 "typeid "},
3029 {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "},
3030};
3031template <typename Derived, typename Alloc>
3032const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) /
3033 sizeof(Ops[0]);
3034
3035// If the next 2 chars are an operator encoding, consume them and return their
3036// OperatorInfo. Otherwise return nullptr.
3037template <typename Derived, typename Alloc>
3038const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
3039AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
3040 if (numLeft() < 2)
3041 return nullptr;
3042
3043 // We can't use lower_bound as that can link to symbols in the C++ library,
3044 // and this must remain independant of that.
3045 size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds.
3046 while (upper != lower) {
3047 size_t middle = (upper + lower) / 2;
3048 if (Ops[middle] < First)
3049 lower = middle + 1;
3050 else
3051 upper = middle;
3052 }
3053 if (Ops[lower] != First)
3054 return nullptr;
3055
3056 First += 2;
3057 return &Ops[lower];
3058}
3059
3060// <operator-name> ::= See parseOperatorEncoding()
2792// ::= li <source-name> # operator "" 3061// ::= li <source-name> # operator ""
2793// ::= ls # << 3062// ::= v <digit> <source-name> # vendor extended operator
2794// ::= lS # <<=
2795// ::= lt # <
2796// ::= mi # -
2797// ::= mI # -=
2798// ::= ml # *
2799// ::= mL # *=
2800// ::= mm # -- (postfix in <expression> context)
2801// ::= na # new[]
2802// ::= ne # !=
2803// ::= ng # - (unary)
2804// ::= nt # !
2805// ::= nw # new
2806// ::= oo # ||
2807// ::= or # |
2808// ::= oR # |=
2809// ::= pm # ->*
2810// ::= pl # +
2811// ::= pL # +=
2812// ::= pp # ++ (postfix in <expression> context)
2813// ::= ps # + (unary)
2814// ::= pt # ->
2815// ::= qu # ?
2816// ::= rm # %
2817// ::= rM # %=
2818// ::= rs # >>
2819// ::= rS # >>=
2820// ::= ss # <=> C++2a
2821// ::= v <digit> <source-name> # vendor extended operator
2822template <typename Derived, typename Alloc> 3063template <typename Derived, typename Alloc>
2823Node * 3064Node *
2824AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { 3065AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
2825 switch (look()) { 3066 if (const auto *Op = parseOperatorEncoding()) {
2826 case 'a': 3067 if (Op->getKind() == OperatorInfo::CCast) {
2827 switch (look(1)) { 3068 // ::= cv <type> # (cast)
2828 case 'a': 3069 ScopedOverride<bool> SaveTemplate(TryToParseTemplateArgs, false);
2829 First += 2;
2830 return make<NameType>("operator&&");
2831 case 'd':
2832 case 'n':
2833 First += 2;
2834 return make<NameType>("operator&");
2835 case 'N':
2836 First += 2;
2837 return make<NameType>("operator&=");
2838 case 'S':
2839 First += 2;
2840 return make<NameType>("operator=");
2841 }
2842 return nullptr;
2843 case 'c':
2844 switch (look(1)) {
2845 case 'l':
2846 First += 2;
2847 return make<NameType>("operator()");
2848 case 'm':
2849 First += 2;
2850 return make<NameType>("operator,");
2851 case 'o':
2852 First += 2;
2853 return make<NameType>("operator~");
2854 // ::= cv <type> # (cast)
2855 case 'v': {
2856 First += 2;
2857 SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
2858 // If we're parsing an encoding, State != nullptr and the conversion 3070 // If we're parsing an encoding, State != nullptr and the conversion
2859 // operators' <type> could have a <template-param> that refers to some 3071 // operators' <type> could have a <template-param> that refers to some
2860 // <template-arg>s further ahead in the mangled name. 3072 // <template-arg>s further ahead in the mangled name.
2861 SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences, 3073 ScopedOverride<bool> SavePermit(PermitForwardTemplateReferences,
2862 PermitForwardTemplateReferences || 3074 PermitForwardTemplateReferences ||
2863 State != nullptr); 3075 State != nullptr);
2864 Node *Ty = getDerived().parseType(); 3076 Node *Ty = getDerived().parseType();
@@ -2867,185 +3079,29 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
2867 if (State) State->CtorDtorConversion = true; 3079 if (State) State->CtorDtorConversion = true;
2868 return make<ConversionOperatorType>(Ty); 3080 return make<ConversionOperatorType>(Ty);
2869 } 3081 }
2870 } 3082
2871 return nullptr; 3083 if (Op->getKind() >= OperatorInfo::Unnameable)
2872 case 'd': 3084 /* Not a nameable operator. */
2873 switch (look(1)) { 3085 return nullptr;
2874 case 'a': 3086 if (Op->getKind() == OperatorInfo::Member && !Op->getFlag())
2875 First += 2; 3087 /* Not a nameable MemberExpr */
2876 return make<NameType>("operator delete[]"); 3088 return nullptr;
2877 case 'e': 3089
2878 First += 2; 3090 return make<NameType>(Op->getName());
2879 return make<NameType>("operator*"); 3091 }
2880 case 'l': 3092
2881 First += 2; 3093 if (consumeIf("li")) {
2882 return make<NameType>("operator delete");
2883 case 'v':
2884 First += 2;
2885 return make<NameType>("operator/");
2886 case 'V':
2887 First += 2;
2888 return make<NameType>("operator/=");
2889 }
2890 return nullptr;
2891 case 'e':
2892 switch (look(1)) {
2893 case 'o':
2894 First += 2;
2895 return make<NameType>("operator^");
2896 case 'O':
2897 First += 2;
2898 return make<NameType>("operator^=");
2899 case 'q':
2900 First += 2;
2901 return make<NameType>("operator==");
2902 }
2903 return nullptr;
2904 case 'g':
2905 switch (look(1)) {
2906 case 'e':
2907 First += 2;
2908 return make<NameType>("operator>=");
2909 case 't':
2910 First += 2;
2911 return make<NameType>("operator>");
2912 }
2913 return nullptr;
2914 case 'i':
2915 if (look(1) == 'x') {
2916 First += 2;
2917 return make<NameType>("operator[]");
2918 }
2919 return nullptr;
2920 case 'l':
2921 switch (look(1)) {
2922 case 'e':
2923 First += 2;
2924 return make<NameType>("operator<=");
2925 // ::= li <source-name> # operator "" 3094 // ::= li <source-name> # operator ""
2926 case 'i': { 3095 Node *SN = getDerived().parseSourceName(State);
2927 First += 2; 3096 if (SN == nullptr)
2928 Node *SN = getDerived().parseSourceName(State); 3097 return nullptr;
2929 if (SN == nullptr) 3098 return make<LiteralOperator>(SN);
2930 return nullptr; 3099 }
2931 return make<LiteralOperator>(SN); 3100
2932 } 3101 if (consumeIf('v')) {
2933 case 's': 3102 // ::= v <digit> <source-name> # vendor extended operator
2934 First += 2; 3103 if (look() >= '0' && look() <= '9') {
2935 return make<NameType>("operator<<"); 3104 First++;
2936 case 'S':
2937 First += 2;
2938 return make<NameType>("operator<<=");
2939 case 't':
2940 First += 2;
2941 return make<NameType>("operator<");
2942 }
2943 return nullptr;
2944 case 'm':
2945 switch (look(1)) {
2946 case 'i':
2947 First += 2;
2948 return make<NameType>("operator-");
2949 case 'I':
2950 First += 2;
2951 return make<NameType>("operator-=");
2952 case 'l':
2953 First += 2;
2954 return make<NameType>("operator*");
2955 case 'L':
2956 First += 2;
2957 return make<NameType>("operator*=");
2958 case 'm':
2959 First += 2;
2960 return make<NameType>("operator--");
2961 }
2962 return nullptr;
2963 case 'n':
2964 switch (look(1)) {
2965 case 'a':
2966 First += 2;
2967 return make<NameType>("operator new[]");
2968 case 'e':
2969 First += 2;
2970 return make<NameType>("operator!=");
2971 case 'g':
2972 First += 2;
2973 return make<NameType>("operator-");
2974 case 't':
2975 First += 2;
2976 return make<NameType>("operator!");
2977 case 'w':
2978 First += 2;
2979 return make<NameType>("operator new");
2980 }
2981 return nullptr;
2982 case 'o':
2983 switch (look(1)) {
2984 case 'o':
2985 First += 2;
2986 return make<NameType>("operator||");
2987 case 'r':
2988 First += 2;
2989 return make<NameType>("operator|");
2990 case 'R':
2991 First += 2;
2992 return make<NameType>("operator|=");
2993 }
2994 return nullptr;
2995 case 'p':
2996 switch (look(1)) {
2997 case 'm':
2998 First += 2;
2999 return make<NameType>("operator->*");
3000 case 'l':
3001 First += 2;
3002 return make<NameType>("operator+");
3003 case 'L':
3004 First += 2;
3005 return make<NameType>("operator+=");
3006 case 'p':
3007 First += 2;
3008 return make<NameType>("operator++");
3009 case 's':
3010 First += 2;
3011 return make<NameType>("operator+");
3012 case 't':
3013 First += 2;
3014 return make<NameType>("operator->");
3015 }
3016 return nullptr;
3017 case 'q':
3018 if (look(1) == 'u') {
3019 First += 2;
3020 return make<NameType>("operator?");
3021 }
3022 return nullptr;
3023 case 'r':
3024 switch (look(1)) {
3025 case 'm':
3026 First += 2;
3027 return make<NameType>("operator%");
3028 case 'M':
3029 First += 2;
3030 return make<NameType>("operator%=");
3031 case 's':
3032 First += 2;
3033 return make<NameType>("operator>>");
3034 case 'S':
3035 First += 2;
3036 return make<NameType>("operator>>=");
3037 }
3038 return nullptr;
3039 case 's':
3040 if (look(1) == 's') {
3041 First += 2;
3042 return make<NameType>("operator<=>");
3043 }
3044 return nullptr;
3045 // ::= v <digit> <source-name> # vendor extended operator
3046 case 'v':
3047 if (std::isdigit(look(1))) {
3048 First += 2;
3049 Node *SN = getDerived().parseSourceName(State); 3105 Node *SN = getDerived().parseSourceName(State);
3050 if (SN == nullptr) 3106 if (SN == nullptr)
3051 return nullptr; 3107 return nullptr;
@@ -3053,6 +3109,7 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
3053 } 3109 }
3054 return nullptr; 3110 return nullptr;
3055 } 3111 }
3112
3056 return nullptr; 3113 return nullptr;
3057} 3114}
3058 3115
@@ -3071,19 +3128,11 @@ Node *
3071AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, 3128AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
3072 NameState *State) { 3129 NameState *State) {
3073 if (SoFar->getKind() == Node::KSpecialSubstitution) { 3130 if (SoFar->getKind() == Node::KSpecialSubstitution) {
3074 auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK; 3131 // Expand the special substitution.
3075 switch (SSK) { 3132 SoFar = make<ExpandedSpecialSubstitution>(
3076 case SpecialSubKind::string: 3133 static_cast<SpecialSubstitution *>(SoFar));
3077 case SpecialSubKind::istream: 3134 if (!SoFar)
3078 case SpecialSubKind::ostream: 3135 return nullptr;
3079 case SpecialSubKind::iostream:
3080 SoFar = make<ExpandedSpecialSubstitution>(SSK);
3081 if (!SoFar)
3082 return nullptr;
3083 break;
3084 default:
3085 break;
3086 }
3087 } 3136 }
3088 3137
3089 if (consumeIf('C')) { 3138 if (consumeIf('C')) {
@@ -3112,8 +3161,10 @@ AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
3112 return nullptr; 3161 return nullptr;
3113} 3162}
3114 3163
3115// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E 3164// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix>
3116// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E 3165// <unqualified-name> E
3166// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix>
3167// <template-args> E
3117// 3168//
3118// <prefix> ::= <prefix> <unqualified-name> 3169// <prefix> ::= <prefix> <unqualified-name>
3119// ::= <template-prefix> <template-args> 3170// ::= <template-prefix> <template-args>
@@ -3122,7 +3173,7 @@ AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
3122// ::= # empty 3173// ::= # empty
3123// ::= <substitution> 3174// ::= <substitution>
3124// ::= <prefix> <data-member-prefix> 3175// ::= <prefix> <data-member-prefix>
3125// extension ::= L 3176// [*] extension
3126// 3177//
3127// <data-member-prefix> := <member source-name> [<template-args>] M 3178// <data-member-prefix> := <member source-name> [<template-args>] M
3128// 3179//
@@ -3142,90 +3193,76 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
3142 if (State) State->ReferenceQualifier = FrefQualRValue; 3193 if (State) State->ReferenceQualifier = FrefQualRValue;
3143 } else if (consumeIf('R')) { 3194 } else if (consumeIf('R')) {
3144 if (State) State->ReferenceQualifier = FrefQualLValue; 3195 if (State) State->ReferenceQualifier = FrefQualLValue;
3145 } else 3196 } else {
3146 if (State) State->ReferenceQualifier = FrefQualNone; 3197 if (State) State->ReferenceQualifier = FrefQualNone;
3147
3148 Node *SoFar = nullptr;
3149 auto PushComponent = [&](Node *Comp) {
3150 if (!Comp) return false;
3151 if (SoFar) SoFar = make<NestedName>(SoFar, Comp);
3152 else SoFar = Comp;
3153 if (State) State->EndsWithTemplateArgs = false;
3154 return SoFar != nullptr;
3155 };
3156
3157 if (consumeIf("St")) {
3158 SoFar = make<NameType>("std");
3159 if (!SoFar)
3160 return nullptr;
3161 } 3198 }
3162 3199
3200 Node *SoFar = nullptr;
3163 while (!consumeIf('E')) { 3201 while (!consumeIf('E')) {
3164 consumeIf('L'); // extension 3202 if (State)
3203 // Only set end-with-template on the case that does that.
3204 State->EndsWithTemplateArgs = false;
3165 3205
3166 // <data-member-prefix> := <member source-name> [<template-args>] M
3167 if (consumeIf('M')) {
3168 if (SoFar == nullptr)
3169 return nullptr;
3170 continue;
3171 }
3172
3173 // ::= <template-param>
3174 if (look() == 'T') { 3206 if (look() == 'T') {
3175 if (!PushComponent(getDerived().parseTemplateParam())) 3207 // ::= <template-param>
3176 return nullptr; 3208 if (SoFar != nullptr)
3177 Subs.push_back(SoFar); 3209 return nullptr; // Cannot have a prefix.
3178 continue; 3210 SoFar = getDerived().parseTemplateParam();
3179 } 3211 } else if (look() == 'I') {
3180 3212 // ::= <template-prefix> <template-args>
3181 // ::= <template-prefix> <template-args> 3213 if (SoFar == nullptr)
3182 if (look() == 'I') { 3214 return nullptr; // Must have a prefix.
3183 Node *TA = getDerived().parseTemplateArgs(State != nullptr); 3215 Node *TA = getDerived().parseTemplateArgs(State != nullptr);
3184 if (TA == nullptr || SoFar == nullptr) 3216 if (TA == nullptr)
3185 return nullptr;
3186 SoFar = make<NameWithTemplateArgs>(SoFar, TA);
3187 if (!SoFar)
3188 return nullptr;
3189 if (State) State->EndsWithTemplateArgs = true;
3190 Subs.push_back(SoFar);
3191 continue;
3192 }
3193
3194 // ::= <decltype>
3195 if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
3196 if (!PushComponent(getDerived().parseDecltype()))
3197 return nullptr; 3217 return nullptr;
3198 Subs.push_back(SoFar); 3218 if (SoFar->getKind() == Node::KNameWithTemplateArgs)
3199 continue; 3219 // Semantically <template-args> <template-args> cannot be generated by a
3200 } 3220 // C++ entity. There will always be [something like] a name between
3201 3221 // them.
3202 // ::= <substitution>
3203 if (look() == 'S' && look(1) != 't') {
3204 Node *S = getDerived().parseSubstitution();
3205 if (!PushComponent(S))
3206 return nullptr; 3222 return nullptr;
3207 if (SoFar != S) 3223 if (State)
3208 Subs.push_back(S); 3224 State->EndsWithTemplateArgs = true;
3209 continue; 3225 SoFar = make<NameWithTemplateArgs>(SoFar, TA);
3210 } 3226 } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
3227 // ::= <decltype>
3228 if (SoFar != nullptr)
3229 return nullptr; // Cannot have a prefix.
3230 SoFar = getDerived().parseDecltype();
3231 } else {
3232 ModuleName *Module = nullptr;
3233
3234 if (look() == 'S') {
3235 // ::= <substitution>
3236 Node *S = nullptr;
3237 if (look(1) == 't') {
3238 First += 2;
3239 S = make<NameType>("std");
3240 } else {
3241 S = getDerived().parseSubstitution();
3242 }
3243 if (!S)
3244 return nullptr;
3245 if (S->getKind() == Node::KModuleName) {
3246 Module = static_cast<ModuleName *>(S);
3247 } else if (SoFar != nullptr) {
3248 return nullptr; // Cannot have a prefix.
3249 } else {
3250 SoFar = S;
3251 continue; // Do not push a new substitution.
3252 }
3253 }
3211 3254
3212 // Parse an <unqualified-name> thats actually a <ctor-dtor-name>. 3255 // ::= [<prefix>] <unqualified-name>
3213 if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { 3256 SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module);
3214 if (SoFar == nullptr)
3215 return nullptr;
3216 if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State)))
3217 return nullptr;
3218 SoFar = getDerived().parseAbiTags(SoFar);
3219 if (SoFar == nullptr)
3220 return nullptr;
3221 Subs.push_back(SoFar);
3222 continue;
3223 } 3257 }
3224 3258
3225 // ::= <prefix> <unqualified-name> 3259 if (SoFar == nullptr)
3226 if (!PushComponent(getDerived().parseUnqualifiedName(State)))
3227 return nullptr; 3260 return nullptr;
3228 Subs.push_back(SoFar); 3261 Subs.push_back(SoFar);
3262
3263 // No longer used.
3264 // <data-member-prefix> := <member source-name> [<template-args>] M
3265 consumeIf('M');
3229 } 3266 }
3230 3267
3231 if (SoFar == nullptr || Subs.empty()) 3268 if (SoFar == nullptr || Subs.empty())
@@ -3320,6 +3357,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() {
3320// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x 3357// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
3321// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> 3358// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
3322// # A::x, N::y, A<T>::z; "gs" means leading "::" 3359// # A::x, N::y, A<T>::z; "gs" means leading "::"
3360// [gs] has been parsed by caller.
3323// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x 3361// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
3324// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> 3362// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
3325// # T::N::x /decltype(p)::N::x 3363// # T::N::x /decltype(p)::N::x
@@ -3327,7 +3365,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() {
3327// 3365//
3328// <unresolved-qualifier-level> ::= <simple-id> 3366// <unresolved-qualifier-level> ::= <simple-id>
3329template <typename Derived, typename Alloc> 3367template <typename Derived, typename Alloc>
3330Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() { 3368Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) {
3331 Node *SoFar = nullptr; 3369 Node *SoFar = nullptr;
3332 3370
3333 // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> 3371 // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
@@ -3361,8 +3399,6 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
3361 return make<QualifiedName>(SoFar, Base); 3399 return make<QualifiedName>(SoFar, Base);
3362 } 3400 }
3363 3401
3364 bool Global = consumeIf("gs");
3365
3366 // [gs] <base-unresolved-name> # x or (with "gs") ::x 3402 // [gs] <base-unresolved-name> # x or (with "gs") ::x
3367 if (!consumeIf("sr")) { 3403 if (!consumeIf("sr")) {
3368 SoFar = getDerived().parseBaseUnresolvedName(); 3404 SoFar = getDerived().parseBaseUnresolvedName();
@@ -3419,7 +3455,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
3419template <typename Derived, typename Alloc> 3455template <typename Derived, typename Alloc>
3420Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) { 3456Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) {
3421 while (consumeIf('B')) { 3457 while (consumeIf('B')) {
3422 StringView SN = parseBareSourceName(); 3458 std::string_view SN = parseBareSourceName();
3423 if (SN.empty()) 3459 if (SN.empty())
3424 return nullptr; 3460 return nullptr;
3425 N = make<AbiTagAttr>(N, SN); 3461 N = make<AbiTagAttr>(N, SN);
@@ -3431,16 +3467,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) {
3431 3467
3432// <number> ::= [n] <non-negative decimal integer> 3468// <number> ::= [n] <non-negative decimal integer>
3433template <typename Alloc, typename Derived> 3469template <typename Alloc, typename Derived>
3434StringView 3470std::string_view
3435AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) { 3471AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) {
3436 const char *Tmp = First; 3472 const char *Tmp = First;
3437 if (AllowNegative) 3473 if (AllowNegative)
3438 consumeIf('n'); 3474 consumeIf('n');
3439 if (numLeft() == 0 || !std::isdigit(*First)) 3475 if (numLeft() == 0 || !std::isdigit(*First))
3440 return StringView(); 3476 return std::string_view();
3441 while (numLeft() != 0 && std::isdigit(*First)) 3477 while (numLeft() != 0 && std::isdigit(*First))
3442 ++First; 3478 ++First;
3443 return StringView(Tmp, First); 3479 return std::string_view(Tmp, First - Tmp);
3444} 3480}
3445 3481
3446// <positive length number> ::= [0-9]* 3482// <positive length number> ::= [0-9]*
@@ -3457,11 +3493,11 @@ bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) {
3457} 3493}
3458 3494
3459template <typename Alloc, typename Derived> 3495template <typename Alloc, typename Derived>
3460StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() { 3496std::string_view AbstractManglingParser<Alloc, Derived>::parseBareSourceName() {
3461 size_t Int = 0; 3497 size_t Int = 0;
3462 if (parsePositiveInteger(&Int) || numLeft() < Int) 3498 if (parsePositiveInteger(&Int) || numLeft() < Int)
3463 return StringView(); 3499 return {};
3464 StringView R(First, First + Int); 3500 std::string_view R(First, Int);
3465 First += Int; 3501 First += Int;
3466 return R; 3502 return R;
3467} 3503}
@@ -3549,7 +3585,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() {
3549 if (!consumeIf("Dv")) 3585 if (!consumeIf("Dv"))
3550 return nullptr; 3586 return nullptr;
3551 if (look() >= '1' && look() <= '9') { 3587 if (look() >= '1' && look() <= '9') {
3552 StringView DimensionNumber = parseNumber(); 3588 Node *DimensionNumber = make<NameType>(parseNumber());
3589 if (!DimensionNumber)
3590 return nullptr;
3553 if (!consumeIf('_')) 3591 if (!consumeIf('_'))
3554 return nullptr; 3592 return nullptr;
3555 if (consumeIf('p')) 3593 if (consumeIf('p'))
@@ -3574,7 +3612,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() {
3574 Node *ElemType = getDerived().parseType(); 3612 Node *ElemType = getDerived().parseType();
3575 if (!ElemType) 3613 if (!ElemType)
3576 return nullptr; 3614 return nullptr;
3577 return make<VectorType>(ElemType, StringView()); 3615 return make<VectorType>(ElemType, /*Dimension=*/nullptr);
3578} 3616}
3579 3617
3580// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) 3618// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
@@ -3590,7 +3628,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() {
3590 return nullptr; 3628 return nullptr;
3591 if (!consumeIf('E')) 3629 if (!consumeIf('E'))
3592 return nullptr; 3630 return nullptr;
3593 return make<EnclosingExpr>("decltype(", E, ")"); 3631 return make<EnclosingExpr>("decltype", E);
3594} 3632}
3595 3633
3596// <array-type> ::= A <positive dimension number> _ <element type> 3634// <array-type> ::= A <positive dimension number> _ <element type>
@@ -3600,10 +3638,12 @@ Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() {
3600 if (!consumeIf('A')) 3638 if (!consumeIf('A'))
3601 return nullptr; 3639 return nullptr;
3602 3640
3603 NodeOrString Dimension; 3641 Node *Dimension = nullptr;
3604 3642
3605 if (std::isdigit(look())) { 3643 if (std::isdigit(look())) {
3606 Dimension = parseNumber(); 3644 Dimension = make<NameType>(parseNumber());
3645 if (!Dimension)
3646 return nullptr;
3607 if (!consumeIf('_')) 3647 if (!consumeIf('_'))
3608 return nullptr; 3648 return nullptr;
3609 } else if (!consumeIf('_')) { 3649 } else if (!consumeIf('_')) {
@@ -3641,7 +3681,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() {
3641// ::= Te <name> # dependent elaborated type specifier using 'enum' 3681// ::= Te <name> # dependent elaborated type specifier using 'enum'
3642template <typename Derived, typename Alloc> 3682template <typename Derived, typename Alloc>
3643Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() { 3683Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() {
3644 StringView ElabSpef; 3684 std::string_view ElabSpef;
3645 if (consumeIf("Ts")) 3685 if (consumeIf("Ts"))
3646 ElabSpef = "struct"; 3686 ElabSpef = "struct";
3647 else if (consumeIf("Tu")) 3687 else if (consumeIf("Tu"))
@@ -3665,19 +3705,18 @@ Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() {
3665template <typename Derived, typename Alloc> 3705template <typename Derived, typename Alloc>
3666Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() { 3706Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
3667 if (consumeIf('U')) { 3707 if (consumeIf('U')) {
3668 StringView Qual = parseBareSourceName(); 3708 std::string_view Qual = parseBareSourceName();
3669 if (Qual.empty()) 3709 if (Qual.empty())
3670 return nullptr; 3710 return nullptr;
3671 3711
3672 // FIXME parse the optional <template-args> here!
3673
3674 // extension ::= U <objc-name> <objc-type> # objc-type<identifier> 3712 // extension ::= U <objc-name> <objc-type> # objc-type<identifier>
3675 if (Qual.startsWith("objcproto")) { 3713 if (llvm::itanium_demangle::starts_with(Qual, "objcproto")) {
3676 StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); 3714 constexpr size_t Len = sizeof("objcproto") - 1;
3677 StringView Proto; 3715 std::string_view ProtoSourceName(Qual.data() + Len, Qual.size() - Len);
3716 std::string_view Proto;
3678 { 3717 {
3679 SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()), 3718 ScopedOverride<const char *> SaveFirst(First, ProtoSourceName.data()),
3680 SaveLast(Last, ProtoSourceName.end()); 3719 SaveLast(Last, &*ProtoSourceName.rbegin() + 1);
3681 Proto = parseBareSourceName(); 3720 Proto = parseBareSourceName();
3682 } 3721 }
3683 if (Proto.empty()) 3722 if (Proto.empty())
@@ -3688,10 +3727,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
3688 return make<ObjCProtoName>(Child, Proto); 3727 return make<ObjCProtoName>(Child, Proto);
3689 } 3728 }
3690 3729
3730 Node *TA = nullptr;
3731 if (look() == 'I') {
3732 TA = getDerived().parseTemplateArgs();
3733 if (TA == nullptr)
3734 return nullptr;
3735 }
3736
3691 Node *Child = getDerived().parseQualifiedType(); 3737 Node *Child = getDerived().parseQualifiedType();
3692 if (Child == nullptr) 3738 if (Child == nullptr)
3693 return nullptr; 3739 return nullptr;
3694 return make<VendorExtQualType>(Child, Qual); 3740 return make<VendorExtQualType>(Child, Qual, TA);
3695 } 3741 }
3696 3742
3697 Qualifiers Quals = parseCVQualifiers(); 3743 Qualifiers Quals = parseCVQualifiers();
@@ -3838,7 +3884,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
3838 // <builtin-type> ::= u <source-name> # vendor extended type 3884 // <builtin-type> ::= u <source-name> # vendor extended type
3839 case 'u': { 3885 case 'u': {
3840 ++First; 3886 ++First;
3841 StringView Res = parseBareSourceName(); 3887 std::string_view Res = parseBareSourceName();
3842 if (Res.empty()) 3888 if (Res.empty())
3843 return nullptr; 3889 return nullptr;
3844 // Typically, <builtin-type>s are not considered substitution candidates, 3890 // Typically, <builtin-type>s are not considered substitution candidates,
@@ -3864,7 +3910,33 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
3864 // ::= Dh # IEEE 754r half-precision floating point (16 bits) 3910 // ::= Dh # IEEE 754r half-precision floating point (16 bits)
3865 case 'h': 3911 case 'h':
3866 First += 2; 3912 First += 2;
3867 return make<NameType>("decimal16"); 3913 return make<NameType>("half");
3914 // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point (N bits)
3915 case 'F': {
3916 First += 2;
3917 Node *DimensionNumber = make<NameType>(parseNumber());
3918 if (!DimensionNumber)
3919 return nullptr;
3920 if (!consumeIf('_'))
3921 return nullptr;
3922 return make<BinaryFPType>(DimensionNumber);
3923 }
3924 // ::= DB <number> _ # C23 signed _BitInt(N)
3925 // ::= DB <instantiation-dependent expression> _ # C23 signed _BitInt(N)
3926 // ::= DU <number> _ # C23 unsigned _BitInt(N)
3927 // ::= DU <instantiation-dependent expression> _ # C23 unsigned _BitInt(N)
3928 case 'B':
3929 case 'U': {
3930 bool Signed = look(1) == 'B';
3931 First += 2;
3932 Node *Size = std::isdigit(look()) ? make<NameType>(parseNumber())
3933 : getDerived().parseExpr();
3934 if (!Size)
3935 return nullptr;
3936 if (!consumeIf('_'))
3937 return nullptr;
3938 return make<BitIntType>(Size, Signed);
3939 }
3868 // ::= Di # char32_t 3940 // ::= Di # char32_t
3869 case 'i': 3941 case 'i':
3870 First += 2; 3942 First += 2;
@@ -4012,9 +4084,10 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
4012 } 4084 }
4013 // ::= <substitution> # See Compression below 4085 // ::= <substitution> # See Compression below
4014 case 'S': { 4086 case 'S': {
4015 if (look(1) && look(1) != 't') { 4087 if (look(1) != 't') {
4016 Node *Sub = getDerived().parseSubstitution(); 4088 bool IsSubst = false;
4017 if (Sub == nullptr) 4089 Result = getDerived().parseUnscopedName(nullptr, &IsSubst);
4090 if (!Result)
4018 return nullptr; 4091 return nullptr;
4019 4092
4020 // Sub could be either of: 4093 // Sub could be either of:
@@ -4027,17 +4100,19 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
4027 // If this is followed by some <template-args>, and we're permitted to 4100 // If this is followed by some <template-args>, and we're permitted to
4028 // parse them, take the second production. 4101 // parse them, take the second production.
4029 4102
4030 if (TryToParseTemplateArgs && look() == 'I') { 4103 if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) {
4104 if (!IsSubst)
4105 Subs.push_back(Result);
4031 Node *TA = getDerived().parseTemplateArgs(); 4106 Node *TA = getDerived().parseTemplateArgs();
4032 if (TA == nullptr) 4107 if (TA == nullptr)
4033 return nullptr; 4108 return nullptr;
4034 Result = make<NameWithTemplateArgs>(Sub, TA); 4109 Result = make<NameWithTemplateArgs>(Result, TA);
4035 break; 4110 } else if (IsSubst) {
4111 // If all we parsed was a substitution, don't re-insert into the
4112 // substitution table.
4113 return Result;
4036 } 4114 }
4037 4115 break;
4038 // If all we parsed was a substitution, don't re-insert into the
4039 // substitution table.
4040 return Sub;
4041 } 4116 }
4042 DEMANGLE_FALLTHROUGH; 4117 DEMANGLE_FALLTHROUGH;
4043 } 4118 }
@@ -4057,28 +4132,32 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
4057} 4132}
4058 4133
4059template <typename Derived, typename Alloc> 4134template <typename Derived, typename Alloc>
4060Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) { 4135Node *
4136AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(std::string_view Kind,
4137 Node::Prec Prec) {
4061 Node *E = getDerived().parseExpr(); 4138 Node *E = getDerived().parseExpr();
4062 if (E == nullptr) 4139 if (E == nullptr)
4063 return nullptr; 4140 return nullptr;
4064 return make<PrefixExpr>(Kind, E); 4141 return make<PrefixExpr>(Kind, E, Prec);
4065} 4142}
4066 4143
4067template <typename Derived, typename Alloc> 4144template <typename Derived, typename Alloc>
4068Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) { 4145Node *
4146AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(std::string_view Kind,
4147 Node::Prec Prec) {
4069 Node *LHS = getDerived().parseExpr(); 4148 Node *LHS = getDerived().parseExpr();
4070 if (LHS == nullptr) 4149 if (LHS == nullptr)
4071 return nullptr; 4150 return nullptr;
4072 Node *RHS = getDerived().parseExpr(); 4151 Node *RHS = getDerived().parseExpr();
4073 if (RHS == nullptr) 4152 if (RHS == nullptr)
4074 return nullptr; 4153 return nullptr;
4075 return make<BinaryExpr>(LHS, Kind, RHS); 4154 return make<BinaryExpr>(LHS, Kind, RHS, Prec);
4076} 4155}
4077 4156
4078template <typename Derived, typename Alloc> 4157template <typename Derived, typename Alloc>
4079Node * 4158Node *AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(
4080AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) { 4159 std::string_view Lit) {
4081 StringView Tmp = parseNumber(true); 4160 std::string_view Tmp = parseNumber(true);
4082 if (!Tmp.empty() && consumeIf('E')) 4161 if (!Tmp.empty() && consumeIf('E'))
4083 return make<IntegerLiteral>(Lit, Tmp); 4162 return make<IntegerLiteral>(Lit, Tmp);
4084 return nullptr; 4163 return nullptr;
@@ -4101,11 +4180,14 @@ Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() {
4101// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters 4180// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
4102// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter 4181// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter
4103// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters 4182// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
4183// ::= fpT # 'this' expression (not part of standard?)
4104template <typename Derived, typename Alloc> 4184template <typename Derived, typename Alloc>
4105Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { 4185Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
4186 if (consumeIf("fpT"))
4187 return make<NameType>("this");
4106 if (consumeIf("fp")) { 4188 if (consumeIf("fp")) {
4107 parseCVQualifiers(); 4189 parseCVQualifiers();
4108 StringView Num = parseNumber(); 4190 std::string_view Num = parseNumber();
4109 if (!consumeIf('_')) 4191 if (!consumeIf('_'))
4110 return nullptr; 4192 return nullptr;
4111 return make<FunctionParam>(Num); 4193 return make<FunctionParam>(Num);
@@ -4116,7 +4198,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
4116 if (!consumeIf('p')) 4198 if (!consumeIf('p'))
4117 return nullptr; 4199 return nullptr;
4118 parseCVQualifiers(); 4200 parseCVQualifiers();
4119 StringView Num = parseNumber(); 4201 std::string_view Num = parseNumber();
4120 if (!consumeIf('_')) 4202 if (!consumeIf('_'))
4121 return nullptr; 4203 return nullptr;
4122 return make<FunctionParam>(Num); 4204 return make<FunctionParam>(Num);
@@ -4124,43 +4206,6 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
4124 return nullptr; 4206 return nullptr;
4125} 4207}
4126 4208
4127// [gs] nw <expression>* _ <type> E # new (expr-list) type
4128// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
4129// [gs] na <expression>* _ <type> E # new[] (expr-list) type
4130// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
4131// <initializer> ::= pi <expression>* E # parenthesized initialization
4132template <typename Derived, typename Alloc>
4133Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() {
4134 bool Global = consumeIf("gs");
4135 bool IsArray = look(1) == 'a';
4136 if (!consumeIf("nw") && !consumeIf("na"))
4137 return nullptr;
4138 size_t Exprs = Names.size();
4139 while (!consumeIf('_')) {
4140 Node *Ex = getDerived().parseExpr();
4141 if (Ex == nullptr)
4142 return nullptr;
4143 Names.push_back(Ex);
4144 }
4145 NodeArray ExprList = popTrailingNodeArray(Exprs);
4146 Node *Ty = getDerived().parseType();
4147 if (Ty == nullptr)
4148 return Ty;
4149 if (consumeIf("pi")) {
4150 size_t InitsBegin = Names.size();
4151 while (!consumeIf('E')) {
4152 Node *Init = getDerived().parseExpr();
4153 if (Init == nullptr)
4154 return Init;
4155 Names.push_back(Init);
4156 }
4157 NodeArray Inits = popTrailingNodeArray(InitsBegin);
4158 return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
4159 } else if (!consumeIf('E'))
4160 return nullptr;
4161 return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
4162}
4163
4164// cv <type> <expression> # conversion with one argument 4209// cv <type> <expression> # conversion with one argument
4165// cv <type> _ <expression>* E # conversion with a different number of arguments 4210// cv <type> _ <expression>* E # conversion with a different number of arguments
4166template <typename Derived, typename Alloc> 4211template <typename Derived, typename Alloc>
@@ -4169,7 +4214,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() {
4169 return nullptr; 4214 return nullptr;
4170 Node *Ty; 4215 Node *Ty;
4171 { 4216 {
4172 SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false); 4217 ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false);
4173 Ty = getDerived().parseType(); 4218 Ty = getDerived().parseType();
4174 } 4219 }
4175 4220
@@ -4262,7 +4307,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
4262 return getDerived().template parseFloatingLiteral<double>(); 4307 return getDerived().template parseFloatingLiteral<double>();
4263 case 'e': 4308 case 'e':
4264 ++First; 4309 ++First;
4310#if defined(__powerpc__) || defined(__s390__)
4311 // Handle cases where long doubles encoded with e have the same size
4312 // and representation as doubles.
4313 return getDerived().template parseFloatingLiteral<double>();
4314#else
4265 return getDerived().template parseFloatingLiteral<long double>(); 4315 return getDerived().template parseFloatingLiteral<long double>();
4316#endif
4266 case '_': 4317 case '_':
4267 if (consumeIf("_Z")) { 4318 if (consumeIf("_Z")) {
4268 Node *R = getDerived().parseEncoding(); 4319 Node *R = getDerived().parseEncoding();
@@ -4280,7 +4331,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
4280 return nullptr; 4331 return nullptr;
4281 } 4332 }
4282 case 'D': 4333 case 'D':
4283 if (consumeIf("DnE")) 4334 if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E')))
4284 return make<NameType>("nullptr"); 4335 return make<NameType>("nullptr");
4285 return nullptr; 4336 return nullptr;
4286 case 'T': 4337 case 'T':
@@ -4301,12 +4352,12 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
4301 Node *T = getDerived().parseType(); 4352 Node *T = getDerived().parseType();
4302 if (T == nullptr) 4353 if (T == nullptr)
4303 return nullptr; 4354 return nullptr;
4304 StringView N = parseNumber(); 4355 std::string_view N = parseNumber(/*AllowNegative=*/true);
4305 if (N.empty()) 4356 if (N.empty())
4306 return nullptr; 4357 return nullptr;
4307 if (!consumeIf('E')) 4358 if (!consumeIf('E'))
4308 return nullptr; 4359 return nullptr;
4309 return make<IntegerCastExpr>(T, N); 4360 return make<EnumLiteral>(T, N);
4310 } 4361 }
4311 } 4362 }
4312} 4363}
@@ -4367,55 +4418,38 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
4367 if (!consumeIf('f')) 4418 if (!consumeIf('f'))
4368 return nullptr; 4419 return nullptr;
4369 4420
4370 char FoldKind = look(); 4421 bool IsLeftFold = false, HasInitializer = false;
4371 bool IsLeftFold, HasInitializer; 4422 switch (look()) {
4372 HasInitializer = FoldKind == 'L' || FoldKind == 'R'; 4423 default:
4373 if (FoldKind == 'l' || FoldKind == 'L')
4374 IsLeftFold = true;
4375 else if (FoldKind == 'r' || FoldKind == 'R')
4376 IsLeftFold = false;
4377 else
4378 return nullptr; 4424 return nullptr;
4425 case 'L':
4426 IsLeftFold = true;
4427 HasInitializer = true;
4428 break;
4429 case 'R':
4430 HasInitializer = true;
4431 break;
4432 case 'l':
4433 IsLeftFold = true;
4434 break;
4435 case 'r':
4436 break;
4437 }
4379 ++First; 4438 ++First;
4380 4439
4381 // FIXME: This map is duplicated in parseOperatorName and parseExpr. 4440 const auto *Op = parseOperatorEncoding();
4382 StringView OperatorName; 4441 if (!Op)
4383 if (consumeIf("aa")) OperatorName = "&&"; 4442 return nullptr;
4384 else if (consumeIf("an")) OperatorName = "&"; 4443 if (!(Op->getKind() == OperatorInfo::Binary
4385 else if (consumeIf("aN")) OperatorName = "&="; 4444 || (Op->getKind() == OperatorInfo::Member
4386 else if (consumeIf("aS")) OperatorName = "="; 4445 && Op->getName().back() == '*')))
4387 else if (consumeIf("cm")) OperatorName = ","; 4446 return nullptr;
4388 else if (consumeIf("ds")) OperatorName = ".*"; 4447
4389 else if (consumeIf("dv")) OperatorName = "/"; 4448 Node *Pack = getDerived().parseExpr();
4390 else if (consumeIf("dV")) OperatorName = "/=";
4391 else if (consumeIf("eo")) OperatorName = "^";
4392 else if (consumeIf("eO")) OperatorName = "^=";
4393 else if (consumeIf("eq")) OperatorName = "==";
4394 else if (consumeIf("ge")) OperatorName = ">=";
4395 else if (consumeIf("gt")) OperatorName = ">";
4396 else if (consumeIf("le")) OperatorName = "<=";
4397 else if (consumeIf("ls")) OperatorName = "<<";
4398 else if (consumeIf("lS")) OperatorName = "<<=";
4399 else if (consumeIf("lt")) OperatorName = "<";
4400 else if (consumeIf("mi")) OperatorName = "-";
4401 else if (consumeIf("mI")) OperatorName = "-=";
4402 else if (consumeIf("ml")) OperatorName = "*";
4403 else if (consumeIf("mL")) OperatorName = "*=";
4404 else if (consumeIf("ne")) OperatorName = "!=";
4405 else if (consumeIf("oo")) OperatorName = "||";
4406 else if (consumeIf("or")) OperatorName = "|";
4407 else if (consumeIf("oR")) OperatorName = "|=";
4408 else if (consumeIf("pl")) OperatorName = "+";
4409 else if (consumeIf("pL")) OperatorName = "+=";
4410 else if (consumeIf("rm")) OperatorName = "%";
4411 else if (consumeIf("rM")) OperatorName = "%=";
4412 else if (consumeIf("rs")) OperatorName = ">>";
4413 else if (consumeIf("rS")) OperatorName = ">>=";
4414 else return nullptr;
4415
4416 Node *Pack = getDerived().parseExpr(), *Init = nullptr;
4417 if (Pack == nullptr) 4449 if (Pack == nullptr)
4418 return nullptr; 4450 return nullptr;
4451
4452 Node *Init = nullptr;
4419 if (HasInitializer) { 4453 if (HasInitializer) {
4420 Init = getDerived().parseExpr(); 4454 Init = getDerived().parseExpr();
4421 if (Init == nullptr) 4455 if (Init == nullptr)
@@ -4425,7 +4459,53 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
4425 if (IsLeftFold && Init) 4459 if (IsLeftFold && Init)
4426 std::swap(Pack, Init); 4460 std::swap(Pack, Init);
4427 4461
4428 return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init); 4462 return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init);
4463}
4464
4465// <expression> ::= mc <parameter type> <expr> [<offset number>] E
4466//
4467// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
4468template <typename Derived, typename Alloc>
4469Node *
4470AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr(
4471 Node::Prec Prec) {
4472 Node *Ty = getDerived().parseType();
4473 if (!Ty)
4474 return nullptr;
4475 Node *Expr = getDerived().parseExpr();
4476 if (!Expr)
4477 return nullptr;
4478 std::string_view Offset = getDerived().parseNumber(true);
4479 if (!consumeIf('E'))
4480 return nullptr;
4481 return make<PointerToMemberConversionExpr>(Ty, Expr, Offset, Prec);
4482}
4483
4484// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
4485// <union-selector> ::= _ [<number>]
4486//
4487// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
4488template <typename Derived, typename Alloc>
4489Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
4490 Node *Ty = getDerived().parseType();
4491 if (!Ty)
4492 return nullptr;
4493 Node *Expr = getDerived().parseExpr();
4494 if (!Expr)
4495 return nullptr;
4496 std::string_view Offset = getDerived().parseNumber(true);
4497 size_t SelectorsBegin = Names.size();
4498 while (consumeIf('_')) {
4499 Node *Selector = make<NameType>(parseNumber());
4500 if (!Selector)
4501 return nullptr;
4502 Names.push_back(Selector);
4503 }
4504 bool OnePastTheEnd = consumeIf('p');
4505 if (!consumeIf('E'))
4506 return nullptr;
4507 return make<SubobjectExpr>(
4508 Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
4429} 4509}
4430 4510
4431// <expression> ::= <unary operator-name> <expression> 4511// <expression> ::= <unary operator-name> <expression>
@@ -4475,313 +4555,127 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
4475template <typename Derived, typename Alloc> 4555template <typename Derived, typename Alloc>
4476Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { 4556Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
4477 bool Global = consumeIf("gs"); 4557 bool Global = consumeIf("gs");
4478 if (numLeft() < 2)
4479 return nullptr;
4480 4558
4481 switch (*First) { 4559 const auto *Op = parseOperatorEncoding();
4482 case 'L': 4560 if (Op) {
4483 return getDerived().parseExprPrimary(); 4561 auto Sym = Op->getSymbol();
4484 case 'T': 4562 switch (Op->getKind()) {
4485 return getDerived().parseTemplateParam(); 4563 case OperatorInfo::Binary:
4486 case 'f': { 4564 // Binary operator: lhs @ rhs
4487 // Disambiguate a fold expression from a <function-param>. 4565 return getDerived().parseBinaryExpr(Sym, Op->getPrecedence());
4488 if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) 4566 case OperatorInfo::Prefix:
4489 return getDerived().parseFunctionParam(); 4567 // Prefix unary operator: @ expr
4490 return getDerived().parseFoldExpr(); 4568 return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
4491 } 4569 case OperatorInfo::Postfix: {
4492 case 'a': 4570 // Postfix unary operator: expr @
4493 switch (First[1]) { 4571 if (consumeIf('_'))
4494 case 'a': 4572 return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
4495 First += 2;
4496 return getDerived().parseBinaryExpr("&&");
4497 case 'd':
4498 First += 2;
4499 return getDerived().parsePrefixExpr("&");
4500 case 'n':
4501 First += 2;
4502 return getDerived().parseBinaryExpr("&");
4503 case 'N':
4504 First += 2;
4505 return getDerived().parseBinaryExpr("&=");
4506 case 'S':
4507 First += 2;
4508 return getDerived().parseBinaryExpr("=");
4509 case 't': {
4510 First += 2;
4511 Node *Ty = getDerived().parseType();
4512 if (Ty == nullptr)
4513 return nullptr;
4514 return make<EnclosingExpr>("alignof (", Ty, ")");
4515 }
4516 case 'z': {
4517 First += 2;
4518 Node *Ty = getDerived().parseExpr();
4519 if (Ty == nullptr)
4520 return nullptr;
4521 return make<EnclosingExpr>("alignof (", Ty, ")");
4522 }
4523 }
4524 return nullptr;
4525 case 'c':
4526 switch (First[1]) {
4527 // cc <type> <expression> # const_cast<type>(expression)
4528 case 'c': {
4529 First += 2;
4530 Node *Ty = getDerived().parseType();
4531 if (Ty == nullptr)
4532 return Ty;
4533 Node *Ex = getDerived().parseExpr();
4534 if (Ex == nullptr)
4535 return Ex;
4536 return make<CastExpr>("const_cast", Ty, Ex);
4537 }
4538 // cl <expression>+ E # call
4539 case 'l': {
4540 First += 2;
4541 Node *Callee = getDerived().parseExpr();
4542 if (Callee == nullptr)
4543 return Callee;
4544 size_t ExprsBegin = Names.size();
4545 while (!consumeIf('E')) {
4546 Node *E = getDerived().parseExpr();
4547 if (E == nullptr)
4548 return E;
4549 Names.push_back(E);
4550 }
4551 return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
4552 }
4553 case 'm':
4554 First += 2;
4555 return getDerived().parseBinaryExpr(",");
4556 case 'o':
4557 First += 2;
4558 return getDerived().parsePrefixExpr("~");
4559 case 'v':
4560 return getDerived().parseConversionExpr();
4561 }
4562 return nullptr;
4563 case 'd':
4564 switch (First[1]) {
4565 case 'a': {
4566 First += 2;
4567 Node *Ex = getDerived().parseExpr();
4568 if (Ex == nullptr)
4569 return Ex;
4570 return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
4571 }
4572 case 'c': {
4573 First += 2;
4574 Node *T = getDerived().parseType();
4575 if (T == nullptr)
4576 return T;
4577 Node *Ex = getDerived().parseExpr(); 4573 Node *Ex = getDerived().parseExpr();
4578 if (Ex == nullptr) 4574 if (Ex == nullptr)
4579 return Ex; 4575 return nullptr;
4580 return make<CastExpr>("dynamic_cast", T, Ex); 4576 return make<PostfixExpr>(Ex, Sym, Op->getPrecedence());
4581 }
4582 case 'e':
4583 First += 2;
4584 return getDerived().parsePrefixExpr("*");
4585 case 'l': {
4586 First += 2;
4587 Node *E = getDerived().parseExpr();
4588 if (E == nullptr)
4589 return E;
4590 return make<DeleteExpr>(E, Global, /*is_array=*/false);
4591 } 4577 }
4592 case 'n': 4578 case OperatorInfo::Array: {
4593 return getDerived().parseUnresolvedName(); 4579 // Array Index: lhs [ rhs ]
4594 case 's': { 4580 Node *Base = getDerived().parseExpr();
4595 First += 2; 4581 if (Base == nullptr)
4596 Node *LHS = getDerived().parseExpr();
4597 if (LHS == nullptr)
4598 return nullptr; 4582 return nullptr;
4599 Node *RHS = getDerived().parseExpr(); 4583 Node *Index = getDerived().parseExpr();
4600 if (RHS == nullptr) 4584 if (Index == nullptr)
4601 return nullptr; 4585 return nullptr;
4602 return make<MemberExpr>(LHS, ".*", RHS); 4586 return make<ArraySubscriptExpr>(Base, Index, Op->getPrecedence());
4603 } 4587 }
4604 case 't': { 4588 case OperatorInfo::Member: {
4605 First += 2; 4589 // Member access lhs @ rhs
4606 Node *LHS = getDerived().parseExpr(); 4590 Node *LHS = getDerived().parseExpr();
4607 if (LHS == nullptr) 4591 if (LHS == nullptr)
4608 return LHS; 4592 return nullptr;
4609 Node *RHS = getDerived().parseExpr(); 4593 Node *RHS = getDerived().parseExpr();
4610 if (RHS == nullptr) 4594 if (RHS == nullptr)
4611 return nullptr; 4595 return nullptr;
4612 return make<MemberExpr>(LHS, ".", RHS); 4596 return make<MemberExpr>(LHS, Sym, RHS, Op->getPrecedence());
4613 } 4597 }
4614 case 'v': 4598 case OperatorInfo::New: {
4615 First += 2; 4599 // New
4616 return getDerived().parseBinaryExpr("/"); 4600 // # new (expr-list) type [(init)]
4617 case 'V': 4601 // [gs] nw <expression>* _ <type> [pi <expression>*] E
4618 First += 2; 4602 // # new[] (expr-list) type [(init)]
4619 return getDerived().parseBinaryExpr("/="); 4603 // [gs] na <expression>* _ <type> [pi <expression>*] E
4620 } 4604 size_t Exprs = Names.size();
4621 return nullptr; 4605 while (!consumeIf('_')) {
4622 case 'e': 4606 Node *Ex = getDerived().parseExpr();
4623 switch (First[1]) { 4607 if (Ex == nullptr)
4624 case 'o': 4608 return nullptr;
4625 First += 2; 4609 Names.push_back(Ex);
4626 return getDerived().parseBinaryExpr("^"); 4610 }
4627 case 'O': 4611 NodeArray ExprList = popTrailingNodeArray(Exprs);
4628 First += 2; 4612 Node *Ty = getDerived().parseType();
4629 return getDerived().parseBinaryExpr("^="); 4613 if (Ty == nullptr)
4630 case 'q':
4631 First += 2;
4632 return getDerived().parseBinaryExpr("==");
4633 }
4634 return nullptr;
4635 case 'g':
4636 switch (First[1]) {
4637 case 'e':
4638 First += 2;
4639 return getDerived().parseBinaryExpr(">=");
4640 case 't':
4641 First += 2;
4642 return getDerived().parseBinaryExpr(">");
4643 }
4644 return nullptr;
4645 case 'i':
4646 switch (First[1]) {
4647 case 'x': {
4648 First += 2;
4649 Node *Base = getDerived().parseExpr();
4650 if (Base == nullptr)
4651 return nullptr; 4614 return nullptr;
4652 Node *Index = getDerived().parseExpr(); 4615 bool HaveInits = consumeIf("pi");
4653 if (Index == nullptr)
4654 return Index;
4655 return make<ArraySubscriptExpr>(Base, Index);
4656 }
4657 case 'l': {
4658 First += 2;
4659 size_t InitsBegin = Names.size(); 4616 size_t InitsBegin = Names.size();
4660 while (!consumeIf('E')) { 4617 while (!consumeIf('E')) {
4661 Node *E = getDerived().parseBracedExpr(); 4618 if (!HaveInits)
4662 if (E == nullptr)
4663 return nullptr; 4619 return nullptr;
4664 Names.push_back(E); 4620 Node *Init = getDerived().parseExpr();
4621 if (Init == nullptr)
4622 return Init;
4623 Names.push_back(Init);
4665 } 4624 }
4666 return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin)); 4625 NodeArray Inits = popTrailingNodeArray(InitsBegin);
4667 } 4626 return make<NewExpr>(ExprList, Ty, Inits, Global,
4627 /*IsArray=*/Op->getFlag(), Op->getPrecedence());
4668 } 4628 }
4669 return nullptr; 4629 case OperatorInfo::Del: {
4670 case 'l': 4630 // Delete
4671 switch (First[1]) {
4672 case 'e':
4673 First += 2;
4674 return getDerived().parseBinaryExpr("<=");
4675 case 's':
4676 First += 2;
4677 return getDerived().parseBinaryExpr("<<");
4678 case 'S':
4679 First += 2;
4680 return getDerived().parseBinaryExpr("<<=");
4681 case 't':
4682 First += 2;
4683 return getDerived().parseBinaryExpr("<");
4684 }
4685 return nullptr;
4686 case 'm':
4687 switch (First[1]) {
4688 case 'i':
4689 First += 2;
4690 return getDerived().parseBinaryExpr("-");
4691 case 'I':
4692 First += 2;
4693 return getDerived().parseBinaryExpr("-=");
4694 case 'l':
4695 First += 2;
4696 return getDerived().parseBinaryExpr("*");
4697 case 'L':
4698 First += 2;
4699 return getDerived().parseBinaryExpr("*=");
4700 case 'm':
4701 First += 2;
4702 if (consumeIf('_'))
4703 return getDerived().parsePrefixExpr("--");
4704 Node *Ex = getDerived().parseExpr(); 4631 Node *Ex = getDerived().parseExpr();
4705 if (Ex == nullptr) 4632 if (Ex == nullptr)
4706 return nullptr; 4633 return nullptr;
4707 return make<PostfixExpr>(Ex, "--"); 4634 return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag(),
4708 } 4635 Op->getPrecedence());
4709 return nullptr;
4710 case 'n':
4711 switch (First[1]) {
4712 case 'a':
4713 case 'w':
4714 return getDerived().parseNewExpr();
4715 case 'e':
4716 First += 2;
4717 return getDerived().parseBinaryExpr("!=");
4718 case 'g':
4719 First += 2;
4720 return getDerived().parsePrefixExpr("-");
4721 case 't':
4722 First += 2;
4723 return getDerived().parsePrefixExpr("!");
4724 case 'x':
4725 First += 2;
4726 Node *Ex = getDerived().parseExpr();
4727 if (Ex == nullptr)
4728 return Ex;
4729 return make<EnclosingExpr>("noexcept (", Ex, ")");
4730 }
4731 return nullptr;
4732 case 'o':
4733 switch (First[1]) {
4734 case 'n':
4735 return getDerived().parseUnresolvedName();
4736 case 'o':
4737 First += 2;
4738 return getDerived().parseBinaryExpr("||");
4739 case 'r':
4740 First += 2;
4741 return getDerived().parseBinaryExpr("|");
4742 case 'R':
4743 First += 2;
4744 return getDerived().parseBinaryExpr("|=");
4745 } 4636 }
4746 return nullptr; 4637 case OperatorInfo::Call: {
4747 case 'p': 4638 // Function Call
4748 switch (First[1]) { 4639 Node *Callee = getDerived().parseExpr();
4749 case 'm': 4640 if (Callee == nullptr)
4750 First += 2; 4641 return nullptr;
4751 return getDerived().parseBinaryExpr("->*"); 4642 size_t ExprsBegin = Names.size();
4752 case 'l': 4643 while (!consumeIf('E')) {
4753 First += 2; 4644 Node *E = getDerived().parseExpr();
4754 return getDerived().parseBinaryExpr("+"); 4645 if (E == nullptr)
4755 case 'L': 4646 return nullptr;
4756 First += 2; 4647 Names.push_back(E);
4757 return getDerived().parseBinaryExpr("+="); 4648 }
4758 case 'p': { 4649 return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin),
4759 First += 2; 4650 Op->getPrecedence());
4760 if (consumeIf('_'))
4761 return getDerived().parsePrefixExpr("++");
4762 Node *Ex = getDerived().parseExpr();
4763 if (Ex == nullptr)
4764 return Ex;
4765 return make<PostfixExpr>(Ex, "++");
4766 } 4651 }
4767 case 's': 4652 case OperatorInfo::CCast: {
4768 First += 2; 4653 // C Cast: (type)expr
4769 return getDerived().parsePrefixExpr("+"); 4654 Node *Ty;
4770 case 't': { 4655 {
4771 First += 2; 4656 ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false);
4772 Node *L = getDerived().parseExpr(); 4657 Ty = getDerived().parseType();
4773 if (L == nullptr) 4658 }
4659 if (Ty == nullptr)
4774 return nullptr; 4660 return nullptr;
4775 Node *R = getDerived().parseExpr(); 4661
4776 if (R == nullptr) 4662 size_t ExprsBegin = Names.size();
4663 bool IsMany = consumeIf('_');
4664 while (!consumeIf('E')) {
4665 Node *E = getDerived().parseExpr();
4666 if (E == nullptr)
4667 return E;
4668 Names.push_back(E);
4669 if (!IsMany)
4670 break;
4671 }
4672 NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
4673 if (!IsMany && Exprs.size() != 1)
4777 return nullptr; 4674 return nullptr;
4778 return make<MemberExpr>(L, "->", R); 4675 return make<ConversionExpr>(Ty, Exprs, Op->getPrecedence());
4779 } 4676 }
4780 } 4677 case OperatorInfo::Conditional: {
4781 return nullptr; 4678 // Conditional operator: expr ? expr : expr
4782 case 'q':
4783 if (First[1] == 'u') {
4784 First += 2;
4785 Node *Cond = getDerived().parseExpr(); 4679 Node *Cond = getDerived().parseExpr();
4786 if (Cond == nullptr) 4680 if (Cond == nullptr)
4787 return nullptr; 4681 return nullptr;
@@ -4791,169 +4685,158 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
4791 Node *RHS = getDerived().parseExpr(); 4685 Node *RHS = getDerived().parseExpr();
4792 if (RHS == nullptr) 4686 if (RHS == nullptr)
4793 return nullptr; 4687 return nullptr;
4794 return make<ConditionalExpr>(Cond, LHS, RHS); 4688 return make<ConditionalExpr>(Cond, LHS, RHS, Op->getPrecedence());
4795 }
4796 return nullptr;
4797 case 'r':
4798 switch (First[1]) {
4799 case 'c': {
4800 First += 2;
4801 Node *T = getDerived().parseType();
4802 if (T == nullptr)
4803 return T;
4804 Node *Ex = getDerived().parseExpr();
4805 if (Ex == nullptr)
4806 return Ex;
4807 return make<CastExpr>("reinterpret_cast", T, Ex);
4808 } 4689 }
4809 case 'm': 4690 case OperatorInfo::NamedCast: {
4810 First += 2; 4691 // Named cast operation, @<type>(expr)
4811 return getDerived().parseBinaryExpr("%");
4812 case 'M':
4813 First += 2;
4814 return getDerived().parseBinaryExpr("%=");
4815 case 's':
4816 First += 2;
4817 return getDerived().parseBinaryExpr(">>");
4818 case 'S':
4819 First += 2;
4820 return getDerived().parseBinaryExpr(">>=");
4821 }
4822 return nullptr;
4823 case 's':
4824 switch (First[1]) {
4825 case 'c': {
4826 First += 2;
4827 Node *T = getDerived().parseType();
4828 if (T == nullptr)
4829 return T;
4830 Node *Ex = getDerived().parseExpr();
4831 if (Ex == nullptr)
4832 return Ex;
4833 return make<CastExpr>("static_cast", T, Ex);
4834 }
4835 case 'p': {
4836 First += 2;
4837 Node *Child = getDerived().parseExpr();
4838 if (Child == nullptr)
4839 return nullptr;
4840 return make<ParameterPackExpansion>(Child);
4841 }
4842 case 'r':
4843 return getDerived().parseUnresolvedName();
4844 case 't': {
4845 First += 2;
4846 Node *Ty = getDerived().parseType(); 4692 Node *Ty = getDerived().parseType();
4847 if (Ty == nullptr) 4693 if (Ty == nullptr)
4848 return Ty; 4694 return nullptr;
4849 return make<EnclosingExpr>("sizeof (", Ty, ")");
4850 }
4851 case 'z': {
4852 First += 2;
4853 Node *Ex = getDerived().parseExpr(); 4695 Node *Ex = getDerived().parseExpr();
4854 if (Ex == nullptr) 4696 if (Ex == nullptr)
4855 return Ex;
4856 return make<EnclosingExpr>("sizeof (", Ex, ")");
4857 }
4858 case 'Z':
4859 First += 2;
4860 if (look() == 'T') {
4861 Node *R = getDerived().parseTemplateParam();
4862 if (R == nullptr)
4863 return nullptr;
4864 return make<SizeofParamPackExpr>(R);
4865 } else if (look() == 'f') {
4866 Node *FP = getDerived().parseFunctionParam();
4867 if (FP == nullptr)
4868 return nullptr;
4869 return make<EnclosingExpr>("sizeof... (", FP, ")");
4870 }
4871 return nullptr;
4872 case 'P': {
4873 First += 2;
4874 size_t ArgsBegin = Names.size();
4875 while (!consumeIf('E')) {
4876 Node *Arg = getDerived().parseTemplateArg();
4877 if (Arg == nullptr)
4878 return nullptr;
4879 Names.push_back(Arg);
4880 }
4881 auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
4882 if (!Pack)
4883 return nullptr; 4697 return nullptr;
4884 return make<EnclosingExpr>("sizeof... (", Pack, ")"); 4698 return make<CastExpr>(Sym, Ty, Ex, Op->getPrecedence());
4885 } 4699 }
4700 case OperatorInfo::OfIdOp: {
4701 // [sizeof/alignof/typeid] ( <type>|<expr> )
4702 Node *Arg =
4703 Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr();
4704 if (!Arg)
4705 return nullptr;
4706 return make<EnclosingExpr>(Sym, Arg, Op->getPrecedence());
4886 } 4707 }
4887 return nullptr; 4708 case OperatorInfo::NameOnly: {
4888 case 't': 4709 // Not valid as an expression operand.
4889 switch (First[1]) { 4710 return nullptr;
4890 case 'e': {
4891 First += 2;
4892 Node *Ex = getDerived().parseExpr();
4893 if (Ex == nullptr)
4894 return Ex;
4895 return make<EnclosingExpr>("typeid (", Ex, ")");
4896 } 4711 }
4897 case 'i': {
4898 First += 2;
4899 Node *Ty = getDerived().parseType();
4900 if (Ty == nullptr)
4901 return Ty;
4902 return make<EnclosingExpr>("typeid (", Ty, ")");
4903 } 4712 }
4904 case 'l': { 4713 DEMANGLE_UNREACHABLE;
4905 First += 2; 4714 }
4906 Node *Ty = getDerived().parseType(); 4715
4907 if (Ty == nullptr) 4716 if (numLeft() < 2)
4717 return nullptr;
4718
4719 if (look() == 'L')
4720 return getDerived().parseExprPrimary();
4721 if (look() == 'T')
4722 return getDerived().parseTemplateParam();
4723 if (look() == 'f') {
4724 // Disambiguate a fold expression from a <function-param>.
4725 if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
4726 return getDerived().parseFunctionParam();
4727 return getDerived().parseFoldExpr();
4728 }
4729 if (consumeIf("il")) {
4730 size_t InitsBegin = Names.size();
4731 while (!consumeIf('E')) {
4732 Node *E = getDerived().parseBracedExpr();
4733 if (E == nullptr)
4908 return nullptr; 4734 return nullptr;
4909 size_t InitsBegin = Names.size(); 4735 Names.push_back(E);
4910 while (!consumeIf('E')) {
4911 Node *E = getDerived().parseBracedExpr();
4912 if (E == nullptr)
4913 return nullptr;
4914 Names.push_back(E);
4915 }
4916 return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
4917 } 4736 }
4918 case 'r': 4737 return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
4919 First += 2; 4738 }
4920 return make<NameType>("throw"); 4739 if (consumeIf("mc"))
4921 case 'w': { 4740 return parsePointerToMemberConversionExpr(Node::Prec::Unary);
4922 First += 2; 4741 if (consumeIf("nx")) {
4923 Node *Ex = getDerived().parseExpr(); 4742 Node *Ex = getDerived().parseExpr();
4924 if (Ex == nullptr) 4743 if (Ex == nullptr)
4744 return Ex;
4745 return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
4746 }
4747 if (consumeIf("so"))
4748 return parseSubobjectExpr();
4749 if (consumeIf("sp")) {
4750 Node *Child = getDerived().parseExpr();
4751 if (Child == nullptr)
4752 return nullptr;
4753 return make<ParameterPackExpansion>(Child);
4754 }
4755 if (consumeIf("sZ")) {
4756 if (look() == 'T') {
4757 Node *R = getDerived().parseTemplateParam();
4758 if (R == nullptr)
4925 return nullptr; 4759 return nullptr;
4926 return make<ThrowExpr>(Ex); 4760 return make<SizeofParamPackExpr>(R);
4927 } 4761 }
4762 Node *FP = getDerived().parseFunctionParam();
4763 if (FP == nullptr)
4764 return nullptr;
4765 return make<EnclosingExpr>("sizeof... ", FP);
4766 }
4767 if (consumeIf("sP")) {
4768 size_t ArgsBegin = Names.size();
4769 while (!consumeIf('E')) {
4770 Node *Arg = getDerived().parseTemplateArg();
4771 if (Arg == nullptr)
4772 return nullptr;
4773 Names.push_back(Arg);
4928 } 4774 }
4929 return nullptr; 4775 auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
4930 case '1': 4776 if (!Pack)
4931 case '2': 4777 return nullptr;
4932 case '3': 4778 return make<EnclosingExpr>("sizeof... ", Pack);
4933 case '4': 4779 }
4934 case '5': 4780 if (consumeIf("tl")) {
4935 case '6':
4936 case '7':
4937 case '8':
4938 case '9':
4939 return getDerived().parseUnresolvedName();
4940 }
4941
4942 if (consumeIf("u8__uuidoft")) {
4943 Node *Ty = getDerived().parseType(); 4781 Node *Ty = getDerived().parseType();
4944 if (!Ty) 4782 if (Ty == nullptr)
4945 return nullptr; 4783 return nullptr;
4946 return make<UUIDOfExpr>(Ty); 4784 size_t InitsBegin = Names.size();
4785 while (!consumeIf('E')) {
4786 Node *E = getDerived().parseBracedExpr();
4787 if (E == nullptr)
4788 return nullptr;
4789 Names.push_back(E);
4790 }
4791 return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
4947 } 4792 }
4948 4793 if (consumeIf("tr"))
4949 if (consumeIf("u8__uuidofz")) { 4794 return make<NameType>("throw");
4795 if (consumeIf("tw")) {
4950 Node *Ex = getDerived().parseExpr(); 4796 Node *Ex = getDerived().parseExpr();
4951 if (!Ex) 4797 if (Ex == nullptr)
4952 return nullptr; 4798 return nullptr;
4953 return make<UUIDOfExpr>(Ex); 4799 return make<ThrowExpr>(Ex);
4800 }
4801 if (consumeIf('u')) {
4802 Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr);
4803 if (!Name)
4804 return nullptr;
4805 // Special case legacy __uuidof mangling. The 't' and 'z' appear where the
4806 // standard encoding expects a <template-arg>, and would be otherwise be
4807 // interpreted as <type> node 'short' or 'ellipsis'. However, neither
4808 // __uuidof(short) nor __uuidof(...) can actually appear, so there is no
4809 // actual conflict here.
4810 bool IsUUID = false;
4811 Node *UUID = nullptr;
4812 if (Name->getBaseName() == "__uuidof") {
4813 if (consumeIf('t')) {
4814 UUID = getDerived().parseType();
4815 IsUUID = true;
4816 } else if (consumeIf('z')) {
4817 UUID = getDerived().parseExpr();
4818 IsUUID = true;
4819 }
4820 }
4821 size_t ExprsBegin = Names.size();
4822 if (IsUUID) {
4823 if (UUID == nullptr)
4824 return nullptr;
4825 Names.push_back(UUID);
4826 } else {
4827 while (!consumeIf('E')) {
4828 Node *E = getDerived().parseTemplateArg();
4829 if (E == nullptr)
4830 return E;
4831 Names.push_back(E);
4832 }
4833 }
4834 return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin),
4835 Node::Prec::Postfix);
4954 } 4836 }
4955 4837
4956 return nullptr; 4838 // Only unresolved names remain.
4839 return getDerived().parseUnresolvedName(Global);
4957} 4840}
4958 4841
4959// <call-offset> ::= h <nv-offset> _ 4842// <call-offset> ::= h <nv-offset> _
@@ -4986,19 +4869,32 @@ bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() {
4986// # second call-offset is result adjustment 4869// # second call-offset is result adjustment
4987// ::= T <call-offset> <base encoding> 4870// ::= T <call-offset> <base encoding>
4988// # base is the nominal target function of thunk 4871// # base is the nominal target function of thunk
4989// ::= GV <object name> # Guard variable for one-time initialization 4872// # Guard variable for one-time initialization
4873// ::= GV <object name>
4990// # No <type> 4874// # No <type>
4991// ::= TW <object name> # Thread-local wrapper 4875// ::= TW <object name> # Thread-local wrapper
4992// ::= TH <object name> # Thread-local initialization 4876// ::= TH <object name> # Thread-local initialization
4993// ::= GR <object name> _ # First temporary 4877// ::= GR <object name> _ # First temporary
4994// ::= GR <object name> <seq-id> _ # Subsequent temporaries 4878// ::= GR <object name> <seq-id> _ # Subsequent temporaries
4995// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first 4879// # construction vtable for second-in-first
4880// extension ::= TC <first type> <number> _ <second type>
4996// extension ::= GR <object name> # reference temporary for object 4881// extension ::= GR <object name> # reference temporary for object
4882// extension ::= GI <module name> # module global initializer
4997template <typename Derived, typename Alloc> 4883template <typename Derived, typename Alloc>
4998Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { 4884Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
4999 switch (look()) { 4885 switch (look()) {
5000 case 'T': 4886 case 'T':
5001 switch (look(1)) { 4887 switch (look(1)) {
4888 // TA <template-arg> # template parameter object
4889 //
4890 // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63
4891 case 'A': {
4892 First += 2;
4893 Node *Arg = getDerived().parseTemplateArg();
4894 if (Arg == nullptr)
4895 return nullptr;
4896 return make<SpecialName>("template parameter object for ", Arg);
4897 }
5002 // TV <type> # virtual table 4898 // TV <type> # virtual table
5003 case 'V': { 4899 case 'V': {
5004 First += 2; 4900 First += 2;
@@ -5110,6 +5006,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
5110 return nullptr; 5006 return nullptr;
5111 return make<SpecialName>("reference temporary for ", Name); 5007 return make<SpecialName>("reference temporary for ", Name);
5112 } 5008 }
5009 // GI <module-name> v
5010 case 'I': {
5011 First += 2;
5012 ModuleName *Module = nullptr;
5013 if (getDerived().parseModuleNameOpt(Module))
5014 return nullptr;
5015 if (Module == nullptr)
5016 return nullptr;
5017 return make<SpecialName>("initializer for module ", Module);
5018 }
5113 } 5019 }
5114 } 5020 }
5115 return nullptr; 5021 return nullptr;
@@ -5120,6 +5026,26 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
5120// ::= <special-name> 5026// ::= <special-name>
5121template <typename Derived, typename Alloc> 5027template <typename Derived, typename Alloc>
5122Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { 5028Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
5029 // The template parameters of an encoding are unrelated to those of the
5030 // enclosing context.
5031 class SaveTemplateParams {
5032 AbstractManglingParser *Parser;
5033 decltype(TemplateParams) OldParams;
5034 decltype(OuterTemplateParams) OldOuterParams;
5035
5036 public:
5037 SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
5038 OldParams = std::move(Parser->TemplateParams);
5039 OldOuterParams = std::move(Parser->OuterTemplateParams);
5040 Parser->TemplateParams.clear();
5041 Parser->OuterTemplateParams.clear();
5042 }
5043 ~SaveTemplateParams() {
5044 Parser->TemplateParams = std::move(OldParams);
5045 Parser->OuterTemplateParams = std::move(OldOuterParams);
5046 }
5047 } SaveTemplateParams(this);
5048
5123 if (look() == 'G' || look() == 'T') 5049 if (look() == 'G' || look() == 'T')
5124 return getDerived().parseSpecialName(); 5050 return getDerived().parseSpecialName();
5125 5051
@@ -5204,14 +5130,19 @@ template <>
5204struct FloatData<long double> 5130struct FloatData<long double>
5205{ 5131{
5206#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ 5132#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
5207 defined(__wasm__) 5133 defined(__wasm__) || defined(__riscv) || defined(__loongarch__)
5208 static const size_t mangled_size = 32; 5134 static const size_t mangled_size = 32;
5209#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) 5135#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
5210 static const size_t mangled_size = 16; 5136 static const size_t mangled_size = 16;
5211#else 5137#else
5212 static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms 5138 static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
5213#endif 5139#endif
5214 static const size_t max_demangled_size = 40; 5140 // `-0x1.ffffffffffffffffffffffffffffp+16383` + 'L' + '\0' == 42 bytes.
5141 // 28 'f's * 4 bits == 112 bits, which is the number of mantissa bits.
5142 // Negatives are one character longer than positives.
5143 // `0x1.` and `p` are constant, and exponents `+16383` and `-16382` are the
5144 // same length. 1 sign bit, 112 mantissa bits, and 15 exponent bits == 128.
5145 static const size_t max_demangled_size = 42;
5215 static constexpr const char *spec = "%LaL"; 5146 static constexpr const char *spec = "%LaL";
5216}; 5147};
5217 5148
@@ -5221,7 +5152,7 @@ Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() {
5221 const size_t N = FloatData<Float>::mangled_size; 5152 const size_t N = FloatData<Float>::mangled_size;
5222 if (numLeft() <= N) 5153 if (numLeft() <= N)
5223 return nullptr; 5154 return nullptr;
5224 StringView Data(First, First + N); 5155 std::string_view Data(First, N);
5225 for (char C : Data) 5156 for (char C : Data)
5226 if (!std::isxdigit(C)) 5157 if (!std::isxdigit(C))
5227 return nullptr; 5158 return nullptr;
@@ -5264,43 +5195,41 @@ bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) {
5264// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > 5195// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
5265// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > 5196// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
5266// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > 5197// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
5198// The St case is handled specially in parseNestedName.
5267template <typename Derived, typename Alloc> 5199template <typename Derived, typename Alloc>
5268Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { 5200Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
5269 if (!consumeIf('S')) 5201 if (!consumeIf('S'))
5270 return nullptr; 5202 return nullptr;
5271 5203
5272 if (std::islower(look())) { 5204 if (look() >= 'a' && look() <= 'z') {
5273 Node *SpecialSub; 5205 SpecialSubKind Kind;
5274 switch (look()) { 5206 switch (look()) {
5275 case 'a': 5207 case 'a':
5276 ++First; 5208 Kind = SpecialSubKind::allocator;
5277 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
5278 break; 5209 break;
5279 case 'b': 5210 case 'b':
5280 ++First; 5211 Kind = SpecialSubKind::basic_string;
5281 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);
5282 break; 5212 break;
5283 case 's': 5213 case 'd':
5284 ++First; 5214 Kind = SpecialSubKind::iostream;
5285 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
5286 break; 5215 break;
5287 case 'i': 5216 case 'i':
5288 ++First; 5217 Kind = SpecialSubKind::istream;
5289 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
5290 break; 5218 break;
5291 case 'o': 5219 case 'o':
5292 ++First; 5220 Kind = SpecialSubKind::ostream;
5293 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
5294 break; 5221 break;
5295 case 'd': 5222 case 's':
5296 ++First; 5223 Kind = SpecialSubKind::string;
5297 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
5298 break; 5224 break;
5299 default: 5225 default:
5300 return nullptr; 5226 return nullptr;
5301 } 5227 }
5228 ++First;
5229 auto *SpecialSub = make<SpecialSubstitution>(Kind);
5302 if (!SpecialSub) 5230 if (!SpecialSub)
5303 return nullptr; 5231 return nullptr;
5232
5304 // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution> 5233 // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>
5305 // has ABI tags, the tags are appended to the substitution; the result is a 5234 // has ABI tags, the tags are appended to the substitution; the result is a
5306 // substitutable component. 5235 // substitutable component.
@@ -5543,7 +5472,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() {
5543 if (Encoding == nullptr) 5472 if (Encoding == nullptr)
5544 return nullptr; 5473 return nullptr;
5545 if (look() == '.') { 5474 if (look() == '.') {
5546 Encoding = make<DotSuffix>(Encoding, StringView(First, Last)); 5475 Encoding =
5476 make<DotSuffix>(Encoding, std::string_view(First, Last - First));
5547 First = Last; 5477 First = Last;
5548 } 5478 }
5549 if (numLeft() != 0) 5479 if (numLeft() != 0)
diff --git a/externals/demangle/llvm/Demangle/ItaniumNodes.def b/externals/demangle/llvm/Demangle/ItaniumNodes.def
new file mode 100644
index 000000000..5985769ef
--- /dev/null
+++ b/externals/demangle/llvm/Demangle/ItaniumNodes.def
@@ -0,0 +1,96 @@
1//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===//
2// Do not edit! See README.txt.
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-FileCopyrightText: Part of the LLVM Project
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9//
10// Define the demangler's node names
11
12#ifndef NODE
13#error Define NODE to handle nodes
14#endif
15
16NODE(NodeArrayNode)
17NODE(DotSuffix)
18NODE(VendorExtQualType)
19NODE(QualType)
20NODE(ConversionOperatorType)
21NODE(PostfixQualifiedType)
22NODE(ElaboratedTypeSpefType)
23NODE(NameType)
24NODE(AbiTagAttr)
25NODE(EnableIfAttr)
26NODE(ObjCProtoName)
27NODE(PointerType)
28NODE(ReferenceType)
29NODE(PointerToMemberType)
30NODE(ArrayType)
31NODE(FunctionType)
32NODE(NoexceptSpec)
33NODE(DynamicExceptionSpec)
34NODE(FunctionEncoding)
35NODE(LiteralOperator)
36NODE(SpecialName)
37NODE(CtorVtableSpecialName)
38NODE(QualifiedName)
39NODE(NestedName)
40NODE(LocalName)
41NODE(ModuleName)
42NODE(ModuleEntity)
43NODE(VectorType)
44NODE(PixelVectorType)
45NODE(BinaryFPType)
46NODE(BitIntType)
47NODE(SyntheticTemplateParamName)
48NODE(TypeTemplateParamDecl)
49NODE(NonTypeTemplateParamDecl)
50NODE(TemplateTemplateParamDecl)
51NODE(TemplateParamPackDecl)
52NODE(ParameterPack)
53NODE(TemplateArgumentPack)
54NODE(ParameterPackExpansion)
55NODE(TemplateArgs)
56NODE(ForwardTemplateReference)
57NODE(NameWithTemplateArgs)
58NODE(GlobalQualifiedName)
59NODE(ExpandedSpecialSubstitution)
60NODE(SpecialSubstitution)
61NODE(CtorDtorName)
62NODE(DtorName)
63NODE(UnnamedTypeName)
64NODE(ClosureTypeName)
65NODE(StructuredBindingName)
66NODE(BinaryExpr)
67NODE(ArraySubscriptExpr)
68NODE(PostfixExpr)
69NODE(ConditionalExpr)
70NODE(MemberExpr)
71NODE(SubobjectExpr)
72NODE(EnclosingExpr)
73NODE(CastExpr)
74NODE(SizeofParamPackExpr)
75NODE(CallExpr)
76NODE(NewExpr)
77NODE(DeleteExpr)
78NODE(PrefixExpr)
79NODE(FunctionParam)
80NODE(ConversionExpr)
81NODE(PointerToMemberConversionExpr)
82NODE(InitListExpr)
83NODE(FoldExpr)
84NODE(ThrowExpr)
85NODE(BoolExpr)
86NODE(StringLiteral)
87NODE(LambdaExpr)
88NODE(EnumLiteral)
89NODE(IntegerLiteral)
90NODE(FloatLiteral)
91NODE(DoubleLiteral)
92NODE(LongDoubleLiteral)
93NODE(BracedExpr)
94NODE(BracedRangeExpr)
95
96#undef NODE
diff --git a/externals/demangle/llvm/Demangle/StringView.h b/externals/demangle/llvm/Demangle/StringView.h
index 44d2b18a3..76b215252 100644
--- a/externals/demangle/llvm/Demangle/StringView.h
+++ b/externals/demangle/llvm/Demangle/StringView.h
@@ -1,5 +1,5 @@
1//===--- StringView.h -------------------------------------------*- C++ -*-===// 1//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===//
2// 2// Do not edit! See README.txt.
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information. 4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-FileCopyrightText: Part of the LLVM Project 5// SPDX-FileCopyrightText: Part of the LLVM Project
@@ -8,6 +8,9 @@
8//===----------------------------------------------------------------------===// 8//===----------------------------------------------------------------------===//
9// 9//
10// FIXME: Use std::string_view instead when we support C++17. 10// FIXME: Use std::string_view instead when we support C++17.
11// There are two copies of this file in the source tree. The one under
12// libcxxabi is the original and the one under llvm is the copy. Use
13// cp-to-llvm.sh to update the copy. See README.txt for more details.
11// 14//
12//===----------------------------------------------------------------------===// 15//===----------------------------------------------------------------------===//
13 16
@@ -15,7 +18,6 @@
15#define DEMANGLE_STRINGVIEW_H 18#define DEMANGLE_STRINGVIEW_H
16 19
17#include "DemangleConfig.h" 20#include "DemangleConfig.h"
18#include <algorithm>
19#include <cassert> 21#include <cassert>
20#include <cstring> 22#include <cstring>
21 23
@@ -37,29 +39,23 @@ public:
37 StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} 39 StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
38 StringView() : First(nullptr), Last(nullptr) {} 40 StringView() : First(nullptr), Last(nullptr) {}
39 41
40 StringView substr(size_t From) const { 42 StringView substr(size_t Pos, size_t Len = npos) const {
41 return StringView(begin() + From, size() - From); 43 assert(Pos <= size());
44 if (Len > size() - Pos)
45 Len = size() - Pos;
46 return StringView(begin() + Pos, Len);
42 } 47 }
43 48
44 size_t find(char C, size_t From = 0) const { 49 size_t find(char C, size_t From = 0) const {
45 size_t FindBegin = std::min(From, size());
46 // Avoid calling memchr with nullptr. 50 // Avoid calling memchr with nullptr.
47 if (FindBegin < size()) { 51 if (From < size()) {
48 // Just forward to memchr, which is faster than a hand-rolled loop. 52 // Just forward to memchr, which is faster than a hand-rolled loop.
49 if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) 53 if (const void *P = ::memchr(First + From, C, size() - From))
50 return size_t(static_cast<const char *>(P) - First); 54 return size_t(static_cast<const char *>(P) - First);
51 } 55 }
52 return npos; 56 return npos;
53 } 57 }
54 58
55 StringView substr(size_t From, size_t To) const {
56 if (To >= size())
57 To = size() - 1;
58 if (From >= size())
59 From = size() - 1;
60 return StringView(First + From, First + To);
61 }
62
63 StringView dropFront(size_t N = 1) const { 59 StringView dropFront(size_t N = 1) const {
64 if (N >= size()) 60 if (N >= size())
65 N = size(); 61 N = size();
@@ -106,7 +102,7 @@ public:
106 bool startsWith(StringView Str) const { 102 bool startsWith(StringView Str) const {
107 if (Str.size() > size()) 103 if (Str.size() > size())
108 return false; 104 return false;
109 return std::equal(Str.begin(), Str.end(), begin()); 105 return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
110 } 106 }
111 107
112 const char &operator[](size_t Idx) const { return *(begin() + Idx); } 108 const char &operator[](size_t Idx) const { return *(begin() + Idx); }
@@ -119,7 +115,7 @@ public:
119 115
120inline bool operator==(const StringView &LHS, const StringView &RHS) { 116inline bool operator==(const StringView &LHS, const StringView &RHS) {
121 return LHS.size() == RHS.size() && 117 return LHS.size() == RHS.size() &&
122 std::equal(LHS.begin(), LHS.end(), RHS.begin()); 118 std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
123} 119}
124 120
125DEMANGLE_NAMESPACE_END 121DEMANGLE_NAMESPACE_END
diff --git a/externals/demangle/llvm/Demangle/StringViewExtras.h b/externals/demangle/llvm/Demangle/StringViewExtras.h
new file mode 100644
index 000000000..83685c304
--- /dev/null
+++ b/externals/demangle/llvm/Demangle/StringViewExtras.h
@@ -0,0 +1,39 @@
1//===--- StringViewExtras.h ----------*- mode:c++;eval:(read-only-mode) -*-===//
2// Do not edit! See README.txt.
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-FileCopyrightText: Part of the LLVM Project
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9//
10// There are two copies of this file in the source tree. The one under
11// libcxxabi is the original and the one under llvm is the copy. Use
12// cp-to-llvm.sh to update the copy. See README.txt for more details.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef DEMANGLE_STRINGVIEW_H
17#define DEMANGLE_STRINGVIEW_H
18
19#include "DemangleConfig.h"
20
21#include <string_view>
22
23DEMANGLE_NAMESPACE_BEGIN
24
25inline bool starts_with(std::string_view self, char C) noexcept {
26 return !self.empty() && *self.begin() == C;
27}
28
29inline bool starts_with(std::string_view haystack,
30 std::string_view needle) noexcept {
31 if (needle.size() > haystack.size())
32 return false;
33 haystack.remove_suffix(haystack.size() - needle.size());
34 return haystack == needle;
35}
36
37DEMANGLE_NAMESPACE_END
38
39#endif
diff --git a/externals/demangle/llvm/Demangle/Utility.h b/externals/demangle/llvm/Demangle/Utility.h
index 50d05c6b1..30dfbfc8d 100644
--- a/externals/demangle/llvm/Demangle/Utility.h
+++ b/externals/demangle/llvm/Demangle/Utility.h
@@ -1,5 +1,5 @@
1//===--- Utility.h ----------------------------------------------*- C++ -*-===// 1//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
2// 2// Do not edit! See README.txt.
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information. 4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-FileCopyrightText: Part of the LLVM Project 5// SPDX-FileCopyrightText: Part of the LLVM Project
@@ -7,70 +7,83 @@
7// 7//
8//===----------------------------------------------------------------------===// 8//===----------------------------------------------------------------------===//
9// 9//
10// Provide some utility classes for use in the demangler(s). 10// Provide some utility classes for use in the demangler.
11// There are two copies of this file in the source tree. The one in libcxxabi
12// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
13// the copy. See README.txt for more details.
11// 14//
12//===----------------------------------------------------------------------===// 15//===----------------------------------------------------------------------===//
13 16
14#ifndef DEMANGLE_UTILITY_H 17#ifndef DEMANGLE_UTILITY_H
15#define DEMANGLE_UTILITY_H 18#define DEMANGLE_UTILITY_H
16 19
17#include "StringView.h" 20#include "DemangleConfig.h"
21
22#include <array>
23#include <cassert>
18#include <cstdint> 24#include <cstdint>
19#include <cstdlib> 25#include <cstdlib>
20#include <cstring> 26#include <cstring>
21#include <iterator> 27#include <exception>
22#include <limits> 28#include <limits>
29#include <string_view>
23 30
24DEMANGLE_NAMESPACE_BEGIN 31DEMANGLE_NAMESPACE_BEGIN
25 32
26// Stream that AST nodes write their string representation into after the AST 33// Stream that AST nodes write their string representation into after the AST
27// has been parsed. 34// has been parsed.
28class OutputStream { 35class OutputBuffer {
29 char *Buffer; 36 char *Buffer = nullptr;
30 size_t CurrentPosition; 37 size_t CurrentPosition = 0;
31 size_t BufferCapacity; 38 size_t BufferCapacity = 0;
32 39
33 // Ensure there is at least n more positions in buffer. 40 // Ensure there are at least N more positions in the buffer.
34 void grow(size_t N) { 41 void grow(size_t N) {
35 if (N + CurrentPosition >= BufferCapacity) { 42 size_t Need = N + CurrentPosition;
43 if (Need > BufferCapacity) {
44 // Reduce the number of reallocations, with a bit of hysteresis. The
45 // number here is chosen so the first allocation will more-than-likely not
46 // allocate more than 1K.
47 Need += 1024 - 32;
36 BufferCapacity *= 2; 48 BufferCapacity *= 2;
37 if (BufferCapacity < N + CurrentPosition) 49 if (BufferCapacity < Need)
38 BufferCapacity = N + CurrentPosition; 50 BufferCapacity = Need;
39 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); 51 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
40 if (Buffer == nullptr) 52 if (Buffer == nullptr)
41 std::terminate(); 53 std::terminate();
42 } 54 }
43 } 55 }
44 56
45 void writeUnsigned(uint64_t N, bool isNeg = false) { 57 OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
46 // Handle special case... 58 std::array<char, 21> Temp;
47 if (N == 0) { 59 char *TempPtr = Temp.data() + Temp.size();
48 *this << '0';
49 return;
50 }
51
52 char Temp[21];
53 char *TempPtr = std::end(Temp);
54 60
55 while (N) { 61 // Output at least one character.
56 *--TempPtr = '0' + char(N % 10); 62 do {
63 *--TempPtr = char('0' + N % 10);
57 N /= 10; 64 N /= 10;
58 } 65 } while (N);
59 66
60 // Add negative sign... 67 // Add negative sign.
61 if (isNeg) 68 if (isNeg)
62 *--TempPtr = '-'; 69 *--TempPtr = '-';
63 this->operator<<(StringView(TempPtr, std::end(Temp))); 70
71 return operator+=(
72 std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
64 } 73 }
65 74
66public: 75public:
67 OutputStream(char *StartBuf, size_t Size) 76 OutputBuffer(char *StartBuf, size_t Size)
68 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} 77 : Buffer(StartBuf), BufferCapacity(Size) {}
69 OutputStream() = default; 78 OutputBuffer(char *StartBuf, size_t *SizePtr)
70 void reset(char *Buffer_, size_t BufferCapacity_) { 79 : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
71 CurrentPosition = 0; 80 OutputBuffer() = default;
72 Buffer = Buffer_; 81 // Non-copyable
73 BufferCapacity = BufferCapacity_; 82 OutputBuffer(const OutputBuffer &) = delete;
83 OutputBuffer &operator=(const OutputBuffer &) = delete;
84
85 operator std::string_view() const {
86 return std::string_view(Buffer, CurrentPosition);
74 } 87 }
75 88
76 /// If a ParameterPackExpansion (or similar type) is encountered, the offset 89 /// If a ParameterPackExpansion (or similar type) is encountered, the offset
@@ -78,115 +91,116 @@ public:
78 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); 91 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
79 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); 92 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
80 93
81 OutputStream &operator+=(StringView R) { 94 /// When zero, we're printing template args and '>' needs to be parenthesized.
82 size_t Size = R.size(); 95 /// Use a counter so we can simply increment inside parentheses.
83 if (Size == 0) 96 unsigned GtIsGt = 1;
84 return *this; 97
85 grow(Size); 98 bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
86 std::memmove(Buffer + CurrentPosition, R.begin(), Size); 99
87 CurrentPosition += Size; 100 void printOpen(char Open = '(') {
101 GtIsGt++;
102 *this += Open;
103 }
104 void printClose(char Close = ')') {
105 GtIsGt--;
106 *this += Close;
107 }
108
109 OutputBuffer &operator+=(std::string_view R) {
110 if (size_t Size = R.size()) {
111 grow(Size);
112 std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);
113 CurrentPosition += Size;
114 }
88 return *this; 115 return *this;
89 } 116 }
90 117
91 OutputStream &operator+=(char C) { 118 OutputBuffer &operator+=(char C) {
92 grow(1); 119 grow(1);
93 Buffer[CurrentPosition++] = C; 120 Buffer[CurrentPosition++] = C;
94 return *this; 121 return *this;
95 } 122 }
96 123
97 OutputStream &operator<<(StringView R) { return (*this += R); } 124 OutputBuffer &prepend(std::string_view R) {
125 size_t Size = R.size();
98 126
99 OutputStream &operator<<(char C) { return (*this += C); } 127 grow(Size);
128 std::memmove(Buffer + Size, Buffer, CurrentPosition);
129 std::memcpy(Buffer, &*R.begin(), Size);
130 CurrentPosition += Size;
100 131
101 OutputStream &operator<<(long long N) {
102 if (N < 0)
103 writeUnsigned(static_cast<unsigned long long>(-N), true);
104 else
105 writeUnsigned(static_cast<unsigned long long>(N));
106 return *this; 132 return *this;
107 } 133 }
108 134
109 OutputStream &operator<<(unsigned long long N) { 135 OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
110 writeUnsigned(N, false); 136
111 return *this; 137 OutputBuffer &operator<<(char C) { return (*this += C); }
138
139 OutputBuffer &operator<<(long long N) {
140 return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
112 } 141 }
113 142
114 OutputStream &operator<<(long N) { 143 OutputBuffer &operator<<(unsigned long long N) {
144 return writeUnsigned(N, false);
145 }
146
147 OutputBuffer &operator<<(long N) {
115 return this->operator<<(static_cast<long long>(N)); 148 return this->operator<<(static_cast<long long>(N));
116 } 149 }
117 150
118 OutputStream &operator<<(unsigned long N) { 151 OutputBuffer &operator<<(unsigned long N) {
119 return this->operator<<(static_cast<unsigned long long>(N)); 152 return this->operator<<(static_cast<unsigned long long>(N));
120 } 153 }
121 154
122 OutputStream &operator<<(int N) { 155 OutputBuffer &operator<<(int N) {
123 return this->operator<<(static_cast<long long>(N)); 156 return this->operator<<(static_cast<long long>(N));
124 } 157 }
125 158
126 OutputStream &operator<<(unsigned int N) { 159 OutputBuffer &operator<<(unsigned int N) {
127 return this->operator<<(static_cast<unsigned long long>(N)); 160 return this->operator<<(static_cast<unsigned long long>(N));
128 } 161 }
129 162
163 void insert(size_t Pos, const char *S, size_t N) {
164 assert(Pos <= CurrentPosition);
165 if (N == 0)
166 return;
167 grow(N);
168 std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
169 std::memcpy(Buffer + Pos, S, N);
170 CurrentPosition += N;
171 }
172
130 size_t getCurrentPosition() const { return CurrentPosition; } 173 size_t getCurrentPosition() const { return CurrentPosition; }
131 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } 174 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
132 175
133 char back() const { 176 char back() const {
134 return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; 177 assert(CurrentPosition);
178 return Buffer[CurrentPosition - 1];
135 } 179 }
136 180
137 bool empty() const { return CurrentPosition == 0; } 181 bool empty() const { return CurrentPosition == 0; }
138 182
139 char *getBuffer() { return Buffer; } 183 char *getBuffer() { return Buffer; }
140 char *getBufferEnd() { return Buffer + CurrentPosition - 1; } 184 char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
141 size_t getBufferCapacity() { return BufferCapacity; } 185 size_t getBufferCapacity() const { return BufferCapacity; }
142}; 186};
143 187
144template <class T> class SwapAndRestore { 188template <class T> class ScopedOverride {
145 T &Restore; 189 T &Loc;
146 T OriginalValue; 190 T Original;
147 bool ShouldRestore = true;
148 191
149public: 192public:
150 SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} 193 ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
151
152 SwapAndRestore(T &Restore_, T NewVal)
153 : Restore(Restore_), OriginalValue(Restore) {
154 Restore = std::move(NewVal);
155 }
156 ~SwapAndRestore() {
157 if (ShouldRestore)
158 Restore = std::move(OriginalValue);
159 }
160 194
161 void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } 195 ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
162 196 Loc_ = std::move(NewVal);
163 void restoreNow(bool Force) {
164 if (!Force && !ShouldRestore)
165 return;
166
167 Restore = std::move(OriginalValue);
168 ShouldRestore = false;
169 } 197 }
198 ~ScopedOverride() { Loc = std::move(Original); }
170 199
171 SwapAndRestore(const SwapAndRestore &) = delete; 200 ScopedOverride(const ScopedOverride &) = delete;
172 SwapAndRestore &operator=(const SwapAndRestore &) = delete; 201 ScopedOverride &operator=(const ScopedOverride &) = delete;
173}; 202};
174 203
175inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
176 size_t InitSize) {
177 size_t BufferSize;
178 if (Buf == nullptr) {
179 Buf = static_cast<char *>(std::malloc(InitSize));
180 if (Buf == nullptr)
181 return false;
182 BufferSize = InitSize;
183 } else
184 BufferSize = *N;
185
186 S.reset(Buf, BufferSize);
187 return true;
188}
189
190DEMANGLE_NAMESPACE_END 204DEMANGLE_NAMESPACE_END
191 205
192#endif 206#endif
diff --git a/externals/vma/VulkanMemoryAllocator b/externals/vma/VulkanMemoryAllocator
deleted file mode 160000
Subproject 0aa3989b8f382f185fdf646cc83a1d16fa31d6a
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml
index 742685fb0..6184f3eb6 100644
--- a/src/android/app/src/main/AndroidManifest.xml
+++ b/src/android/app/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
22 android:label="@string/app_name_suffixed" 22 android:label="@string/app_name_suffixed"
23 android:icon="@drawable/ic_launcher" 23 android:icon="@drawable/ic_launcher"
24 android:allowBackup="true" 24 android:allowBackup="true"
25 android:hasFragileUserData="true" 25 android:hasFragileUserData="false"
26 android:supportsRtl="true" 26 android:supportsRtl="true"
27 android:isGame="true" 27 android:isGame="true"
28 android:localeConfig="@xml/locales_config" 28 android:localeConfig="@xml/locales_config"
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
index d3df3bc81..aadc445f9 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
@@ -12,6 +12,7 @@ import androidx.core.content.res.ResourcesCompat
12import androidx.recyclerview.widget.RecyclerView 12import androidx.recyclerview.widget.RecyclerView
13import org.yuzu.yuzu_emu.R 13import org.yuzu.yuzu_emu.R
14import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding 14import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
15import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
15import org.yuzu.yuzu_emu.model.HomeSetting 16import org.yuzu.yuzu_emu.model.HomeSetting
16 17
17class HomeSettingAdapter(private val activity: AppCompatActivity, var options: List<HomeSetting>) : 18class HomeSettingAdapter(private val activity: AppCompatActivity, var options: List<HomeSetting>) :
@@ -34,7 +35,14 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
34 35
35 override fun onClick(view: View) { 36 override fun onClick(view: View) {
36 val holder = view.tag as HomeOptionViewHolder 37 val holder = view.tag as HomeOptionViewHolder
37 holder.option.onClick.invoke() 38 if (holder.option.isEnabled.invoke()) {
39 holder.option.onClick.invoke()
40 } else {
41 MessageDialogFragment.newInstance(
42 holder.option.disabledTitleId,
43 holder.option.disabledMessageId
44 ).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
45 }
38 } 46 }
39 47
40 inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) : 48 inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
@@ -65,6 +73,12 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
65 R.drawable.premium_background 73 R.drawable.premium_background
66 ) 74 )
67 } 75 }
76
77 if (!option.isEnabled.invoke()) {
78 binding.optionTitle.alpha = 0.5f
79 binding.optionDescription.alpha = 0.5f
80 binding.optionIcon.alpha = 0.5f
81 }
68 } 82 }
69 } 83 }
70} 84}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
index 5a36ffad4..c001af892 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
@@ -73,102 +73,113 @@ class HomeSettingsFragment : Fragment() {
73 HomeSetting( 73 HomeSetting(
74 R.string.advanced_settings, 74 R.string.advanced_settings,
75 R.string.settings_description, 75 R.string.settings_description,
76 R.drawable.ic_settings 76 R.drawable.ic_settings,
77 ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") } 77 { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
78 )
78 ) 79 )
79 add( 80 add(
80 HomeSetting( 81 HomeSetting(
81 R.string.open_user_folder, 82 R.string.open_user_folder,
82 R.string.open_user_folder_description, 83 R.string.open_user_folder_description,
83 R.drawable.ic_folder_open 84 R.drawable.ic_folder_open,
84 ) { openFileManager() } 85 { openFileManager() }
86 )
85 ) 87 )
86 add( 88 add(
87 HomeSetting( 89 HomeSetting(
88 R.string.preferences_theme, 90 R.string.preferences_theme,
89 R.string.theme_and_color_description, 91 R.string.theme_and_color_description,
90 R.drawable.ic_palette 92 R.drawable.ic_palette,
91 ) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") } 93 { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
94 )
92 ) 95 )
93 96 add(
94 if (GpuDriverHelper.supportsCustomDriverLoading()) { 97 HomeSetting(
95 add( 98 R.string.install_gpu_driver,
96 HomeSetting( 99 R.string.install_gpu_driver_description,
97 R.string.install_gpu_driver, 100 R.drawable.ic_exit,
98 R.string.install_gpu_driver_description, 101 { driverInstaller() },
99 R.drawable.ic_exit 102 { GpuDriverHelper.supportsCustomDriverLoading() },
100 ) { driverInstaller() } 103 R.string.custom_driver_not_supported,
104 R.string.custom_driver_not_supported_description
101 ) 105 )
102 } 106 )
103
104 add( 107 add(
105 HomeSetting( 108 HomeSetting(
106 R.string.install_amiibo_keys, 109 R.string.install_amiibo_keys,
107 R.string.install_amiibo_keys_description, 110 R.string.install_amiibo_keys_description,
108 R.drawable.ic_nfc 111 R.drawable.ic_nfc,
109 ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) } 112 { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
113 )
110 ) 114 )
111 add( 115 add(
112 HomeSetting( 116 HomeSetting(
113 R.string.install_game_content, 117 R.string.install_game_content,
114 R.string.install_game_content_description, 118 R.string.install_game_content_description,
115 R.drawable.ic_system_update_alt 119 R.drawable.ic_system_update_alt,
116 ) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) } 120 { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
121 )
117 ) 122 )
118 add( 123 add(
119 HomeSetting( 124 HomeSetting(
120 R.string.select_games_folder, 125 R.string.select_games_folder,
121 R.string.select_games_folder_description, 126 R.string.select_games_folder_description,
122 R.drawable.ic_add 127 R.drawable.ic_add,
123 ) { 128 {
124 mainActivity.getGamesDirectory.launch( 129 mainActivity.getGamesDirectory.launch(
125 Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data 130 Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
126 ) 131 )
127 } 132 }
133 )
128 ) 134 )
129 add( 135 add(
130 HomeSetting( 136 HomeSetting(
131 R.string.manage_save_data, 137 R.string.manage_save_data,
132 R.string.import_export_saves_description, 138 R.string.import_export_saves_description,
133 R.drawable.ic_save 139 R.drawable.ic_save,
134 ) { 140 {
135 ImportExportSavesFragment().show( 141 ImportExportSavesFragment().show(
136 parentFragmentManager, 142 parentFragmentManager,
137 ImportExportSavesFragment.TAG 143 ImportExportSavesFragment.TAG
138 ) 144 )
139 } 145 }
146 )
140 ) 147 )
141 add( 148 add(
142 HomeSetting( 149 HomeSetting(
143 R.string.install_prod_keys, 150 R.string.install_prod_keys,
144 R.string.install_prod_keys_description, 151 R.string.install_prod_keys_description,
145 R.drawable.ic_unlock 152 R.drawable.ic_unlock,
146 ) { mainActivity.getProdKey.launch(arrayOf("*/*")) } 153 { mainActivity.getProdKey.launch(arrayOf("*/*")) }
154 )
147 ) 155 )
148 add( 156 add(
149 HomeSetting( 157 HomeSetting(
150 R.string.install_firmware, 158 R.string.install_firmware,
151 R.string.install_firmware_description, 159 R.string.install_firmware_description,
152 R.drawable.ic_firmware 160 R.drawable.ic_firmware,
153 ) { mainActivity.getFirmware.launch(arrayOf("application/zip")) } 161 { mainActivity.getFirmware.launch(arrayOf("application/zip")) }
162 )
154 ) 163 )
155 add( 164 add(
156 HomeSetting( 165 HomeSetting(
157 R.string.share_log, 166 R.string.share_log,
158 R.string.share_log_description, 167 R.string.share_log_description,
159 R.drawable.ic_log 168 R.drawable.ic_log,
160 ) { shareLog() } 169 { shareLog() }
170 )
161 ) 171 )
162 add( 172 add(
163 HomeSetting( 173 HomeSetting(
164 R.string.about, 174 R.string.about,
165 R.string.about_description, 175 R.string.about_description,
166 R.drawable.ic_info_outline 176 R.drawable.ic_info_outline,
167 ) { 177 {
168 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) 178 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
169 parentFragmentManager.primaryNavigationFragment?.findNavController() 179 parentFragmentManager.primaryNavigationFragment?.findNavController()
170 ?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment) 180 ?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
171 } 181 }
182 )
172 ) 183 )
173 } 184 }
174 185
@@ -178,12 +189,13 @@ class HomeSettingsFragment : Fragment() {
178 HomeSetting( 189 HomeSetting(
179 R.string.get_early_access, 190 R.string.get_early_access,
180 R.string.get_early_access_description, 191 R.string.get_early_access_description,
181 R.drawable.ic_diamond 192 R.drawable.ic_diamond,
182 ) { 193 {
183 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) 194 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
184 parentFragmentManager.primaryNavigationFragment?.findNavController() 195 parentFragmentManager.primaryNavigationFragment?.findNavController()
185 ?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment) 196 ?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment)
186 } 197 }
198 )
187 ) 199 )
188 } 200 }
189 201
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeSetting.kt
index 7049f2fa5..522d07c37 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeSetting.kt
@@ -7,5 +7,8 @@ data class HomeSetting(
7 val titleId: Int, 7 val titleId: Int,
8 val descriptionId: Int, 8 val descriptionId: Int,
9 val iconId: Int, 9 val iconId: Int,
10 val onClick: () -> Unit 10 val onClick: () -> Unit,
11 val isEnabled: () -> Boolean = { true },
12 val disabledTitleId: Int = 0,
13 val disabledMessageId: Int = 0
11) 14)
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 8bc6a4a04..c23b2f19e 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -449,7 +449,7 @@ private:
449 loader->ReadTitle(entry.title); 449 loader->ReadTitle(entry.title);
450 loader->ReadIcon(entry.icon); 450 loader->ReadIcon(entry.icon);
451 if (loader->GetFileType() == Loader::FileType::NRO) { 451 if (loader->GetFileType() == Loader::FileType::NRO) {
452 jauto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get()); 452 jauto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
453 entry.isHomebrew = loader_nro->IsHomebrew(); 453 entry.isHomebrew = loader_nro->IsHomebrew();
454 } else { 454 } else {
455 entry.isHomebrew = false; 455 entry.isHomebrew = false;
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index b3c737979..bfdebd35b 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -113,6 +113,8 @@
113 <string name="install_game_content_success_install">%1$d installed successfully</string> 113 <string name="install_game_content_success_install">%1$d installed successfully</string>
114 <string name="install_game_content_success_overwrite">%1$d overwritten successfully</string> 114 <string name="install_game_content_success_overwrite">%1$d overwritten successfully</string>
115 <string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string> 115 <string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
116 <string name="custom_driver_not_supported">Custom drivers not supported</string>
117 <string name="custom_driver_not_supported_description">Custom driver loading isn\'t currently supported for this device.\nCheck this option again in the future to see if support was added!</string>
116 118
117 <!-- About screen strings --> 119 <!-- About screen strings -->
118 <string name="gaia_is_not_real">Gaia isn\'t real</string> 120 <string name="gaia_is_not_real">Gaia isn\'t real</string>
@@ -230,7 +232,7 @@
230 232
231 <!-- ROM loading errors --> 233 <!-- ROM loading errors -->
232 <string name="loader_error_encrypted">Your ROM is encrypted</string> 234 <string name="loader_error_encrypted">Your ROM is encrypted</string>
233 <string name="loader_error_encrypted_roms_description"><![CDATA[Please follow the guides to redump your <a href="https://yuzu-emu.org/help/quickstart/#dumping-cartridge-games">game cartidges</a> or <a href="https://yuzu-emu.org/help/quickstart/#dumping-installed-titles-eshop">installed titles</a>.]]></string> 235 <string name="loader_error_encrypted_roms_description"><![CDATA[Please follow the guides to redump your <a href="https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards">game cartidges</a> or <a href="https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop">installed titles</a>.]]></string>
234 <string name="loader_error_encrypted_keys_description"><![CDATA[Please ensure your <a href="https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys">prod.keys</a> file is installed so that games can be decrypted.]]></string> 236 <string name="loader_error_encrypted_keys_description"><![CDATA[Please ensure your <a href="https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys">prod.keys</a> file is installed so that games can be decrypted.]]></string>
235 <string name="loader_error_video_core">An error occurred initializing the video core</string> 237 <string name="loader_error_video_core">An error occurred initializing the video core</string>
236 <string name="loader_error_video_core_description">This is usually caused by an incompatible GPU driver. Installing a custom GPU driver may resolve this problem.</string> 238 <string name="loader_error_video_core_description">This is usually caused by an incompatible GPU driver. Installing a custom GPU driver may resolve this problem.</string>
diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp
index 86811fcb8..c41d9d1ea 100644
--- a/src/audio_core/device/device_session.cpp
+++ b/src/audio_core/device/device_session.cpp
@@ -92,9 +92,9 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
92 if (type == Sink::StreamType::In) { 92 if (type == Sink::StreamType::In) {
93 stream->AppendBuffer(new_buffer, tmp_samples); 93 stream->AppendBuffer(new_buffer, tmp_samples);
94 } else { 94 } else {
95 system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(), 95 Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
96 buffer.size); 96 system.ApplicationMemory(), buffer.samples, buffer.size / sizeof(s16));
97 stream->AppendBuffer(new_buffer, tmp_samples); 97 stream->AppendBuffer(new_buffer, samples);
98 } 98 }
99 } 99 }
100} 100}
diff --git a/src/audio_core/renderer/command/data_source/decode.cpp b/src/audio_core/renderer/command/data_source/decode.cpp
index f45933203..257aa866e 100644
--- a/src/audio_core/renderer/command/data_source/decode.cpp
+++ b/src/audio_core/renderer/command/data_source/decode.cpp
@@ -28,7 +28,6 @@ constexpr std::array<u8, 3> PitchBySrcQuality = {4, 8, 4};
28template <typename T> 28template <typename T>
29static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, 29static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
30 const DecodeArg& req) { 30 const DecodeArg& req) {
31 std::array<T, TempBufferSize> tmp_samples{};
32 constexpr s32 min{std::numeric_limits<s16>::min()}; 31 constexpr s32 min{std::numeric_limits<s16>::min()};
33 constexpr s32 max{std::numeric_limits<s16>::max()}; 32 constexpr s32 max{std::numeric_limits<s16>::max()};
34 33
@@ -49,19 +48,18 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
49 const VAddr source{req.buffer + 48 const VAddr source{req.buffer +
50 (((req.start_offset + req.offset) * channel_count) * sizeof(T))}; 49 (((req.start_offset + req.offset) * channel_count) * sizeof(T))};
51 const u64 size{channel_count * samples_to_decode}; 50 const u64 size{channel_count * samples_to_decode};
52 const u64 size_bytes{size * sizeof(T)};
53
54 memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes);
55 51
52 Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
53 memory, source, size);
56 if constexpr (std::is_floating_point_v<T>) { 54 if constexpr (std::is_floating_point_v<T>) {
57 for (u32 i = 0; i < samples_to_decode; i++) { 55 for (u32 i = 0; i < samples_to_decode; i++) {
58 auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] * 56 auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
59 std::numeric_limits<s16>::max())}; 57 std::numeric_limits<s16>::max())};
60 out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); 58 out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
61 } 59 }
62 } else { 60 } else {
63 for (u32 i = 0; i < samples_to_decode; i++) { 61 for (u32 i = 0; i < samples_to_decode; i++) {
64 out_buffer[i] = tmp_samples[i * channel_count + req.target_channel]; 62 out_buffer[i] = samples[i * channel_count + req.target_channel];
65 } 63 }
66 } 64 }
67 } break; 65 } break;
@@ -74,16 +72,17 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
74 } 72 }
75 73
76 const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))}; 74 const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
77 memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T)); 75 Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
76 memory, source, samples_to_decode);
78 77
79 if constexpr (std::is_floating_point_v<T>) { 78 if constexpr (std::is_floating_point_v<T>) {
80 for (u32 i = 0; i < samples_to_decode; i++) { 79 for (u32 i = 0; i < samples_to_decode; i++) {
81 auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] * 80 auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
82 std::numeric_limits<s16>::max())}; 81 std::numeric_limits<s16>::max())};
83 out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); 82 out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
84 } 83 }
85 } else { 84 } else {
86 std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16)); 85 std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16));
87 } 86 }
88 break; 87 break;
89 } 88 }
@@ -101,7 +100,6 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
101 */ 100 */
102static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, 101static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
103 const DecodeArg& req) { 102 const DecodeArg& req) {
104 std::array<u8, TempBufferSize> wavebuffer{};
105 constexpr u32 SamplesPerFrame{14}; 103 constexpr u32 SamplesPerFrame{14};
106 constexpr u32 NibblesPerFrame{16}; 104 constexpr u32 NibblesPerFrame{16};
107 105
@@ -139,7 +137,8 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
139 } 137 }
140 138
141 const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)}; 139 const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
142 memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size); 140 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> wavebuffer(
141 memory, req.buffer + position_in_frame / 2, size);
143 142
144 auto context{req.adpcm_context}; 143 auto context{req.adpcm_context};
145 auto header{context->header}; 144 auto header{context->header};
diff --git a/src/audio_core/renderer/command/effect/aux_.cpp b/src/audio_core/renderer/command/effect/aux_.cpp
index c5650effa..a3e12b3e7 100644
--- a/src/audio_core/renderer/command/effect/aux_.cpp
+++ b/src/audio_core/renderer/command/effect/aux_.cpp
@@ -21,23 +21,13 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
21 } 21 }
22 22
23 AuxInfo::AuxInfoDsp info{}; 23 AuxInfo::AuxInfoDsp info{};
24 auto info_ptr{&info}; 24 memory.ReadBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp));
25 bool host_safe{(aux_info & Core::Memory::YUZU_PAGEMASK) <=
26 (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp))};
27 25
28 if (host_safe) [[likely]] { 26 info.read_offset = 0;
29 info_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(aux_info); 27 info.write_offset = 0;
30 } else { 28 info.total_sample_count = 0;
31 memory.ReadBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
32 }
33 29
34 info_ptr->read_offset = 0; 30 memory.WriteBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp));
35 info_ptr->write_offset = 0;
36 info_ptr->total_sample_count = 0;
37
38 if (!host_safe) [[unlikely]] {
39 memory.WriteBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
40 }
41} 31}
42 32
43/** 33/**
@@ -86,17 +76,9 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
86 } 76 }
87 77
88 AuxInfo::AuxInfoDsp send_info{}; 78 AuxInfo::AuxInfoDsp send_info{};
89 auto send_ptr = &send_info; 79 memory.ReadBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
90 bool host_safe = (send_info_ & Core::Memory::YUZU_PAGEMASK) <=
91 (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
92
93 if (host_safe) [[likely]] {
94 send_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(send_info_);
95 } else {
96 memory.ReadBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
97 }
98 80
99 u32 target_write_offset{send_ptr->write_offset + write_offset}; 81 u32 target_write_offset{send_info.write_offset + write_offset};
100 if (target_write_offset > count_max) { 82 if (target_write_offset > count_max) {
101 return 0; 83 return 0;
102 } 84 }
@@ -105,15 +87,9 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
105 u32 read_pos{0}; 87 u32 read_pos{0};
106 while (write_count > 0) { 88 while (write_count > 0) {
107 u32 to_write{std::min(count_max - target_write_offset, write_count)}; 89 u32 to_write{std::min(count_max - target_write_offset, write_count)};
108 const auto write_addr = send_buffer + target_write_offset * sizeof(s32); 90 if (to_write > 0) {
109 bool write_safe{(write_addr & Core::Memory::YUZU_PAGEMASK) <= 91 const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
110 (Core::Memory::YUZU_PAGESIZE - (write_addr + to_write * sizeof(s32)))}; 92 memory.WriteBlockUnsafe(write_addr, &input[read_pos], to_write * sizeof(s32));
111 if (write_safe) [[likely]] {
112 auto ptr = memory.GetPointer(write_addr);
113 std::memcpy(ptr, &input[read_pos], to_write * sizeof(s32));
114 } else {
115 memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
116 &input[read_pos], to_write * sizeof(s32));
117 } 93 }
118 target_write_offset = (target_write_offset + to_write) % count_max; 94 target_write_offset = (target_write_offset + to_write) % count_max;
119 write_count -= to_write; 95 write_count -= to_write;
@@ -121,13 +97,10 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
121 } 97 }
122 98
123 if (update_count) { 99 if (update_count) {
124 send_ptr->write_offset = (send_ptr->write_offset + update_count) % count_max; 100 send_info.write_offset = (send_info.write_offset + update_count) % count_max;
125 }
126
127 if (!host_safe) [[unlikely]] {
128 memory.WriteBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
129 } 101 }
130 102
103 memory.WriteBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
131 return write_count_; 104 return write_count_;
132} 105}
133 106
@@ -174,17 +147,9 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
174 } 147 }
175 148
176 AuxInfo::AuxInfoDsp return_info{}; 149 AuxInfo::AuxInfoDsp return_info{};
177 auto return_ptr = &return_info; 150 memory.ReadBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
178 bool host_safe = (return_info_ & Core::Memory::YUZU_PAGEMASK) <=
179 (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
180 151
181 if (host_safe) [[likely]] { 152 u32 target_read_offset{return_info.read_offset + read_offset};
182 return_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(return_info_);
183 } else {
184 memory.ReadBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
185 }
186
187 u32 target_read_offset{return_ptr->read_offset + read_offset};
188 if (target_read_offset > count_max) { 153 if (target_read_offset > count_max) {
189 return 0; 154 return 0;
190 } 155 }
@@ -193,15 +158,9 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
193 u32 write_pos{0}; 158 u32 write_pos{0};
194 while (read_count > 0) { 159 while (read_count > 0) {
195 u32 to_read{std::min(count_max - target_read_offset, read_count)}; 160 u32 to_read{std::min(count_max - target_read_offset, read_count)};
196 const auto read_addr = return_buffer + target_read_offset * sizeof(s32); 161 if (to_read > 0) {
197 bool read_safe{(read_addr & Core::Memory::YUZU_PAGEMASK) <= 162 const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
198 (Core::Memory::YUZU_PAGESIZE - (read_addr + to_read * sizeof(s32)))}; 163 memory.ReadBlockUnsafe(read_addr, &output[write_pos], to_read * sizeof(s32));
199 if (read_safe) [[likely]] {
200 auto ptr = memory.GetPointer(read_addr);
201 std::memcpy(&output[write_pos], ptr, to_read * sizeof(s32));
202 } else {
203 memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
204 &output[write_pos], to_read * sizeof(s32));
205 } 164 }
206 target_read_offset = (target_read_offset + to_read) % count_max; 165 target_read_offset = (target_read_offset + to_read) % count_max;
207 read_count -= to_read; 166 read_count -= to_read;
@@ -209,13 +168,10 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
209 } 168 }
210 169
211 if (update_count) { 170 if (update_count) {
212 return_ptr->read_offset = (return_ptr->read_offset + update_count) % count_max; 171 return_info.read_offset = (return_info.read_offset + update_count) % count_max;
213 }
214
215 if (!host_safe) [[unlikely]] {
216 memory.WriteBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
217 } 172 }
218 173
174 memory.WriteBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
219 return read_count_; 175 return read_count_;
220} 176}
221 177
diff --git a/src/common/demangle.cpp b/src/common/demangle.cpp
index 3310faf86..6e117cb41 100644
--- a/src/common/demangle.cpp
+++ b/src/common/demangle.cpp
@@ -23,7 +23,7 @@ std::string DemangleSymbol(const std::string& mangled) {
23 SCOPE_EXIT({ std::free(demangled); }); 23 SCOPE_EXIT({ std::free(demangled); });
24 24
25 if (is_itanium(mangled)) { 25 if (is_itanium(mangled)) {
26 demangled = llvm::itaniumDemangle(mangled.c_str(), nullptr, nullptr, nullptr); 26 demangled = llvm::itaniumDemangle(mangled.c_str());
27 } 27 }
28 28
29 if (!demangled) { 29 if (!demangled) {
diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp
index da64848da..f2ed795cc 100644
--- a/src/common/detached_tasks.cpp
+++ b/src/common/detached_tasks.cpp
@@ -30,8 +30,8 @@ DetachedTasks::~DetachedTasks() {
30void DetachedTasks::AddTask(std::function<void()> task) { 30void DetachedTasks::AddTask(std::function<void()> task) {
31 std::unique_lock lock{instance->mutex}; 31 std::unique_lock lock{instance->mutex};
32 ++instance->count; 32 ++instance->count;
33 std::thread([task{std::move(task)}]() { 33 std::thread([task_{std::move(task)}]() {
34 task(); 34 task_();
35 std::unique_lock thread_lock{instance->mutex}; 35 std::unique_lock thread_lock{instance->mutex};
36 --instance->count; 36 --instance->count;
37 std::notify_all_at_thread_exit(instance->cv, std::move(thread_lock)); 37 std::notify_all_at_thread_exit(instance->cv, std::move(thread_lock));
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp
index b744b68ce..4b1690269 100644
--- a/src/common/page_table.cpp
+++ b/src/common/page_table.cpp
@@ -66,6 +66,7 @@ void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page
66 << (address_space_width_in_bits - page_size_in_bits)}; 66 << (address_space_width_in_bits - page_size_in_bits)};
67 pointers.resize(num_page_table_entries); 67 pointers.resize(num_page_table_entries);
68 backing_addr.resize(num_page_table_entries); 68 backing_addr.resize(num_page_table_entries);
69 blocks.resize(num_page_table_entries);
69 current_address_space_width_in_bits = address_space_width_in_bits; 70 current_address_space_width_in_bits = address_space_width_in_bits;
70 page_size = 1ULL << page_size_in_bits; 71 page_size = 1ULL << page_size_in_bits;
71} 72}
diff --git a/src/common/page_table.h b/src/common/page_table.h
index 1ad3a9f8b..fec8378f3 100644
--- a/src/common/page_table.h
+++ b/src/common/page_table.h
@@ -122,6 +122,7 @@ struct PageTable {
122 * corresponding attribute element is of type `Memory`. 122 * corresponding attribute element is of type `Memory`.
123 */ 123 */
124 VirtualBuffer<PageInfo> pointers; 124 VirtualBuffer<PageInfo> pointers;
125 VirtualBuffer<u64> blocks;
125 126
126 VirtualBuffer<u64> backing_addr; 127 VirtualBuffer<u64> backing_addr;
127 128
diff --git a/src/common/scratch_buffer.h b/src/common/scratch_buffer.h
index d5961b020..2a98cda53 100644
--- a/src/common/scratch_buffer.h
+++ b/src/common/scratch_buffer.h
@@ -40,8 +40,21 @@ public:
40 ~ScratchBuffer() = default; 40 ~ScratchBuffer() = default;
41 ScratchBuffer(const ScratchBuffer&) = delete; 41 ScratchBuffer(const ScratchBuffer&) = delete;
42 ScratchBuffer& operator=(const ScratchBuffer&) = delete; 42 ScratchBuffer& operator=(const ScratchBuffer&) = delete;
43 ScratchBuffer(ScratchBuffer&&) = default; 43
44 ScratchBuffer& operator=(ScratchBuffer&&) = default; 44 ScratchBuffer(ScratchBuffer&& other) noexcept {
45 swap(other);
46 other.last_requested_size = 0;
47 other.buffer_capacity = 0;
48 other.buffer.reset();
49 }
50
51 ScratchBuffer& operator=(ScratchBuffer&& other) noexcept {
52 swap(other);
53 other.last_requested_size = 0;
54 other.buffer_capacity = 0;
55 other.buffer.reset();
56 return *this;
57 }
45 58
46 /// This will only grow the buffer's capacity if size is greater than the current capacity. 59 /// This will only grow the buffer's capacity if size is greater than the current capacity.
47 /// The previously held data will remain intact. 60 /// The previously held data will remain intact.
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 6cbbea1b2..d4e55f988 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -26,9 +26,10 @@ std::string GetTimeZoneString() {
26 26
27 std::string location_name; 27 std::string location_name;
28 if (time_zone_index == 0) { // Auto 28 if (time_zone_index == 0) { // Auto
29#if __cpp_lib_chrono >= 201907L 29#if __cpp_lib_chrono >= 201907L && !defined(MINGW)
30 const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); 30 // Disabled for MinGW -- tzdb always returns Etc/UTC
31 try { 31 try {
32 const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
32 const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); 33 const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
33 std::string_view current_zone_name = current_zone->name(); 34 std::string_view current_zone_name = current_zone->name();
34 location_name = current_zone_name; 35 location_name = current_zone_name;
diff --git a/src/common/socket_types.h b/src/common/socket_types.h
index 0a801a443..63824a5c4 100644
--- a/src/common/socket_types.h
+++ b/src/common/socket_types.h
@@ -3,17 +3,22 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <optional>
7#include <string>
8
6#include "common/common_types.h" 9#include "common/common_types.h"
7 10
8namespace Network { 11namespace Network {
9 12
10/// Address families 13/// Address families
11enum class Domain : u8 { 14enum class Domain : u8 {
12 INET, ///< Address family for IPv4 15 Unspecified, ///< Represents 0, used in getaddrinfo hints
16 INET, ///< Address family for IPv4
13}; 17};
14 18
15/// Socket types 19/// Socket types
16enum class Type { 20enum class Type {
21 Unspecified, ///< Represents 0, used in getaddrinfo hints
17 STREAM, 22 STREAM,
18 DGRAM, 23 DGRAM,
19 RAW, 24 RAW,
@@ -22,6 +27,7 @@ enum class Type {
22 27
23/// Protocol values for sockets 28/// Protocol values for sockets
24enum class Protocol : u8 { 29enum class Protocol : u8 {
30 Unspecified, ///< Represents 0, usable in various places
25 ICMP, 31 ICMP,
26 TCP, 32 TCP,
27 UDP, 33 UDP,
@@ -48,4 +54,13 @@ constexpr u32 FLAG_MSG_PEEK = 0x2;
48constexpr u32 FLAG_MSG_DONTWAIT = 0x80; 54constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
49constexpr u32 FLAG_O_NONBLOCK = 0x800; 55constexpr u32 FLAG_O_NONBLOCK = 0x800;
50 56
57/// Cross-platform addrinfo structure
58struct AddrInfo {
59 Domain family;
60 Type socket_type;
61 Protocol protocol;
62 SockAddrIn addr;
63 std::optional<std::string> canon_name;
64};
65
51} // namespace Network 66} // namespace Network
diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp
index d8d7896c6..69e728a9d 100644
--- a/src/common/time_zone.cpp
+++ b/src/common/time_zone.cpp
@@ -4,13 +4,13 @@
4#include <chrono> 4#include <chrono>
5#include <exception> 5#include <exception>
6#include <iomanip> 6#include <iomanip>
7#include <map>
7#include <sstream> 8#include <sstream>
8#include <stdexcept> 9#include <stdexcept>
9#include <fmt/chrono.h> 10#include <fmt/chrono.h>
10#include <fmt/core.h> 11#include <fmt/core.h>
11 12
12#include "common/logging/log.h" 13#include "common/logging/log.h"
13#include "common/settings.h"
14#include "common/time_zone.h" 14#include "common/time_zone.h"
15 15
16namespace Common::TimeZone { 16namespace Common::TimeZone {
@@ -33,32 +33,29 @@ std::string GetDefaultTimeZone() {
33 return "GMT"; 33 return "GMT";
34} 34}
35 35
36static std::string GetOsTimeZoneOffset() { 36// Results are not comparable to seconds since Epoch
37 const std::time_t t{std::time(nullptr)}; 37static std::time_t TmSpecToSeconds(const struct std::tm& spec) {
38 const std::tm tm{*std::localtime(&t)}; 38 const int year = spec.tm_year - 1; // Years up to now
39 39 const int leap_years = year / 4 - year / 100;
40 return fmt::format("{:%z}", tm); 40 std::time_t cumulative = spec.tm_year;
41} 41 cumulative = cumulative * 365 + leap_years + spec.tm_yday; // Years to days
42 42 cumulative = cumulative * 24 + spec.tm_hour; // Days to hours
43static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) { 43 cumulative = cumulative * 60 + spec.tm_min; // Hours to minutes
44 try { 44 cumulative = cumulative * 60 + spec.tm_sec; // Minutes to seconds
45 return std::stoi(timezone); 45 return cumulative;
46 } catch (const std::invalid_argument&) {
47 LOG_CRITICAL(Common, "invalid_argument with {}!", timezone);
48 return 0;
49 } catch (const std::out_of_range&) {
50 LOG_CRITICAL(Common, "out_of_range with {}!", timezone);
51 return 0;
52 }
53} 46}
54 47
55std::chrono::seconds GetCurrentOffsetSeconds() { 48std::chrono::seconds GetCurrentOffsetSeconds() {
56 const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())}; 49 const std::time_t t{std::time(nullptr)};
50 const std::tm local{*std::localtime(&t)};
51 const std::tm gmt{*std::gmtime(&t)};
57 52
58 int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds 53 // gmt_seconds is a different offset than time(nullptr)
59 seconds += (offset % 100) * 60; // Convert minute component to seconds 54 const auto gmt_seconds = TmSpecToSeconds(gmt);
55 const auto local_seconds = TmSpecToSeconds(local);
56 const auto seconds_offset = local_seconds - gmt_seconds;
60 57
61 return std::chrono::seconds{seconds}; 58 return std::chrono::seconds{seconds_offset};
62} 59}
63 60
64// Key is [Hours * 100 + Minutes], multiplied by 100 if DST 61// Key is [Hours * 100 + Minutes], multiplied by 100 if DST
@@ -71,11 +68,6 @@ const static std::map<s64, const char*> off_timezones = {
71}; 68};
72 69
73std::string FindSystemTimeZone() { 70std::string FindSystemTimeZone() {
74#if defined(MINGW)
75 // MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
76 // e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
77 return timezones[0];
78#else
79 const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count()); 71 const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count());
80 72
81 const s64 minutes = seconds / 60; 73 const s64 minutes = seconds / 60;
@@ -97,7 +89,6 @@ std::string FindSystemTimeZone() {
97 } 89 }
98 } 90 }
99 return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours)); 91 return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours));
100#endif
101} 92}
102 93
103} // namespace Common::TimeZone 94} // namespace Common::TimeZone
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 3655b8478..4b7395be8 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -285,6 +285,7 @@ add_library(core STATIC
285 hle/kernel/kernel.cpp 285 hle/kernel/kernel.cpp
286 hle/kernel/kernel.h 286 hle/kernel/kernel.h
287 hle/kernel/memory_types.h 287 hle/kernel/memory_types.h
288 hle/kernel/message_buffer.h
288 hle/kernel/physical_core.cpp 289 hle/kernel/physical_core.cpp
289 hle/kernel/physical_core.h 290 hle/kernel/physical_core.h
290 hle/kernel/physical_memory.h 291 hle/kernel/physical_memory.h
@@ -722,6 +723,7 @@ add_library(core STATIC
722 hle/service/spl/spl_types.h 723 hle/service/spl/spl_types.h
723 hle/service/ssl/ssl.cpp 724 hle/service/ssl/ssl.cpp
724 hle/service/ssl/ssl.h 725 hle/service/ssl/ssl.h
726 hle/service/ssl/ssl_backend.h
725 hle/service/time/clock_types.h 727 hle/service/time/clock_types.h
726 hle/service/time/ephemeral_network_system_clock_context_writer.h 728 hle/service/time/ephemeral_network_system_clock_context_writer.h
727 hle/service/time/ephemeral_network_system_clock_core.h 729 hle/service/time/ephemeral_network_system_clock_core.h
@@ -863,6 +865,23 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
863 target_link_libraries(core PRIVATE dynarmic::dynarmic) 865 target_link_libraries(core PRIVATE dynarmic::dynarmic)
864endif() 866endif()
865 867
868if(ENABLE_OPENSSL)
869 target_sources(core PRIVATE
870 hle/service/ssl/ssl_backend_openssl.cpp)
871 target_link_libraries(core PRIVATE OpenSSL::SSL)
872elseif (APPLE)
873 target_sources(core PRIVATE
874 hle/service/ssl/ssl_backend_securetransport.cpp)
875 target_link_libraries(core PRIVATE "-framework Security")
876elseif (WIN32)
877 target_sources(core PRIVATE
878 hle/service/ssl/ssl_backend_schannel.cpp)
879 target_link_libraries(core PRIVATE crypt32 secur32)
880else()
881 target_sources(core PRIVATE
882 hle/service/ssl/ssl_backend_none.cpp)
883endif()
884
866if (YUZU_USE_PRECOMPILED_HEADERS) 885if (YUZU_USE_PRECOMPILED_HEADERS)
867 target_precompile_headers(core PRIVATE precompiled_headers.h) 886 target_precompile_headers(core PRIVATE precompiled_headers.h)
868endif() 887endif()
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index beaea64b3..aa0eb9791 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -185,7 +185,7 @@ void ARM_Interface::Run() {
185 // Notify the debugger and go to sleep if a breakpoint was hit, 185 // Notify the debugger and go to sleep if a breakpoint was hit,
186 // or if the thread is unable to continue for any reason. 186 // or if the thread is unable to continue for any reason.
187 if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) { 187 if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
188 if (!True(hr & HaltReason::InstructionBreakpoint)) { 188 if (!True(hr & HaltReason::PrefetchAbort)) {
189 RewindBreakpointInstruction(); 189 RewindBreakpointInstruction();
190 } 190 }
191 if (system.DebuggerEnabled()) { 191 if (system.DebuggerEnabled()) {
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 3b82fb73c..c97158a71 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -346,11 +346,11 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
346} 346}
347 347
348ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, 348ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
349 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_) 349 DynarmicExclusiveMonitor& exclusive_monitor_,
350 std::size_t core_index_)
350 : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)), 351 : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
351 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_}, 352 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
352 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, 353 exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
353 null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
354 354
355ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; 355ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
356 356
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index a990845cb..92fb3f836 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -12,7 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/hash.h" 13#include "common/hash.h"
14#include "core/arm/arm_interface.h" 14#include "core/arm/arm_interface.h"
15#include "core/arm/exclusive_monitor.h" 15#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
16 16
17namespace Core::Memory { 17namespace Core::Memory {
18class Memory; 18class Memory;
@@ -28,8 +28,8 @@ class System;
28 28
29class ARM_Dynarmic_32 final : public ARM_Interface { 29class ARM_Dynarmic_32 final : public ARM_Interface {
30public: 30public:
31 ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, 31 ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
32 std::size_t core_index_); 32 DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
33 ~ARM_Dynarmic_32() override; 33 ~ARM_Dynarmic_32() override;
34 34
35 void SetPC(u64 pc) override; 35 void SetPC(u64 pc) override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index bb97ed5bc..791d466ca 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -405,11 +405,11 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
405} 405}
406 406
407ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, 407ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
408 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_) 408 DynarmicExclusiveMonitor& exclusive_monitor_,
409 std::size_t core_index_)
409 : ARM_Interface{system_, uses_wall_clock_}, 410 : ARM_Interface{system_, uses_wall_clock_},
410 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_}, 411 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
411 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, 412 exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
412 null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
413 413
414ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; 414ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
415 415
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index af2aa1f1c..2b88a08e2 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -11,7 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/hash.h" 12#include "common/hash.h"
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/arm/exclusive_monitor.h" 14#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
15 15
16namespace Core::Memory { 16namespace Core::Memory {
17class Memory; 17class Memory;
@@ -25,8 +25,8 @@ class System;
25 25
26class ARM_Dynarmic_64 final : public ARM_Interface { 26class ARM_Dynarmic_64 final : public ARM_Interface {
27public: 27public:
28 ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, 28 ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
29 std::size_t core_index_); 29 DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
30 ~ARM_Dynarmic_64() override; 30 ~ARM_Dynarmic_64() override;
31 31
32 void SetPC(u64 pc) override; 32 void SetPC(u64 pc) override;
diff --git a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
index 57e6dd0d0..fbfcd8d95 100644
--- a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
@@ -6,8 +6,6 @@
6#include <dynarmic/interface/exclusive_monitor.h> 6#include <dynarmic/interface/exclusive_monitor.h>
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/arm/dynarmic/arm_dynarmic_32.h"
10#include "core/arm/dynarmic/arm_dynarmic_64.h"
11#include "core/arm/exclusive_monitor.h" 9#include "core/arm/exclusive_monitor.h"
12 10
13namespace Core::Memory { 11namespace Core::Memory {
@@ -16,6 +14,9 @@ class Memory;
16 14
17namespace Core { 15namespace Core {
18 16
17class ARM_Dynarmic_32;
18class ARM_Dynarmic_64;
19
19class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 20class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
20public: 21public:
21 explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_); 22 explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 9e3eb3795..48233d7c8 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -880,6 +880,14 @@ const FileSys::ContentProvider& System::GetContentProvider() const {
880 return *impl->content_provider; 880 return *impl->content_provider;
881} 881}
882 882
883FileSys::ContentProviderUnion& System::GetContentProviderUnion() {
884 return *impl->content_provider;
885}
886
887const FileSys::ContentProviderUnion& System::GetContentProviderUnion() const {
888 return *impl->content_provider;
889}
890
883Service::FileSystem::FileSystemController& System::GetFileSystemController() { 891Service::FileSystem::FileSystemController& System::GetFileSystemController() {
884 return impl->fs_controller; 892 return impl->fs_controller;
885} 893}
diff --git a/src/core/core.h b/src/core/core.h
index 14b2f7785..c70ea1965 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -381,6 +381,9 @@ public:
381 [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); 381 [[nodiscard]] FileSys::ContentProvider& GetContentProvider();
382 [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const; 382 [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const;
383 383
384 [[nodiscard]] FileSys::ContentProviderUnion& GetContentProviderUnion();
385 [[nodiscard]] const FileSys::ContentProviderUnion& GetContentProviderUnion() const;
386
384 [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController(); 387 [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController();
385 [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const; 388 [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;
386 389
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index e6112a3c9..b98a0cb33 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -70,7 +70,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
70 -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; 70 -> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
71 ev_lost = CreateEvent("_lost_event", empty_timed_callback); 71 ev_lost = CreateEvent("_lost_event", empty_timed_callback);
72 if (is_multicore) { 72 if (is_multicore) {
73 timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this)); 73 timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
74 } 74 }
75} 75}
76 76
@@ -255,7 +255,6 @@ void CoreTiming::ThreadLoop() {
255#ifdef _WIN32 255#ifdef _WIN32
256 while (!paused && !event.IsSet() && wait_time > 0) { 256 while (!paused && !event.IsSet() && wait_time > 0) {
257 wait_time = *next_time - GetGlobalTimeNs().count(); 257 wait_time = *next_time - GetGlobalTimeNs().count();
258
259 if (wait_time >= timer_resolution_ns) { 258 if (wait_time >= timer_resolution_ns) {
260 Common::Windows::SleepForOneTick(); 259 Common::Windows::SleepForOneTick();
261 } else { 260 } else {
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 5bca1c78d..c20e906fb 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -163,7 +163,7 @@ private:
163 Common::Event pause_event{}; 163 Common::Event pause_event{};
164 std::mutex basic_lock; 164 std::mutex basic_lock;
165 std::mutex advance_lock; 165 std::mutex advance_lock;
166 std::unique_ptr<std::thread> timer_thread; 166 std::unique_ptr<std::jthread> timer_thread;
167 std::atomic<bool> paused{}; 167 std::atomic<bool> paused{};
168 std::atomic<bool> paused_set{}; 168 std::atomic<bool> paused_set{};
169 std::atomic<bool> wait_set{}; 169 std::atomic<bool> wait_set{};
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index e2a13bbd2..da6078372 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -556,7 +556,7 @@ void GDBStub::HandleQuery(std::string_view command) {
556 } else { 556 } else {
557 SendReply(fmt::format( 557 SendReply(fmt::format(
558 "TextSeg={:x}", 558 "TextSeg={:x}",
559 GetInteger(system.ApplicationProcess()->PageTable().GetCodeRegionStart()))); 559 GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart())));
560 } 560 }
561 } else if (command.starts_with("Xfer:libraries:read::")) { 561 } else if (command.starts_with("Xfer:libraries:read::")) {
562 Loader::AppLoader::Modules modules; 562 Loader::AppLoader::Modules modules;
@@ -731,7 +731,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
731 std::string reply; 731 std::string reply;
732 732
733 auto* process = system.ApplicationProcess(); 733 auto* process = system.ApplicationProcess();
734 auto& page_table = process->PageTable(); 734 auto& page_table = process->GetPageTable();
735 735
736 const char* commands = "Commands:\n" 736 const char* commands = "Commands:\n"
737 " get fastmem\n" 737 " get fastmem\n"
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 50303fe42..06efab46d 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -57,11 +57,34 @@ struct NCASectionHeaderBlock {
57}; 57};
58static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); 58static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
59 59
60struct NCABucketInfo {
61 u64 table_offset;
62 u64 table_size;
63 std::array<u8, 0x10> table_header;
64};
65static_assert(sizeof(NCABucketInfo) == 0x20, "NCABucketInfo has incorrect size.");
66
67struct NCASparseInfo {
68 NCABucketInfo bucket;
69 u64 physical_offset;
70 u16 generation;
71 INSERT_PADDING_BYTES_NOINIT(0x6);
72};
73static_assert(sizeof(NCASparseInfo) == 0x30, "NCASparseInfo has incorrect size.");
74
75struct NCACompressionInfo {
76 NCABucketInfo bucket;
77 INSERT_PADDING_BYTES_NOINIT(0x8);
78};
79static_assert(sizeof(NCACompressionInfo) == 0x28, "NCACompressionInfo has incorrect size.");
80
60struct NCASectionRaw { 81struct NCASectionRaw {
61 NCASectionHeaderBlock header; 82 NCASectionHeaderBlock header;
62 std::array<u8, 0x138> block_data; 83 std::array<u8, 0x138> block_data;
63 std::array<u8, 0x8> section_ctr; 84 std::array<u8, 0x8> section_ctr;
64 INSERT_PADDING_BYTES_NOINIT(0xB8); 85 NCASparseInfo sparse_info;
86 NCACompressionInfo compression_info;
87 INSERT_PADDING_BYTES_NOINIT(0x60);
65}; 88};
66static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size."); 89static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size.");
67 90
@@ -225,6 +248,20 @@ bool NCA::ReadSections(const std::vector<NCASectionHeader>& sections, u64 bktr_b
225 for (std::size_t i = 0; i < sections.size(); ++i) { 248 for (std::size_t i = 0; i < sections.size(); ++i) {
226 const auto& section = sections[i]; 249 const auto& section = sections[i];
227 250
251 if (section.raw.sparse_info.bucket.table_offset != 0 &&
252 section.raw.sparse_info.bucket.table_size != 0) {
253 LOG_ERROR(Loader, "Sparse NCAs are not supported.");
254 status = Loader::ResultStatus::ErrorSparseNCA;
255 return false;
256 }
257
258 if (section.raw.compression_info.bucket.table_offset != 0 &&
259 section.raw.compression_info.bucket.table_size != 0) {
260 LOG_ERROR(Loader, "Compressed NCAs are not supported.");
261 status = Loader::ResultStatus::ErrorCompressedNCA;
262 return false;
263 }
264
228 if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) { 265 if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
229 if (!ReadRomFSSection(section, header.section_tables[i], bktr_base_ivfc_offset)) { 266 if (!ReadRomFSSection(section, header.section_tables[i], bktr_base_ivfc_offset)) {
230 return false; 267 return false;
diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp
index 3583bee44..7454be55c 100644
--- a/src/core/hle/kernel/k_code_memory.cpp
+++ b/src/core/hle/kernel/k_code_memory.cpp
@@ -25,7 +25,7 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, KProcessAddres
25 m_owner = GetCurrentProcessPointer(m_kernel); 25 m_owner = GetCurrentProcessPointer(m_kernel);
26 26
27 // Get the owner page table. 27 // Get the owner page table.
28 auto& page_table = m_owner->PageTable(); 28 auto& page_table = m_owner->GetPageTable();
29 29
30 // Construct the page group. 30 // Construct the page group.
31 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager()); 31 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
@@ -53,7 +53,7 @@ void KCodeMemory::Finalize() {
53 // Unlock. 53 // Unlock.
54 if (!m_is_mapped && !m_is_owner_mapped) { 54 if (!m_is_mapped && !m_is_owner_mapped) {
55 const size_t size = m_page_group->GetNumPages() * PageSize; 55 const size_t size = m_page_group->GetNumPages() * PageSize;
56 m_owner->PageTable().UnlockForCodeMemory(m_address, size, *m_page_group); 56 m_owner->GetPageTable().UnlockForCodeMemory(m_address, size, *m_page_group);
57 } 57 }
58 58
59 // Close the page group. 59 // Close the page group.
@@ -75,7 +75,7 @@ Result KCodeMemory::Map(KProcessAddress address, size_t size) {
75 R_UNLESS(!m_is_mapped, ResultInvalidState); 75 R_UNLESS(!m_is_mapped, ResultInvalidState);
76 76
77 // Map the memory. 77 // Map the memory.
78 R_TRY(GetCurrentProcess(m_kernel).PageTable().MapPageGroup( 78 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
79 address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); 79 address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
80 80
81 // Mark ourselves as mapped. 81 // Mark ourselves as mapped.
@@ -92,8 +92,8 @@ Result KCodeMemory::Unmap(KProcessAddress address, size_t size) {
92 KScopedLightLock lk(m_lock); 92 KScopedLightLock lk(m_lock);
93 93
94 // Unmap the memory. 94 // Unmap the memory.
95 R_TRY(GetCurrentProcess(m_kernel).PageTable().UnmapPageGroup(address, *m_page_group, 95 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group,
96 KMemoryState::CodeOut)); 96 KMemoryState::CodeOut));
97 97
98 // Mark ourselves as unmapped. 98 // Mark ourselves as unmapped.
99 m_is_mapped = false; 99 m_is_mapped = false;
@@ -126,8 +126,8 @@ Result KCodeMemory::MapToOwner(KProcessAddress address, size_t size, Svc::Memory
126 } 126 }
127 127
128 // Map the memory. 128 // Map the memory.
129 R_TRY(m_owner->PageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode, 129 R_TRY(m_owner->GetPageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode,
130 k_perm)); 130 k_perm));
131 131
132 // Mark ourselves as mapped. 132 // Mark ourselves as mapped.
133 m_is_owner_mapped = true; 133 m_is_owner_mapped = true;
@@ -143,7 +143,8 @@ Result KCodeMemory::UnmapFromOwner(KProcessAddress address, size_t size) {
143 KScopedLightLock lk(m_lock); 143 KScopedLightLock lk(m_lock);
144 144
145 // Unmap the memory. 145 // Unmap the memory.
146 R_TRY(m_owner->PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode)); 146 R_TRY(m_owner->GetPageTable().UnmapPageGroup(address, *m_page_group,
147 KMemoryState::GeneratedCode));
147 148
148 // Mark ourselves as unmapped. 149 // Mark ourselves as unmapped.
149 m_is_owner_mapped = false; 150 m_is_owner_mapped = false;
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 022d15f35..b9e8c6042 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -388,39 +388,6 @@ public:
388 constexpr size_t GetHeapSize() const { 388 constexpr size_t GetHeapSize() const {
389 return m_current_heap_end - m_heap_region_start; 389 return m_current_heap_end - m_heap_region_start;
390 } 390 }
391 constexpr bool IsInsideAddressSpace(KProcessAddress address, size_t size) const {
392 return m_address_space_start <= address && address + size - 1 <= m_address_space_end - 1;
393 }
394 constexpr bool IsOutsideAliasRegion(KProcessAddress address, size_t size) const {
395 return m_alias_region_start > address || address + size - 1 > m_alias_region_end - 1;
396 }
397 constexpr bool IsOutsideStackRegion(KProcessAddress address, size_t size) const {
398 return m_stack_region_start > address || address + size - 1 > m_stack_region_end - 1;
399 }
400 constexpr bool IsInvalidRegion(KProcessAddress address, size_t size) const {
401 return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1;
402 }
403 constexpr bool IsInsideHeapRegion(KProcessAddress address, size_t size) const {
404 return address + size > m_heap_region_start && m_heap_region_end > address;
405 }
406 constexpr bool IsInsideAliasRegion(KProcessAddress address, size_t size) const {
407 return address + size > m_alias_region_start && m_alias_region_end > address;
408 }
409 constexpr bool IsOutsideASLRRegion(KProcessAddress address, size_t size) const {
410 if (IsInvalidRegion(address, size)) {
411 return true;
412 }
413 if (IsInsideHeapRegion(address, size)) {
414 return true;
415 }
416 if (IsInsideAliasRegion(address, size)) {
417 return true;
418 }
419 return {};
420 }
421 constexpr bool IsInsideASLRRegion(KProcessAddress address, size_t size) const {
422 return !IsOutsideASLRRegion(address, size);
423 }
424 constexpr size_t GetNumGuardPages() const { 391 constexpr size_t GetNumGuardPages() const {
425 return IsKernel() ? 1 : 4; 392 return IsKernel() ? 1 : 4;
426 } 393 }
@@ -436,6 +403,14 @@ public:
436 return m_address_space_start <= addr && addr < addr + size && 403 return m_address_space_start <= addr && addr < addr + size &&
437 addr + size - 1 <= m_address_space_end - 1; 404 addr + size - 1 <= m_address_space_end - 1;
438 } 405 }
406 constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const {
407 return this->Contains(addr, size) && m_alias_region_start <= addr &&
408 addr + size - 1 <= m_alias_region_end - 1;
409 }
410 constexpr bool IsInHeapRegion(KProcessAddress addr, size_t size) const {
411 return this->Contains(addr, size) && m_heap_region_start <= addr &&
412 addr + size - 1 <= m_heap_region_end - 1;
413 }
439 414
440public: 415public:
441 static KVirtualAddress GetLinearMappedVirtualAddress(const KMemoryLayout& layout, 416 static KVirtualAddress GetLinearMappedVirtualAddress(const KMemoryLayout& layout,
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index efe86ad27..44c7cb22f 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -38,7 +38,7 @@ namespace {
38 */ 38 */
39void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, 39void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority,
40 KProcessAddress stack_top) { 40 KProcessAddress stack_top) {
41 const KProcessAddress entry_point = owner_process.PageTable().GetCodeRegionStart(); 41 const KProcessAddress entry_point = owner_process.GetPageTable().GetCodeRegionStart();
42 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1)); 42 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
43 43
44 KThread* thread = KThread::Create(system.Kernel()); 44 KThread* thread = KThread::Create(system.Kernel());
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 925981d06..c9b37e138 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -110,16 +110,6 @@ public:
110 ProcessType type, KResourceLimit* res_limit); 110 ProcessType type, KResourceLimit* res_limit);
111 111
112 /// Gets a reference to the process' page table. 112 /// Gets a reference to the process' page table.
113 KPageTable& PageTable() {
114 return m_page_table;
115 }
116
117 /// Gets const a reference to the process' page table.
118 const KPageTable& PageTable() const {
119 return m_page_table;
120 }
121
122 /// Gets a reference to the process' page table.
123 KPageTable& GetPageTable() { 113 KPageTable& GetPageTable() {
124 return m_page_table; 114 return m_page_table;
125 } 115 }
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index c66aff501..c64ceb530 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -20,12 +20,132 @@
20#include "core/hle/kernel/k_thread.h" 20#include "core/hle/kernel/k_thread.h"
21#include "core/hle/kernel/k_thread_queue.h" 21#include "core/hle/kernel/k_thread_queue.h"
22#include "core/hle/kernel/kernel.h" 22#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/message_buffer.h"
23#include "core/hle/service/hle_ipc.h" 24#include "core/hle/service/hle_ipc.h"
24#include "core/hle/service/ipc_helpers.h" 25#include "core/hle/service/ipc_helpers.h"
25#include "core/memory.h" 26#include "core/memory.h"
26 27
27namespace Kernel { 28namespace Kernel {
28 29
30namespace {
31
32template <bool MoveHandleAllowed>
33Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, KThread& src_thread,
34 MessageBuffer& dst_msg, const MessageBuffer& src_msg,
35 MessageBuffer::SpecialHeader& src_special_header) {
36 // Copy the special header to the destination.
37 s32 offset = dst_msg.Set(src_special_header);
38
39 // Copy the process ID.
40 if (src_special_header.GetHasProcessId()) {
41 offset = dst_msg.SetProcessId(offset, src_process.GetProcessId());
42 }
43
44 // Prepare to process handles.
45 auto& dst_handle_table = dst_process.GetHandleTable();
46 auto& src_handle_table = src_process.GetHandleTable();
47 Result result = ResultSuccess;
48
49 // Process copy handles.
50 for (auto i = 0; i < src_special_header.GetCopyHandleCount(); ++i) {
51 // Get the handles.
52 const Handle src_handle = src_msg.GetHandle(offset);
53 Handle dst_handle = Svc::InvalidHandle;
54
55 // If we're in a success state, try to move the handle to the new table.
56 if (R_SUCCEEDED(result) && src_handle != Svc::InvalidHandle) {
57 KScopedAutoObject obj =
58 src_handle_table.GetObjectForIpc(src_handle, std::addressof(src_thread));
59 if (obj.IsNotNull()) {
60 Result add_result =
61 dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe());
62 if (R_FAILED(add_result)) {
63 result = add_result;
64 dst_handle = Svc::InvalidHandle;
65 }
66 } else {
67 result = ResultInvalidHandle;
68 }
69 }
70
71 // Set the handle.
72 offset = dst_msg.SetHandle(offset, dst_handle);
73 }
74
75 // Process move handles.
76 if constexpr (MoveHandleAllowed) {
77 for (auto i = 0; i < src_special_header.GetMoveHandleCount(); ++i) {
78 // Get the handles.
79 const Handle src_handle = src_msg.GetHandle(offset);
80 Handle dst_handle = Svc::InvalidHandle;
81
82 // Whether or not we've succeeded, we need to remove the handles from the source table.
83 if (src_handle != Svc::InvalidHandle) {
84 if (R_SUCCEEDED(result)) {
85 KScopedAutoObject obj =
86 src_handle_table.GetObjectForIpcWithoutPseudoHandle(src_handle);
87 if (obj.IsNotNull()) {
88 Result add_result = dst_handle_table.Add(std::addressof(dst_handle),
89 obj.GetPointerUnsafe());
90
91 src_handle_table.Remove(src_handle);
92
93 if (R_FAILED(add_result)) {
94 result = add_result;
95 dst_handle = Svc::InvalidHandle;
96 }
97 } else {
98 result = ResultInvalidHandle;
99 }
100 } else {
101 src_handle_table.Remove(src_handle);
102 }
103 }
104
105 // Set the handle.
106 offset = dst_msg.SetHandle(offset, dst_handle);
107 }
108 }
109
110 R_RETURN(result);
111}
112
113void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) {
114 // Parse the message.
115 const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
116 const MessageBuffer::MessageHeader dst_header(dst_msg);
117 const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header);
118
119 // Check that the size is big enough.
120 if (MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) > dst_buffer_size) {
121 return;
122 }
123
124 // Set the special header.
125 int offset = dst_msg.Set(dst_special_header);
126
127 // Clear the process id, if needed.
128 if (dst_special_header.GetHasProcessId()) {
129 offset = dst_msg.SetProcessId(offset, 0);
130 }
131
132 // Clear handles, as relevant.
133 auto& dst_handle_table = dst_process.GetHandleTable();
134 for (auto i = 0;
135 i < (dst_special_header.GetCopyHandleCount() + dst_special_header.GetMoveHandleCount());
136 ++i) {
137 const Handle handle = dst_msg.GetHandle(offset);
138
139 if (handle != Svc::InvalidHandle) {
140 dst_handle_table.Remove(handle);
141 }
142
143 offset = dst_msg.SetHandle(offset, Svc::InvalidHandle);
144 }
145}
146
147} // namespace
148
29using ThreadQueueImplForKServerSessionRequest = KThreadQueue; 149using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
30 150
31KServerSession::KServerSession(KernelCore& kernel) 151KServerSession::KServerSession(KernelCore& kernel)
@@ -223,12 +343,27 @@ Result KServerSession::SendReply(bool is_hle) {
223 // the reply has already been written in this case. 343 // the reply has already been written in this case.
224 } else { 344 } else {
225 Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; 345 Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
226 KThread* server_thread{GetCurrentThreadPointer(m_kernel)}; 346 KThread* server_thread = GetCurrentThreadPointer(m_kernel);
347 KProcess& src_process = *client_thread->GetOwnerProcess();
348 KProcess& dst_process = *server_thread->GetOwnerProcess();
227 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 349 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
228 350
229 auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress()); 351 auto* src_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
230 auto* dst_msg_buffer = memory.GetPointer(client_message); 352 auto* dst_msg_buffer = memory.GetPointer<u32>(client_message);
231 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); 353 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
354
355 // Translate special header ad-hoc.
356 MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
357 MessageBuffer::MessageHeader src_header(src_msg);
358 MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
359 if (src_header.GetHasSpecialHeader()) {
360 MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
361 result = ProcessMessageSpecialData<true>(dst_process, src_process, *server_thread,
362 dst_msg, src_msg, src_special_header);
363 if (R_FAILED(result)) {
364 CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
365 }
366 }
232 } 367 }
233 } else { 368 } else {
234 result = ResultSessionClosed; 369 result = ResultSessionClosed;
@@ -330,12 +465,28 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
330 ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), 465 ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
331 cmd_buf); 466 cmd_buf);
332 } else { 467 } else {
333 KThread* server_thread{GetCurrentThreadPointer(m_kernel)}; 468 KThread* server_thread = GetCurrentThreadPointer(m_kernel);
334 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 469 KProcess& src_process = *client_thread->GetOwnerProcess();
470 KProcess& dst_process = *server_thread->GetOwnerProcess();
471 UNIMPLEMENTED_IF(client_thread->GetOwnerProcess() != server_thread->GetOwnerProcess());
335 472
336 auto* src_msg_buffer = memory.GetPointer(client_message); 473 auto* src_msg_buffer = memory.GetPointer<u32>(client_message);
337 auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress()); 474 auto* dst_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
338 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); 475 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
476
477 // Translate special header ad-hoc.
478 // TODO: fix this mess
479 MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
480 MessageBuffer::MessageHeader src_header(src_msg);
481 MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
482 if (src_header.GetHasSpecialHeader()) {
483 MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
484 Result res = ProcessMessageSpecialData<false>(dst_process, src_process, *client_thread,
485 dst_msg, src_msg, src_special_header);
486 if (R_FAILED(res)) {
487 CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
488 }
489 }
339 } 490 }
340 491
341 // We succeeded. 492 // We succeeded.
diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp
index efb5699de..f713968f6 100644
--- a/src/core/hle/kernel/k_shared_memory.cpp
+++ b/src/core/hle/kernel/k_shared_memory.cpp
@@ -90,8 +90,8 @@ Result KSharedMemory::Map(KProcess& target_process, KProcessAddress address, std
90 R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission); 90 R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission);
91 } 91 }
92 92
93 R_RETURN(target_process.PageTable().MapPageGroup(address, *m_page_group, KMemoryState::Shared, 93 R_RETURN(target_process.GetPageTable().MapPageGroup(
94 ConvertToKMemoryPermission(map_perm))); 94 address, *m_page_group, KMemoryState::Shared, ConvertToKMemoryPermission(map_perm)));
95} 95}
96 96
97Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address, 97Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address,
@@ -100,7 +100,7 @@ Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address,
100 R_UNLESS(m_size == unmap_size, ResultInvalidSize); 100 R_UNLESS(m_size == unmap_size, ResultInvalidSize);
101 101
102 R_RETURN( 102 R_RETURN(
103 target_process.PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::Shared)); 103 target_process.GetPageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::Shared));
104} 104}
105 105
106} // namespace Kernel 106} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index adb6ec581..d88909889 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -302,12 +302,12 @@ Result KThread::InitializeServiceThread(Core::System& system, KThread* thread,
302 std::function<void()>&& func, s32 prio, s32 virt_core, 302 std::function<void()>&& func, s32 prio, s32 virt_core,
303 KProcess* owner) { 303 KProcess* owner) {
304 system.Kernel().GlobalSchedulerContext().AddThread(thread); 304 system.Kernel().GlobalSchedulerContext().AddThread(thread);
305 std::function<void()> func2{[&system, func{std::move(func)}] { 305 std::function<void()> func2{[&system, func_{std::move(func)}] {
306 // Similar to UserModeThreadStarter. 306 // Similar to UserModeThreadStarter.
307 system.Kernel().CurrentScheduler()->OnThreadStart(); 307 system.Kernel().CurrentScheduler()->OnThreadStart();
308 308
309 // Run the guest function. 309 // Run the guest function.
310 func(); 310 func_();
311 311
312 // Exit. 312 // Exit.
313 Svc::ExitThread(system); 313 Svc::ExitThread(system);
diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp
index b4a1e3cdb..2c45b4232 100644
--- a/src/core/hle/kernel/k_thread_local_page.cpp
+++ b/src/core/hle/kernel/k_thread_local_page.cpp
@@ -25,9 +25,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
25 25
26 // Map the address in. 26 // Map the address in.
27 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf); 27 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
28 R_TRY(m_owner->PageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr, 28 R_TRY(m_owner->GetPageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr,
29 KMemoryState::ThreadLocal, 29 KMemoryState::ThreadLocal,
30 KMemoryPermission::UserReadWrite)); 30 KMemoryPermission::UserReadWrite));
31 31
32 // We succeeded. 32 // We succeeded.
33 page_buf_guard.Cancel(); 33 page_buf_guard.Cancel();
@@ -37,11 +37,11 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
37 37
38Result KThreadLocalPage::Finalize() { 38Result KThreadLocalPage::Finalize() {
39 // Get the physical address of the page. 39 // Get the physical address of the page.
40 const KPhysicalAddress phys_addr = m_owner->PageTable().GetPhysicalAddr(m_virt_addr); 40 const KPhysicalAddress phys_addr = m_owner->GetPageTable().GetPhysicalAddr(m_virt_addr);
41 ASSERT(phys_addr); 41 ASSERT(phys_addr);
42 42
43 // Unmap the page. 43 // Unmap the page.
44 R_TRY(m_owner->PageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal)); 44 R_TRY(m_owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal));
45 45
46 // Free the page. 46 // Free the page.
47 KPageBuffer::Free(*m_kernel, KPageBuffer::FromPhysicalAddress(m_kernel->System(), phys_addr)); 47 KPageBuffer::Free(*m_kernel, KPageBuffer::FromPhysicalAddress(m_kernel->System(), phys_addr));
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f33600ca5..ebe7582c6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1089,15 +1089,15 @@ static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process,
1089 KThread::Register(kernel, thread); 1089 KThread::Register(kernel, thread);
1090 1090
1091 return std::jthread( 1091 return std::jthread(
1092 [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] { 1092 [&kernel, thread, thread_name_{std::move(thread_name)}, func_{std::move(func)}] {
1093 // Set the thread name. 1093 // Set the thread name.
1094 Common::SetCurrentThreadName(thread_name.c_str()); 1094 Common::SetCurrentThreadName(thread_name_.c_str());
1095 1095
1096 // Set the thread as current. 1096 // Set the thread as current.
1097 kernel.RegisterHostThread(thread); 1097 kernel.RegisterHostThread(thread);
1098 1098
1099 // Run the callback. 1099 // Run the callback.
1100 func(); 1100 func_();
1101 1101
1102 // Close the thread. 1102 // Close the thread.
1103 // This will free the process if it is the last reference. 1103 // This will free the process if it is the last reference.
diff --git a/src/core/hle/kernel/message_buffer.h b/src/core/hle/kernel/message_buffer.h
new file mode 100644
index 000000000..75b275310
--- /dev/null
+++ b/src/core/hle/kernel/message_buffer.h
@@ -0,0 +1,612 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/alignment.h"
7#include "common/bit_field.h"
8#include "core/hle/kernel/k_thread.h"
9
10namespace Kernel {
11
12constexpr inline size_t MessageBufferSize = 0x100;
13
14class MessageBuffer {
15public:
16 class MessageHeader {
17 private:
18 static constexpr inline u64 NullTag = 0;
19
20 public:
21 enum class ReceiveListCountType : u32 {
22 None = 0,
23 ToMessageBuffer = 1,
24 ToSingleBuffer = 2,
25
26 CountOffset = 2,
27 CountMax = 13,
28 };
29
30 private:
31 union {
32 std::array<u32, 2> raw;
33
34 struct {
35 // Define fields for the first header word.
36 union {
37 BitField<0, 16, u16> tag;
38 BitField<16, 4, u32> pointer_count;
39 BitField<20, 4, u32> send_count;
40 BitField<24, 4, u32> receive_count;
41 BitField<28, 4, u32> exchange_count;
42 };
43
44 // Define fields for the second header word.
45 union {
46 BitField<0, 10, u32> raw_count;
47 BitField<10, 4, ReceiveListCountType> receive_list_count;
48 BitField<14, 6, u32> reserved0;
49 BitField<20, 11, u32> receive_list_offset;
50 BitField<31, 1, u32> has_special_header;
51 };
52 };
53 } m_header;
54
55 public:
56 constexpr MessageHeader() : m_header{} {}
57
58 constexpr MessageHeader(u16 tag, bool special, s32 ptr, s32 send, s32 recv, s32 exch,
59 s32 raw, ReceiveListCountType recv_list)
60 : m_header{} {
61 m_header.raw[0] = 0;
62 m_header.raw[1] = 0;
63
64 m_header.tag.Assign(tag);
65 m_header.pointer_count.Assign(ptr);
66 m_header.send_count.Assign(send);
67 m_header.receive_count.Assign(recv);
68 m_header.exchange_count.Assign(exch);
69
70 m_header.raw_count.Assign(raw);
71 m_header.receive_list_count.Assign(recv_list);
72 m_header.has_special_header.Assign(special);
73 }
74
75 explicit MessageHeader(const MessageBuffer& buf) : m_header{} {
76 buf.Get(0, m_header.raw.data(), 2);
77 }
78
79 explicit MessageHeader(const u32* msg) : m_header{{msg[0], msg[1]}} {}
80
81 constexpr u16 GetTag() const {
82 return m_header.tag;
83 }
84
85 constexpr s32 GetPointerCount() const {
86 return m_header.pointer_count;
87 }
88
89 constexpr s32 GetSendCount() const {
90 return m_header.send_count;
91 }
92
93 constexpr s32 GetReceiveCount() const {
94 return m_header.receive_count;
95 }
96
97 constexpr s32 GetExchangeCount() const {
98 return m_header.exchange_count;
99 }
100
101 constexpr s32 GetMapAliasCount() const {
102 return this->GetSendCount() + this->GetReceiveCount() + this->GetExchangeCount();
103 }
104
105 constexpr s32 GetRawCount() const {
106 return m_header.raw_count;
107 }
108
109 constexpr ReceiveListCountType GetReceiveListCount() const {
110 return m_header.receive_list_count;
111 }
112
113 constexpr s32 GetReceiveListOffset() const {
114 return m_header.receive_list_offset;
115 }
116
117 constexpr bool GetHasSpecialHeader() const {
118 return m_header.has_special_header.Value() != 0;
119 }
120
121 constexpr void SetReceiveListCount(ReceiveListCountType recv_list) {
122 m_header.receive_list_count.Assign(recv_list);
123 }
124
125 constexpr const u32* GetData() const {
126 return m_header.raw.data();
127 }
128
129 static constexpr size_t GetDataSize() {
130 return sizeof(m_header);
131 }
132 };
133
134 class SpecialHeader {
135 private:
136 union {
137 std::array<u32, 1> raw;
138
139 // Define fields for the header word.
140 BitField<0, 1, u32> has_process_id;
141 BitField<1, 4, u32> copy_handle_count;
142 BitField<5, 4, u32> move_handle_count;
143 } m_header;
144 bool m_has_header;
145
146 public:
147 constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move)
148 : m_header{}, m_has_header(true) {
149 m_header.has_process_id.Assign(pid);
150 m_header.copy_handle_count.Assign(copy);
151 m_header.move_handle_count.Assign(move);
152 }
153
154 constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move, bool _has_header)
155 : m_header{}, m_has_header(_has_header) {
156 m_header.has_process_id.Assign(pid);
157 m_header.copy_handle_count.Assign(copy);
158 m_header.move_handle_count.Assign(move);
159 }
160
161 explicit SpecialHeader(const MessageBuffer& buf, const MessageHeader& hdr)
162 : m_header{}, m_has_header(hdr.GetHasSpecialHeader()) {
163 if (m_has_header) {
164 buf.Get(static_cast<s32>(MessageHeader::GetDataSize() / sizeof(u32)),
165 m_header.raw.data(), sizeof(m_header) / sizeof(u32));
166 }
167 }
168
169 constexpr bool GetHasProcessId() const {
170 return m_header.has_process_id.Value() != 0;
171 }
172
173 constexpr s32 GetCopyHandleCount() const {
174 return m_header.copy_handle_count;
175 }
176
177 constexpr s32 GetMoveHandleCount() const {
178 return m_header.move_handle_count;
179 }
180
181 constexpr const u32* GetHeader() const {
182 return m_header.raw.data();
183 }
184
185 constexpr size_t GetHeaderSize() const {
186 if (m_has_header) {
187 return sizeof(m_header);
188 } else {
189 return 0;
190 }
191 }
192
193 constexpr size_t GetDataSize() const {
194 if (m_has_header) {
195 return (this->GetHasProcessId() ? sizeof(u64) : 0) +
196 (this->GetCopyHandleCount() * sizeof(Handle)) +
197 (this->GetMoveHandleCount() * sizeof(Handle));
198 } else {
199 return 0;
200 }
201 }
202 };
203
204 class MapAliasDescriptor {
205 public:
206 enum class Attribute : u32 {
207 Ipc = 0,
208 NonSecureIpc = 1,
209 NonDeviceIpc = 3,
210 };
211
212 private:
213 static constexpr u32 SizeLowCount = 32;
214 static constexpr u32 SizeHighCount = 4;
215 static constexpr u32 AddressLowCount = 32;
216 static constexpr u32 AddressMidCount = 4;
217
218 constexpr u32 GetAddressMid(u64 address) {
219 return static_cast<u32>(address >> AddressLowCount) & ((1U << AddressMidCount) - 1);
220 }
221
222 constexpr u32 GetAddressHigh(u64 address) {
223 return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
224 }
225
226 private:
227 union {
228 std::array<u32, 3> raw;
229
230 struct {
231 // Define fields for the first two words.
232 u32 size_low;
233 u32 address_low;
234
235 // Define fields for the packed descriptor word.
236 union {
237 BitField<0, 2, Attribute> attributes;
238 BitField<2, 3, u32> address_high;
239 BitField<5, 19, u32> reserved;
240 BitField<24, 4, u32> size_high;
241 BitField<28, 4, u32> address_mid;
242 };
243 };
244 } m_data;
245
246 public:
247 constexpr MapAliasDescriptor() : m_data{} {}
248
249 MapAliasDescriptor(const void* buffer, size_t _size, Attribute attr = Attribute::Ipc)
250 : m_data{} {
251 const u64 address = reinterpret_cast<u64>(buffer);
252 const u64 size = static_cast<u64>(_size);
253 m_data.size_low = static_cast<u32>(size);
254 m_data.address_low = static_cast<u32>(address);
255 m_data.attributes.Assign(attr);
256 m_data.address_mid.Assign(GetAddressMid(address));
257 m_data.size_high.Assign(static_cast<u32>(size >> SizeLowCount));
258 m_data.address_high.Assign(GetAddressHigh(address));
259 }
260
261 MapAliasDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
262 buf.Get(index, m_data.raw.data(), 3);
263 }
264
265 constexpr uintptr_t GetAddress() const {
266 return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
267 << AddressLowCount) |
268 m_data.address_low;
269 }
270
271 constexpr uintptr_t GetSize() const {
272 return (static_cast<u64>(m_data.size_high) << SizeLowCount) | m_data.size_low;
273 }
274
275 constexpr Attribute GetAttribute() const {
276 return m_data.attributes;
277 }
278
279 constexpr const u32* GetData() const {
280 return m_data.raw.data();
281 }
282
283 static constexpr size_t GetDataSize() {
284 return sizeof(m_data);
285 }
286 };
287
288 class PointerDescriptor {
289 private:
290 static constexpr u32 AddressLowCount = 32;
291 static constexpr u32 AddressMidCount = 4;
292
293 constexpr u32 GetAddressMid(u64 address) {
294 return static_cast<u32>(address >> AddressLowCount) & ((1u << AddressMidCount) - 1);
295 }
296
297 constexpr u32 GetAddressHigh(u64 address) {
298 return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
299 }
300
301 private:
302 union {
303 std::array<u32, 2> raw;
304
305 struct {
306 // Define fields for the packed descriptor word.
307 union {
308 BitField<0, 4, u32> index;
309 BitField<4, 2, u32> reserved0;
310 BitField<6, 3, u32> address_high;
311 BitField<9, 3, u32> reserved1;
312 BitField<12, 4, u32> address_mid;
313 BitField<16, 16, u32> size;
314 };
315
316 // Define fields for the second word.
317 u32 address_low;
318 };
319 } m_data;
320
321 public:
322 constexpr PointerDescriptor() : m_data{} {}
323
324 PointerDescriptor(const void* buffer, size_t size, s32 index) : m_data{} {
325 const u64 address = reinterpret_cast<u64>(buffer);
326
327 m_data.index.Assign(index);
328 m_data.address_high.Assign(GetAddressHigh(address));
329 m_data.address_mid.Assign(GetAddressMid(address));
330 m_data.size.Assign(static_cast<u32>(size));
331
332 m_data.address_low = static_cast<u32>(address);
333 }
334
335 PointerDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
336 buf.Get(index, m_data.raw.data(), 2);
337 }
338
339 constexpr s32 GetIndex() const {
340 return m_data.index;
341 }
342
343 constexpr uintptr_t GetAddress() const {
344 return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
345 << AddressLowCount) |
346 m_data.address_low;
347 }
348
349 constexpr size_t GetSize() const {
350 return m_data.size;
351 }
352
353 constexpr const u32* GetData() const {
354 return m_data.raw.data();
355 }
356
357 static constexpr size_t GetDataSize() {
358 return sizeof(m_data);
359 }
360 };
361
362 class ReceiveListEntry {
363 private:
364 static constexpr u32 AddressLowCount = 32;
365
366 constexpr u32 GetAddressHigh(u64 address) {
367 return static_cast<u32>(address >> (AddressLowCount));
368 }
369
370 private:
371 union {
372 std::array<u32, 2> raw;
373
374 struct {
375 // Define fields for the first word.
376 u32 address_low;
377
378 // Define fields for the packed descriptor word.
379 union {
380 BitField<0, 7, u32> address_high;
381 BitField<7, 9, u32> reserved;
382 BitField<16, 16, u32> size;
383 };
384 };
385 } m_data;
386
387 public:
388 constexpr ReceiveListEntry() : m_data{} {}
389
390 ReceiveListEntry(const void* buffer, size_t size) : m_data{} {
391 const u64 address = reinterpret_cast<u64>(buffer);
392
393 m_data.address_low = static_cast<u32>(address);
394
395 m_data.address_high.Assign(GetAddressHigh(address));
396 m_data.size.Assign(static_cast<u32>(size));
397 }
398
399 ReceiveListEntry(u32 a, u32 b) : m_data{{a, b}} {}
400
401 constexpr uintptr_t GetAddress() const {
402 return (static_cast<u64>(m_data.address_high) << AddressLowCount) | m_data.address_low;
403 }
404
405 constexpr size_t GetSize() const {
406 return m_data.size;
407 }
408
409 constexpr const u32* GetData() const {
410 return m_data.raw.data();
411 }
412
413 static constexpr size_t GetDataSize() {
414 return sizeof(m_data);
415 }
416 };
417
418private:
419 u32* m_buffer;
420 size_t m_size;
421
422public:
423 constexpr MessageBuffer(u32* b, size_t sz) : m_buffer(b), m_size(sz) {}
424 constexpr explicit MessageBuffer(u32* b) : m_buffer(b), m_size(MessageBufferSize) {}
425
426 constexpr void* GetBufferForDebug() const {
427 return m_buffer;
428 }
429
430 constexpr size_t GetBufferSize() const {
431 return m_size;
432 }
433
434 void Get(s32 index, u32* dst, size_t count) const {
435 // Ensure that this doesn't get re-ordered.
436 std::atomic_thread_fence(std::memory_order_seq_cst);
437
438 // Get the words.
439 static_assert(sizeof(*dst) == sizeof(*m_buffer));
440
441 memcpy(dst, m_buffer + index, count * sizeof(*dst));
442 }
443
444 s32 Set(s32 index, u32* src, size_t count) const {
445 // Ensure that this doesn't get re-ordered.
446 std::atomic_thread_fence(std::memory_order_seq_cst);
447
448 // Set the words.
449 memcpy(m_buffer + index, src, count * sizeof(*src));
450
451 // Ensure that this doesn't get re-ordered.
452 std::atomic_thread_fence(std::memory_order_seq_cst);
453
454 return static_cast<s32>(index + count);
455 }
456
457 template <typename T>
458 const T& GetRaw(s32 index) const {
459 return *reinterpret_cast<const T*>(m_buffer + index);
460 }
461
462 template <typename T>
463 s32 SetRaw(s32 index, const T& val) const {
464 *reinterpret_cast<const T*>(m_buffer + index) = val;
465 return index + (Common::AlignUp(sizeof(val), sizeof(*m_buffer)) / sizeof(*m_buffer));
466 }
467
468 void GetRawArray(s32 index, void* dst, size_t len) const {
469 memcpy(dst, m_buffer + index, len);
470 }
471
472 void SetRawArray(s32 index, const void* src, size_t len) const {
473 memcpy(m_buffer + index, src, len);
474 }
475
476 void SetNull() const {
477 this->Set(MessageHeader());
478 }
479
480 s32 Set(const MessageHeader& hdr) const {
481 memcpy(m_buffer, hdr.GetData(), hdr.GetDataSize());
482 return static_cast<s32>(hdr.GetDataSize() / sizeof(*m_buffer));
483 }
484
485 s32 Set(const SpecialHeader& spc) const {
486 const s32 index = static_cast<s32>(MessageHeader::GetDataSize() / sizeof(*m_buffer));
487 memcpy(m_buffer + index, spc.GetHeader(), spc.GetHeaderSize());
488 return static_cast<s32>(index + (spc.GetHeaderSize() / sizeof(*m_buffer)));
489 }
490
491 s32 SetHandle(s32 index, const Handle& hnd) const {
492 memcpy(m_buffer + index, std::addressof(hnd), sizeof(hnd));
493 return static_cast<s32>(index + (sizeof(hnd) / sizeof(*m_buffer)));
494 }
495
496 s32 SetProcessId(s32 index, const u64 pid) const {
497 memcpy(m_buffer + index, std::addressof(pid), sizeof(pid));
498 return static_cast<s32>(index + (sizeof(pid) / sizeof(*m_buffer)));
499 }
500
501 s32 Set(s32 index, const MapAliasDescriptor& desc) const {
502 memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
503 return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
504 }
505
506 s32 Set(s32 index, const PointerDescriptor& desc) const {
507 memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
508 return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
509 }
510
511 s32 Set(s32 index, const ReceiveListEntry& desc) const {
512 memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
513 return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
514 }
515
516 s32 Set(s32 index, const u32 val) const {
517 memcpy(m_buffer + index, std::addressof(val), sizeof(val));
518 return static_cast<s32>(index + (sizeof(val) / sizeof(*m_buffer)));
519 }
520
521 Result GetAsyncResult() const {
522 MessageHeader hdr(m_buffer);
523 MessageHeader null{};
524 if (memcmp(hdr.GetData(), null.GetData(), MessageHeader::GetDataSize()) != 0) [[unlikely]] {
525 R_SUCCEED();
526 }
527 return Result(m_buffer[MessageHeader::GetDataSize() / sizeof(*m_buffer)]);
528 }
529
530 void SetAsyncResult(Result res) const {
531 const s32 index = this->Set(MessageHeader());
532 const auto value = res.raw;
533 memcpy(m_buffer + index, std::addressof(value), sizeof(value));
534 }
535
536 u32 Get32(s32 index) const {
537 return m_buffer[index];
538 }
539
540 u64 Get64(s32 index) const {
541 u64 value;
542 memcpy(std::addressof(value), m_buffer + index, sizeof(value));
543 return value;
544 }
545
546 u64 GetProcessId(s32 index) const {
547 return this->Get64(index);
548 }
549
550 Handle GetHandle(s32 index) const {
551 static_assert(sizeof(Handle) == sizeof(*m_buffer));
552 return Handle(m_buffer[index]);
553 }
554
555 static constexpr s32 GetSpecialDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
556 return static_cast<s32>((MessageHeader::GetDataSize() / sizeof(u32)) +
557 (spc.GetHeaderSize() / sizeof(u32)));
558 }
559
560 static constexpr s32 GetPointerDescriptorIndex(const MessageHeader& hdr,
561 const SpecialHeader& spc) {
562 return static_cast<s32>(GetSpecialDataIndex(hdr, spc) + (spc.GetDataSize() / sizeof(u32)));
563 }
564
565 static constexpr s32 GetMapAliasDescriptorIndex(const MessageHeader& hdr,
566 const SpecialHeader& spc) {
567 return GetPointerDescriptorIndex(hdr, spc) +
568 static_cast<s32>(hdr.GetPointerCount() * PointerDescriptor::GetDataSize() /
569 sizeof(u32));
570 }
571
572 static constexpr s32 GetRawDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
573 return GetMapAliasDescriptorIndex(hdr, spc) +
574 static_cast<s32>(hdr.GetMapAliasCount() * MapAliasDescriptor::GetDataSize() /
575 sizeof(u32));
576 }
577
578 static constexpr s32 GetReceiveListIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
579 if (const s32 recv_list_index = hdr.GetReceiveListOffset()) {
580 return recv_list_index;
581 } else {
582 return GetRawDataIndex(hdr, spc) + hdr.GetRawCount();
583 }
584 }
585
586 static constexpr size_t GetMessageBufferSize(const MessageHeader& hdr,
587 const SpecialHeader& spc) {
588 // Get the size of the plain message.
589 size_t msg_size = GetReceiveListIndex(hdr, spc) * sizeof(u32);
590
591 // Add the size of the receive list.
592 const auto count = hdr.GetReceiveListCount();
593 switch (count) {
594 case MessageHeader::ReceiveListCountType::None:
595 break;
596 case MessageHeader::ReceiveListCountType::ToMessageBuffer:
597 break;
598 case MessageHeader::ReceiveListCountType::ToSingleBuffer:
599 msg_size += ReceiveListEntry::GetDataSize();
600 break;
601 default:
602 msg_size += (static_cast<s32>(count) -
603 static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
604 ReceiveListEntry::GetDataSize();
605 break;
606 }
607
608 return msg_size;
609 }
610};
611
612} // namespace Kernel
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 2e0c36129..5ee869fa2 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -17,7 +17,9 @@ PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KSchedu
17 // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. 17 // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
18 auto& kernel = system.Kernel(); 18 auto& kernel = system.Kernel();
19 m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( 19 m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
20 system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index); 20 system, kernel.IsMulticore(),
21 reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
22 m_core_index);
21#else 23#else
22#error Platform not supported yet. 24#error Platform not supported yet.
23#endif 25#endif
@@ -31,7 +33,9 @@ void PhysicalCore::Initialize(bool is_64_bit) {
31 if (!is_64_bit) { 33 if (!is_64_bit) {
32 // We already initialized a 64-bit core, replace with a 32-bit one. 34 // We already initialized a 64-bit core, replace with a 32-bit one.
33 m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( 35 m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
34 m_system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index); 36 m_system, kernel.IsMulticore(),
37 reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
38 m_core_index);
35 } 39 }
36#else 40#else
37#error Platform not supported yet. 41#error Platform not supported yet.
diff --git a/src/core/hle/kernel/svc/svc_cache.cpp b/src/core/hle/kernel/svc/svc_cache.cpp
index 082942dab..c2c8be10f 100644
--- a/src/core/hle/kernel/svc/svc_cache.cpp
+++ b/src/core/hle/kernel/svc/svc_cache.cpp
@@ -42,7 +42,7 @@ Result FlushProcessDataCache(Core::System& system, Handle process_handle, u64 ad
42 R_UNLESS(process.IsNotNull(), ResultInvalidHandle); 42 R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
43 43
44 // Verify the region is within range. 44 // Verify the region is within range.
45 auto& page_table = process->PageTable(); 45 auto& page_table = process->GetPageTable();
46 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); 46 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
47 47
48 // Perform the operation. 48 // Perform the operation.
diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp
index 687baff82..bae4cb0cd 100644
--- a/src/core/hle/kernel/svc/svc_code_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_code_memory.cpp
@@ -48,7 +48,7 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t
48 SCOPE_EXIT({ code_mem->Close(); }); 48 SCOPE_EXIT({ code_mem->Close(); });
49 49
50 // Verify that the region is in range. 50 // Verify that the region is in range.
51 R_UNLESS(GetCurrentProcess(system.Kernel()).PageTable().Contains(address, size), 51 R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
52 ResultInvalidCurrentMemory); 52 ResultInvalidCurrentMemory);
53 53
54 // Initialize the code memory. 54 // Initialize the code memory.
@@ -92,7 +92,7 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
92 case CodeMemoryOperation::Map: { 92 case CodeMemoryOperation::Map: {
93 // Check that the region is in range. 93 // Check that the region is in range.
94 R_UNLESS(GetCurrentProcess(system.Kernel()) 94 R_UNLESS(GetCurrentProcess(system.Kernel())
95 .PageTable() 95 .GetPageTable()
96 .CanContain(address, size, KMemoryState::CodeOut), 96 .CanContain(address, size, KMemoryState::CodeOut),
97 ResultInvalidMemoryRegion); 97 ResultInvalidMemoryRegion);
98 98
@@ -105,7 +105,7 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
105 case CodeMemoryOperation::Unmap: { 105 case CodeMemoryOperation::Unmap: {
106 // Check that the region is in range. 106 // Check that the region is in range.
107 R_UNLESS(GetCurrentProcess(system.Kernel()) 107 R_UNLESS(GetCurrentProcess(system.Kernel())
108 .PageTable() 108 .GetPageTable()
109 .CanContain(address, size, KMemoryState::CodeOut), 109 .CanContain(address, size, KMemoryState::CodeOut),
110 ResultInvalidMemoryRegion); 110 ResultInvalidMemoryRegion);
111 111
@@ -117,8 +117,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
117 } break; 117 } break;
118 case CodeMemoryOperation::MapToOwner: { 118 case CodeMemoryOperation::MapToOwner: {
119 // Check that the region is in range. 119 // Check that the region is in range.
120 R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, 120 R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size,
121 KMemoryState::GeneratedCode), 121 KMemoryState::GeneratedCode),
122 ResultInvalidMemoryRegion); 122 ResultInvalidMemoryRegion);
123 123
124 // Check the memory permission. 124 // Check the memory permission.
@@ -129,8 +129,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
129 } break; 129 } break;
130 case CodeMemoryOperation::UnmapFromOwner: { 130 case CodeMemoryOperation::UnmapFromOwner: {
131 // Check that the region is in range. 131 // Check that the region is in range.
132 R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, 132 R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size,
133 KMemoryState::GeneratedCode), 133 KMemoryState::GeneratedCode),
134 ResultInvalidMemoryRegion); 134 ResultInvalidMemoryRegion);
135 135
136 // Check the memory permission. 136 // Check the memory permission.
diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp
index ec3143e67..42add9473 100644
--- a/src/core/hle/kernel/svc/svc_device_address_space.cpp
+++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp
@@ -107,7 +107,7 @@ Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Han
107 R_UNLESS(process.IsNotNull(), ResultInvalidHandle); 107 R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
108 108
109 // Validate that the process address is within range. 109 // Validate that the process address is within range.
110 auto& page_table = process->PageTable(); 110 auto& page_table = process->GetPageTable();
111 R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); 111 R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
112 112
113 // Map. 113 // Map.
@@ -148,7 +148,7 @@ Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Han
148 R_UNLESS(process.IsNotNull(), ResultInvalidHandle); 148 R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
149 149
150 // Validate that the process address is within range. 150 // Validate that the process address is within range.
151 auto& page_table = process->PageTable(); 151 auto& page_table = process->GetPageTable();
152 R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); 152 R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
153 153
154 // Map. 154 // Map.
@@ -180,7 +180,7 @@ Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle p
180 R_UNLESS(process.IsNotNull(), ResultInvalidHandle); 180 R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
181 181
182 // Validate that the process address is within range. 182 // Validate that the process address is within range.
183 auto& page_table = process->PageTable(); 183 auto& page_table = process->GetPageTable();
184 R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); 184 R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
185 185
186 R_RETURN(das->Unmap(std::addressof(page_table), process_address, size, device_address)); 186 R_RETURN(das->Unmap(std::addressof(page_table), process_address, size, device_address));
diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp
index 445cdd87b..f99964028 100644
--- a/src/core/hle/kernel/svc/svc_info.cpp
+++ b/src/core/hle/kernel/svc/svc_info.cpp
@@ -54,35 +54,35 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
54 R_SUCCEED(); 54 R_SUCCEED();
55 55
56 case InfoType::AliasRegionAddress: 56 case InfoType::AliasRegionAddress:
57 *result = GetInteger(process->PageTable().GetAliasRegionStart()); 57 *result = GetInteger(process->GetPageTable().GetAliasRegionStart());
58 R_SUCCEED(); 58 R_SUCCEED();
59 59
60 case InfoType::AliasRegionSize: 60 case InfoType::AliasRegionSize:
61 *result = process->PageTable().GetAliasRegionSize(); 61 *result = process->GetPageTable().GetAliasRegionSize();
62 R_SUCCEED(); 62 R_SUCCEED();
63 63
64 case InfoType::HeapRegionAddress: 64 case InfoType::HeapRegionAddress:
65 *result = GetInteger(process->PageTable().GetHeapRegionStart()); 65 *result = GetInteger(process->GetPageTable().GetHeapRegionStart());
66 R_SUCCEED(); 66 R_SUCCEED();
67 67
68 case InfoType::HeapRegionSize: 68 case InfoType::HeapRegionSize:
69 *result = process->PageTable().GetHeapRegionSize(); 69 *result = process->GetPageTable().GetHeapRegionSize();
70 R_SUCCEED(); 70 R_SUCCEED();
71 71
72 case InfoType::AslrRegionAddress: 72 case InfoType::AslrRegionAddress:
73 *result = GetInteger(process->PageTable().GetAliasCodeRegionStart()); 73 *result = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
74 R_SUCCEED(); 74 R_SUCCEED();
75 75
76 case InfoType::AslrRegionSize: 76 case InfoType::AslrRegionSize:
77 *result = process->PageTable().GetAliasCodeRegionSize(); 77 *result = process->GetPageTable().GetAliasCodeRegionSize();
78 R_SUCCEED(); 78 R_SUCCEED();
79 79
80 case InfoType::StackRegionAddress: 80 case InfoType::StackRegionAddress:
81 *result = GetInteger(process->PageTable().GetStackRegionStart()); 81 *result = GetInteger(process->GetPageTable().GetStackRegionStart());
82 R_SUCCEED(); 82 R_SUCCEED();
83 83
84 case InfoType::StackRegionSize: 84 case InfoType::StackRegionSize:
85 *result = process->PageTable().GetStackRegionSize(); 85 *result = process->GetPageTable().GetStackRegionSize();
86 R_SUCCEED(); 86 R_SUCCEED();
87 87
88 case InfoType::TotalMemorySize: 88 case InfoType::TotalMemorySize:
diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp
index 5dcb7f045..2cab74127 100644
--- a/src/core/hle/kernel/svc/svc_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_memory.cpp
@@ -63,36 +63,13 @@ Result MapUnmapMemorySanityChecks(const KPageTable& manager, u64 dst_addr, u64 s
63 R_THROW(ResultInvalidCurrentMemory); 63 R_THROW(ResultInvalidCurrentMemory);
64 } 64 }
65 65
66 if (!manager.IsInsideAddressSpace(src_addr, size)) { 66 if (!manager.Contains(src_addr, size)) {
67 LOG_ERROR(Kernel_SVC, 67 LOG_ERROR(Kernel_SVC,
68 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", 68 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
69 src_addr, size); 69 src_addr, size);
70 R_THROW(ResultInvalidCurrentMemory); 70 R_THROW(ResultInvalidCurrentMemory);
71 } 71 }
72 72
73 if (manager.IsOutsideStackRegion(dst_addr, size)) {
74 LOG_ERROR(Kernel_SVC,
75 "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
76 dst_addr, size);
77 R_THROW(ResultInvalidMemoryRegion);
78 }
79
80 if (manager.IsInsideHeapRegion(dst_addr, size)) {
81 LOG_ERROR(Kernel_SVC,
82 "Destination does not fit within the heap region, addr=0x{:016X}, "
83 "size=0x{:016X}",
84 dst_addr, size);
85 R_THROW(ResultInvalidMemoryRegion);
86 }
87
88 if (manager.IsInsideAliasRegion(dst_addr, size)) {
89 LOG_ERROR(Kernel_SVC,
90 "Destination does not fit within the map region, addr=0x{:016X}, "
91 "size=0x{:016X}",
92 dst_addr, size);
93 R_THROW(ResultInvalidMemoryRegion);
94 }
95
96 R_SUCCEED(); 73 R_SUCCEED();
97} 74}
98 75
@@ -112,7 +89,7 @@ Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPe
112 R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission); 89 R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission);
113 90
114 // Validate that the region is in range for the current process. 91 // Validate that the region is in range for the current process.
115 auto& page_table = GetCurrentProcess(system.Kernel()).PageTable(); 92 auto& page_table = GetCurrentProcess(system.Kernel()).GetPageTable();
116 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); 93 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
117 94
118 // Set the memory attribute. 95 // Set the memory attribute.
@@ -136,7 +113,7 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask,
136 R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination); 113 R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination);
137 114
138 // Validate that the region is in range for the current process. 115 // Validate that the region is in range for the current process.
139 auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; 116 auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()};
140 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); 117 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
141 118
142 // Set the memory attribute. 119 // Set the memory attribute.
@@ -148,7 +125,7 @@ Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) {
148 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, 125 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
149 src_addr, size); 126 src_addr, size);
150 127
151 auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; 128 auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()};
152 129
153 if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; 130 if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
154 result.IsError()) { 131 result.IsError()) {
@@ -163,7 +140,7 @@ Result UnmapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) {
163 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, 140 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
164 src_addr, size); 141 src_addr, size);
165 142
166 auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; 143 auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()};
167 144
168 if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; 145 if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
169 result.IsError()) { 146 result.IsError()) {
diff --git a/src/core/hle/kernel/svc/svc_physical_memory.cpp b/src/core/hle/kernel/svc/svc_physical_memory.cpp
index c2fbfb59a..d3545f232 100644
--- a/src/core/hle/kernel/svc/svc_physical_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_physical_memory.cpp
@@ -16,7 +16,7 @@ Result SetHeapSize(Core::System& system, u64* out_address, u64 size) {
16 R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); 16 R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize);
17 17
18 // Set the heap size. 18 // Set the heap size.
19 R_RETURN(GetCurrentProcess(system.Kernel()).PageTable().SetHeapSize(out_address, size)); 19 R_RETURN(GetCurrentProcess(system.Kernel()).GetPageTable().SetHeapSize(out_address, size));
20} 20}
21 21
22/// Maps memory at a desired address 22/// Maps memory at a desired address
@@ -44,21 +44,21 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) {
44 } 44 }
45 45
46 KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; 46 KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
47 auto& page_table{current_process->PageTable()}; 47 auto& page_table{current_process->GetPageTable()};
48 48
49 if (current_process->GetSystemResourceSize() == 0) { 49 if (current_process->GetSystemResourceSize() == 0) {
50 LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); 50 LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
51 R_THROW(ResultInvalidState); 51 R_THROW(ResultInvalidState);
52 } 52 }
53 53
54 if (!page_table.IsInsideAddressSpace(addr, size)) { 54 if (!page_table.Contains(addr, size)) {
55 LOG_ERROR(Kernel_SVC, 55 LOG_ERROR(Kernel_SVC,
56 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, 56 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
57 size); 57 size);
58 R_THROW(ResultInvalidMemoryRegion); 58 R_THROW(ResultInvalidMemoryRegion);
59 } 59 }
60 60
61 if (page_table.IsOutsideAliasRegion(addr, size)) { 61 if (!page_table.IsInAliasRegion(addr, size)) {
62 LOG_ERROR(Kernel_SVC, 62 LOG_ERROR(Kernel_SVC,
63 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, 63 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
64 size); 64 size);
@@ -93,21 +93,21 @@ Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) {
93 } 93 }
94 94
95 KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; 95 KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
96 auto& page_table{current_process->PageTable()}; 96 auto& page_table{current_process->GetPageTable()};
97 97
98 if (current_process->GetSystemResourceSize() == 0) { 98 if (current_process->GetSystemResourceSize() == 0) {
99 LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); 99 LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
100 R_THROW(ResultInvalidState); 100 R_THROW(ResultInvalidState);
101 } 101 }
102 102
103 if (!page_table.IsInsideAddressSpace(addr, size)) { 103 if (!page_table.Contains(addr, size)) {
104 LOG_ERROR(Kernel_SVC, 104 LOG_ERROR(Kernel_SVC,
105 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, 105 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
106 size); 106 size);
107 R_THROW(ResultInvalidMemoryRegion); 107 R_THROW(ResultInvalidMemoryRegion);
108 } 108 }
109 109
110 if (page_table.IsOutsideAliasRegion(addr, size)) { 110 if (!page_table.IsInAliasRegion(addr, size)) {
111 LOG_ERROR(Kernel_SVC, 111 LOG_ERROR(Kernel_SVC,
112 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, 112 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
113 size); 113 size);
diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp
index 619ed16a3..caa8bee9a 100644
--- a/src/core/hle/kernel/svc/svc_process.cpp
+++ b/src/core/hle/kernel/svc/svc_process.cpp
@@ -66,8 +66,8 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc
66 auto& kernel = system.Kernel(); 66 auto& kernel = system.Kernel();
67 const auto total_copy_size = out_process_ids_size * sizeof(u64); 67 const auto total_copy_size = out_process_ids_size * sizeof(u64);
68 68
69 if (out_process_ids_size > 0 && !GetCurrentProcess(kernel).PageTable().IsInsideAddressSpace( 69 if (out_process_ids_size > 0 &&
70 out_process_ids, total_copy_size)) { 70 !GetCurrentProcess(kernel).GetPageTable().Contains(out_process_ids, total_copy_size)) {
71 LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", 71 LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
72 out_process_ids, out_process_ids + total_copy_size); 72 out_process_ids, out_process_ids + total_copy_size);
73 R_THROW(ResultInvalidCurrentMemory); 73 R_THROW(ResultInvalidCurrentMemory);
diff --git a/src/core/hle/kernel/svc/svc_process_memory.cpp b/src/core/hle/kernel/svc/svc_process_memory.cpp
index aee0f2f36..07cd48175 100644
--- a/src/core/hle/kernel/svc/svc_process_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_process_memory.cpp
@@ -49,7 +49,7 @@ Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u
49 R_UNLESS(process.IsNotNull(), ResultInvalidHandle); 49 R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
50 50
51 // Validate that the address is in range. 51 // Validate that the address is in range.
52 auto& page_table = process->PageTable(); 52 auto& page_table = process->GetPageTable();
53 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); 53 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
54 54
55 // Set the memory permission. 55 // Set the memory permission.
@@ -77,8 +77,8 @@ Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_ha
77 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); 77 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
78 78
79 // Get the page tables. 79 // Get the page tables.
80 auto& dst_pt = dst_process->PageTable(); 80 auto& dst_pt = dst_process->GetPageTable();
81 auto& src_pt = src_process->PageTable(); 81 auto& src_pt = src_process->GetPageTable();
82 82
83 // Validate that the mapping is in range. 83 // Validate that the mapping is in range.
84 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); 84 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
@@ -118,8 +118,8 @@ Result UnmapProcessMemory(Core::System& system, u64 dst_address, Handle process_
118 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); 118 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
119 119
120 // Get the page tables. 120 // Get the page tables.
121 auto& dst_pt = dst_process->PageTable(); 121 auto& dst_pt = dst_process->GetPageTable();
122 auto& src_pt = src_process->PageTable(); 122 auto& src_pt = src_process->GetPageTable();
123 123
124 // Validate that the mapping is in range. 124 // Validate that the mapping is in range.
125 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); 125 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
@@ -178,8 +178,8 @@ Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst
178 R_THROW(ResultInvalidHandle); 178 R_THROW(ResultInvalidHandle);
179 } 179 }
180 180
181 auto& page_table = process->PageTable(); 181 auto& page_table = process->GetPageTable();
182 if (!page_table.IsInsideAddressSpace(src_address, size)) { 182 if (!page_table.Contains(src_address, size)) {
183 LOG_ERROR(Kernel_SVC, 183 LOG_ERROR(Kernel_SVC,
184 "Source address range is not within the address space (src_address=0x{:016X}, " 184 "Source address range is not within the address space (src_address=0x{:016X}, "
185 "size=0x{:016X}).", 185 "size=0x{:016X}).",
@@ -187,14 +187,6 @@ Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst
187 R_THROW(ResultInvalidCurrentMemory); 187 R_THROW(ResultInvalidCurrentMemory);
188 } 188 }
189 189
190 if (!page_table.IsInsideASLRRegion(dst_address, size)) {
191 LOG_ERROR(Kernel_SVC,
192 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
193 "size=0x{:016X}).",
194 dst_address, size);
195 R_THROW(ResultInvalidMemoryRegion);
196 }
197
198 R_RETURN(page_table.MapCodeMemory(dst_address, src_address, size)); 190 R_RETURN(page_table.MapCodeMemory(dst_address, src_address, size));
199} 191}
200 192
@@ -246,8 +238,8 @@ Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 d
246 R_THROW(ResultInvalidHandle); 238 R_THROW(ResultInvalidHandle);
247 } 239 }
248 240
249 auto& page_table = process->PageTable(); 241 auto& page_table = process->GetPageTable();
250 if (!page_table.IsInsideAddressSpace(src_address, size)) { 242 if (!page_table.Contains(src_address, size)) {
251 LOG_ERROR(Kernel_SVC, 243 LOG_ERROR(Kernel_SVC,
252 "Source address range is not within the address space (src_address=0x{:016X}, " 244 "Source address range is not within the address space (src_address=0x{:016X}, "
253 "size=0x{:016X}).", 245 "size=0x{:016X}).",
@@ -255,14 +247,6 @@ Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 d
255 R_THROW(ResultInvalidCurrentMemory); 247 R_THROW(ResultInvalidCurrentMemory);
256 } 248 }
257 249
258 if (!page_table.IsInsideASLRRegion(dst_address, size)) {
259 LOG_ERROR(Kernel_SVC,
260 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
261 "size=0x{:016X}).",
262 dst_address, size);
263 R_THROW(ResultInvalidMemoryRegion);
264 }
265
266 R_RETURN(page_table.UnmapCodeMemory(dst_address, src_address, size, 250 R_RETURN(page_table.UnmapCodeMemory(dst_address, src_address, size,
267 KPageTable::ICacheInvalidationStrategy::InvalidateAll)); 251 KPageTable::ICacheInvalidationStrategy::InvalidateAll));
268} 252}
diff --git a/src/core/hle/kernel/svc/svc_query_memory.cpp b/src/core/hle/kernel/svc/svc_query_memory.cpp
index 4d9fcd25f..51af06e97 100644
--- a/src/core/hle/kernel/svc/svc_query_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_query_memory.cpp
@@ -31,7 +31,7 @@ Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageIn
31 } 31 }
32 32
33 auto& current_memory{GetCurrentMemory(system.Kernel())}; 33 auto& current_memory{GetCurrentMemory(system.Kernel())};
34 const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()}; 34 const auto memory_info{process->GetPageTable().QueryInfo(address).GetSvcMemoryInfo()};
35 35
36 current_memory.WriteBlock(out_memory_info, std::addressof(memory_info), sizeof(memory_info)); 36 current_memory.WriteBlock(out_memory_info, std::addressof(memory_info), sizeof(memory_info));
37 37
diff --git a/src/core/hle/kernel/svc/svc_shared_memory.cpp b/src/core/hle/kernel/svc/svc_shared_memory.cpp
index a698596aa..012b1ae2b 100644
--- a/src/core/hle/kernel/svc/svc_shared_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_shared_memory.cpp
@@ -43,7 +43,7 @@ Result MapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, u
43 43
44 // Get the current process. 44 // Get the current process.
45 auto& process = GetCurrentProcess(system.Kernel()); 45 auto& process = GetCurrentProcess(system.Kernel());
46 auto& page_table = process.PageTable(); 46 auto& page_table = process.GetPageTable();
47 47
48 // Get the shared memory. 48 // Get the shared memory.
49 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); 49 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
@@ -73,7 +73,7 @@ Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, u64 address,
73 73
74 // Get the current process. 74 // Get the current process.
75 auto& process = GetCurrentProcess(system.Kernel()); 75 auto& process = GetCurrentProcess(system.Kernel());
76 auto& page_table = process.PageTable(); 76 auto& page_table = process.GetPageTable();
77 77
78 // Get the shared memory. 78 // Get the shared memory.
79 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); 79 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp
index 36b94e6bf..92bcea72b 100644
--- a/src/core/hle/kernel/svc/svc_thread.cpp
+++ b/src/core/hle/kernel/svc/svc_thread.cpp
@@ -236,7 +236,7 @@ Result GetThreadList(Core::System& system, s32* out_num_threads, u64 out_thread_
236 const auto total_copy_size = out_thread_ids_size * sizeof(u64); 236 const auto total_copy_size = out_thread_ids_size * sizeof(u64);
237 237
238 if (out_thread_ids_size > 0 && 238 if (out_thread_ids_size > 0 &&
239 !current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) { 239 !current_process->GetPageTable().Contains(out_thread_ids, total_copy_size)) {
240 LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", 240 LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
241 out_thread_ids, out_thread_ids + total_copy_size); 241 out_thread_ids, out_thread_ids + total_copy_size);
242 R_THROW(ResultInvalidCurrentMemory); 242 R_THROW(ResultInvalidCurrentMemory);
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
index 82d469a37..7d94e7f09 100644
--- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
@@ -55,7 +55,7 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
55 SCOPE_EXIT({ trmem->Close(); }); 55 SCOPE_EXIT({ trmem->Close(); });
56 56
57 // Ensure that the region is in range. 57 // Ensure that the region is in range.
58 R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory); 58 R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
59 59
60 // Initialize the transfer memory. 60 // Initialize the transfer memory.
61 R_TRY(trmem->Initialize(address, size, map_perm)); 61 R_TRY(trmem->Initialize(address, size, map_perm));
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index a2375508a..4f400d341 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -506,8 +506,8 @@ void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
506void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { 506void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
507 IPC::RequestParser rp{ctx}; 507 IPC::RequestParser rp{ctx};
508 idle_time_detection_extension = rp.Pop<u32>(); 508 idle_time_detection_extension = rp.Pop<u32>();
509 LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}", 509 LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
510 idle_time_detection_extension); 510 idle_time_detection_extension);
511 511
512 IPC::ResponseBuilder rb{ctx, 2}; 512 IPC::ResponseBuilder rb{ctx, 2};
513 rb.Push(ResultSuccess); 513 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index 2290df705..f6a1e54f2 100644
--- a/src/core/hle/service/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -329,8 +329,22 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
329} 329}
330 330
331std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { 331std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
332 static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a; 332 static thread_local std::array read_buffer_a{
333 static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x; 333 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
334 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
335 };
336 static thread_local std::array read_buffer_data_a{
337 Common::ScratchBuffer<u8>(),
338 Common::ScratchBuffer<u8>(),
339 };
340 static thread_local std::array read_buffer_x{
341 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
342 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
343 };
344 static thread_local std::array read_buffer_data_x{
345 Common::ScratchBuffer<u8>(),
346 Common::ScratchBuffer<u8>(),
347 };
334 348
335 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && 349 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
336 BufferDescriptorA()[buffer_index].Size()}; 350 BufferDescriptorA()[buffer_index].Size()};
@@ -339,19 +353,17 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
339 BufferDescriptorA().size() > buffer_index, { return {}; }, 353 BufferDescriptorA().size() > buffer_index, { return {}; },
340 "BufferDescriptorA invalid buffer_index {}", buffer_index); 354 "BufferDescriptorA invalid buffer_index {}", buffer_index);
341 auto& read_buffer = read_buffer_a[buffer_index]; 355 auto& read_buffer = read_buffer_a[buffer_index];
342 read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size()); 356 return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(),
343 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(), 357 BufferDescriptorA()[buffer_index].Size(),
344 read_buffer.size()); 358 &read_buffer_data_a[buffer_index]);
345 return read_buffer;
346 } else { 359 } else {
347 ASSERT_OR_EXECUTE_MSG( 360 ASSERT_OR_EXECUTE_MSG(
348 BufferDescriptorX().size() > buffer_index, { return {}; }, 361 BufferDescriptorX().size() > buffer_index, { return {}; },
349 "BufferDescriptorX invalid buffer_index {}", buffer_index); 362 "BufferDescriptorX invalid buffer_index {}", buffer_index);
350 auto& read_buffer = read_buffer_x[buffer_index]; 363 auto& read_buffer = read_buffer_x[buffer_index];
351 read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size()); 364 return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(),
352 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(), 365 BufferDescriptorX()[buffer_index].Size(),
353 read_buffer.size()); 366 &read_buffer_data_x[buffer_index]);
354 return read_buffer;
355 } 367 }
356} 368}
357 369
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index c42489ff9..055c0a2db 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -318,15 +318,15 @@ public:
318 return false; 318 return false;
319 } 319 }
320 320
321 if (!page_table.IsInsideAddressSpace(out_addr, size)) { 321 if (!page_table.Contains(out_addr, size)) {
322 return false; 322 return false;
323 } 323 }
324 324
325 if (page_table.IsInsideHeapRegion(out_addr, size)) { 325 if (page_table.IsInHeapRegion(out_addr, size)) {
326 return false; 326 return false;
327 } 327 }
328 328
329 if (page_table.IsInsideAliasRegion(out_addr, size)) { 329 if (page_table.IsInAliasRegion(out_addr, size)) {
330 return false; 330 return false;
331 } 331 }
332 332
@@ -358,7 +358,7 @@ public:
358 } 358 }
359 359
360 ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) { 360 ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) {
361 auto& page_table{process->PageTable()}; 361 auto& page_table{process->GetPageTable()};
362 VAddr addr{}; 362 VAddr addr{};
363 363
364 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { 364 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
@@ -382,7 +382,7 @@ public:
382 ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size, 382 ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
383 VAddr bss_addr, std::size_t bss_size, std::size_t size) { 383 VAddr bss_addr, std::size_t bss_size, std::size_t size) {
384 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { 384 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
385 auto& page_table{process->PageTable()}; 385 auto& page_table{process->GetPageTable()};
386 VAddr addr{}; 386 VAddr addr{};
387 387
388 CASCADE_RESULT(addr, MapProcessCodeMemory(process, nro_addr, nro_size)); 388 CASCADE_RESULT(addr, MapProcessCodeMemory(process, nro_addr, nro_size));
@@ -437,12 +437,12 @@ public:
437 CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, 437 CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
438 nro_header.segment_headers[DATA_INDEX].memory_size); 438 nro_header.segment_headers[DATA_INDEX].memory_size);
439 439
440 CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( 440 CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
441 text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute)); 441 text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
442 CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( 442 CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
443 ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read)); 443 ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
444 444
445 return process->PageTable().SetProcessMemoryPermission( 445 return process->GetPageTable().SetProcessMemoryPermission(
446 data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite); 446 data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite);
447 } 447 }
448 448
@@ -571,7 +571,7 @@ public:
571 571
572 Result UnmapNro(const NROInfo& info) { 572 Result UnmapNro(const NROInfo& info) {
573 // Each region must be unmapped separately to validate memory state 573 // Each region must be unmapped separately to validate memory state
574 auto& page_table{system.ApplicationProcess()->PageTable()}; 574 auto& page_table{system.ApplicationProcess()->GetPageTable()};
575 575
576 if (info.bss_size != 0) { 576 if (info.bss_size != 0) {
577 CASCADE_CODE(page_table.UnmapCodeMemory( 577 CASCADE_CODE(page_table.UnmapCodeMemory(
@@ -643,7 +643,7 @@ public:
643 643
644 initialized = true; 644 initialized = true;
645 current_map_addr = 645 current_map_addr =
646 GetInteger(system.ApplicationProcess()->PageTable().GetAliasCodeRegionStart()); 646 GetInteger(system.ApplicationProcess()->GetPageTable().GetAliasCodeRegionStart());
647 647
648 IPC::ResponseBuilder rb{ctx, 2}; 648 IPC::ResponseBuilder rb{ctx, 2};
649 rb.Push(ResultSuccess); 649 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
index bc232c334..9556e9193 100644
--- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -180,7 +180,7 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
180} 180}
181 181
182void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, 182void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
183 const std::vector<u8>& seed) { 183 std::span<const u8> seed) {
184 // Initialize context 184 // Initialize context
185 ctx.used = false; 185 ctx.used = false;
186 ctx.counter = 0; 186 ctx.counter = 0;
diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.h b/src/core/hle/service/nfc/common/amiibo_crypto.h
index 6a3e0841e..2cc0e4d51 100644
--- a/src/core/hle/service/nfc/common/amiibo_crypto.h
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.h
@@ -75,7 +75,7 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
75 75
76// Initializes mbedtls context 76// Initializes mbedtls context
77void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, 77void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
78 const std::vector<u8>& seed); 78 std::span<const u8> seed);
79 79
80// Feeds data to mbedtls context to generate the derived key 80// Feeds data to mbedtls context to generate the derived key
81void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output); 81void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output);
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 2d633b03f..49446bc42 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -34,8 +34,6 @@
34#include "core/hle/service/nfc/mifare_result.h" 34#include "core/hle/service/nfc/mifare_result.h"
35#include "core/hle/service/nfc/nfc_result.h" 35#include "core/hle/service/nfc/nfc_result.h"
36#include "core/hle/service/time/time_manager.h" 36#include "core/hle/service/time/time_manager.h"
37#include "core/hle/service/time/time_zone_content_manager.h"
38#include "core/hle/service/time/time_zone_types.h"
39 37
40namespace Service::NFC { 38namespace Service::NFC {
41NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, 39NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
@@ -1486,6 +1484,7 @@ DeviceState NfcDevice::GetCurrentState() const {
1486} 1484}
1487 1485
1488Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const { 1486Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const {
1487 // TODO: This should get the npad id from nn::hid::system::GetXcdHandleForNpadWithNfc
1489 out_npad_id = npad_id; 1488 out_npad_id = npad_id;
1490 return ResultSuccess; 1489 return ResultSuccess;
1491} 1490}
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index 562f3a28e..a71d26157 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include <algorithm>
5
4#include "common/logging/log.h" 6#include "common/logging/log.h"
5#include "core/core.h" 7#include "core/core.h"
6#include "core/hid/hid_types.h" 8#include "core/hid/hid_types.h"
@@ -10,6 +12,7 @@
10#include "core/hle/service/nfc/common/device_manager.h" 12#include "core/hle/service/nfc/common/device_manager.h"
11#include "core/hle/service/nfc/nfc_result.h" 13#include "core/hle/service/nfc/nfc_result.h"
12#include "core/hle/service/time/clock_types.h" 14#include "core/hle/service/time/clock_types.h"
15#include "core/hle/service/time/time_manager.h"
13 16
14namespace Service::NFC { 17namespace Service::NFC {
15 18
@@ -51,22 +54,53 @@ Result DeviceManager::Finalize() {
51 return ResultSuccess; 54 return ResultSuccess;
52} 55}
53 56
54Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, 57Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices,
55 std::size_t max_allowed_devices) const { 58 bool skip_fatal_errors) const {
59 std::scoped_lock lock{mutex};
60 if (max_allowed_devices < 1) {
61 return ResultInvalidArgument;
62 }
63
64 Result result = IsNfcParameterSet();
65 if (result.IsError()) {
66 return result;
67 }
68
69 result = IsNfcEnabled();
70 if (result.IsError()) {
71 return result;
72 }
73
74 result = IsNfcInitialized();
75 if (result.IsError()) {
76 return result;
77 }
78
56 for (auto& device : devices) { 79 for (auto& device : devices) {
57 if (nfp_devices.size() >= max_allowed_devices) { 80 if (nfp_devices.size() >= max_allowed_devices) {
58 continue; 81 continue;
59 } 82 }
60 if (device->GetCurrentState() != DeviceState::Unavailable) { 83 if (skip_fatal_errors) {
61 nfp_devices.push_back(device->GetHandle()); 84 constexpr u64 MinimumRecoveryTime = 60;
85 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
86 const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point -
87 time_since_last_error;
88
89 if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
90 continue;
91 }
62 } 92 }
93 if (device->GetCurrentState() == DeviceState::Unavailable) {
94 continue;
95 }
96 nfp_devices.push_back(device->GetHandle());
63 } 97 }
64 98
65 if (nfp_devices.empty()) { 99 if (nfp_devices.empty()) {
66 return ResultDeviceNotFound; 100 return ResultDeviceNotFound;
67 } 101 }
68 102
69 return ResultSuccess; 103 return result;
70} 104}
71 105
72DeviceState DeviceManager::GetDeviceState(u64 device_handle) const { 106DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
@@ -79,10 +113,10 @@ DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
79 return device->GetCurrentState(); 113 return device->GetCurrentState();
80 } 114 }
81 115
82 return DeviceState::Unavailable; 116 return DeviceState::Finalized;
83} 117}
84 118
85Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const { 119Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) {
86 std::scoped_lock lock{mutex}; 120 std::scoped_lock lock{mutex};
87 121
88 std::shared_ptr<NfcDevice> device = nullptr; 122 std::shared_ptr<NfcDevice> device = nullptr;
@@ -128,7 +162,7 @@ Result DeviceManager::StopDetection(u64 device_handle) {
128 return result; 162 return result;
129} 163}
130 164
131Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const { 165Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) {
132 std::scoped_lock lock{mutex}; 166 std::scoped_lock lock{mutex};
133 167
134 std::shared_ptr<NfcDevice> device = nullptr; 168 std::shared_ptr<NfcDevice> device = nullptr;
@@ -142,24 +176,46 @@ Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const {
142 return result; 176 return result;
143} 177}
144 178
145Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const { 179Result DeviceManager::AttachActivateEvent(Kernel::KReadableEvent** out_event,
146 std::scoped_lock lock{mutex}; 180 u64 device_handle) const {
147 181 std::vector<u64> nfp_devices;
148 std::shared_ptr<NfcDevice> device = nullptr; 182 std::shared_ptr<NfcDevice> device = nullptr;
149 GetDeviceFromHandle(device_handle, device, false); 183 Result result = ListDevices(nfp_devices, 9, false);
150 184
151 // TODO: Return proper error code on failure 185 if (result.IsSuccess()) {
152 return device->GetActivateEvent(); 186 result = CheckHandleOnList(device_handle, nfp_devices);
153} 187 }
154 188
155Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const { 189 if (result.IsSuccess()) {
156 std::scoped_lock lock{mutex}; 190 result = GetDeviceFromHandle(device_handle, device, false);
191 }
192
193 if (result.IsSuccess()) {
194 *out_event = &device->GetActivateEvent();
195 }
196
197 return result;
198}
157 199
200Result DeviceManager::AttachDeactivateEvent(Kernel::KReadableEvent** out_event,
201 u64 device_handle) const {
202 std::vector<u64> nfp_devices;
158 std::shared_ptr<NfcDevice> device = nullptr; 203 std::shared_ptr<NfcDevice> device = nullptr;
159 GetDeviceFromHandle(device_handle, device, false); 204 Result result = ListDevices(nfp_devices, 9, false);
160 205
161 // TODO: Return proper error code on failure 206 if (result.IsSuccess()) {
162 return device->GetDeactivateEvent(); 207 result = CheckHandleOnList(device_handle, nfp_devices);
208 }
209
210 if (result.IsSuccess()) {
211 result = GetDeviceFromHandle(device_handle, device, false);
212 }
213
214 if (result.IsSuccess()) {
215 *out_event = &device->GetDeactivateEvent();
216 }
217
218 return result;
163} 219}
164 220
165Result DeviceManager::ReadMifare(u64 device_handle, 221Result DeviceManager::ReadMifare(u64 device_handle,
@@ -253,7 +309,7 @@ Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
253 return result; 309 return result;
254} 310}
255 311
256Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const { 312Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) {
257 std::scoped_lock lock{mutex}; 313 std::scoped_lock lock{mutex};
258 314
259 std::shared_ptr<NfcDevice> device = nullptr; 315 std::shared_ptr<NfcDevice> device = nullptr;
@@ -324,7 +380,7 @@ Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
324 return result; 380 return result;
325} 381}
326 382
327Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const { 383Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) {
328 std::scoped_lock lock{mutex}; 384 std::scoped_lock lock{mutex};
329 385
330 std::shared_ptr<NfcDevice> device = nullptr; 386 std::shared_ptr<NfcDevice> device = nullptr;
@@ -338,7 +394,7 @@ Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& regi
338 return result; 394 return result;
339} 395}
340 396
341Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const { 397Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) {
342 std::scoped_lock lock{mutex}; 398 std::scoped_lock lock{mutex};
343 399
344 std::shared_ptr<NfcDevice> device = nullptr; 400 std::shared_ptr<NfcDevice> device = nullptr;
@@ -352,7 +408,7 @@ Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_i
352 return result; 408 return result;
353} 409}
354 410
355Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const { 411Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) {
356 std::scoped_lock lock{mutex}; 412 std::scoped_lock lock{mutex};
357 413
358 std::shared_ptr<NfcDevice> device = nullptr; 414 std::shared_ptr<NfcDevice> device = nullptr;
@@ -399,7 +455,7 @@ Result DeviceManager::Format(u64 device_handle) {
399 return result; 455 return result;
400} 456}
401 457
402Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const { 458Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) {
403 std::scoped_lock lock{mutex}; 459 std::scoped_lock lock{mutex};
404 460
405 std::shared_ptr<NfcDevice> device = nullptr; 461 std::shared_ptr<NfcDevice> device = nullptr;
@@ -414,7 +470,7 @@ Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info
414} 470}
415 471
416Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle, 472Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
417 NFP::RegisterInfoPrivate& register_info) const { 473 NFP::RegisterInfoPrivate& register_info) {
418 std::scoped_lock lock{mutex}; 474 std::scoped_lock lock{mutex};
419 475
420 std::shared_ptr<NfcDevice> device = nullptr; 476 std::shared_ptr<NfcDevice> device = nullptr;
@@ -471,7 +527,7 @@ Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
471 return result; 527 return result;
472} 528}
473 529
474Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const { 530Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) {
475 std::scoped_lock lock{mutex}; 531 std::scoped_lock lock{mutex};
476 532
477 std::shared_ptr<NfcDevice> device = nullptr; 533 std::shared_ptr<NfcDevice> device = nullptr;
@@ -485,7 +541,7 @@ Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_applica
485 return result; 541 return result;
486} 542}
487 543
488Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const { 544Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) {
489 std::scoped_lock lock{mutex}; 545 std::scoped_lock lock{mutex};
490 546
491 std::shared_ptr<NfcDevice> device = nullptr; 547 std::shared_ptr<NfcDevice> device = nullptr;
@@ -541,7 +597,7 @@ Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
541 return result; 597 return result;
542} 598}
543 599
544Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const { 600Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) {
545 std::scoped_lock lock{mutex}; 601 std::scoped_lock lock{mutex};
546 602
547 std::shared_ptr<NfcDevice> device = nullptr; 603 std::shared_ptr<NfcDevice> device = nullptr;
@@ -593,6 +649,19 @@ Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<cons
593 return result; 649 return result;
594} 650}
595 651
652Result DeviceManager::CheckHandleOnList(u64 device_handle,
653 const std::span<const u64> device_list) const {
654 if (device_list.size() < 1) {
655 return ResultDeviceNotFound;
656 }
657
658 if (std::find(device_list.begin(), device_list.end(), device_handle) != device_list.end()) {
659 return ResultSuccess;
660 }
661
662 return ResultDeviceNotFound;
663}
664
596Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device, 665Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
597 bool check_state) const { 666 bool check_state) const {
598 if (check_state) { 667 if (check_state) {
@@ -647,7 +716,7 @@ Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& de
647} 716}
648 717
649Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device, 718Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
650 Result operation_result) const { 719 Result operation_result) {
651 if (operation_result.IsSuccess()) { 720 if (operation_result.IsSuccess()) {
652 return operation_result; 721 return operation_result;
653 } 722 }
@@ -669,6 +738,12 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
669 return device_state; 738 return device_state;
670 } 739 }
671 740
741 if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 ||
742 operation_result == ResultUnknown115) {
743 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
744 time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point;
745 }
746
672 return operation_result; 747 return operation_result;
673} 748}
674 749
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
index c61ba0cf3..c9f038e32 100644
--- a/src/core/hle/service/nfc/common/device_manager.h
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -27,15 +27,16 @@ public:
27 // Nfc device manager 27 // Nfc device manager
28 Result Initialize(); 28 Result Initialize();
29 Result Finalize(); 29 Result Finalize();
30 Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const; 30 Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices,
31 bool skip_fatal_errors) const;
31 DeviceState GetDeviceState(u64 device_handle) const; 32 DeviceState GetDeviceState(u64 device_handle) const;
32 Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const; 33 Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id);
33 Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; 34 Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
34 Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); 35 Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
35 Result StopDetection(u64 device_handle); 36 Result StopDetection(u64 device_handle);
36 Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const; 37 Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info);
37 Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; 38 Result AttachActivateEvent(Kernel::KReadableEvent** event, u64 device_handle) const;
38 Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; 39 Result AttachDeactivateEvent(Kernel::KReadableEvent** event, u64 device_handle) const;
39 Result ReadMifare(u64 device_handle, 40 Result ReadMifare(u64 device_handle,
40 const std::span<const MifareReadBlockParameter> read_parameters, 41 const std::span<const MifareReadBlockParameter> read_parameters,
41 std::span<MifareReadBlockData> read_data); 42 std::span<MifareReadBlockData> read_data);
@@ -48,28 +49,28 @@ public:
48 Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target); 49 Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);
49 Result Unmount(u64 device_handle); 50 Result Unmount(u64 device_handle);
50 Result OpenApplicationArea(u64 device_handle, u32 access_id); 51 Result OpenApplicationArea(u64 device_handle, u32 access_id);
51 Result GetApplicationArea(u64 device_handle, std::span<u8> data) const; 52 Result GetApplicationArea(u64 device_handle, std::span<u8> data);
52 Result SetApplicationArea(u64 device_handle, std::span<const u8> data); 53 Result SetApplicationArea(u64 device_handle, std::span<const u8> data);
53 Result Flush(u64 device_handle); 54 Result Flush(u64 device_handle);
54 Result Restore(u64 device_handle); 55 Result Restore(u64 device_handle);
55 Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data); 56 Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
56 Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const; 57 Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info);
57 Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const; 58 Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info);
58 Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const; 59 Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info);
59 u32 GetApplicationAreaSize() const; 60 u32 GetApplicationAreaSize() const;
60 Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data); 61 Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
61 Result Format(u64 device_handle); 62 Result Format(u64 device_handle);
62 Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const; 63 Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info);
63 Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const; 64 Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info);
64 Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info); 65 Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info);
65 Result DeleteRegisterInfo(u64 device_handle); 66 Result DeleteRegisterInfo(u64 device_handle);
66 Result DeleteApplicationArea(u64 device_handle); 67 Result DeleteApplicationArea(u64 device_handle);
67 Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const; 68 Result ExistsApplicationArea(u64 device_handle, bool& has_application_area);
68 Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const; 69 Result GetAll(u64 device_handle, NFP::NfpData& nfp_data);
69 Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data); 70 Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data);
70 Result FlushDebug(u64 device_handle); 71 Result FlushDebug(u64 device_handle);
71 Result BreakTag(u64 device_handle, NFP::BreakType break_type); 72 Result BreakTag(u64 device_handle, NFP::BreakType break_type);
72 Result ReadBackupData(u64 device_handle, std::span<u8> data) const; 73 Result ReadBackupData(u64 device_handle, std::span<u8> data);
73 Result WriteBackupData(u64 device_handle, std::span<const u8> data); 74 Result WriteBackupData(u64 device_handle, std::span<const u8> data);
74 Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data); 75 Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data);
75 76
@@ -78,17 +79,20 @@ private:
78 Result IsNfcParameterSet() const; 79 Result IsNfcParameterSet() const;
79 Result IsNfcInitialized() const; 80 Result IsNfcInitialized() const;
80 81
82 Result CheckHandleOnList(u64 device_handle, std::span<const u64> device_list) const;
83
81 Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device, 84 Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device,
82 bool check_state) const; 85 bool check_state) const;
83 86
84 Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const; 87 Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const;
85 Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const; 88 Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result);
86 Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const; 89 Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const;
87 90
88 std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); 91 std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
89 const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; 92 const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
90 93
91 bool is_initialized = false; 94 bool is_initialized = false;
95 u64 time_since_last_error = 0;
92 mutable std::mutex mutex; 96 mutable std::mutex mutex;
93 std::array<std::shared_ptr<NfcDevice>, 10> devices{}; 97 std::array<std::shared_ptr<NfcDevice>, 10> devices{};
94 98
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index e7ca7582e..179c7ba2c 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -79,7 +79,7 @@ void NfcInterface::ListDevices(HLERequestContext& ctx) {
79 const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); 79 const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
80 LOG_DEBUG(Service_NFC, "called"); 80 LOG_DEBUG(Service_NFC, "called");
81 81
82 auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices); 82 auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices, true);
83 result = TranslateResultToServiceError(result); 83 result = TranslateResultToServiceError(result);
84 84
85 if (result.IsError()) { 85 if (result.IsError()) {
@@ -190,9 +190,13 @@ void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
190 const auto device_handle{rp.Pop<u64>()}; 190 const auto device_handle{rp.Pop<u64>()};
191 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); 191 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
192 192
193 Kernel::KReadableEvent* out_event = nullptr;
194 auto result = GetManager()->AttachActivateEvent(&out_event, device_handle);
195 result = TranslateResultToServiceError(result);
196
193 IPC::ResponseBuilder rb{ctx, 2, 1}; 197 IPC::ResponseBuilder rb{ctx, 2, 1};
194 rb.Push(ResultSuccess); 198 rb.Push(result);
195 rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle)); 199 rb.PushCopyObjects(out_event);
196} 200}
197 201
198void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) { 202void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
@@ -200,9 +204,13 @@ void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
200 const auto device_handle{rp.Pop<u64>()}; 204 const auto device_handle{rp.Pop<u64>()};
201 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); 205 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
202 206
207 Kernel::KReadableEvent* out_event = nullptr;
208 auto result = GetManager()->AttachDeactivateEvent(&out_event, device_handle);
209 result = TranslateResultToServiceError(result);
210
203 IPC::ResponseBuilder rb{ctx, 2, 1}; 211 IPC::ResponseBuilder rb{ctx, 2, 1};
204 rb.Push(ResultSuccess); 212 rb.Push(result);
205 rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle)); 213 rb.PushCopyObjects(out_event);
206} 214}
207 215
208void NfcInterface::ReadMifare(HLERequestContext& ctx) { 216void NfcInterface::ReadMifare(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
index 715c0e80c..464b5fd69 100644
--- a/src/core/hle/service/nfc/nfc_result.h
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -17,7 +17,10 @@ constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
17constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80); 17constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
18constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88); 18constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88);
19constexpr Result ResultTagRemoved(ErrorModule::NFC, 97); 19constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
20constexpr Result ResultUnknown112(ErrorModule::NFC, 112);
20constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113); 21constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113);
22constexpr Result ResultUnknown114(ErrorModule::NFC, 114);
23constexpr Result ResultUnknown115(ErrorModule::NFC, 115);
21constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120); 24constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120);
22constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128); 25constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128);
23constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136); 26constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 91d42853e..21b06d10b 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -7,6 +7,7 @@
7#include "core/hle/service/kernel_helpers.h" 7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/nifm/nifm.h" 8#include "core/hle/service/nifm/nifm.h"
9#include "core/hle/service/server_manager.h" 9#include "core/hle/service/server_manager.h"
10#include "network/network.h"
10 11
11namespace { 12namespace {
12 13
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 9b20e6823..ae99c4695 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -4,14 +4,15 @@
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/service.h" 6#include "core/hle/service/service.h"
7#include "network/network.h"
8#include "network/room.h"
9#include "network/room_member.h"
10 7
11namespace Core { 8namespace Core {
12class System; 9class System;
13} 10}
14 11
12namespace Network {
13class RoomNetwork;
14}
15
15namespace Service::NIFM { 16namespace Service::NIFM {
16 17
17void LoopProcess(Core::System& system); 18void LoopProcess(Core::System& system);
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index e7f7e273b..968eaa175 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -128,7 +128,7 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
128 } 128 }
129 bool is_out_io{}; 129 bool is_out_io{};
130 ASSERT(system.ApplicationProcess() 130 ASSERT(system.ApplicationProcess()
131 ->PageTable() 131 ->GetPageTable()
132 .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, 132 .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,
133 handle_description->size, 133 handle_description->size,
134 Kernel::KMemoryPermission::None, true, false) 134 Kernel::KMemoryPermission::None, true, false)
@@ -255,7 +255,7 @@ NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
255 if (auto freeInfo{file.FreeHandle(params.handle, false)}) { 255 if (auto freeInfo{file.FreeHandle(params.handle, false)}) {
256 if (freeInfo->can_unlock) { 256 if (freeInfo->can_unlock) {
257 ASSERT(system.ApplicationProcess() 257 ASSERT(system.ApplicationProcess()
258 ->PageTable() 258 ->GetPageTable()
259 .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) 259 .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size)
260 .IsSuccess()); 260 .IsSuccess());
261 } 261 }
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index bce45d321..e63b0a357 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -20,6 +20,9 @@
20#include "core/internal_network/sockets.h" 20#include "core/internal_network/sockets.h"
21#include "network/network.h" 21#include "network/network.h"
22 22
23using Common::Expected;
24using Common::Unexpected;
25
23namespace Service::Sockets { 26namespace Service::Sockets {
24 27
25namespace { 28namespace {
@@ -265,16 +268,19 @@ void BSD::GetSockOpt(HLERequestContext& ctx) {
265 const u32 level = rp.Pop<u32>(); 268 const u32 level = rp.Pop<u32>();
266 const auto optname = static_cast<OptName>(rp.Pop<u32>()); 269 const auto optname = static_cast<OptName>(rp.Pop<u32>());
267 270
268 LOG_WARNING(Service, "(STUBBED) called. fd={} level={} optname=0x{:x}", fd, level, optname);
269
270 std::vector<u8> optval(ctx.GetWriteBufferSize()); 271 std::vector<u8> optval(ctx.GetWriteBufferSize());
271 272
273 LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} len=0x{:x}", fd, level, optname,
274 optval.size());
275
276 const Errno err = GetSockOptImpl(fd, level, optname, optval);
277
272 ctx.WriteBuffer(optval); 278 ctx.WriteBuffer(optval);
273 279
274 IPC::ResponseBuilder rb{ctx, 5}; 280 IPC::ResponseBuilder rb{ctx, 5};
275 rb.Push(ResultSuccess); 281 rb.Push(ResultSuccess);
276 rb.Push<s32>(-1); 282 rb.Push<s32>(err == Errno::SUCCESS ? 0 : -1);
277 rb.PushEnum(Errno::NOTCONN); 283 rb.PushEnum(err);
278 rb.Push<u32>(static_cast<u32>(optval.size())); 284 rb.Push<u32>(static_cast<u32>(optval.size()));
279} 285}
280 286
@@ -436,6 +442,31 @@ void BSD::Close(HLERequestContext& ctx) {
436 BuildErrnoResponse(ctx, CloseImpl(fd)); 442 BuildErrnoResponse(ctx, CloseImpl(fd));
437} 443}
438 444
445void BSD::DuplicateSocket(HLERequestContext& ctx) {
446 struct InputParameters {
447 s32 fd;
448 u64 reserved;
449 };
450 static_assert(sizeof(InputParameters) == 0x10);
451
452 struct OutputParameters {
453 s32 ret;
454 Errno bsd_errno;
455 };
456 static_assert(sizeof(OutputParameters) == 0x8);
457
458 IPC::RequestParser rp{ctx};
459 auto input = rp.PopRaw<InputParameters>();
460
461 Expected<s32, Errno> res = DuplicateSocketImpl(input.fd);
462 IPC::ResponseBuilder rb{ctx, 4};
463 rb.Push(ResultSuccess);
464 rb.PushRaw(OutputParameters{
465 .ret = res.value_or(0),
466 .bsd_errno = res ? Errno::SUCCESS : res.error(),
467 });
468}
469
439void BSD::EventFd(HLERequestContext& ctx) { 470void BSD::EventFd(HLERequestContext& ctx) {
440 IPC::RequestParser rp{ctx}; 471 IPC::RequestParser rp{ctx};
441 const u64 initval = rp.Pop<u64>(); 472 const u64 initval = rp.Pop<u64>();
@@ -477,12 +508,12 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
477 508
478 auto room_member = room_network.GetRoomMember().lock(); 509 auto room_member = room_network.GetRoomMember().lock();
479 if (room_member && room_member->IsConnected()) { 510 if (room_member && room_member->IsConnected()) {
480 descriptor.socket = std::make_unique<Network::ProxySocket>(room_network); 511 descriptor.socket = std::make_shared<Network::ProxySocket>(room_network);
481 } else { 512 } else {
482 descriptor.socket = std::make_unique<Network::Socket>(); 513 descriptor.socket = std::make_shared<Network::Socket>();
483 } 514 }
484 515
485 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol)); 516 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(protocol));
486 descriptor.is_connection_based = IsConnectionBased(type); 517 descriptor.is_connection_based = IsConnectionBased(type);
487 518
488 return {fd, Errno::SUCCESS}; 519 return {fd, Errno::SUCCESS};
@@ -538,7 +569,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
538 std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) { 569 std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) {
539 Network::PollFD result; 570 Network::PollFD result;
540 result.socket = file_descriptors[pollfd.fd]->socket.get(); 571 result.socket = file_descriptors[pollfd.fd]->socket.get();
541 result.events = TranslatePollEventsToHost(pollfd.events); 572 result.events = Translate(pollfd.events);
542 result.revents = Network::PollEvents{}; 573 result.revents = Network::PollEvents{};
543 return result; 574 return result;
544 }); 575 });
@@ -547,7 +578,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
547 578
548 const size_t num = host_pollfds.size(); 579 const size_t num = host_pollfds.size();
549 for (size_t i = 0; i < num; ++i) { 580 for (size_t i = 0; i < num; ++i) {
550 fds[i].revents = TranslatePollEventsToGuest(host_pollfds[i].revents); 581 fds[i].revents = Translate(host_pollfds[i].revents);
551 } 582 }
552 std::memcpy(write_buffer.data(), fds.data(), length); 583 std::memcpy(write_buffer.data(), fds.data(), length);
553 584
@@ -617,7 +648,8 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
617 } 648 }
618 const SockAddrIn guest_addrin = Translate(addr_in); 649 const SockAddrIn guest_addrin = Translate(addr_in);
619 650
620 ASSERT(write_buffer.size() == sizeof(guest_addrin)); 651 ASSERT(write_buffer.size() >= sizeof(guest_addrin));
652 write_buffer.resize(sizeof(guest_addrin));
621 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); 653 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
622 return Translate(bsd_errno); 654 return Translate(bsd_errno);
623} 655}
@@ -633,7 +665,8 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
633 } 665 }
634 const SockAddrIn guest_addrin = Translate(addr_in); 666 const SockAddrIn guest_addrin = Translate(addr_in);
635 667
636 ASSERT(write_buffer.size() == sizeof(guest_addrin)); 668 ASSERT(write_buffer.size() >= sizeof(guest_addrin));
669 write_buffer.resize(sizeof(guest_addrin));
637 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); 670 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
638 return Translate(bsd_errno); 671 return Translate(bsd_errno);
639} 672}
@@ -671,13 +704,47 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
671 } 704 }
672} 705}
673 706
674Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { 707Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
675 UNIMPLEMENTED_IF(level != 0xffff); // SOL_SOCKET 708 if (!IsFileDescriptorValid(fd)) {
709 return Errno::BADF;
710 }
711
712 if (level != static_cast<u32>(SocketLevel::SOCKET)) {
713 UNIMPLEMENTED_MSG("Unknown getsockopt level");
714 return Errno::SUCCESS;
715 }
716
717 Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
718
719 switch (optname) {
720 case OptName::ERROR_: {
721 auto [pending_err, getsockopt_err] = socket->GetPendingError();
722 if (getsockopt_err == Network::Errno::SUCCESS) {
723 Errno translated_pending_err = Translate(pending_err);
724 ASSERT_OR_EXECUTE_MSG(
725 optval.size() == sizeof(Errno), { return Errno::INVAL; },
726 "Incorrect getsockopt option size");
727 optval.resize(sizeof(Errno));
728 memcpy(optval.data(), &translated_pending_err, sizeof(Errno));
729 }
730 return Translate(getsockopt_err);
731 }
732 default:
733 UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
734 return Errno::SUCCESS;
735 }
736}
676 737
738Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
677 if (!IsFileDescriptorValid(fd)) { 739 if (!IsFileDescriptorValid(fd)) {
678 return Errno::BADF; 740 return Errno::BADF;
679 } 741 }
680 742
743 if (level != static_cast<u32>(SocketLevel::SOCKET)) {
744 UNIMPLEMENTED_MSG("Unknown setsockopt level");
745 return Errno::SUCCESS;
746 }
747
681 Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); 748 Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
682 749
683 if (optname == OptName::LINGER) { 750 if (optname == OptName::LINGER) {
@@ -711,6 +778,9 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con
711 return Translate(socket->SetSndTimeo(value)); 778 return Translate(socket->SetSndTimeo(value));
712 case OptName::RCVTIMEO: 779 case OptName::RCVTIMEO:
713 return Translate(socket->SetRcvTimeo(value)); 780 return Translate(socket->SetRcvTimeo(value));
781 case OptName::NOSIGPIPE:
782 LOG_WARNING(Service, "(STUBBED) setting NOSIGPIPE to {}", value);
783 return Errno::SUCCESS;
714 default: 784 default:
715 UNIMPLEMENTED_MSG("Unimplemented optname={}", optname); 785 UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
716 return Errno::SUCCESS; 786 return Errno::SUCCESS;
@@ -841,6 +911,28 @@ Errno BSD::CloseImpl(s32 fd) {
841 return bsd_errno; 911 return bsd_errno;
842} 912}
843 913
914Expected<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
915 if (!IsFileDescriptorValid(fd)) {
916 return Unexpected(Errno::BADF);
917 }
918
919 const s32 new_fd = FindFreeFileDescriptorHandle();
920 if (new_fd < 0) {
921 LOG_ERROR(Service, "No more file descriptors available");
922 return Unexpected(Errno::MFILE);
923 }
924
925 file_descriptors[new_fd] = file_descriptors[fd];
926 return new_fd;
927}
928
929std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
930 if (!IsFileDescriptorValid(fd)) {
931 return std::nullopt;
932 }
933 return file_descriptors[fd]->socket;
934}
935
844s32 BSD::FindFreeFileDescriptorHandle() noexcept { 936s32 BSD::FindFreeFileDescriptorHandle() noexcept {
845 for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) { 937 for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
846 if (!file_descriptors[fd]) { 938 if (!file_descriptors[fd]) {
@@ -911,7 +1003,7 @@ BSD::BSD(Core::System& system_, const char* name)
911 {24, &BSD::Write, "Write"}, 1003 {24, &BSD::Write, "Write"},
912 {25, &BSD::Read, "Read"}, 1004 {25, &BSD::Read, "Read"},
913 {26, &BSD::Close, "Close"}, 1005 {26, &BSD::Close, "Close"},
914 {27, nullptr, "DuplicateSocket"}, 1006 {27, &BSD::DuplicateSocket, "DuplicateSocket"},
915 {28, nullptr, "GetResourceStatistics"}, 1007 {28, nullptr, "GetResourceStatistics"},
916 {29, nullptr, "RecvMMsg"}, 1008 {29, nullptr, "RecvMMsg"},
917 {30, nullptr, "SendMMsg"}, 1009 {30, nullptr, "SendMMsg"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 30ae9c140..430edb97c 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -8,6 +8,7 @@
8#include <vector> 8#include <vector>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/expected.h"
11#include "common/socket_types.h" 12#include "common/socket_types.h"
12#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
13#include "core/hle/service/sockets/sockets.h" 14#include "core/hle/service/sockets/sockets.h"
@@ -29,12 +30,19 @@ public:
29 explicit BSD(Core::System& system_, const char* name); 30 explicit BSD(Core::System& system_, const char* name);
30 ~BSD() override; 31 ~BSD() override;
31 32
33 // These methods are called from SSL; the first two are also called from
34 // this class for the corresponding IPC methods.
35 // On the real device, the SSL service makes IPC calls to this service.
36 Common::Expected<s32, Errno> DuplicateSocketImpl(s32 fd);
37 Errno CloseImpl(s32 fd);
38 std::optional<std::shared_ptr<Network::SocketBase>> GetSocket(s32 fd);
39
32private: 40private:
33 /// Maximum number of file descriptors 41 /// Maximum number of file descriptors
34 static constexpr size_t MAX_FD = 128; 42 static constexpr size_t MAX_FD = 128;
35 43
36 struct FileDescriptor { 44 struct FileDescriptor {
37 std::unique_ptr<Network::SocketBase> socket; 45 std::shared_ptr<Network::SocketBase> socket;
38 s32 flags = 0; 46 s32 flags = 0;
39 bool is_connection_based = false; 47 bool is_connection_based = false;
40 }; 48 };
@@ -138,6 +146,7 @@ private:
138 void Write(HLERequestContext& ctx); 146 void Write(HLERequestContext& ctx);
139 void Read(HLERequestContext& ctx); 147 void Read(HLERequestContext& ctx);
140 void Close(HLERequestContext& ctx); 148 void Close(HLERequestContext& ctx);
149 void DuplicateSocket(HLERequestContext& ctx);
141 void EventFd(HLERequestContext& ctx); 150 void EventFd(HLERequestContext& ctx);
142 151
143 template <typename Work> 152 template <typename Work>
@@ -153,6 +162,7 @@ private:
153 Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer); 162 Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
154 Errno ListenImpl(s32 fd, s32 backlog); 163 Errno ListenImpl(s32 fd, s32 backlog);
155 std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); 164 std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
165 Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval);
156 Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval); 166 Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval);
157 Errno ShutdownImpl(s32 fd, s32 how); 167 Errno ShutdownImpl(s32 fd, s32 how);
158 std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); 168 std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
@@ -161,7 +171,6 @@ private:
161 std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message); 171 std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
162 std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message, 172 std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
163 std::span<const u8> addr); 173 std::span<const u8> addr);
164 Errno CloseImpl(s32 fd);
165 174
166 s32 FindFreeFileDescriptorHandle() noexcept; 175 s32 FindFreeFileDescriptorHandle() noexcept;
167 bool IsFileDescriptorValid(s32 fd) const noexcept; 176 bool IsFileDescriptorValid(s32 fd) const noexcept;
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index 6491a73be..36c6cd05c 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -1,10 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/ipc_helpers.h"
4#include "core/hle/service/sockets/nsd.h" 5#include "core/hle/service/sockets/nsd.h"
5 6
7#include "common/string_util.h"
8
6namespace Service::Sockets { 9namespace Service::Sockets {
7 10
11constexpr Result ResultOverflow{ErrorModule::NSD, 6};
12
13// This is nn::oe::ServerEnvironmentType
14enum class ServerEnvironmentType : u8 {
15 Dd,
16 Lp,
17 Sd,
18 Sp,
19 Dp,
20};
21
8NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { 22NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
9 // clang-format off 23 // clang-format off
10 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
@@ -15,8 +29,8 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
15 {13, nullptr, "DeleteSettings"}, 29 {13, nullptr, "DeleteSettings"},
16 {14, nullptr, "ImportSettings"}, 30 {14, nullptr, "ImportSettings"},
17 {15, nullptr, "SetChangeEnvironmentIdentifierDisabled"}, 31 {15, nullptr, "SetChangeEnvironmentIdentifierDisabled"},
18 {20, nullptr, "Resolve"}, 32 {20, &NSD::Resolve, "Resolve"},
19 {21, nullptr, "ResolveEx"}, 33 {21, &NSD::ResolveEx, "ResolveEx"},
20 {30, nullptr, "GetNasServiceSetting"}, 34 {30, nullptr, "GetNasServiceSetting"},
21 {31, nullptr, "GetNasServiceSettingEx"}, 35 {31, nullptr, "GetNasServiceSettingEx"},
22 {40, nullptr, "GetNasRequestFqdn"}, 36 {40, nullptr, "GetNasRequestFqdn"},
@@ -31,7 +45,7 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
31 {62, nullptr, "DeleteSaveDataOfFsForTest"}, 45 {62, nullptr, "DeleteSaveDataOfFsForTest"},
32 {63, nullptr, "IsChangeEnvironmentIdentifierDisabled"}, 46 {63, nullptr, "IsChangeEnvironmentIdentifierDisabled"},
33 {64, nullptr, "SetWithoutDomainExchangeFqdns"}, 47 {64, nullptr, "SetWithoutDomainExchangeFqdns"},
34 {100, nullptr, "GetApplicationServerEnvironmentType"}, 48 {100, &NSD::GetApplicationServerEnvironmentType, "GetApplicationServerEnvironmentType"},
35 {101, nullptr, "SetApplicationServerEnvironmentType"}, 49 {101, nullptr, "SetApplicationServerEnvironmentType"},
36 {102, nullptr, "DeleteApplicationServerEnvironmentType"}, 50 {102, nullptr, "DeleteApplicationServerEnvironmentType"},
37 }; 51 };
@@ -40,6 +54,61 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
40 RegisterHandlers(functions); 54 RegisterHandlers(functions);
41} 55}
42 56
57static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
58 // The real implementation makes various substitutions.
59 // For now we just return the string as-is, which is good enough when not
60 // connecting to real Nintendo servers.
61 LOG_WARNING(Service, "(STUBBED) called, fqdn_in={}", fqdn_in);
62 return fqdn_in;
63}
64
65static Result ResolveCommon(const std::string& fqdn_in, std::array<char, 0x100>& fqdn_out) {
66 const auto res = ResolveImpl(fqdn_in);
67 if (res.Failed()) {
68 return res.Code();
69 }
70 if (res->size() >= fqdn_out.size()) {
71 return ResultOverflow;
72 }
73 std::memcpy(fqdn_out.data(), res->c_str(), res->size() + 1);
74 return ResultSuccess;
75}
76
77void NSD::Resolve(HLERequestContext& ctx) {
78 const std::string fqdn_in = Common::StringFromBuffer(ctx.ReadBuffer(0));
79
80 std::array<char, 0x100> fqdn_out{};
81 const Result res = ResolveCommon(fqdn_in, fqdn_out);
82
83 ctx.WriteBuffer(fqdn_out);
84 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(res);
86}
87
88void NSD::ResolveEx(HLERequestContext& ctx) {
89 const std::string fqdn_in = Common::StringFromBuffer(ctx.ReadBuffer(0));
90
91 std::array<char, 0x100> fqdn_out;
92 const Result res = ResolveCommon(fqdn_in, fqdn_out);
93
94 if (res.IsError()) {
95 IPC::ResponseBuilder rb{ctx, 2};
96 rb.Push(res);
97 return;
98 }
99
100 ctx.WriteBuffer(fqdn_out);
101 IPC::ResponseBuilder rb{ctx, 4};
102 rb.Push(ResultSuccess);
103 rb.Push(ResultSuccess);
104}
105
106void NSD::GetApplicationServerEnvironmentType(HLERequestContext& ctx) {
107 IPC::ResponseBuilder rb{ctx, 3};
108 rb.Push(ResultSuccess);
109 rb.Push(static_cast<u32>(ServerEnvironmentType::Lp));
110}
111
43NSD::~NSD() = default; 112NSD::~NSD() = default;
44 113
45} // namespace Service::Sockets 114} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h
index 5cc12b855..57760a0c8 100644
--- a/src/core/hle/service/sockets/nsd.h
+++ b/src/core/hle/service/sockets/nsd.h
@@ -15,6 +15,11 @@ class NSD final : public ServiceFramework<NSD> {
15public: 15public:
16 explicit NSD(Core::System& system_, const char* name); 16 explicit NSD(Core::System& system_, const char* name);
17 ~NSD() override; 17 ~NSD() override;
18
19private:
20 void Resolve(HLERequestContext& ctx);
21 void ResolveEx(HLERequestContext& ctx);
22 void GetApplicationServerEnvironmentType(HLERequestContext& ctx);
18}; 23};
19 24
20} // namespace Service::Sockets 25} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 132dd5797..84cc79de8 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -10,27 +10,18 @@
10#include "core/core.h" 10#include "core/core.h"
11#include "core/hle/service/ipc_helpers.h" 11#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/sockets/sfdnsres.h" 12#include "core/hle/service/sockets/sfdnsres.h"
13#include "core/hle/service/sockets/sockets.h"
14#include "core/hle/service/sockets/sockets_translate.h"
15#include "core/internal_network/network.h"
13#include "core/memory.h" 16#include "core/memory.h"
14 17
15#ifdef _WIN32
16#include <ws2tcpip.h>
17#elif YUZU_UNIX
18#include <arpa/inet.h>
19#include <netdb.h>
20#include <netinet/in.h>
21#include <sys/socket.h>
22#ifndef EAI_NODATA
23#define EAI_NODATA EAI_NONAME
24#endif
25#endif
26
27namespace Service::Sockets { 18namespace Service::Sockets {
28 19
29SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} { 20SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
30 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
31 {0, nullptr, "SetDnsAddressesPrivateRequest"}, 22 {0, nullptr, "SetDnsAddressesPrivateRequest"},
32 {1, nullptr, "GetDnsAddressPrivateRequest"}, 23 {1, nullptr, "GetDnsAddressPrivateRequest"},
33 {2, nullptr, "GetHostByNameRequest"}, 24 {2, &SFDNSRES::GetHostByNameRequest, "GetHostByNameRequest"},
34 {3, nullptr, "GetHostByAddrRequest"}, 25 {3, nullptr, "GetHostByAddrRequest"},
35 {4, nullptr, "GetHostStringErrorRequest"}, 26 {4, nullptr, "GetHostStringErrorRequest"},
36 {5, nullptr, "GetGaiStringErrorRequest"}, 27 {5, nullptr, "GetGaiStringErrorRequest"},
@@ -38,11 +29,11 @@ SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"
38 {7, nullptr, "GetNameInfoRequest"}, 29 {7, nullptr, "GetNameInfoRequest"},
39 {8, nullptr, "RequestCancelHandleRequest"}, 30 {8, nullptr, "RequestCancelHandleRequest"},
40 {9, nullptr, "CancelRequest"}, 31 {9, nullptr, "CancelRequest"},
41 {10, nullptr, "GetHostByNameRequestWithOptions"}, 32 {10, &SFDNSRES::GetHostByNameRequestWithOptions, "GetHostByNameRequestWithOptions"},
42 {11, nullptr, "GetHostByAddrRequestWithOptions"}, 33 {11, nullptr, "GetHostByAddrRequestWithOptions"},
43 {12, &SFDNSRES::GetAddrInfoRequestWithOptions, "GetAddrInfoRequestWithOptions"}, 34 {12, &SFDNSRES::GetAddrInfoRequestWithOptions, "GetAddrInfoRequestWithOptions"},
44 {13, nullptr, "GetNameInfoRequestWithOptions"}, 35 {13, nullptr, "GetNameInfoRequestWithOptions"},
45 {14, nullptr, "ResolverSetOptionRequest"}, 36 {14, &SFDNSRES::ResolverSetOptionRequest, "ResolverSetOptionRequest"},
46 {15, nullptr, "ResolverGetOptionRequest"}, 37 {15, nullptr, "ResolverGetOptionRequest"},
47 }; 38 };
48 RegisterHandlers(functions); 39 RegisterHandlers(functions);
@@ -59,188 +50,285 @@ enum class NetDbError : s32 {
59 NoData = 4, 50 NoData = 4,
60}; 51};
61 52
62static NetDbError AddrInfoErrorToNetDbError(s32 result) { 53static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
63 // Best effort guess to map errors 54 // These combinations have been verified on console (but are not
55 // exhaustive).
64 switch (result) { 56 switch (result) {
65 case 0: 57 case GetAddrInfoError::SUCCESS:
66 return NetDbError::Success; 58 return NetDbError::Success;
67 case EAI_AGAIN: 59 case GetAddrInfoError::AGAIN:
68 return NetDbError::TryAgain; 60 return NetDbError::TryAgain;
69 case EAI_NODATA: 61 case GetAddrInfoError::NODATA:
70 return NetDbError::NoData; 62 return NetDbError::HostNotFound;
63 case GetAddrInfoError::SERVICE:
64 return NetDbError::Success;
71 default: 65 default:
72 return NetDbError::HostNotFound; 66 return NetDbError::HostNotFound;
73 } 67 }
74} 68}
75 69
76static std::vector<u8> SerializeAddrInfo(const addrinfo* addrinfo, s32 result_code, 70static Errno GetAddrInfoErrorToErrno(GetAddrInfoError result) {
71 // These combinations have been verified on console (but are not
72 // exhaustive).
73 switch (result) {
74 case GetAddrInfoError::SUCCESS:
75 // Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
76 // some reason, but that doesn't seem useful to implement.
77 return Errno::SUCCESS;
78 case GetAddrInfoError::AGAIN:
79 return Errno::SUCCESS;
80 case GetAddrInfoError::NODATA:
81 return Errno::SUCCESS;
82 case GetAddrInfoError::SERVICE:
83 return Errno::INVAL;
84 default:
85 return Errno::SUCCESS;
86 }
87}
88
89template <typename T>
90static void Append(std::vector<u8>& vec, T t) {
91 const size_t offset = vec.size();
92 vec.resize(offset + sizeof(T));
93 std::memcpy(vec.data() + offset, &t, sizeof(T));
94}
95
96static void AppendNulTerminated(std::vector<u8>& vec, std::string_view str) {
97 const size_t offset = vec.size();
98 vec.resize(offset + str.size() + 1);
99 std::memmove(vec.data() + offset, str.data(), str.size());
100}
101
102// We implement gethostbyname using the host's getaddrinfo rather than the
103// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
104// behaves the same on Unix and Windows, unlike gethostbyname where Windows
105// doesn't implement h_errno.
106static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::AddrInfo>& vec,
107 std::string_view host) {
108
109 std::vector<u8> data;
110 // h_name: use the input hostname (append nul-terminated)
111 AppendNulTerminated(data, host);
112 // h_aliases: leave empty
113
114 Append<u32_be>(data, 0); // count of h_aliases
115 // (If the count were nonzero, the aliases would be appended as nul-terminated here.)
116 Append<u16_be>(data, static_cast<u16>(Domain::INET)); // h_addrtype
117 Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
118 // h_addr_list:
119 size_t count = vec.size();
120 ASSERT(count <= UINT32_MAX);
121 Append<u32_be>(data, static_cast<uint32_t>(count));
122 for (const Network::AddrInfo& addrinfo : vec) {
123 // On the Switch, this is passed through htonl despite already being
124 // big-endian, so it ends up as little-endian.
125 Append<u32_le>(data, Network::IPv4AddressToInteger(addrinfo.addr.ip));
126
127 LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host,
128 Network::IPv4AddressToString(addrinfo.addr.ip));
129 }
130 return data;
131}
132
133static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
134 struct InputParameters {
135 u8 use_nsd_resolve;
136 u32 cancel_handle;
137 u64 process_id;
138 };
139 static_assert(sizeof(InputParameters) == 0x10);
140
141 IPC::RequestParser rp{ctx};
142 const auto parameters = rp.PopRaw<InputParameters>();
143
144 LOG_WARNING(
145 Service,
146 "called with ignored parameters: use_nsd_resolve={}, cancel_handle={}, process_id={}",
147 parameters.use_nsd_resolve, parameters.cancel_handle, parameters.process_id);
148
149 const auto host_buffer = ctx.ReadBuffer(0);
150 const std::string host = Common::StringFromBuffer(host_buffer);
151 // For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
152
153 auto res = Network::GetAddressInfo(host, /*service*/ std::nullopt);
154 if (!res.has_value()) {
155 return {0, Translate(res.error())};
156 }
157
158 const std::vector<u8> data = SerializeAddrInfoAsHostEnt(res.value(), host);
159 const u32 data_size = static_cast<u32>(data.size());
160 ctx.WriteBuffer(data, 0);
161
162 return {data_size, GetAddrInfoError::SUCCESS};
163}
164
165void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
166 auto [data_size, emu_gai_err] = GetHostByNameRequestImpl(ctx);
167
168 struct OutputParameters {
169 NetDbError netdb_error;
170 Errno bsd_errno;
171 u32 data_size;
172 };
173 static_assert(sizeof(OutputParameters) == 0xc);
174
175 IPC::ResponseBuilder rb{ctx, 5};
176 rb.Push(ResultSuccess);
177 rb.PushRaw(OutputParameters{
178 .netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
179 .bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
180 .data_size = data_size,
181 });
182}
183
184void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
185 auto [data_size, emu_gai_err] = GetHostByNameRequestImpl(ctx);
186
187 struct OutputParameters {
188 u32 data_size;
189 NetDbError netdb_error;
190 Errno bsd_errno;
191 };
192 static_assert(sizeof(OutputParameters) == 0xc);
193
194 IPC::ResponseBuilder rb{ctx, 5};
195 rb.Push(ResultSuccess);
196 rb.PushRaw(OutputParameters{
197 .data_size = data_size,
198 .netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
199 .bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
200 });
201}
202
203static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& vec,
77 std::string_view host) { 204 std::string_view host) {
78 // Adapted from 205 // Adapted from
79 // https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190 206 // https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
80 std::vector<u8> data; 207 std::vector<u8> data;
81 208
82 auto* current = addrinfo; 209 for (const Network::AddrInfo& addrinfo : vec) {
83 while (current != nullptr) { 210 // serialized addrinfo:
84 struct SerializedResponseHeader { 211 Append<u32_be>(data, 0xBEEFCAFE); // magic
85 u32 magic; 212 Append<u32_be>(data, 0); // ai_flags
86 s32 flags; 213 Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
87 s32 family; 214 Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
88 s32 socket_type; 215 Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
89 s32 protocol; 216 Append<u32_be>(data, sizeof(SockAddrIn)); // ai_addrlen
90 u32 address_length; 217 // ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
91 }; 218
92 static_assert(sizeof(SerializedResponseHeader) == 0x18, 219 // ai_addr:
93 "Response header size must be 0x18 bytes"); 220 Append<u16_be>(data, static_cast<u16>(Translate(addrinfo.addr.family))); // sin_family
94 221 // On the Switch, the following fields are passed through htonl despite
95 constexpr auto header_size = sizeof(SerializedResponseHeader); 222 // already being big-endian, so they end up as little-endian.
96 const auto addr_size = 223 Append<u16_le>(data, addrinfo.addr.portno); // sin_port
97 current->ai_addr && current->ai_addrlen > 0 ? current->ai_addrlen : 4; 224 Append<u32_le>(data, Network::IPv4AddressToInteger(addrinfo.addr.ip)); // sin_addr
98 const auto canonname_size = current->ai_canonname ? strlen(current->ai_canonname) + 1 : 1; 225 data.resize(data.size() + 8, 0); // sin_zero
99 226
100 const auto last_size = data.size(); 227 if (addrinfo.canon_name.has_value()) {
101 data.resize(last_size + header_size + addr_size + canonname_size); 228 AppendNulTerminated(data, *addrinfo.canon_name);
102
103 // Header in network byte order
104 SerializedResponseHeader header{};
105
106 constexpr auto HEADER_MAGIC = 0xBEEFCAFE;
107 header.magic = htonl(HEADER_MAGIC);
108 header.family = htonl(current->ai_family);
109 header.flags = htonl(current->ai_flags);
110 header.socket_type = htonl(current->ai_socktype);
111 header.protocol = htonl(current->ai_protocol);
112 header.address_length = current->ai_addr ? htonl((u32)current->ai_addrlen) : 0;
113
114 auto* header_ptr = data.data() + last_size;
115 std::memcpy(header_ptr, &header, header_size);
116
117 if (header.address_length == 0) {
118 std::memset(header_ptr + header_size, 0, 4);
119 } else {
120 switch (current->ai_family) {
121 case AF_INET: {
122 struct SockAddrIn {
123 s16 sin_family;
124 u16 sin_port;
125 u32 sin_addr;
126 u8 sin_zero[8];
127 };
128
129 SockAddrIn serialized_addr{};
130 const auto addr = *reinterpret_cast<sockaddr_in*>(current->ai_addr);
131 serialized_addr.sin_port = htons(addr.sin_port);
132 serialized_addr.sin_family = htons(addr.sin_family);
133 serialized_addr.sin_addr = htonl(addr.sin_addr.s_addr);
134 std::memcpy(header_ptr + header_size, &serialized_addr, sizeof(SockAddrIn));
135
136 char addr_string_buf[64]{};
137 inet_ntop(AF_INET, &addr.sin_addr, addr_string_buf, std::size(addr_string_buf));
138 LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host, addr_string_buf);
139 break;
140 }
141 case AF_INET6: {
142 struct SockAddrIn6 {
143 s16 sin6_family;
144 u16 sin6_port;
145 u32 sin6_flowinfo;
146 u8 sin6_addr[16];
147 u32 sin6_scope_id;
148 };
149
150 SockAddrIn6 serialized_addr{};
151 const auto addr = *reinterpret_cast<sockaddr_in6*>(current->ai_addr);
152 serialized_addr.sin6_family = htons(addr.sin6_family);
153 serialized_addr.sin6_port = htons(addr.sin6_port);
154 serialized_addr.sin6_flowinfo = htonl(addr.sin6_flowinfo);
155 serialized_addr.sin6_scope_id = htonl(addr.sin6_scope_id);
156 std::memcpy(serialized_addr.sin6_addr, &addr.sin6_addr,
157 sizeof(SockAddrIn6::sin6_addr));
158 std::memcpy(header_ptr + header_size, &serialized_addr, sizeof(SockAddrIn6));
159
160 char addr_string_buf[64]{};
161 inet_ntop(AF_INET6, &addr.sin6_addr, addr_string_buf, std::size(addr_string_buf));
162 LOG_INFO(Service, "Resolved host '{}' to IPv6 address {}", host, addr_string_buf);
163 break;
164 }
165 default:
166 std::memcpy(header_ptr + header_size, current->ai_addr, addr_size);
167 break;
168 }
169 }
170 if (current->ai_canonname) {
171 std::memcpy(header_ptr + addr_size, current->ai_canonname, canonname_size);
172 } else { 229 } else {
173 *(header_ptr + header_size + addr_size) = 0; 230 data.push_back(0);
174 } 231 }
175 232
176 current = current->ai_next; 233 LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host,
234 Network::IPv4AddressToString(addrinfo.addr.ip));
177 } 235 }
178 236
179 // 4-byte sentinel value 237 data.resize(data.size() + 4, 0); // 4-byte sentinel value
180 data.push_back(0);
181 data.push_back(0);
182 data.push_back(0);
183 data.push_back(0);
184 238
185 return data; 239 return data;
186} 240}
187 241
188static std::pair<u32, s32> GetAddrInfoRequestImpl(HLERequestContext& ctx) { 242static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
189 struct Parameters { 243 struct InputParameters {
190 u8 use_nsd_resolve; 244 u8 use_nsd_resolve;
191 u32 unknown; 245 u32 cancel_handle;
192 u64 process_id; 246 u64 process_id;
193 }; 247 };
248 static_assert(sizeof(InputParameters) == 0x10);
194 249
195 IPC::RequestParser rp{ctx}; 250 IPC::RequestParser rp{ctx};
196 const auto parameters = rp.PopRaw<Parameters>(); 251 const auto parameters = rp.PopRaw<InputParameters>();
252
253 LOG_WARNING(
254 Service,
255 "called with ignored parameters: use_nsd_resolve={}, cancel_handle={}, process_id={}",
256 parameters.use_nsd_resolve, parameters.cancel_handle, parameters.process_id);
197 257
198 LOG_WARNING(Service, 258 // TODO: If use_nsd_resolve is true, pass the name through NSD::Resolve
199 "called with ignored parameters: use_nsd_resolve={}, unknown={}, process_id={}", 259 // before looking up.
200 parameters.use_nsd_resolve, parameters.unknown, parameters.process_id);
201 260
202 const auto host_buffer = ctx.ReadBuffer(0); 261 const auto host_buffer = ctx.ReadBuffer(0);
203 const std::string host = Common::StringFromBuffer(host_buffer); 262 const std::string host = Common::StringFromBuffer(host_buffer);
204 263
205 const auto service_buffer = ctx.ReadBuffer(1); 264 std::optional<std::string> service = std::nullopt;
206 const std::string service = Common::StringFromBuffer(service_buffer); 265 if (ctx.CanReadBuffer(1)) {
207 266 const std::span<const u8> service_buffer = ctx.ReadBuffer(1);
208 addrinfo* addrinfo; 267 service = Common::StringFromBuffer(service_buffer);
209 // Pass null for hints. Serialized hints are also passed in a buffer, but are ignored for now 268 }
210 s32 result_code = getaddrinfo(host.c_str(), service.c_str(), nullptr, &addrinfo);
211 269
212 u32 data_size = 0; 270 // Serialized hints are also passed in a buffer, but are ignored for now.
213 if (result_code == 0 && addrinfo != nullptr) {
214 const std::vector<u8>& data = SerializeAddrInfo(addrinfo, result_code, host);
215 data_size = static_cast<u32>(data.size());
216 freeaddrinfo(addrinfo);
217 271
218 ctx.WriteBuffer(data, 0); 272 auto res = Network::GetAddressInfo(host, service);
273 if (!res.has_value()) {
274 return {0, Translate(res.error())};
219 } 275 }
220 276
221 return std::make_pair(data_size, result_code); 277 const std::vector<u8> data = SerializeAddrInfo(res.value(), host);
278 const u32 data_size = static_cast<u32>(data.size());
279 ctx.WriteBuffer(data, 0);
280
281 return {data_size, GetAddrInfoError::SUCCESS};
222} 282}
223 283
224void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) { 284void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
225 auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx); 285 auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
286
287 struct OutputParameters {
288 Errno bsd_errno;
289 GetAddrInfoError gai_error;
290 u32 data_size;
291 };
292 static_assert(sizeof(OutputParameters) == 0xc);
226 293
227 IPC::ResponseBuilder rb{ctx, 4}; 294 IPC::ResponseBuilder rb{ctx, 5};
228 rb.Push(ResultSuccess); 295 rb.Push(ResultSuccess);
229 rb.Push(static_cast<s32>(AddrInfoErrorToNetDbError(result_code))); // NetDBErrorCode 296 rb.PushRaw(OutputParameters{
230 rb.Push(result_code); // errno 297 .bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
231 rb.Push(data_size); // serialized size 298 .gai_error = emu_gai_err,
299 .data_size = data_size,
300 });
232} 301}
233 302
234void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) { 303void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
235 // Additional options are ignored 304 // Additional options are ignored
236 auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx); 305 auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
306
307 struct OutputParameters {
308 u32 data_size;
309 GetAddrInfoError gai_error;
310 NetDbError netdb_error;
311 Errno bsd_errno;
312 };
313 static_assert(sizeof(OutputParameters) == 0x10);
314
315 IPC::ResponseBuilder rb{ctx, 6};
316 rb.Push(ResultSuccess);
317 rb.PushRaw(OutputParameters{
318 .data_size = data_size,
319 .gai_error = emu_gai_err,
320 .netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
321 .bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
322 });
323}
324
325void SFDNSRES::ResolverSetOptionRequest(HLERequestContext& ctx) {
326 LOG_WARNING(Service, "(STUBBED) called");
327
328 IPC::ResponseBuilder rb{ctx, 3};
237 329
238 IPC::ResponseBuilder rb{ctx, 5};
239 rb.Push(ResultSuccess); 330 rb.Push(ResultSuccess);
240 rb.Push(data_size); // serialized size 331 rb.Push<s32>(0); // bsd errno
241 rb.Push(result_code); // errno
242 rb.Push(static_cast<s32>(AddrInfoErrorToNetDbError(result_code))); // NetDBErrorCode
243 rb.Push(0);
244} 332}
245 333
246} // namespace Service::Sockets 334} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index 18e3cd60c..d99a9d560 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -17,8 +17,11 @@ public:
17 ~SFDNSRES() override; 17 ~SFDNSRES() override;
18 18
19private: 19private:
20 void GetHostByNameRequest(HLERequestContext& ctx);
21 void GetHostByNameRequestWithOptions(HLERequestContext& ctx);
20 void GetAddrInfoRequest(HLERequestContext& ctx); 22 void GetAddrInfoRequest(HLERequestContext& ctx);
21 void GetAddrInfoRequestWithOptions(HLERequestContext& ctx); 23 void GetAddrInfoRequestWithOptions(HLERequestContext& ctx);
24 void ResolverSetOptionRequest(HLERequestContext& ctx);
22}; 25};
23 26
24} // namespace Service::Sockets 27} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index acd2dae7b..77426c46e 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -22,13 +22,35 @@ enum class Errno : u32 {
22 CONNRESET = 104, 22 CONNRESET = 104,
23 NOTCONN = 107, 23 NOTCONN = 107,
24 TIMEDOUT = 110, 24 TIMEDOUT = 110,
25 INPROGRESS = 115,
26};
27
28enum class GetAddrInfoError : s32 {
29 SUCCESS = 0,
30 ADDRFAMILY = 1,
31 AGAIN = 2,
32 BADFLAGS = 3,
33 FAIL = 4,
34 FAMILY = 5,
35 MEMORY = 6,
36 NODATA = 7,
37 NONAME = 8,
38 SERVICE = 9,
39 SOCKTYPE = 10,
40 SYSTEM = 11,
41 BADHINTS = 12,
42 PROTOCOL = 13,
43 OVERFLOW_ = 14, // avoid name collision with Windows macro
44 OTHER = 15,
25}; 45};
26 46
27enum class Domain : u32 { 47enum class Domain : u32 {
48 Unspecified = 0,
28 INET = 2, 49 INET = 2,
29}; 50};
30 51
31enum class Type : u32 { 52enum class Type : u32 {
53 Unspecified = 0,
32 STREAM = 1, 54 STREAM = 1,
33 DGRAM = 2, 55 DGRAM = 2,
34 RAW = 3, 56 RAW = 3,
@@ -36,12 +58,16 @@ enum class Type : u32 {
36}; 58};
37 59
38enum class Protocol : u32 { 60enum class Protocol : u32 {
39 UNSPECIFIED = 0, 61 Unspecified = 0,
40 ICMP = 1, 62 ICMP = 1,
41 TCP = 6, 63 TCP = 6,
42 UDP = 17, 64 UDP = 17,
43}; 65};
44 66
67enum class SocketLevel : u32 {
68 SOCKET = 0xffff, // i.e. SOL_SOCKET
69};
70
45enum class OptName : u32 { 71enum class OptName : u32 {
46 REUSEADDR = 0x4, 72 REUSEADDR = 0x4,
47 KEEPALIVE = 0x8, 73 KEEPALIVE = 0x8,
@@ -51,6 +77,8 @@ enum class OptName : u32 {
51 RCVBUF = 0x1002, 77 RCVBUF = 0x1002,
52 SNDTIMEO = 0x1005, 78 SNDTIMEO = 0x1005,
53 RCVTIMEO = 0x1006, 79 RCVTIMEO = 0x1006,
80 ERROR_ = 0x1007, // avoid name collision with Windows macro
81 NOSIGPIPE = 0x800, // at least according to libnx
54}; 82};
55 83
56enum class ShutdownHow : s32 { 84enum class ShutdownHow : s32 {
@@ -80,6 +108,9 @@ enum class PollEvents : u16 {
80 Err = 1 << 3, 108 Err = 1 << 3,
81 Hup = 1 << 4, 109 Hup = 1 << 4,
82 Nval = 1 << 5, 110 Nval = 1 << 5,
111 RdNorm = 1 << 6,
112 RdBand = 1 << 7,
113 WrBand = 1 << 8,
83}; 114};
84 115
85DECLARE_ENUM_FLAG_OPERATORS(PollEvents); 116DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
index 594e58f90..2f9a0e39c 100644
--- a/src/core/hle/service/sockets/sockets_translate.cpp
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -29,6 +29,8 @@ Errno Translate(Network::Errno value) {
29 return Errno::TIMEDOUT; 29 return Errno::TIMEDOUT;
30 case Network::Errno::CONNRESET: 30 case Network::Errno::CONNRESET:
31 return Errno::CONNRESET; 31 return Errno::CONNRESET;
32 case Network::Errno::INPROGRESS:
33 return Errno::INPROGRESS;
32 default: 34 default:
33 UNIMPLEMENTED_MSG("Unimplemented errno={}", value); 35 UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
34 return Errno::SUCCESS; 36 return Errno::SUCCESS;
@@ -39,8 +41,50 @@ std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
39 return {value.first, Translate(value.second)}; 41 return {value.first, Translate(value.second)};
40} 42}
41 43
44GetAddrInfoError Translate(Network::GetAddrInfoError error) {
45 switch (error) {
46 case Network::GetAddrInfoError::SUCCESS:
47 return GetAddrInfoError::SUCCESS;
48 case Network::GetAddrInfoError::ADDRFAMILY:
49 return GetAddrInfoError::ADDRFAMILY;
50 case Network::GetAddrInfoError::AGAIN:
51 return GetAddrInfoError::AGAIN;
52 case Network::GetAddrInfoError::BADFLAGS:
53 return GetAddrInfoError::BADFLAGS;
54 case Network::GetAddrInfoError::FAIL:
55 return GetAddrInfoError::FAIL;
56 case Network::GetAddrInfoError::FAMILY:
57 return GetAddrInfoError::FAMILY;
58 case Network::GetAddrInfoError::MEMORY:
59 return GetAddrInfoError::MEMORY;
60 case Network::GetAddrInfoError::NODATA:
61 return GetAddrInfoError::NODATA;
62 case Network::GetAddrInfoError::NONAME:
63 return GetAddrInfoError::NONAME;
64 case Network::GetAddrInfoError::SERVICE:
65 return GetAddrInfoError::SERVICE;
66 case Network::GetAddrInfoError::SOCKTYPE:
67 return GetAddrInfoError::SOCKTYPE;
68 case Network::GetAddrInfoError::SYSTEM:
69 return GetAddrInfoError::SYSTEM;
70 case Network::GetAddrInfoError::BADHINTS:
71 return GetAddrInfoError::BADHINTS;
72 case Network::GetAddrInfoError::PROTOCOL:
73 return GetAddrInfoError::PROTOCOL;
74 case Network::GetAddrInfoError::OVERFLOW_:
75 return GetAddrInfoError::OVERFLOW_;
76 case Network::GetAddrInfoError::OTHER:
77 return GetAddrInfoError::OTHER;
78 default:
79 UNIMPLEMENTED_MSG("Unimplemented GetAddrInfoError={}", error);
80 return GetAddrInfoError::OTHER;
81 }
82}
83
42Network::Domain Translate(Domain domain) { 84Network::Domain Translate(Domain domain) {
43 switch (domain) { 85 switch (domain) {
86 case Domain::Unspecified:
87 return Network::Domain::Unspecified;
44 case Domain::INET: 88 case Domain::INET:
45 return Network::Domain::INET; 89 return Network::Domain::INET;
46 default: 90 default:
@@ -51,6 +95,8 @@ Network::Domain Translate(Domain domain) {
51 95
52Domain Translate(Network::Domain domain) { 96Domain Translate(Network::Domain domain) {
53 switch (domain) { 97 switch (domain) {
98 case Network::Domain::Unspecified:
99 return Domain::Unspecified;
54 case Network::Domain::INET: 100 case Network::Domain::INET:
55 return Domain::INET; 101 return Domain::INET;
56 default: 102 default:
@@ -61,39 +107,69 @@ Domain Translate(Network::Domain domain) {
61 107
62Network::Type Translate(Type type) { 108Network::Type Translate(Type type) {
63 switch (type) { 109 switch (type) {
110 case Type::Unspecified:
111 return Network::Type::Unspecified;
64 case Type::STREAM: 112 case Type::STREAM:
65 return Network::Type::STREAM; 113 return Network::Type::STREAM;
66 case Type::DGRAM: 114 case Type::DGRAM:
67 return Network::Type::DGRAM; 115 return Network::Type::DGRAM;
116 case Type::RAW:
117 return Network::Type::RAW;
118 case Type::SEQPACKET:
119 return Network::Type::SEQPACKET;
68 default: 120 default:
69 UNIMPLEMENTED_MSG("Unimplemented type={}", type); 121 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
70 return Network::Type{}; 122 return Network::Type{};
71 } 123 }
72} 124}
73 125
74Network::Protocol Translate(Type type, Protocol protocol) { 126Type Translate(Network::Type type) {
127 switch (type) {
128 case Network::Type::Unspecified:
129 return Type::Unspecified;
130 case Network::Type::STREAM:
131 return Type::STREAM;
132 case Network::Type::DGRAM:
133 return Type::DGRAM;
134 case Network::Type::RAW:
135 return Type::RAW;
136 case Network::Type::SEQPACKET:
137 return Type::SEQPACKET;
138 default:
139 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
140 return Type{};
141 }
142}
143
144Network::Protocol Translate(Protocol protocol) {
75 switch (protocol) { 145 switch (protocol) {
76 case Protocol::UNSPECIFIED: 146 case Protocol::Unspecified:
77 LOG_WARNING(Service, "Unspecified protocol, assuming protocol from type"); 147 return Network::Protocol::Unspecified;
78 switch (type) {
79 case Type::DGRAM:
80 return Network::Protocol::UDP;
81 case Type::STREAM:
82 return Network::Protocol::TCP;
83 default:
84 return Network::Protocol::TCP;
85 }
86 case Protocol::TCP: 148 case Protocol::TCP:
87 return Network::Protocol::TCP; 149 return Network::Protocol::TCP;
88 case Protocol::UDP: 150 case Protocol::UDP:
89 return Network::Protocol::UDP; 151 return Network::Protocol::UDP;
90 default: 152 default:
91 UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol); 153 UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
92 return Network::Protocol::TCP; 154 return Network::Protocol::Unspecified;
155 }
156}
157
158Protocol Translate(Network::Protocol protocol) {
159 switch (protocol) {
160 case Network::Protocol::Unspecified:
161 return Protocol::Unspecified;
162 case Network::Protocol::TCP:
163 return Protocol::TCP;
164 case Network::Protocol::UDP:
165 return Protocol::UDP;
166 default:
167 UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
168 return Protocol::Unspecified;
93 } 169 }
94} 170}
95 171
96Network::PollEvents TranslatePollEventsToHost(PollEvents flags) { 172Network::PollEvents Translate(PollEvents flags) {
97 Network::PollEvents result{}; 173 Network::PollEvents result{};
98 const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) { 174 const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) {
99 if (True(flags & from)) { 175 if (True(flags & from)) {
@@ -107,12 +183,15 @@ Network::PollEvents TranslatePollEventsToHost(PollEvents flags) {
107 translate(PollEvents::Err, Network::PollEvents::Err); 183 translate(PollEvents::Err, Network::PollEvents::Err);
108 translate(PollEvents::Hup, Network::PollEvents::Hup); 184 translate(PollEvents::Hup, Network::PollEvents::Hup);
109 translate(PollEvents::Nval, Network::PollEvents::Nval); 185 translate(PollEvents::Nval, Network::PollEvents::Nval);
186 translate(PollEvents::RdNorm, Network::PollEvents::RdNorm);
187 translate(PollEvents::RdBand, Network::PollEvents::RdBand);
188 translate(PollEvents::WrBand, Network::PollEvents::WrBand);
110 189
111 UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags); 190 UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
112 return result; 191 return result;
113} 192}
114 193
115PollEvents TranslatePollEventsToGuest(Network::PollEvents flags) { 194PollEvents Translate(Network::PollEvents flags) {
116 PollEvents result{}; 195 PollEvents result{};
117 const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) { 196 const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) {
118 if (True(flags & from)) { 197 if (True(flags & from)) {
@@ -127,13 +206,18 @@ PollEvents TranslatePollEventsToGuest(Network::PollEvents flags) {
127 translate(Network::PollEvents::Err, PollEvents::Err); 206 translate(Network::PollEvents::Err, PollEvents::Err);
128 translate(Network::PollEvents::Hup, PollEvents::Hup); 207 translate(Network::PollEvents::Hup, PollEvents::Hup);
129 translate(Network::PollEvents::Nval, PollEvents::Nval); 208 translate(Network::PollEvents::Nval, PollEvents::Nval);
209 translate(Network::PollEvents::RdNorm, PollEvents::RdNorm);
210 translate(Network::PollEvents::RdBand, PollEvents::RdBand);
211 translate(Network::PollEvents::WrBand, PollEvents::WrBand);
130 212
131 UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags); 213 UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
132 return result; 214 return result;
133} 215}
134 216
135Network::SockAddrIn Translate(SockAddrIn value) { 217Network::SockAddrIn Translate(SockAddrIn value) {
136 ASSERT(value.len == 0 || value.len == sizeof(value)); 218 // Note: 6 is incorrect, but can be passed by homebrew (because libnx sets
219 // sin_len to 6 when deserializing getaddrinfo results).
220 ASSERT(value.len == 0 || value.len == sizeof(value) || value.len == 6);
137 221
138 return { 222 return {
139 .family = Translate(static_cast<Domain>(value.family)), 223 .family = Translate(static_cast<Domain>(value.family)),
diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h
index c93291d3e..694868b37 100644
--- a/src/core/hle/service/sockets/sockets_translate.h
+++ b/src/core/hle/service/sockets/sockets_translate.h
@@ -17,6 +17,9 @@ Errno Translate(Network::Errno value);
17/// Translate abstract return value errno pair to guest return value errno pair 17/// Translate abstract return value errno pair to guest return value errno pair
18std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value); 18std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
19 19
20/// Translate abstract getaddrinfo error to guest getaddrinfo error
21GetAddrInfoError Translate(Network::GetAddrInfoError value);
22
20/// Translate guest domain to abstract domain 23/// Translate guest domain to abstract domain
21Network::Domain Translate(Domain domain); 24Network::Domain Translate(Domain domain);
22 25
@@ -26,14 +29,20 @@ Domain Translate(Network::Domain domain);
26/// Translate guest type to abstract type 29/// Translate guest type to abstract type
27Network::Type Translate(Type type); 30Network::Type Translate(Type type);
28 31
32/// Translate abstract type to guest type
33Type Translate(Network::Type type);
34
29/// Translate guest protocol to abstract protocol 35/// Translate guest protocol to abstract protocol
30Network::Protocol Translate(Type type, Protocol protocol); 36Network::Protocol Translate(Protocol protocol);
31 37
32/// Translate abstract poll event flags to guest poll event flags 38/// Translate abstract protocol to guest protocol
33Network::PollEvents TranslatePollEventsToHost(PollEvents flags); 39Protocol Translate(Network::Protocol protocol);
34 40
35/// Translate guest poll event flags to abstract poll event flags 41/// Translate guest poll event flags to abstract poll event flags
36PollEvents TranslatePollEventsToGuest(Network::PollEvents flags); 42Network::PollEvents Translate(PollEvents flags);
43
44/// Translate abstract poll event flags to guest poll event flags
45PollEvents Translate(Network::PollEvents flags);
37 46
38/// Translate guest socket address structure to abstract socket address structure 47/// Translate guest socket address structure to abstract socket address structure
39Network::SockAddrIn Translate(SockAddrIn value); 48Network::SockAddrIn Translate(SockAddrIn value);
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 2b99dd7ac..9c96f9763 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -1,10 +1,18 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/string_util.h"
5
6#include "core/core.h"
4#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
5#include "core/hle/service/server_manager.h" 8#include "core/hle/service/server_manager.h"
6#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10#include "core/hle/service/sm/sm.h"
11#include "core/hle/service/sockets/bsd.h"
7#include "core/hle/service/ssl/ssl.h" 12#include "core/hle/service/ssl/ssl.h"
13#include "core/hle/service/ssl/ssl_backend.h"
14#include "core/internal_network/network.h"
15#include "core/internal_network/sockets.h"
8 16
9namespace Service::SSL { 17namespace Service::SSL {
10 18
@@ -20,6 +28,18 @@ enum class ContextOption : u32 {
20 CrlImportDateCheckEnable = 1, 28 CrlImportDateCheckEnable = 1,
21}; 29};
22 30
31// This is nn::ssl::Connection::IoMode
32enum class IoMode : u32 {
33 Blocking = 1,
34 NonBlocking = 2,
35};
36
37// This is nn::ssl::sf::OptionType
38enum class OptionType : u32 {
39 DoNotCloseSocket = 0,
40 GetServerCertChain = 1,
41};
42
23// This is nn::ssl::sf::SslVersion 43// This is nn::ssl::sf::SslVersion
24struct SslVersion { 44struct SslVersion {
25 union { 45 union {
@@ -34,35 +54,42 @@ struct SslVersion {
34 }; 54 };
35}; 55};
36 56
57struct SslContextSharedData {
58 u32 connection_count = 0;
59};
60
37class ISslConnection final : public ServiceFramework<ISslConnection> { 61class ISslConnection final : public ServiceFramework<ISslConnection> {
38public: 62public:
39 explicit ISslConnection(Core::System& system_, SslVersion version) 63 explicit ISslConnection(Core::System& system_in, SslVersion ssl_version_in,
40 : ServiceFramework{system_, "ISslConnection"}, ssl_version{version} { 64 std::shared_ptr<SslContextSharedData>& shared_data_in,
65 std::unique_ptr<SSLConnectionBackend>&& backend_in)
66 : ServiceFramework{system_in, "ISslConnection"}, ssl_version{ssl_version_in},
67 shared_data{shared_data_in}, backend{std::move(backend_in)} {
41 // clang-format off 68 // clang-format off
42 static const FunctionInfo functions[] = { 69 static const FunctionInfo functions[] = {
43 {0, nullptr, "SetSocketDescriptor"}, 70 {0, &ISslConnection::SetSocketDescriptor, "SetSocketDescriptor"},
44 {1, nullptr, "SetHostName"}, 71 {1, &ISslConnection::SetHostName, "SetHostName"},
45 {2, nullptr, "SetVerifyOption"}, 72 {2, &ISslConnection::SetVerifyOption, "SetVerifyOption"},
46 {3, nullptr, "SetIoMode"}, 73 {3, &ISslConnection::SetIoMode, "SetIoMode"},
47 {4, nullptr, "GetSocketDescriptor"}, 74 {4, nullptr, "GetSocketDescriptor"},
48 {5, nullptr, "GetHostName"}, 75 {5, nullptr, "GetHostName"},
49 {6, nullptr, "GetVerifyOption"}, 76 {6, nullptr, "GetVerifyOption"},
50 {7, nullptr, "GetIoMode"}, 77 {7, nullptr, "GetIoMode"},
51 {8, nullptr, "DoHandshake"}, 78 {8, &ISslConnection::DoHandshake, "DoHandshake"},
52 {9, nullptr, "DoHandshakeGetServerCert"}, 79 {9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"},
53 {10, nullptr, "Read"}, 80 {10, &ISslConnection::Read, "Read"},
54 {11, nullptr, "Write"}, 81 {11, &ISslConnection::Write, "Write"},
55 {12, nullptr, "Pending"}, 82 {12, &ISslConnection::Pending, "Pending"},
56 {13, nullptr, "Peek"}, 83 {13, nullptr, "Peek"},
57 {14, nullptr, "Poll"}, 84 {14, nullptr, "Poll"},
58 {15, nullptr, "GetVerifyCertError"}, 85 {15, nullptr, "GetVerifyCertError"},
59 {16, nullptr, "GetNeededServerCertBufferSize"}, 86 {16, nullptr, "GetNeededServerCertBufferSize"},
60 {17, nullptr, "SetSessionCacheMode"}, 87 {17, &ISslConnection::SetSessionCacheMode, "SetSessionCacheMode"},
61 {18, nullptr, "GetSessionCacheMode"}, 88 {18, nullptr, "GetSessionCacheMode"},
62 {19, nullptr, "FlushSessionCache"}, 89 {19, nullptr, "FlushSessionCache"},
63 {20, nullptr, "SetRenegotiationMode"}, 90 {20, nullptr, "SetRenegotiationMode"},
64 {21, nullptr, "GetRenegotiationMode"}, 91 {21, nullptr, "GetRenegotiationMode"},
65 {22, nullptr, "SetOption"}, 92 {22, &ISslConnection::SetOption, "SetOption"},
66 {23, nullptr, "GetOption"}, 93 {23, nullptr, "GetOption"},
67 {24, nullptr, "GetVerifyCertErrors"}, 94 {24, nullptr, "GetVerifyCertErrors"},
68 {25, nullptr, "GetCipherInfo"}, 95 {25, nullptr, "GetCipherInfo"},
@@ -80,21 +107,299 @@ public:
80 // clang-format on 107 // clang-format on
81 108
82 RegisterHandlers(functions); 109 RegisterHandlers(functions);
110
111 shared_data->connection_count++;
112 }
113
114 ~ISslConnection() {
115 shared_data->connection_count--;
116 if (fd_to_close.has_value()) {
117 const s32 fd = *fd_to_close;
118 if (!do_not_close_socket) {
119 LOG_ERROR(Service_SSL,
120 "do_not_close_socket was changed after setting socket; is this right?");
121 } else {
122 auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
123 if (bsd) {
124 auto err = bsd->CloseImpl(fd);
125 if (err != Service::Sockets::Errno::SUCCESS) {
126 LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
127 }
128 }
129 }
130 }
83 } 131 }
84 132
85private: 133private:
86 SslVersion ssl_version; 134 SslVersion ssl_version;
135 std::shared_ptr<SslContextSharedData> shared_data;
136 std::unique_ptr<SSLConnectionBackend> backend;
137 std::optional<int> fd_to_close;
138 bool do_not_close_socket = false;
139 bool get_server_cert_chain = false;
140 std::shared_ptr<Network::SocketBase> socket;
141 bool did_set_host_name = false;
142 bool did_handshake = false;
143
144 ResultVal<s32> SetSocketDescriptorImpl(s32 fd) {
145 LOG_DEBUG(Service_SSL, "called, fd={}", fd);
146 ASSERT(!did_handshake);
147 auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
148 ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
149 s32 ret_fd;
150 // Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor
151 if (do_not_close_socket) {
152 auto res = bsd->DuplicateSocketImpl(fd);
153 if (!res.has_value()) {
154 LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
155 return ResultInvalidSocket;
156 }
157 fd = *res;
158 fd_to_close = fd;
159 ret_fd = fd;
160 } else {
161 ret_fd = -1;
162 }
163 std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
164 if (!sock.has_value()) {
165 LOG_ERROR(Service_SSL, "invalid socket fd {}", fd);
166 return ResultInvalidSocket;
167 }
168 socket = std::move(*sock);
169 backend->SetSocket(socket);
170 return ret_fd;
171 }
172
173 Result SetHostNameImpl(const std::string& hostname) {
174 LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
175 ASSERT(!did_handshake);
176 Result res = backend->SetHostName(hostname);
177 if (res == ResultSuccess) {
178 did_set_host_name = true;
179 }
180 return res;
181 }
182
183 Result SetVerifyOptionImpl(u32 option) {
184 ASSERT(!did_handshake);
185 LOG_WARNING(Service_SSL, "(STUBBED) called. option={}", option);
186 return ResultSuccess;
187 }
188
189 Result SetIoModeImpl(u32 input_mode) {
190 auto mode = static_cast<IoMode>(input_mode);
191 ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
192 ASSERT_OR_EXECUTE(socket, { return ResultNoSocket; });
193
194 const bool non_block = mode == IoMode::NonBlocking;
195 const Network::Errno error = socket->SetNonBlock(non_block);
196 if (error != Network::Errno::SUCCESS) {
197 LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
198 }
199 return ResultSuccess;
200 }
201
202 Result SetSessionCacheModeImpl(u32 mode) {
203 ASSERT(!did_handshake);
204 LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
205 return ResultSuccess;
206 }
207
208 Result DoHandshakeImpl() {
209 ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
210 ASSERT_OR_EXECUTE_MSG(
211 did_set_host_name, { return ResultInternalError; },
212 "Expected SetHostName before DoHandshake");
213 Result res = backend->DoHandshake();
214 did_handshake = res.IsSuccess();
215 return res;
216 }
217
218 std::vector<u8> SerializeServerCerts(const std::vector<std::vector<u8>>& certs) {
219 struct Header {
220 u64 magic;
221 u32 count;
222 u32 pad;
223 };
224 struct EntryHeader {
225 u32 size;
226 u32 offset;
227 };
228 if (!get_server_cert_chain) {
229 // Just return the first one, unencoded.
230 ASSERT_OR_EXECUTE_MSG(
231 !certs.empty(), { return {}; }, "Should be at least one server cert");
232 return certs[0];
233 }
234 std::vector<u8> ret;
235 Header header{0x4E4D684374726543, static_cast<u32>(certs.size()), 0};
236 ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1));
237 size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader);
238 for (auto& cert : certs) {
239 EntryHeader entry_header{static_cast<u32>(cert.size()), static_cast<u32>(data_offset)};
240 data_offset += cert.size();
241 ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header),
242 reinterpret_cast<u8*>(&entry_header + 1));
243 }
244 for (auto& cert : certs) {
245 ret.insert(ret.end(), cert.begin(), cert.end());
246 }
247 return ret;
248 }
249
250 ResultVal<std::vector<u8>> ReadImpl(size_t size) {
251 ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
252 std::vector<u8> res(size);
253 ResultVal<size_t> actual = backend->Read(res);
254 if (actual.Failed()) {
255 return actual.Code();
256 }
257 res.resize(*actual);
258 return res;
259 }
260
261 ResultVal<size_t> WriteImpl(std::span<const u8> data) {
262 ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
263 return backend->Write(data);
264 }
265
266 ResultVal<s32> PendingImpl() {
267 LOG_WARNING(Service_SSL, "(STUBBED) called.");
268 return 0;
269 }
270
271 void SetSocketDescriptor(HLERequestContext& ctx) {
272 IPC::RequestParser rp{ctx};
273 const s32 fd = rp.Pop<s32>();
274 const ResultVal<s32> res = SetSocketDescriptorImpl(fd);
275 IPC::ResponseBuilder rb{ctx, 3};
276 rb.Push(res.Code());
277 rb.Push<s32>(res.ValueOr(-1));
278 }
279
280 void SetHostName(HLERequestContext& ctx) {
281 const std::string hostname = Common::StringFromBuffer(ctx.ReadBuffer());
282 const Result res = SetHostNameImpl(hostname);
283 IPC::ResponseBuilder rb{ctx, 2};
284 rb.Push(res);
285 }
286
287 void SetVerifyOption(HLERequestContext& ctx) {
288 IPC::RequestParser rp{ctx};
289 const u32 option = rp.Pop<u32>();
290 const Result res = SetVerifyOptionImpl(option);
291 IPC::ResponseBuilder rb{ctx, 2};
292 rb.Push(res);
293 }
294
295 void SetIoMode(HLERequestContext& ctx) {
296 IPC::RequestParser rp{ctx};
297 const u32 mode = rp.Pop<u32>();
298 const Result res = SetIoModeImpl(mode);
299 IPC::ResponseBuilder rb{ctx, 2};
300 rb.Push(res);
301 }
302
303 void DoHandshake(HLERequestContext& ctx) {
304 const Result res = DoHandshakeImpl();
305 IPC::ResponseBuilder rb{ctx, 2};
306 rb.Push(res);
307 }
308
309 void DoHandshakeGetServerCert(HLERequestContext& ctx) {
310 struct OutputParameters {
311 u32 certs_size;
312 u32 certs_count;
313 };
314 static_assert(sizeof(OutputParameters) == 0x8);
315
316 const Result res = DoHandshakeImpl();
317 OutputParameters out{};
318 if (res == ResultSuccess) {
319 auto certs = backend->GetServerCerts();
320 if (certs.Succeeded()) {
321 const std::vector<u8> certs_buf = SerializeServerCerts(*certs);
322 ctx.WriteBuffer(certs_buf);
323 out.certs_count = static_cast<u32>(certs->size());
324 out.certs_size = static_cast<u32>(certs_buf.size());
325 }
326 }
327 IPC::ResponseBuilder rb{ctx, 4};
328 rb.Push(res);
329 rb.PushRaw(out);
330 }
331
332 void Read(HLERequestContext& ctx) {
333 const ResultVal<std::vector<u8>> res = ReadImpl(ctx.GetWriteBufferSize());
334 IPC::ResponseBuilder rb{ctx, 3};
335 rb.Push(res.Code());
336 if (res.Succeeded()) {
337 rb.Push(static_cast<u32>(res->size()));
338 ctx.WriteBuffer(*res);
339 } else {
340 rb.Push(static_cast<u32>(0));
341 }
342 }
343
344 void Write(HLERequestContext& ctx) {
345 const ResultVal<size_t> res = WriteImpl(ctx.ReadBuffer());
346 IPC::ResponseBuilder rb{ctx, 3};
347 rb.Push(res.Code());
348 rb.Push(static_cast<u32>(res.ValueOr(0)));
349 }
350
351 void Pending(HLERequestContext& ctx) {
352 const ResultVal<s32> res = PendingImpl();
353 IPC::ResponseBuilder rb{ctx, 3};
354 rb.Push(res.Code());
355 rb.Push<s32>(res.ValueOr(0));
356 }
357
358 void SetSessionCacheMode(HLERequestContext& ctx) {
359 IPC::RequestParser rp{ctx};
360 const u32 mode = rp.Pop<u32>();
361 const Result res = SetSessionCacheModeImpl(mode);
362 IPC::ResponseBuilder rb{ctx, 2};
363 rb.Push(res);
364 }
365
366 void SetOption(HLERequestContext& ctx) {
367 struct Parameters {
368 OptionType option;
369 s32 value;
370 };
371 static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
372
373 IPC::RequestParser rp{ctx};
374 const auto parameters = rp.PopRaw<Parameters>();
375
376 switch (parameters.option) {
377 case OptionType::DoNotCloseSocket:
378 do_not_close_socket = static_cast<bool>(parameters.value);
379 break;
380 case OptionType::GetServerCertChain:
381 get_server_cert_chain = static_cast<bool>(parameters.value);
382 break;
383 default:
384 LOG_WARNING(Service_SSL, "Unknown option={}, value={}", parameters.option,
385 parameters.value);
386 }
387
388 IPC::ResponseBuilder rb{ctx, 2};
389 rb.Push(ResultSuccess);
390 }
87}; 391};
88 392
89class ISslContext final : public ServiceFramework<ISslContext> { 393class ISslContext final : public ServiceFramework<ISslContext> {
90public: 394public:
91 explicit ISslContext(Core::System& system_, SslVersion version) 395 explicit ISslContext(Core::System& system_, SslVersion version)
92 : ServiceFramework{system_, "ISslContext"}, ssl_version{version} { 396 : ServiceFramework{system_, "ISslContext"}, ssl_version{version},
397 shared_data{std::make_shared<SslContextSharedData>()} {
93 static const FunctionInfo functions[] = { 398 static const FunctionInfo functions[] = {
94 {0, &ISslContext::SetOption, "SetOption"}, 399 {0, &ISslContext::SetOption, "SetOption"},
95 {1, nullptr, "GetOption"}, 400 {1, nullptr, "GetOption"},
96 {2, &ISslContext::CreateConnection, "CreateConnection"}, 401 {2, &ISslContext::CreateConnection, "CreateConnection"},
97 {3, nullptr, "GetConnectionCount"}, 402 {3, &ISslContext::GetConnectionCount, "GetConnectionCount"},
98 {4, &ISslContext::ImportServerPki, "ImportServerPki"}, 403 {4, &ISslContext::ImportServerPki, "ImportServerPki"},
99 {5, &ISslContext::ImportClientPki, "ImportClientPki"}, 404 {5, &ISslContext::ImportClientPki, "ImportClientPki"},
100 {6, nullptr, "RemoveServerPki"}, 405 {6, nullptr, "RemoveServerPki"},
@@ -111,6 +416,7 @@ public:
111 416
112private: 417private:
113 SslVersion ssl_version; 418 SslVersion ssl_version;
419 std::shared_ptr<SslContextSharedData> shared_data;
114 420
115 void SetOption(HLERequestContext& ctx) { 421 void SetOption(HLERequestContext& ctx) {
116 struct Parameters { 422 struct Parameters {
@@ -130,11 +436,24 @@ private:
130 } 436 }
131 437
132 void CreateConnection(HLERequestContext& ctx) { 438 void CreateConnection(HLERequestContext& ctx) {
133 LOG_WARNING(Service_SSL, "(STUBBED) called"); 439 LOG_WARNING(Service_SSL, "called");
440
441 auto backend_res = CreateSSLConnectionBackend();
134 442
135 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 443 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
444 rb.Push(backend_res.Code());
445 if (backend_res.Succeeded()) {
446 rb.PushIpcInterface<ISslConnection>(system, ssl_version, shared_data,
447 std::move(*backend_res));
448 }
449 }
450
451 void GetConnectionCount(HLERequestContext& ctx) {
452 LOG_DEBUG(Service_SSL, "connection_count={}", shared_data->connection_count);
453
454 IPC::ResponseBuilder rb{ctx, 3};
136 rb.Push(ResultSuccess); 455 rb.Push(ResultSuccess);
137 rb.PushIpcInterface<ISslConnection>(system, ssl_version); 456 rb.Push(shared_data->connection_count);
138 } 457 }
139 458
140 void ImportServerPki(HLERequestContext& ctx) { 459 void ImportServerPki(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/ssl/ssl_backend.h b/src/core/hle/service/ssl/ssl_backend.h
new file mode 100644
index 000000000..409f4367c
--- /dev/null
+++ b/src/core/hle/service/ssl/ssl_backend.h
@@ -0,0 +1,45 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <span>
8#include <string>
9#include <vector>
10
11#include "common/common_types.h"
12
13#include "core/hle/result.h"
14
15namespace Network {
16class SocketBase;
17}
18
19namespace Service::SSL {
20
21constexpr Result ResultNoSocket{ErrorModule::SSLSrv, 103};
22constexpr Result ResultInvalidSocket{ErrorModule::SSLSrv, 106};
23constexpr Result ResultTimeout{ErrorModule::SSLSrv, 205};
24constexpr Result ResultInternalError{ErrorModule::SSLSrv, 999}; // made up
25
26// ResultWouldBlock is returned from Read and Write, and oddly, DoHandshake,
27// with no way in the latter case to distinguish whether the client should poll
28// for read or write. The one official client I've seen handles this by always
29// polling for read (with a timeout).
30constexpr Result ResultWouldBlock{ErrorModule::SSLSrv, 204};
31
32class SSLConnectionBackend {
33public:
34 virtual ~SSLConnectionBackend() {}
35 virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
36 virtual Result SetHostName(const std::string& hostname) = 0;
37 virtual Result DoHandshake() = 0;
38 virtual ResultVal<size_t> Read(std::span<u8> data) = 0;
39 virtual ResultVal<size_t> Write(std::span<const u8> data) = 0;
40 virtual ResultVal<std::vector<std::vector<u8>>> GetServerCerts() = 0;
41};
42
43ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend();
44
45} // namespace Service::SSL
diff --git a/src/core/hle/service/ssl/ssl_backend_none.cpp b/src/core/hle/service/ssl/ssl_backend_none.cpp
new file mode 100644
index 000000000..2f4f23c42
--- /dev/null
+++ b/src/core/hle/service/ssl/ssl_backend_none.cpp
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5
6#include "core/hle/service/ssl/ssl_backend.h"
7
8namespace Service::SSL {
9
10ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
11 LOG_ERROR(Service_SSL,
12 "Can't create SSL connection because no SSL backend is available on this platform");
13 return ResultInternalError;
14}
15
16} // namespace Service::SSL
diff --git a/src/core/hle/service/ssl/ssl_backend_openssl.cpp b/src/core/hle/service/ssl/ssl_backend_openssl.cpp
new file mode 100644
index 000000000..6ca869dbf
--- /dev/null
+++ b/src/core/hle/service/ssl/ssl_backend_openssl.cpp
@@ -0,0 +1,351 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <mutex>
5
6#include <openssl/bio.h>
7#include <openssl/err.h>
8#include <openssl/ssl.h>
9#include <openssl/x509.h>
10
11#include "common/fs/file.h"
12#include "common/hex_util.h"
13#include "common/string_util.h"
14
15#include "core/hle/service/ssl/ssl_backend.h"
16#include "core/internal_network/network.h"
17#include "core/internal_network/sockets.h"
18
19using namespace Common::FS;
20
21namespace Service::SSL {
22
23// Import OpenSSL's `SSL` type into the namespace. This is needed because the
24// namespace is also named `SSL`.
25using ::SSL;
26
27namespace {
28
29std::once_flag one_time_init_flag;
30bool one_time_init_success = false;
31
32SSL_CTX* ssl_ctx;
33IOFile key_log_file; // only open if SSLKEYLOGFILE set in environment
34BIO_METHOD* bio_meth;
35
36Result CheckOpenSSLErrors();
37void OneTimeInit();
38void OneTimeInitLogFile();
39bool OneTimeInitBIO();
40
41} // namespace
42
43class SSLConnectionBackendOpenSSL final : public SSLConnectionBackend {
44public:
45 Result Init() {
46 std::call_once(one_time_init_flag, OneTimeInit);
47
48 if (!one_time_init_success) {
49 LOG_ERROR(Service_SSL,
50 "Can't create SSL connection because OpenSSL one-time initialization failed");
51 return ResultInternalError;
52 }
53
54 ssl = SSL_new(ssl_ctx);
55 if (!ssl) {
56 LOG_ERROR(Service_SSL, "SSL_new failed");
57 return CheckOpenSSLErrors();
58 }
59
60 SSL_set_connect_state(ssl);
61
62 bio = BIO_new(bio_meth);
63 if (!bio) {
64 LOG_ERROR(Service_SSL, "BIO_new failed");
65 return CheckOpenSSLErrors();
66 }
67
68 BIO_set_data(bio, this);
69 BIO_set_init(bio, 1);
70 SSL_set_bio(ssl, bio, bio);
71
72 return ResultSuccess;
73 }
74
75 void SetSocket(std::shared_ptr<Network::SocketBase> socket_in) override {
76 socket = std::move(socket_in);
77 }
78
79 Result SetHostName(const std::string& hostname) override {
80 if (!SSL_set1_host(ssl, hostname.c_str())) { // hostname for verification
81 LOG_ERROR(Service_SSL, "SSL_set1_host({}) failed", hostname);
82 return CheckOpenSSLErrors();
83 }
84 if (!SSL_set_tlsext_host_name(ssl, hostname.c_str())) { // hostname for SNI
85 LOG_ERROR(Service_SSL, "SSL_set_tlsext_host_name({}) failed", hostname);
86 return CheckOpenSSLErrors();
87 }
88 return ResultSuccess;
89 }
90
91 Result DoHandshake() override {
92 SSL_set_verify_result(ssl, X509_V_OK);
93 const int ret = SSL_do_handshake(ssl);
94 const long verify_result = SSL_get_verify_result(ssl);
95 if (verify_result != X509_V_OK) {
96 LOG_ERROR(Service_SSL, "SSL cert verification failed because: {}",
97 X509_verify_cert_error_string(verify_result));
98 return CheckOpenSSLErrors();
99 }
100 if (ret <= 0) {
101 const int ssl_err = SSL_get_error(ssl, ret);
102 if (ssl_err == SSL_ERROR_ZERO_RETURN ||
103 (ssl_err == SSL_ERROR_SYSCALL && got_read_eof)) {
104 LOG_ERROR(Service_SSL, "SSL handshake failed because server hung up");
105 return ResultInternalError;
106 }
107 }
108 return HandleReturn("SSL_do_handshake", 0, ret).Code();
109 }
110
111 ResultVal<size_t> Read(std::span<u8> data) override {
112 size_t actual;
113 const int ret = SSL_read_ex(ssl, data.data(), data.size(), &actual);
114 return HandleReturn("SSL_read_ex", actual, ret);
115 }
116
117 ResultVal<size_t> Write(std::span<const u8> data) override {
118 size_t actual;
119 const int ret = SSL_write_ex(ssl, data.data(), data.size(), &actual);
120 return HandleReturn("SSL_write_ex", actual, ret);
121 }
122
123 ResultVal<size_t> HandleReturn(const char* what, size_t actual, int ret) {
124 const int ssl_err = SSL_get_error(ssl, ret);
125 CheckOpenSSLErrors();
126 switch (ssl_err) {
127 case SSL_ERROR_NONE:
128 return actual;
129 case SSL_ERROR_ZERO_RETURN:
130 LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_ZERO_RETURN", what);
131 // DoHandshake special-cases this, but for Read and Write:
132 return size_t(0);
133 case SSL_ERROR_WANT_READ:
134 LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_WANT_READ", what);
135 return ResultWouldBlock;
136 case SSL_ERROR_WANT_WRITE:
137 LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_WANT_WRITE", what);
138 return ResultWouldBlock;
139 default:
140 if (ssl_err == SSL_ERROR_SYSCALL && got_read_eof) {
141 LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_SYSCALL because server hung up", what);
142 return size_t(0);
143 }
144 LOG_ERROR(Service_SSL, "{} => other SSL_get_error return value {}", what, ssl_err);
145 return ResultInternalError;
146 }
147 }
148
149 ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
150 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
151 if (!chain) {
152 LOG_ERROR(Service_SSL, "SSL_get_peer_cert_chain returned nullptr");
153 return ResultInternalError;
154 }
155 std::vector<std::vector<u8>> ret;
156 int count = sk_X509_num(chain);
157 ASSERT(count >= 0);
158 for (int i = 0; i < count; i++) {
159 X509* x509 = sk_X509_value(chain, i);
160 ASSERT_OR_EXECUTE(x509 != nullptr, { continue; });
161 unsigned char* buf = nullptr;
162 int len = i2d_X509(x509, &buf);
163 ASSERT_OR_EXECUTE(len >= 0 && buf, { continue; });
164 ret.emplace_back(buf, buf + len);
165 OPENSSL_free(buf);
166 }
167 return ret;
168 }
169
170 ~SSLConnectionBackendOpenSSL() {
171 // these are null-tolerant:
172 SSL_free(ssl);
173 BIO_free(bio);
174 }
175
176 static void KeyLogCallback(const SSL* ssl, const char* line) {
177 std::string str(line);
178 str.push_back('\n');
179 // Do this in a single WriteString for atomicity if multiple instances
180 // are running on different threads (though that can't currently
181 // happen).
182 if (key_log_file.WriteString(str) != str.size() || !key_log_file.Flush()) {
183 LOG_CRITICAL(Service_SSL, "Failed to write to SSLKEYLOGFILE");
184 }
185 LOG_DEBUG(Service_SSL, "Wrote to SSLKEYLOGFILE: {}", line);
186 }
187
188 static int WriteCallback(BIO* bio, const char* buf, size_t len, size_t* actual_p) {
189 auto self = static_cast<SSLConnectionBackendOpenSSL*>(BIO_get_data(bio));
190 ASSERT_OR_EXECUTE_MSG(
191 self->socket, { return 0; }, "OpenSSL asked to send but we have no socket");
192 BIO_clear_retry_flags(bio);
193 auto [actual, err] = self->socket->Send({reinterpret_cast<const u8*>(buf), len}, 0);
194 switch (err) {
195 case Network::Errno::SUCCESS:
196 *actual_p = actual;
197 return 1;
198 case Network::Errno::AGAIN:
199 BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
200 return 0;
201 default:
202 LOG_ERROR(Service_SSL, "Socket send returned Network::Errno {}", err);
203 return -1;
204 }
205 }
206
207 static int ReadCallback(BIO* bio, char* buf, size_t len, size_t* actual_p) {
208 auto self = static_cast<SSLConnectionBackendOpenSSL*>(BIO_get_data(bio));
209 ASSERT_OR_EXECUTE_MSG(
210 self->socket, { return 0; }, "OpenSSL asked to recv but we have no socket");
211 BIO_clear_retry_flags(bio);
212 auto [actual, err] = self->socket->Recv(0, {reinterpret_cast<u8*>(buf), len});
213 switch (err) {
214 case Network::Errno::SUCCESS:
215 *actual_p = actual;
216 if (actual == 0) {
217 self->got_read_eof = true;
218 }
219 return actual ? 1 : 0;
220 case Network::Errno::AGAIN:
221 BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
222 return 0;
223 default:
224 LOG_ERROR(Service_SSL, "Socket recv returned Network::Errno {}", err);
225 return -1;
226 }
227 }
228
229 static long CtrlCallback(BIO* bio, int cmd, long l_arg, void* p_arg) {
230 switch (cmd) {
231 case BIO_CTRL_FLUSH:
232 // Nothing to flush.
233 return 1;
234 case BIO_CTRL_PUSH:
235 case BIO_CTRL_POP:
236#ifdef BIO_CTRL_GET_KTLS_SEND
237 case BIO_CTRL_GET_KTLS_SEND:
238 case BIO_CTRL_GET_KTLS_RECV:
239#endif
240 // We don't support these operations, but don't bother logging them
241 // as they're nothing unusual.
242 return 0;
243 default:
244 LOG_DEBUG(Service_SSL, "OpenSSL BIO got ctrl({}, {}, {})", cmd, l_arg, p_arg);
245 return 0;
246 }
247 }
248
249 SSL* ssl = nullptr;
250 BIO* bio = nullptr;
251 bool got_read_eof = false;
252
253 std::shared_ptr<Network::SocketBase> socket;
254};
255
256ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
257 auto conn = std::make_unique<SSLConnectionBackendOpenSSL>();
258 const Result res = conn->Init();
259 if (res.IsFailure()) {
260 return res;
261 }
262 return conn;
263}
264
265namespace {
266
267Result CheckOpenSSLErrors() {
268 unsigned long rc;
269 const char* file;
270 int line;
271 const char* func;
272 const char* data;
273 int flags;
274#if OPENSSL_VERSION_NUMBER >= 0x30000000L
275 while ((rc = ERR_get_error_all(&file, &line, &func, &data, &flags)))
276#else
277 // Can't get function names from OpenSSL on this version, so use mine:
278 func = __func__;
279 while ((rc = ERR_get_error_line_data(&file, &line, &data, &flags)))
280#endif
281 {
282 std::string msg;
283 msg.resize(1024, '\0');
284 ERR_error_string_n(rc, msg.data(), msg.size());
285 msg.resize(strlen(msg.data()), '\0');
286 if (flags & ERR_TXT_STRING) {
287 msg.append(" | ");
288 msg.append(data);
289 }
290 Common::Log::FmtLogMessage(Common::Log::Class::Service_SSL, Common::Log::Level::Error,
291 Common::Log::TrimSourcePath(file), line, func, "OpenSSL: {}",
292 msg);
293 }
294 return ResultInternalError;
295}
296
297void OneTimeInit() {
298 ssl_ctx = SSL_CTX_new(TLS_client_method());
299 if (!ssl_ctx) {
300 LOG_ERROR(Service_SSL, "SSL_CTX_new failed");
301 CheckOpenSSLErrors();
302 return;
303 }
304
305 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, nullptr);
306
307 if (!SSL_CTX_set_default_verify_paths(ssl_ctx)) {
308 LOG_ERROR(Service_SSL, "SSL_CTX_set_default_verify_paths failed");
309 CheckOpenSSLErrors();
310 return;
311 }
312
313 OneTimeInitLogFile();
314
315 if (!OneTimeInitBIO()) {
316 return;
317 }
318
319 one_time_init_success = true;
320}
321
322void OneTimeInitLogFile() {
323 const char* logfile = getenv("SSLKEYLOGFILE");
324 if (logfile) {
325 key_log_file.Open(logfile, FileAccessMode::Append, FileType::TextFile,
326 FileShareFlag::ShareWriteOnly);
327 if (key_log_file.IsOpen()) {
328 SSL_CTX_set_keylog_callback(ssl_ctx, &SSLConnectionBackendOpenSSL::KeyLogCallback);
329 } else {
330 LOG_CRITICAL(Service_SSL,
331 "SSLKEYLOGFILE was set but file could not be opened; not logging keys!");
332 }
333 }
334}
335
336bool OneTimeInitBIO() {
337 bio_meth =
338 BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "SSLConnectionBackendOpenSSL");
339 if (!bio_meth ||
340 !BIO_meth_set_write_ex(bio_meth, &SSLConnectionBackendOpenSSL::WriteCallback) ||
341 !BIO_meth_set_read_ex(bio_meth, &SSLConnectionBackendOpenSSL::ReadCallback) ||
342 !BIO_meth_set_ctrl(bio_meth, &SSLConnectionBackendOpenSSL::CtrlCallback)) {
343 LOG_ERROR(Service_SSL, "Failed to create BIO_METHOD");
344 return false;
345 }
346 return true;
347}
348
349} // namespace
350
351} // namespace Service::SSL
diff --git a/src/core/hle/service/ssl/ssl_backend_schannel.cpp b/src/core/hle/service/ssl/ssl_backend_schannel.cpp
new file mode 100644
index 000000000..d8074339a
--- /dev/null
+++ b/src/core/hle/service/ssl/ssl_backend_schannel.cpp
@@ -0,0 +1,544 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <mutex>
5
6#include "common/error.h"
7#include "common/fs/file.h"
8#include "common/hex_util.h"
9#include "common/string_util.h"
10
11#include "core/hle/service/ssl/ssl_backend.h"
12#include "core/internal_network/network.h"
13#include "core/internal_network/sockets.h"
14
15namespace {
16
17// These includes are inside the namespace to avoid a conflict on MinGW where
18// the headers define an enum containing Network and Service as enumerators
19// (which clash with the correspondingly named namespaces).
20#define SECURITY_WIN32
21#include <schnlsp.h>
22#include <security.h>
23#include <wincrypt.h>
24
25std::once_flag one_time_init_flag;
26bool one_time_init_success = false;
27
28SCHANNEL_CRED schannel_cred{};
29CredHandle cred_handle;
30
31static void OneTimeInit() {
32 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
33 schannel_cred.dwFlags =
34 SCH_USE_STRONG_CRYPTO | // don't allow insecure protocols
35 SCH_CRED_AUTO_CRED_VALIDATION | // validate certs
36 SCH_CRED_NO_DEFAULT_CREDS; // don't automatically present a client certificate
37 // ^ I'm assuming that nobody would want to connect Yuzu to a
38 // service that requires some OS-provided corporate client
39 // certificate, and presenting one to some arbitrary server
40 // might be a privacy concern? Who knows, though.
41
42 const SECURITY_STATUS ret =
43 AcquireCredentialsHandle(nullptr, const_cast<LPTSTR>(UNISP_NAME), SECPKG_CRED_OUTBOUND,
44 nullptr, &schannel_cred, nullptr, nullptr, &cred_handle, nullptr);
45 if (ret != SEC_E_OK) {
46 // SECURITY_STATUS codes are a type of HRESULT and can be used with NativeErrorToString.
47 LOG_ERROR(Service_SSL, "AcquireCredentialsHandle failed: {}",
48 Common::NativeErrorToString(ret));
49 return;
50 }
51
52 if (getenv("SSLKEYLOGFILE")) {
53 LOG_CRITICAL(Service_SSL, "SSLKEYLOGFILE was set but Schannel does not support exporting "
54 "keys; not logging keys!");
55 // Not fatal.
56 }
57
58 one_time_init_success = true;
59}
60
61} // namespace
62
63namespace Service::SSL {
64
65class SSLConnectionBackendSchannel final : public SSLConnectionBackend {
66public:
67 Result Init() {
68 std::call_once(one_time_init_flag, OneTimeInit);
69
70 if (!one_time_init_success) {
71 LOG_ERROR(
72 Service_SSL,
73 "Can't create SSL connection because Schannel one-time initialization failed");
74 return ResultInternalError;
75 }
76
77 return ResultSuccess;
78 }
79
80 void SetSocket(std::shared_ptr<Network::SocketBase> socket_in) override {
81 socket = std::move(socket_in);
82 }
83
84 Result SetHostName(const std::string& hostname_in) override {
85 hostname = hostname_in;
86 return ResultSuccess;
87 }
88
89 Result DoHandshake() override {
90 while (1) {
91 Result r;
92 switch (handshake_state) {
93 case HandshakeState::Initial:
94 if ((r = FlushCiphertextWriteBuf()) != ResultSuccess ||
95 (r = CallInitializeSecurityContext()) != ResultSuccess) {
96 return r;
97 }
98 // CallInitializeSecurityContext updated `handshake_state`.
99 continue;
100 case HandshakeState::ContinueNeeded:
101 case HandshakeState::IncompleteMessage:
102 if ((r = FlushCiphertextWriteBuf()) != ResultSuccess ||
103 (r = FillCiphertextReadBuf()) != ResultSuccess) {
104 return r;
105 }
106 if (ciphertext_read_buf.empty()) {
107 LOG_ERROR(Service_SSL, "SSL handshake failed because server hung up");
108 return ResultInternalError;
109 }
110 if ((r = CallInitializeSecurityContext()) != ResultSuccess) {
111 return r;
112 }
113 // CallInitializeSecurityContext updated `handshake_state`.
114 continue;
115 case HandshakeState::DoneAfterFlush:
116 if ((r = FlushCiphertextWriteBuf()) != ResultSuccess) {
117 return r;
118 }
119 handshake_state = HandshakeState::Connected;
120 return ResultSuccess;
121 case HandshakeState::Connected:
122 LOG_ERROR(Service_SSL, "Called DoHandshake but we already handshook");
123 return ResultInternalError;
124 case HandshakeState::Error:
125 return ResultInternalError;
126 }
127 }
128 }
129
130 Result FillCiphertextReadBuf() {
131 const size_t fill_size = read_buf_fill_size ? read_buf_fill_size : 4096;
132 read_buf_fill_size = 0;
133 // This unnecessarily zeroes the buffer; oh well.
134 const size_t offset = ciphertext_read_buf.size();
135 ASSERT_OR_EXECUTE(offset + fill_size >= offset, { return ResultInternalError; });
136 ciphertext_read_buf.resize(offset + fill_size, 0);
137 const auto read_span = std::span(ciphertext_read_buf).subspan(offset, fill_size);
138 const auto [actual, err] = socket->Recv(0, read_span);
139 switch (err) {
140 case Network::Errno::SUCCESS:
141 ASSERT(static_cast<size_t>(actual) <= fill_size);
142 ciphertext_read_buf.resize(offset + actual);
143 return ResultSuccess;
144 case Network::Errno::AGAIN:
145 ciphertext_read_buf.resize(offset);
146 return ResultWouldBlock;
147 default:
148 ciphertext_read_buf.resize(offset);
149 LOG_ERROR(Service_SSL, "Socket recv returned Network::Errno {}", err);
150 return ResultInternalError;
151 }
152 }
153
154 // Returns success if the write buffer has been completely emptied.
155 Result FlushCiphertextWriteBuf() {
156 while (!ciphertext_write_buf.empty()) {
157 const auto [actual, err] = socket->Send(ciphertext_write_buf, 0);
158 switch (err) {
159 case Network::Errno::SUCCESS:
160 ASSERT(static_cast<size_t>(actual) <= ciphertext_write_buf.size());
161 ciphertext_write_buf.erase(ciphertext_write_buf.begin(),
162 ciphertext_write_buf.begin() + actual);
163 break;
164 case Network::Errno::AGAIN:
165 return ResultWouldBlock;
166 default:
167 LOG_ERROR(Service_SSL, "Socket send returned Network::Errno {}", err);
168 return ResultInternalError;
169 }
170 }
171 return ResultSuccess;
172 }
173
174 Result CallInitializeSecurityContext() {
175 const unsigned long req = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY |
176 ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT |
177 ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM |
178 ISC_REQ_USE_SUPPLIED_CREDS;
179 unsigned long attr;
180 // https://learn.microsoft.com/en-us/windows/win32/secauthn/initializesecuritycontext--schannel
181 std::array<SecBuffer, 2> input_buffers{{
182 // only used if `initial_call_done`
183 {
184 // [0]
185 .cbBuffer = static_cast<unsigned long>(ciphertext_read_buf.size()),
186 .BufferType = SECBUFFER_TOKEN,
187 .pvBuffer = ciphertext_read_buf.data(),
188 },
189 {
190 // [1] (will be replaced by SECBUFFER_MISSING when SEC_E_INCOMPLETE_MESSAGE is
191 // returned, or SECBUFFER_EXTRA when SEC_E_CONTINUE_NEEDED is returned if the
192 // whole buffer wasn't used)
193 .cbBuffer = 0,
194 .BufferType = SECBUFFER_EMPTY,
195 .pvBuffer = nullptr,
196 },
197 }};
198 std::array<SecBuffer, 2> output_buffers{{
199 {
200 .cbBuffer = 0,
201 .BufferType = SECBUFFER_TOKEN,
202 .pvBuffer = nullptr,
203 }, // [0]
204 {
205 .cbBuffer = 0,
206 .BufferType = SECBUFFER_ALERT,
207 .pvBuffer = nullptr,
208 }, // [1]
209 }};
210 SecBufferDesc input_desc{
211 .ulVersion = SECBUFFER_VERSION,
212 .cBuffers = static_cast<unsigned long>(input_buffers.size()),
213 .pBuffers = input_buffers.data(),
214 };
215 SecBufferDesc output_desc{
216 .ulVersion = SECBUFFER_VERSION,
217 .cBuffers = static_cast<unsigned long>(output_buffers.size()),
218 .pBuffers = output_buffers.data(),
219 };
220 ASSERT_OR_EXECUTE_MSG(
221 input_buffers[0].cbBuffer == ciphertext_read_buf.size(),
222 { return ResultInternalError; }, "read buffer too large");
223
224 bool initial_call_done = handshake_state != HandshakeState::Initial;
225 if (initial_call_done) {
226 LOG_DEBUG(Service_SSL, "Passing {} bytes into InitializeSecurityContext",
227 ciphertext_read_buf.size());
228 }
229
230 const SECURITY_STATUS ret =
231 InitializeSecurityContextA(&cred_handle, initial_call_done ? &ctxt : nullptr,
232 // Caller ensured we have set a hostname:
233 const_cast<char*>(hostname.value().c_str()), req,
234 0, // Reserved1
235 0, // TargetDataRep not used with Schannel
236 initial_call_done ? &input_desc : nullptr,
237 0, // Reserved2
238 initial_call_done ? nullptr : &ctxt, &output_desc, &attr,
239 nullptr); // ptsExpiry
240
241 if (output_buffers[0].pvBuffer) {
242 const std::span span(static_cast<u8*>(output_buffers[0].pvBuffer),
243 output_buffers[0].cbBuffer);
244 ciphertext_write_buf.insert(ciphertext_write_buf.end(), span.begin(), span.end());
245 FreeContextBuffer(output_buffers[0].pvBuffer);
246 }
247
248 if (output_buffers[1].pvBuffer) {
249 const std::span span(static_cast<u8*>(output_buffers[1].pvBuffer),
250 output_buffers[1].cbBuffer);
251 // The documentation doesn't explain what format this data is in.
252 LOG_DEBUG(Service_SSL, "Got a {}-byte alert buffer: {}", span.size(),
253 Common::HexToString(span));
254 }
255
256 switch (ret) {
257 case SEC_I_CONTINUE_NEEDED:
258 LOG_DEBUG(Service_SSL, "InitializeSecurityContext => SEC_I_CONTINUE_NEEDED");
259 if (input_buffers[1].BufferType == SECBUFFER_EXTRA) {
260 LOG_DEBUG(Service_SSL, "EXTRA of size {}", input_buffers[1].cbBuffer);
261 ASSERT(input_buffers[1].cbBuffer <= ciphertext_read_buf.size());
262 ciphertext_read_buf.erase(ciphertext_read_buf.begin(),
263 ciphertext_read_buf.end() - input_buffers[1].cbBuffer);
264 } else {
265 ASSERT(input_buffers[1].BufferType == SECBUFFER_EMPTY);
266 ciphertext_read_buf.clear();
267 }
268 handshake_state = HandshakeState::ContinueNeeded;
269 return ResultSuccess;
270 case SEC_E_INCOMPLETE_MESSAGE:
271 LOG_DEBUG(Service_SSL, "InitializeSecurityContext => SEC_E_INCOMPLETE_MESSAGE");
272 ASSERT(input_buffers[1].BufferType == SECBUFFER_MISSING);
273 read_buf_fill_size = input_buffers[1].cbBuffer;
274 handshake_state = HandshakeState::IncompleteMessage;
275 return ResultSuccess;
276 case SEC_E_OK:
277 LOG_DEBUG(Service_SSL, "InitializeSecurityContext => SEC_E_OK");
278 ciphertext_read_buf.clear();
279 handshake_state = HandshakeState::DoneAfterFlush;
280 return GrabStreamSizes();
281 default:
282 LOG_ERROR(Service_SSL,
283 "InitializeSecurityContext failed (probably certificate/protocol issue): {}",
284 Common::NativeErrorToString(ret));
285 handshake_state = HandshakeState::Error;
286 return ResultInternalError;
287 }
288 }
289
290 Result GrabStreamSizes() {
291 const SECURITY_STATUS ret =
292 QueryContextAttributes(&ctxt, SECPKG_ATTR_STREAM_SIZES, &stream_sizes);
293 if (ret != SEC_E_OK) {
294 LOG_ERROR(Service_SSL, "QueryContextAttributes(SECPKG_ATTR_STREAM_SIZES) failed: {}",
295 Common::NativeErrorToString(ret));
296 handshake_state = HandshakeState::Error;
297 return ResultInternalError;
298 }
299 return ResultSuccess;
300 }
301
302 ResultVal<size_t> Read(std::span<u8> data) override {
303 if (handshake_state != HandshakeState::Connected) {
304 LOG_ERROR(Service_SSL, "Called Read but we did not successfully handshake");
305 return ResultInternalError;
306 }
307 if (data.size() == 0 || got_read_eof) {
308 return size_t(0);
309 }
310 while (1) {
311 if (!cleartext_read_buf.empty()) {
312 const size_t read_size = std::min(cleartext_read_buf.size(), data.size());
313 std::memcpy(data.data(), cleartext_read_buf.data(), read_size);
314 cleartext_read_buf.erase(cleartext_read_buf.begin(),
315 cleartext_read_buf.begin() + read_size);
316 return read_size;
317 }
318 if (!ciphertext_read_buf.empty()) {
319 SecBuffer empty{
320 .cbBuffer = 0,
321 .BufferType = SECBUFFER_EMPTY,
322 .pvBuffer = nullptr,
323 };
324 std::array<SecBuffer, 5> buffers{{
325 {
326 .cbBuffer = static_cast<unsigned long>(ciphertext_read_buf.size()),
327 .BufferType = SECBUFFER_DATA,
328 .pvBuffer = ciphertext_read_buf.data(),
329 },
330 empty,
331 empty,
332 empty,
333 }};
334 ASSERT_OR_EXECUTE_MSG(
335 buffers[0].cbBuffer == ciphertext_read_buf.size(),
336 { return ResultInternalError; }, "read buffer too large");
337 SecBufferDesc desc{
338 .ulVersion = SECBUFFER_VERSION,
339 .cBuffers = static_cast<unsigned long>(buffers.size()),
340 .pBuffers = buffers.data(),
341 };
342 SECURITY_STATUS ret =
343 DecryptMessage(&ctxt, &desc, /*MessageSeqNo*/ 0, /*pfQOP*/ nullptr);
344 switch (ret) {
345 case SEC_E_OK:
346 ASSERT_OR_EXECUTE(buffers[0].BufferType == SECBUFFER_STREAM_HEADER,
347 { return ResultInternalError; });
348 ASSERT_OR_EXECUTE(buffers[1].BufferType == SECBUFFER_DATA,
349 { return ResultInternalError; });
350 ASSERT_OR_EXECUTE(buffers[2].BufferType == SECBUFFER_STREAM_TRAILER,
351 { return ResultInternalError; });
352 cleartext_read_buf.assign(static_cast<u8*>(buffers[1].pvBuffer),
353 static_cast<u8*>(buffers[1].pvBuffer) +
354 buffers[1].cbBuffer);
355 if (buffers[3].BufferType == SECBUFFER_EXTRA) {
356 ASSERT(buffers[3].cbBuffer <= ciphertext_read_buf.size());
357 ciphertext_read_buf.erase(ciphertext_read_buf.begin(),
358 ciphertext_read_buf.end() - buffers[3].cbBuffer);
359 } else {
360 ASSERT(buffers[3].BufferType == SECBUFFER_EMPTY);
361 ciphertext_read_buf.clear();
362 }
363 continue;
364 case SEC_E_INCOMPLETE_MESSAGE:
365 break;
366 case SEC_I_CONTEXT_EXPIRED:
367 // Server hung up by sending close_notify.
368 got_read_eof = true;
369 return size_t(0);
370 default:
371 LOG_ERROR(Service_SSL, "DecryptMessage failed: {}",
372 Common::NativeErrorToString(ret));
373 return ResultInternalError;
374 }
375 }
376 const Result r = FillCiphertextReadBuf();
377 if (r != ResultSuccess) {
378 return r;
379 }
380 if (ciphertext_read_buf.empty()) {
381 got_read_eof = true;
382 return size_t(0);
383 }
384 }
385 }
386
387 ResultVal<size_t> Write(std::span<const u8> data) override {
388 if (handshake_state != HandshakeState::Connected) {
389 LOG_ERROR(Service_SSL, "Called Write but we did not successfully handshake");
390 return ResultInternalError;
391 }
392 if (data.size() == 0) {
393 return size_t(0);
394 }
395 data = data.subspan(0, std::min<size_t>(data.size(), stream_sizes.cbMaximumMessage));
396 if (!cleartext_write_buf.empty()) {
397 // Already in the middle of a write. It wouldn't make sense to not
398 // finish sending the entire buffer since TLS has
399 // header/MAC/padding/etc.
400 if (data.size() != cleartext_write_buf.size() ||
401 std::memcmp(data.data(), cleartext_write_buf.data(), data.size())) {
402 LOG_ERROR(Service_SSL, "Called Write but buffer does not match previous buffer");
403 return ResultInternalError;
404 }
405 return WriteAlreadyEncryptedData();
406 } else {
407 cleartext_write_buf.assign(data.begin(), data.end());
408 }
409
410 std::vector<u8> header_buf(stream_sizes.cbHeader, 0);
411 std::vector<u8> tmp_data_buf = cleartext_write_buf;
412 std::vector<u8> trailer_buf(stream_sizes.cbTrailer, 0);
413
414 std::array<SecBuffer, 3> buffers{{
415 {
416 .cbBuffer = stream_sizes.cbHeader,
417 .BufferType = SECBUFFER_STREAM_HEADER,
418 .pvBuffer = header_buf.data(),
419 },
420 {
421 .cbBuffer = static_cast<unsigned long>(tmp_data_buf.size()),
422 .BufferType = SECBUFFER_DATA,
423 .pvBuffer = tmp_data_buf.data(),
424 },
425 {
426 .cbBuffer = stream_sizes.cbTrailer,
427 .BufferType = SECBUFFER_STREAM_TRAILER,
428 .pvBuffer = trailer_buf.data(),
429 },
430 }};
431 ASSERT_OR_EXECUTE_MSG(
432 buffers[1].cbBuffer == tmp_data_buf.size(), { return ResultInternalError; },
433 "temp buffer too large");
434 SecBufferDesc desc{
435 .ulVersion = SECBUFFER_VERSION,
436 .cBuffers = static_cast<unsigned long>(buffers.size()),
437 .pBuffers = buffers.data(),
438 };
439
440 const SECURITY_STATUS ret = EncryptMessage(&ctxt, /*fQOP*/ 0, &desc, /*MessageSeqNo*/ 0);
441 if (ret != SEC_E_OK) {
442 LOG_ERROR(Service_SSL, "EncryptMessage failed: {}", Common::NativeErrorToString(ret));
443 return ResultInternalError;
444 }
445 ciphertext_write_buf.insert(ciphertext_write_buf.end(), header_buf.begin(),
446 header_buf.end());
447 ciphertext_write_buf.insert(ciphertext_write_buf.end(), tmp_data_buf.begin(),
448 tmp_data_buf.end());
449 ciphertext_write_buf.insert(ciphertext_write_buf.end(), trailer_buf.begin(),
450 trailer_buf.end());
451 return WriteAlreadyEncryptedData();
452 }
453
454 ResultVal<size_t> WriteAlreadyEncryptedData() {
455 const Result r = FlushCiphertextWriteBuf();
456 if (r != ResultSuccess) {
457 return r;
458 }
459 // write buf is empty
460 const size_t cleartext_bytes_written = cleartext_write_buf.size();
461 cleartext_write_buf.clear();
462 return cleartext_bytes_written;
463 }
464
465 ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
466 PCCERT_CONTEXT returned_cert = nullptr;
467 const SECURITY_STATUS ret =
468 QueryContextAttributes(&ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &returned_cert);
469 if (ret != SEC_E_OK) {
470 LOG_ERROR(Service_SSL,
471 "QueryContextAttributes(SECPKG_ATTR_REMOTE_CERT_CONTEXT) failed: {}",
472 Common::NativeErrorToString(ret));
473 return ResultInternalError;
474 }
475 PCCERT_CONTEXT some_cert = nullptr;
476 std::vector<std::vector<u8>> certs;
477 while ((some_cert = CertEnumCertificatesInStore(returned_cert->hCertStore, some_cert))) {
478 certs.emplace_back(static_cast<u8*>(some_cert->pbCertEncoded),
479 static_cast<u8*>(some_cert->pbCertEncoded) +
480 some_cert->cbCertEncoded);
481 }
482 std::reverse(certs.begin(),
483 certs.end()); // Windows returns certs in reverse order from what we want
484 CertFreeCertificateContext(returned_cert);
485 return certs;
486 }
487
488 ~SSLConnectionBackendSchannel() {
489 if (handshake_state != HandshakeState::Initial) {
490 DeleteSecurityContext(&ctxt);
491 }
492 }
493
494 enum class HandshakeState {
495 // Haven't called anything yet.
496 Initial,
497 // `SEC_I_CONTINUE_NEEDED` was returned by
498 // `InitializeSecurityContext`; must finish sending data (if any) in
499 // the write buffer, then read at least one byte before calling
500 // `InitializeSecurityContext` again.
501 ContinueNeeded,
502 // `SEC_E_INCOMPLETE_MESSAGE` was returned by
503 // `InitializeSecurityContext`; hopefully the write buffer is empty;
504 // must read at least one byte before calling
505 // `InitializeSecurityContext` again.
506 IncompleteMessage,
507 // `SEC_E_OK` was returned by `InitializeSecurityContext`; must
508 // finish sending data in the write buffer before having `DoHandshake`
509 // report success.
510 DoneAfterFlush,
511 // We finished the above and are now connected. At this point, writing
512 // and reading are separate 'state machines' represented by the
513 // nonemptiness of the ciphertext and cleartext read and write buffers.
514 Connected,
515 // Another error was returned and we shouldn't allow initialization
516 // to continue.
517 Error,
518 } handshake_state = HandshakeState::Initial;
519
520 CtxtHandle ctxt;
521 SecPkgContext_StreamSizes stream_sizes;
522
523 std::shared_ptr<Network::SocketBase> socket;
524 std::optional<std::string> hostname;
525
526 std::vector<u8> ciphertext_read_buf;
527 std::vector<u8> ciphertext_write_buf;
528 std::vector<u8> cleartext_read_buf;
529 std::vector<u8> cleartext_write_buf;
530
531 bool got_read_eof = false;
532 size_t read_buf_fill_size = 0;
533};
534
535ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
536 auto conn = std::make_unique<SSLConnectionBackendSchannel>();
537 const Result res = conn->Init();
538 if (res.IsFailure()) {
539 return res;
540 }
541 return conn;
542}
543
544} // namespace Service::SSL
diff --git a/src/core/hle/service/ssl/ssl_backend_securetransport.cpp b/src/core/hle/service/ssl/ssl_backend_securetransport.cpp
new file mode 100644
index 000000000..b3083cbad
--- /dev/null
+++ b/src/core/hle/service/ssl/ssl_backend_securetransport.cpp
@@ -0,0 +1,222 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <mutex>
5
6// SecureTransport has been deprecated in its entirety in favor of
7// Network.framework, but that does not allow layering TLS on top of an
8// arbitrary socket.
9#if defined(__GNUC__) || defined(__clang__)
10#pragma GCC diagnostic push
11#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
12#include <Security/SecureTransport.h>
13#pragma GCC diagnostic pop
14#endif
15
16#include "core/hle/service/ssl/ssl_backend.h"
17#include "core/internal_network/network.h"
18#include "core/internal_network/sockets.h"
19
20namespace {
21
22template <typename T>
23struct CFReleaser {
24 T ptr;
25
26 YUZU_NON_COPYABLE(CFReleaser);
27 constexpr CFReleaser() : ptr(nullptr) {}
28 constexpr CFReleaser(T ptr) : ptr(ptr) {}
29 constexpr operator T() {
30 return ptr;
31 }
32 ~CFReleaser() {
33 if (ptr) {
34 CFRelease(ptr);
35 }
36 }
37};
38
39std::string CFStringToString(CFStringRef cfstr) {
40 CFReleaser<CFDataRef> cfdata(
41 CFStringCreateExternalRepresentation(nullptr, cfstr, kCFStringEncodingUTF8, 0));
42 ASSERT_OR_EXECUTE(cfdata, { return "???"; });
43 return std::string(reinterpret_cast<const char*>(CFDataGetBytePtr(cfdata)),
44 CFDataGetLength(cfdata));
45}
46
47std::string OSStatusToString(OSStatus status) {
48 CFReleaser<CFStringRef> cfstr(SecCopyErrorMessageString(status, nullptr));
49 if (!cfstr) {
50 return "[unknown error]";
51 }
52 return CFStringToString(cfstr);
53}
54
55} // namespace
56
57namespace Service::SSL {
58
59class SSLConnectionBackendSecureTransport final : public SSLConnectionBackend {
60public:
61 Result Init() {
62 static std::once_flag once_flag;
63 std::call_once(once_flag, []() {
64 if (getenv("SSLKEYLOGFILE")) {
65 LOG_CRITICAL(Service_SSL, "SSLKEYLOGFILE was set but SecureTransport does not "
66 "support exporting keys; not logging keys!");
67 // Not fatal.
68 }
69 });
70
71 context.ptr = SSLCreateContext(nullptr, kSSLClientSide, kSSLStreamType);
72 if (!context) {
73 LOG_ERROR(Service_SSL, "SSLCreateContext failed");
74 return ResultInternalError;
75 }
76
77 OSStatus status;
78 if ((status = SSLSetIOFuncs(context, ReadCallback, WriteCallback)) ||
79 (status = SSLSetConnection(context, this))) {
80 LOG_ERROR(Service_SSL, "SSLContext initialization failed: {}",
81 OSStatusToString(status));
82 return ResultInternalError;
83 }
84
85 return ResultSuccess;
86 }
87
88 void SetSocket(std::shared_ptr<Network::SocketBase> in_socket) override {
89 socket = std::move(in_socket);
90 }
91
92 Result SetHostName(const std::string& hostname) override {
93 OSStatus status = SSLSetPeerDomainName(context, hostname.c_str(), hostname.size());
94 if (status) {
95 LOG_ERROR(Service_SSL, "SSLSetPeerDomainName failed: {}", OSStatusToString(status));
96 return ResultInternalError;
97 }
98 return ResultSuccess;
99 }
100
101 Result DoHandshake() override {
102 OSStatus status = SSLHandshake(context);
103 return HandleReturn("SSLHandshake", 0, status).Code();
104 }
105
106 ResultVal<size_t> Read(std::span<u8> data) override {
107 size_t actual;
108 OSStatus status = SSLRead(context, data.data(), data.size(), &actual);
109 ;
110 return HandleReturn("SSLRead", actual, status);
111 }
112
113 ResultVal<size_t> Write(std::span<const u8> data) override {
114 size_t actual;
115 OSStatus status = SSLWrite(context, data.data(), data.size(), &actual);
116 ;
117 return HandleReturn("SSLWrite", actual, status);
118 }
119
120 ResultVal<size_t> HandleReturn(const char* what, size_t actual, OSStatus status) {
121 switch (status) {
122 case 0:
123 return actual;
124 case errSSLWouldBlock:
125 return ResultWouldBlock;
126 default: {
127 std::string reason;
128 if (got_read_eof) {
129 reason = "server hung up";
130 } else {
131 reason = OSStatusToString(status);
132 }
133 LOG_ERROR(Service_SSL, "{} failed: {}", what, reason);
134 return ResultInternalError;
135 }
136 }
137 }
138
139 ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
140 CFReleaser<SecTrustRef> trust;
141 OSStatus status = SSLCopyPeerTrust(context, &trust.ptr);
142 if (status) {
143 LOG_ERROR(Service_SSL, "SSLCopyPeerTrust failed: {}", OSStatusToString(status));
144 return ResultInternalError;
145 }
146 std::vector<std::vector<u8>> ret;
147 for (CFIndex i = 0, count = SecTrustGetCertificateCount(trust); i < count; i++) {
148 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
149 CFReleaser<CFDataRef> data(SecCertificateCopyData(cert));
150 ASSERT_OR_EXECUTE(data, { return ResultInternalError; });
151 const u8* ptr = CFDataGetBytePtr(data);
152 ret.emplace_back(ptr, ptr + CFDataGetLength(data));
153 }
154 return ret;
155 }
156
157 static OSStatus ReadCallback(SSLConnectionRef connection, void* data, size_t* dataLength) {
158 return ReadOrWriteCallback(connection, data, dataLength, true);
159 }
160
161 static OSStatus WriteCallback(SSLConnectionRef connection, const void* data,
162 size_t* dataLength) {
163 return ReadOrWriteCallback(connection, const_cast<void*>(data), dataLength, false);
164 }
165
166 static OSStatus ReadOrWriteCallback(SSLConnectionRef connection, void* data, size_t* dataLength,
167 bool is_read) {
168 auto self =
169 static_cast<SSLConnectionBackendSecureTransport*>(const_cast<void*>(connection));
170 ASSERT_OR_EXECUTE_MSG(
171 self->socket, { return 0; }, "SecureTransport asked to {} but we have no socket",
172 is_read ? "read" : "write");
173
174 // SecureTransport callbacks (unlike OpenSSL BIO callbacks) are
175 // expected to read/write the full requested dataLength or return an
176 // error, so we have to add a loop ourselves.
177 size_t requested_len = *dataLength;
178 size_t offset = 0;
179 while (offset < requested_len) {
180 std::span cur(reinterpret_cast<u8*>(data) + offset, requested_len - offset);
181 auto [actual, err] = is_read ? self->socket->Recv(0, cur) : self->socket->Send(cur, 0);
182 LOG_CRITICAL(Service_SSL, "op={}, offset={} actual={}/{} err={}", is_read, offset,
183 actual, cur.size(), static_cast<s32>(err));
184 switch (err) {
185 case Network::Errno::SUCCESS:
186 offset += actual;
187 if (actual == 0) {
188 ASSERT(is_read);
189 self->got_read_eof = true;
190 return errSecEndOfData;
191 }
192 break;
193 case Network::Errno::AGAIN:
194 *dataLength = offset;
195 return errSSLWouldBlock;
196 default:
197 LOG_ERROR(Service_SSL, "Socket {} returned Network::Errno {}",
198 is_read ? "recv" : "send", err);
199 return errSecIO;
200 }
201 }
202 ASSERT(offset == requested_len);
203 return 0;
204 }
205
206private:
207 CFReleaser<SSLContextRef> context = nullptr;
208 bool got_read_eof = false;
209
210 std::shared_ptr<Network::SocketBase> socket;
211};
212
213ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
214 auto conn = std::make_unique<SSLConnectionBackendSecureTransport>();
215 const Result res = conn->Init();
216 if (res.IsFailure()) {
217 return res;
218 }
219 return conn;
220}
221
222} // namespace Service::SSL
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index 75ac10a9c..28f89c599 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -27,6 +27,7 @@
27 27
28#include "common/assert.h" 28#include "common/assert.h"
29#include "common/common_types.h" 29#include "common/common_types.h"
30#include "common/expected.h"
30#include "common/logging/log.h" 31#include "common/logging/log.h"
31#include "common/settings.h" 32#include "common/settings.h"
32#include "core/internal_network/network.h" 33#include "core/internal_network/network.h"
@@ -97,6 +98,8 @@ bool EnableNonBlock(SOCKET fd, bool enable) {
97 98
98Errno TranslateNativeError(int e) { 99Errno TranslateNativeError(int e) {
99 switch (e) { 100 switch (e) {
101 case 0:
102 return Errno::SUCCESS;
100 case WSAEBADF: 103 case WSAEBADF:
101 return Errno::BADF; 104 return Errno::BADF;
102 case WSAEINVAL: 105 case WSAEINVAL:
@@ -121,6 +124,8 @@ Errno TranslateNativeError(int e) {
121 return Errno::MSGSIZE; 124 return Errno::MSGSIZE;
122 case WSAETIMEDOUT: 125 case WSAETIMEDOUT:
123 return Errno::TIMEDOUT; 126 return Errno::TIMEDOUT;
127 case WSAEINPROGRESS:
128 return Errno::INPROGRESS;
124 default: 129 default:
125 UNIMPLEMENTED_MSG("Unimplemented errno={}", e); 130 UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
126 return Errno::OTHER; 131 return Errno::OTHER;
@@ -195,6 +200,8 @@ bool EnableNonBlock(int fd, bool enable) {
195 200
196Errno TranslateNativeError(int e) { 201Errno TranslateNativeError(int e) {
197 switch (e) { 202 switch (e) {
203 case 0:
204 return Errno::SUCCESS;
198 case EBADF: 205 case EBADF:
199 return Errno::BADF; 206 return Errno::BADF;
200 case EINVAL: 207 case EINVAL:
@@ -219,8 +226,10 @@ Errno TranslateNativeError(int e) {
219 return Errno::MSGSIZE; 226 return Errno::MSGSIZE;
220 case ETIMEDOUT: 227 case ETIMEDOUT:
221 return Errno::TIMEDOUT; 228 return Errno::TIMEDOUT;
229 case EINPROGRESS:
230 return Errno::INPROGRESS;
222 default: 231 default:
223 UNIMPLEMENTED_MSG("Unimplemented errno={}", e); 232 UNIMPLEMENTED_MSG("Unimplemented errno={} ({})", e, strerror(e));
224 return Errno::OTHER; 233 return Errno::OTHER;
225 } 234 }
226} 235}
@@ -234,15 +243,84 @@ Errno GetAndLogLastError() {
234 int e = errno; 243 int e = errno;
235#endif 244#endif
236 const Errno err = TranslateNativeError(e); 245 const Errno err = TranslateNativeError(e);
237 if (err == Errno::AGAIN || err == Errno::TIMEDOUT) { 246 if (err == Errno::AGAIN || err == Errno::TIMEDOUT || err == Errno::INPROGRESS) {
247 // These happen during normal operation, so only log them at debug level.
248 LOG_DEBUG(Network, "Socket operation error: {}", Common::NativeErrorToString(e));
238 return err; 249 return err;
239 } 250 }
240 LOG_ERROR(Network, "Socket operation error: {}", Common::NativeErrorToString(e)); 251 LOG_ERROR(Network, "Socket operation error: {}", Common::NativeErrorToString(e));
241 return err; 252 return err;
242} 253}
243 254
244int TranslateDomain(Domain domain) { 255GetAddrInfoError TranslateGetAddrInfoErrorFromNative(int gai_err) {
256 switch (gai_err) {
257 case 0:
258 return GetAddrInfoError::SUCCESS;
259#ifdef EAI_ADDRFAMILY
260 case EAI_ADDRFAMILY:
261 return GetAddrInfoError::ADDRFAMILY;
262#endif
263 case EAI_AGAIN:
264 return GetAddrInfoError::AGAIN;
265 case EAI_BADFLAGS:
266 return GetAddrInfoError::BADFLAGS;
267 case EAI_FAIL:
268 return GetAddrInfoError::FAIL;
269 case EAI_FAMILY:
270 return GetAddrInfoError::FAMILY;
271 case EAI_MEMORY:
272 return GetAddrInfoError::MEMORY;
273 case EAI_NONAME:
274 return GetAddrInfoError::NONAME;
275 case EAI_SERVICE:
276 return GetAddrInfoError::SERVICE;
277 case EAI_SOCKTYPE:
278 return GetAddrInfoError::SOCKTYPE;
279 // These codes may not be defined on all systems:
280#ifdef EAI_SYSTEM
281 case EAI_SYSTEM:
282 return GetAddrInfoError::SYSTEM;
283#endif
284#ifdef EAI_BADHINTS
285 case EAI_BADHINTS:
286 return GetAddrInfoError::BADHINTS;
287#endif
288#ifdef EAI_PROTOCOL
289 case EAI_PROTOCOL:
290 return GetAddrInfoError::PROTOCOL;
291#endif
292#ifdef EAI_OVERFLOW
293 case EAI_OVERFLOW:
294 return GetAddrInfoError::OVERFLOW_;
295#endif
296 default:
297#ifdef EAI_NODATA
298 // This can't be a case statement because it would create a duplicate
299 // case on Windows where EAI_NODATA is an alias for EAI_NONAME.
300 if (gai_err == EAI_NODATA) {
301 return GetAddrInfoError::NODATA;
302 }
303#endif
304 return GetAddrInfoError::OTHER;
305 }
306}
307
308Domain TranslateDomainFromNative(int domain) {
309 switch (domain) {
310 case 0:
311 return Domain::Unspecified;
312 case AF_INET:
313 return Domain::INET;
314 default:
315 UNIMPLEMENTED_MSG("Unhandled domain={}", domain);
316 return Domain::INET;
317 }
318}
319
320int TranslateDomainToNative(Domain domain) {
245 switch (domain) { 321 switch (domain) {
322 case Domain::Unspecified:
323 return 0;
246 case Domain::INET: 324 case Domain::INET:
247 return AF_INET; 325 return AF_INET;
248 default: 326 default:
@@ -251,20 +329,58 @@ int TranslateDomain(Domain domain) {
251 } 329 }
252} 330}
253 331
254int TranslateType(Type type) { 332Type TranslateTypeFromNative(int type) {
333 switch (type) {
334 case 0:
335 return Type::Unspecified;
336 case SOCK_STREAM:
337 return Type::STREAM;
338 case SOCK_DGRAM:
339 return Type::DGRAM;
340 case SOCK_RAW:
341 return Type::RAW;
342 case SOCK_SEQPACKET:
343 return Type::SEQPACKET;
344 default:
345 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
346 return Type::STREAM;
347 }
348}
349
350int TranslateTypeToNative(Type type) {
255 switch (type) { 351 switch (type) {
352 case Type::Unspecified:
353 return 0;
256 case Type::STREAM: 354 case Type::STREAM:
257 return SOCK_STREAM; 355 return SOCK_STREAM;
258 case Type::DGRAM: 356 case Type::DGRAM:
259 return SOCK_DGRAM; 357 return SOCK_DGRAM;
358 case Type::RAW:
359 return SOCK_RAW;
260 default: 360 default:
261 UNIMPLEMENTED_MSG("Unimplemented type={}", type); 361 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
262 return 0; 362 return 0;
263 } 363 }
264} 364}
265 365
266int TranslateProtocol(Protocol protocol) { 366Protocol TranslateProtocolFromNative(int protocol) {
367 switch (protocol) {
368 case 0:
369 return Protocol::Unspecified;
370 case IPPROTO_TCP:
371 return Protocol::TCP;
372 case IPPROTO_UDP:
373 return Protocol::UDP;
374 default:
375 UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
376 return Protocol::Unspecified;
377 }
378}
379
380int TranslateProtocolToNative(Protocol protocol) {
267 switch (protocol) { 381 switch (protocol) {
382 case Protocol::Unspecified:
383 return 0;
268 case Protocol::TCP: 384 case Protocol::TCP:
269 return IPPROTO_TCP; 385 return IPPROTO_TCP;
270 case Protocol::UDP: 386 case Protocol::UDP:
@@ -275,21 +391,10 @@ int TranslateProtocol(Protocol protocol) {
275 } 391 }
276} 392}
277 393
278SockAddrIn TranslateToSockAddrIn(sockaddr input_) { 394SockAddrIn TranslateToSockAddrIn(sockaddr_in input, size_t input_len) {
279 sockaddr_in input;
280 std::memcpy(&input, &input_, sizeof(input));
281
282 SockAddrIn result; 395 SockAddrIn result;
283 396
284 switch (input.sin_family) { 397 result.family = TranslateDomainFromNative(input.sin_family);
285 case AF_INET:
286 result.family = Domain::INET;
287 break;
288 default:
289 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.sin_family);
290 result.family = Domain::INET;
291 break;
292 }
293 398
294 result.portno = ntohs(input.sin_port); 399 result.portno = ntohs(input.sin_port);
295 400
@@ -301,22 +406,33 @@ SockAddrIn TranslateToSockAddrIn(sockaddr input_) {
301short TranslatePollEvents(PollEvents events) { 406short TranslatePollEvents(PollEvents events) {
302 short result = 0; 407 short result = 0;
303 408
304 if (True(events & PollEvents::In)) { 409 const auto translate = [&result, &events](PollEvents guest, short host) {
305 events &= ~PollEvents::In; 410 if (True(events & guest)) {
306 result |= POLLIN; 411 events &= ~guest;
307 } 412 result |= host;
308 if (True(events & PollEvents::Pri)) { 413 }
309 events &= ~PollEvents::Pri; 414 };
415
416 translate(PollEvents::In, POLLIN);
417 translate(PollEvents::Pri, POLLPRI);
418 translate(PollEvents::Out, POLLOUT);
419 translate(PollEvents::Err, POLLERR);
420 translate(PollEvents::Hup, POLLHUP);
421 translate(PollEvents::Nval, POLLNVAL);
422 translate(PollEvents::RdNorm, POLLRDNORM);
423 translate(PollEvents::RdBand, POLLRDBAND);
424 translate(PollEvents::WrBand, POLLWRBAND);
425
310#ifdef _WIN32 426#ifdef _WIN32
311 LOG_WARNING(Service, "Winsock doesn't support POLLPRI"); 427 short allowed_events = POLLRDBAND | POLLRDNORM | POLLWRNORM;
312#else 428 // Unlike poll on other OSes, WSAPoll will complain if any other flags are set on input.
313 result |= POLLPRI; 429 if (result & ~allowed_events) {
430 LOG_DEBUG(Network,
431 "Removing WSAPoll input events 0x{:x} because Windows doesn't support them",
432 result & ~allowed_events);
433 }
434 result &= allowed_events;
314#endif 435#endif
315 }
316 if (True(events & PollEvents::Out)) {
317 events &= ~PollEvents::Out;
318 result |= POLLOUT;
319 }
320 436
321 UNIMPLEMENTED_IF_MSG((u16)events != 0, "Unhandled guest events=0x{:x}", (u16)events); 437 UNIMPLEMENTED_IF_MSG((u16)events != 0, "Unhandled guest events=0x{:x}", (u16)events);
322 438
@@ -337,6 +453,10 @@ PollEvents TranslatePollRevents(short revents) {
337 translate(POLLOUT, PollEvents::Out); 453 translate(POLLOUT, PollEvents::Out);
338 translate(POLLERR, PollEvents::Err); 454 translate(POLLERR, PollEvents::Err);
339 translate(POLLHUP, PollEvents::Hup); 455 translate(POLLHUP, PollEvents::Hup);
456 translate(POLLNVAL, PollEvents::Nval);
457 translate(POLLRDNORM, PollEvents::RdNorm);
458 translate(POLLRDBAND, PollEvents::RdBand);
459 translate(POLLWRBAND, PollEvents::WrBand);
340 460
341 UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents); 461 UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents);
342 462
@@ -360,12 +480,51 @@ std::optional<IPv4Address> GetHostIPv4Address() {
360 return {}; 480 return {};
361 } 481 }
362 482
363 std::array<char, 16> ip_addr = {};
364 ASSERT(inet_ntop(AF_INET, &network_interface->ip_address, ip_addr.data(), sizeof(ip_addr)) !=
365 nullptr);
366 return TranslateIPv4(network_interface->ip_address); 483 return TranslateIPv4(network_interface->ip_address);
367} 484}
368 485
486std::string IPv4AddressToString(IPv4Address ip_addr) {
487 std::array<char, INET_ADDRSTRLEN> buf = {};
488 ASSERT(inet_ntop(AF_INET, &ip_addr, buf.data(), sizeof(buf)) == buf.data());
489 return std::string(buf.data());
490}
491
492u32 IPv4AddressToInteger(IPv4Address ip_addr) {
493 return static_cast<u32>(ip_addr[0]) << 24 | static_cast<u32>(ip_addr[1]) << 16 |
494 static_cast<u32>(ip_addr[2]) << 8 | static_cast<u32>(ip_addr[3]);
495}
496
497Common::Expected<std::vector<AddrInfo>, GetAddrInfoError> GetAddressInfo(
498 const std::string& host, const std::optional<std::string>& service) {
499 addrinfo hints{};
500 hints.ai_family = AF_INET; // Switch only supports IPv4.
501 addrinfo* addrinfo;
502 s32 gai_err = getaddrinfo(host.c_str(), service.has_value() ? service->c_str() : nullptr,
503 &hints, &addrinfo);
504 if (gai_err != 0) {
505 return Common::Unexpected(TranslateGetAddrInfoErrorFromNative(gai_err));
506 }
507 std::vector<AddrInfo> ret;
508 for (auto* current = addrinfo; current; current = current->ai_next) {
509 // We should only get AF_INET results due to the hints value.
510 ASSERT_OR_EXECUTE(addrinfo->ai_family == AF_INET &&
511 addrinfo->ai_addrlen == sizeof(sockaddr_in),
512 continue;);
513
514 AddrInfo& out = ret.emplace_back();
515 out.family = TranslateDomainFromNative(current->ai_family);
516 out.socket_type = TranslateTypeFromNative(current->ai_socktype);
517 out.protocol = TranslateProtocolFromNative(current->ai_protocol);
518 out.addr = TranslateToSockAddrIn(*reinterpret_cast<sockaddr_in*>(current->ai_addr),
519 current->ai_addrlen);
520 if (current->ai_canonname != nullptr) {
521 out.canon_name = current->ai_canonname;
522 }
523 }
524 freeaddrinfo(addrinfo);
525 return ret;
526}
527
369std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { 528std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
370 const size_t num = pollfds.size(); 529 const size_t num = pollfds.size();
371 530
@@ -411,9 +570,21 @@ Socket::Socket(Socket&& rhs) noexcept {
411} 570}
412 571
413template <typename T> 572template <typename T>
414Errno Socket::SetSockOpt(SOCKET fd_, int option, T value) { 573std::pair<T, Errno> Socket::GetSockOpt(SOCKET fd_so, int option) {
574 T value{};
575 socklen_t len = sizeof(value);
576 const int result = getsockopt(fd_so, SOL_SOCKET, option, reinterpret_cast<char*>(&value), &len);
577 if (result != SOCKET_ERROR) {
578 ASSERT(len == sizeof(value));
579 return {value, Errno::SUCCESS};
580 }
581 return {value, GetAndLogLastError()};
582}
583
584template <typename T>
585Errno Socket::SetSockOpt(SOCKET fd_so, int option, T value) {
415 const int result = 586 const int result =
416 setsockopt(fd_, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value)); 587 setsockopt(fd_so, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
417 if (result != SOCKET_ERROR) { 588 if (result != SOCKET_ERROR) {
418 return Errno::SUCCESS; 589 return Errno::SUCCESS;
419 } 590 }
@@ -421,7 +592,8 @@ Errno Socket::SetSockOpt(SOCKET fd_, int option, T value) {
421} 592}
422 593
423Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { 594Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
424 fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol)); 595 fd = socket(TranslateDomainToNative(domain), TranslateTypeToNative(type),
596 TranslateProtocolToNative(protocol));
425 if (fd != INVALID_SOCKET) { 597 if (fd != INVALID_SOCKET) {
426 return Errno::SUCCESS; 598 return Errno::SUCCESS;
427 } 599 }
@@ -430,19 +602,17 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
430} 602}
431 603
432std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() { 604std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
433 sockaddr addr; 605 sockaddr_in addr;
434 socklen_t addrlen = sizeof(addr); 606 socklen_t addrlen = sizeof(addr);
435 const SOCKET new_socket = accept(fd, &addr, &addrlen); 607 const SOCKET new_socket = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen);
436 608
437 if (new_socket == INVALID_SOCKET) { 609 if (new_socket == INVALID_SOCKET) {
438 return {AcceptResult{}, GetAndLogLastError()}; 610 return {AcceptResult{}, GetAndLogLastError()};
439 } 611 }
440 612
441 ASSERT(addrlen == sizeof(sockaddr_in));
442
443 AcceptResult result{ 613 AcceptResult result{
444 .socket = std::make_unique<Socket>(new_socket), 614 .socket = std::make_unique<Socket>(new_socket),
445 .sockaddr_in = TranslateToSockAddrIn(addr), 615 .sockaddr_in = TranslateToSockAddrIn(addr, addrlen),
446 }; 616 };
447 617
448 return {std::move(result), Errno::SUCCESS}; 618 return {std::move(result), Errno::SUCCESS};
@@ -458,25 +628,23 @@ Errno Socket::Connect(SockAddrIn addr_in) {
458} 628}
459 629
460std::pair<SockAddrIn, Errno> Socket::GetPeerName() { 630std::pair<SockAddrIn, Errno> Socket::GetPeerName() {
461 sockaddr addr; 631 sockaddr_in addr;
462 socklen_t addrlen = sizeof(addr); 632 socklen_t addrlen = sizeof(addr);
463 if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) { 633 if (getpeername(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen) == SOCKET_ERROR) {
464 return {SockAddrIn{}, GetAndLogLastError()}; 634 return {SockAddrIn{}, GetAndLogLastError()};
465 } 635 }
466 636
467 ASSERT(addrlen == sizeof(sockaddr_in)); 637 return {TranslateToSockAddrIn(addr, addrlen), Errno::SUCCESS};
468 return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
469} 638}
470 639
471std::pair<SockAddrIn, Errno> Socket::GetSockName() { 640std::pair<SockAddrIn, Errno> Socket::GetSockName() {
472 sockaddr addr; 641 sockaddr_in addr;
473 socklen_t addrlen = sizeof(addr); 642 socklen_t addrlen = sizeof(addr);
474 if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) { 643 if (getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen) == SOCKET_ERROR) {
475 return {SockAddrIn{}, GetAndLogLastError()}; 644 return {SockAddrIn{}, GetAndLogLastError()};
476 } 645 }
477 646
478 ASSERT(addrlen == sizeof(sockaddr_in)); 647 return {TranslateToSockAddrIn(addr, addrlen), Errno::SUCCESS};
479 return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
480} 648}
481 649
482Errno Socket::Bind(SockAddrIn addr) { 650Errno Socket::Bind(SockAddrIn addr) {
@@ -519,7 +687,7 @@ Errno Socket::Shutdown(ShutdownHow how) {
519 return GetAndLogLastError(); 687 return GetAndLogLastError();
520} 688}
521 689
522std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { 690std::pair<s32, Errno> Socket::Recv(int flags, std::span<u8> message) {
523 ASSERT(flags == 0); 691 ASSERT(flags == 0);
524 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 692 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
525 693
@@ -532,21 +700,20 @@ std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
532 return {-1, GetAndLogLastError()}; 700 return {-1, GetAndLogLastError()};
533} 701}
534 702
535std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { 703std::pair<s32, Errno> Socket::RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) {
536 ASSERT(flags == 0); 704 ASSERT(flags == 0);
537 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 705 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
538 706
539 sockaddr addr_in{}; 707 sockaddr_in addr_in{};
540 socklen_t addrlen = sizeof(addr_in); 708 socklen_t addrlen = sizeof(addr_in);
541 socklen_t* const p_addrlen = addr ? &addrlen : nullptr; 709 socklen_t* const p_addrlen = addr ? &addrlen : nullptr;
542 sockaddr* const p_addr_in = addr ? &addr_in : nullptr; 710 sockaddr* const p_addr_in = addr ? reinterpret_cast<sockaddr*>(&addr_in) : nullptr;
543 711
544 const auto result = recvfrom(fd, reinterpret_cast<char*>(message.data()), 712 const auto result = recvfrom(fd, reinterpret_cast<char*>(message.data()),
545 static_cast<int>(message.size()), 0, p_addr_in, p_addrlen); 713 static_cast<int>(message.size()), 0, p_addr_in, p_addrlen);
546 if (result != SOCKET_ERROR) { 714 if (result != SOCKET_ERROR) {
547 if (addr) { 715 if (addr) {
548 ASSERT(addrlen == sizeof(addr_in)); 716 *addr = TranslateToSockAddrIn(addr_in, addrlen);
549 *addr = TranslateToSockAddrIn(addr_in);
550 } 717 }
551 return {static_cast<s32>(result), Errno::SUCCESS}; 718 return {static_cast<s32>(result), Errno::SUCCESS};
552 } 719 }
@@ -597,6 +764,11 @@ Errno Socket::Close() {
597 return Errno::SUCCESS; 764 return Errno::SUCCESS;
598} 765}
599 766
767std::pair<Errno, Errno> Socket::GetPendingError() {
768 auto [pending_err, getsockopt_err] = GetSockOpt<int>(fd, SO_ERROR);
769 return {TranslateNativeError(pending_err), getsockopt_err};
770}
771
600Errno Socket::SetLinger(bool enable, u32 linger) { 772Errno Socket::SetLinger(bool enable, u32 linger) {
601 return SetSockOpt(fd, SO_LINGER, MakeLinger(enable, linger)); 773 return SetSockOpt(fd, SO_LINGER, MakeLinger(enable, linger));
602} 774}
diff --git a/src/core/internal_network/network.h b/src/core/internal_network/network.h
index 1e09a007a..badcb8369 100644
--- a/src/core/internal_network/network.h
+++ b/src/core/internal_network/network.h
@@ -5,6 +5,7 @@
5 5
6#include <array> 6#include <array>
7#include <optional> 7#include <optional>
8#include <vector>
8 9
9#include "common/common_funcs.h" 10#include "common/common_funcs.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
@@ -16,6 +17,11 @@
16#include <netinet/in.h> 17#include <netinet/in.h>
17#endif 18#endif
18 19
20namespace Common {
21template <typename T, typename E>
22class Expected;
23}
24
19namespace Network { 25namespace Network {
20 26
21class SocketBase; 27class SocketBase;
@@ -36,6 +42,26 @@ enum class Errno {
36 NETUNREACH, 42 NETUNREACH,
37 TIMEDOUT, 43 TIMEDOUT,
38 MSGSIZE, 44 MSGSIZE,
45 INPROGRESS,
46 OTHER,
47};
48
49enum class GetAddrInfoError {
50 SUCCESS,
51 ADDRFAMILY,
52 AGAIN,
53 BADFLAGS,
54 FAIL,
55 FAMILY,
56 MEMORY,
57 NODATA,
58 NONAME,
59 SERVICE,
60 SOCKTYPE,
61 SYSTEM,
62 BADHINTS,
63 PROTOCOL,
64 OVERFLOW_,
39 OTHER, 65 OTHER,
40}; 66};
41 67
@@ -49,6 +75,9 @@ enum class PollEvents : u16 {
49 Err = 1 << 3, 75 Err = 1 << 3,
50 Hup = 1 << 4, 76 Hup = 1 << 4,
51 Nval = 1 << 5, 77 Nval = 1 << 5,
78 RdNorm = 1 << 6,
79 RdBand = 1 << 7,
80 WrBand = 1 << 8,
52}; 81};
53 82
54DECLARE_ENUM_FLAG_OPERATORS(PollEvents); 83DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
@@ -82,4 +111,11 @@ constexpr IPv4Address TranslateIPv4(in_addr addr) {
82/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array 111/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array
83std::optional<IPv4Address> GetHostIPv4Address(); 112std::optional<IPv4Address> GetHostIPv4Address();
84 113
114std::string IPv4AddressToString(IPv4Address ip_addr);
115u32 IPv4AddressToInteger(IPv4Address ip_addr);
116
117// named to avoid name collision with Windows macro
118Common::Expected<std::vector<AddrInfo>, GetAddrInfoError> GetAddressInfo(
119 const std::string& host, const std::optional<std::string>& service);
120
85} // namespace Network 121} // namespace Network
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
index 7a77171c2..ce0dee970 100644
--- a/src/core/internal_network/socket_proxy.cpp
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -10,6 +10,7 @@
10#include "core/internal_network/network.h" 10#include "core/internal_network/network.h"
11#include "core/internal_network/network_interface.h" 11#include "core/internal_network/network_interface.h"
12#include "core/internal_network/socket_proxy.h" 12#include "core/internal_network/socket_proxy.h"
13#include "network/network.h"
13 14
14#if YUZU_UNIX 15#if YUZU_UNIX
15#include <sys/socket.h> 16#include <sys/socket.h>
@@ -98,7 +99,7 @@ Errno ProxySocket::Shutdown(ShutdownHow how) {
98 return Errno::SUCCESS; 99 return Errno::SUCCESS;
99} 100}
100 101
101std::pair<s32, Errno> ProxySocket::Recv(int flags, std::vector<u8>& message) { 102std::pair<s32, Errno> ProxySocket::Recv(int flags, std::span<u8> message) {
102 LOG_WARNING(Network, "(STUBBED) called"); 103 LOG_WARNING(Network, "(STUBBED) called");
103 ASSERT(flags == 0); 104 ASSERT(flags == 0);
104 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 105 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
@@ -106,7 +107,7 @@ std::pair<s32, Errno> ProxySocket::Recv(int flags, std::vector<u8>& message) {
106 return {static_cast<s32>(0), Errno::SUCCESS}; 107 return {static_cast<s32>(0), Errno::SUCCESS};
107} 108}
108 109
109std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { 110std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) {
110 ASSERT(flags == 0); 111 ASSERT(flags == 0);
111 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 112 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
112 113
@@ -140,8 +141,8 @@ std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::vector<u8>& message,
140 } 141 }
141} 142}
142 143
143std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& message, 144std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> message, SockAddrIn* addr,
144 SockAddrIn* addr, std::size_t max_length) { 145 std::size_t max_length) {
145 ProxyPacket& packet = received_packets.front(); 146 ProxyPacket& packet = received_packets.front();
146 if (addr) { 147 if (addr) {
147 addr->family = Domain::INET; 148 addr->family = Domain::INET;
@@ -153,10 +154,7 @@ std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& mes
153 std::size_t read_bytes; 154 std::size_t read_bytes;
154 if (packet.data.size() > max_length) { 155 if (packet.data.size() > max_length) {
155 read_bytes = max_length; 156 read_bytes = max_length;
156 message.clear(); 157 memcpy(message.data(), packet.data.data(), max_length);
157 std::copy(packet.data.begin(), packet.data.begin() + read_bytes,
158 std::back_inserter(message));
159 message.resize(max_length);
160 158
161 if (protocol == Protocol::UDP) { 159 if (protocol == Protocol::UDP) {
162 if (!peek) { 160 if (!peek) {
@@ -171,9 +169,7 @@ std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& mes
171 } 169 }
172 } else { 170 } else {
173 read_bytes = packet.data.size(); 171 read_bytes = packet.data.size();
174 message.clear(); 172 memcpy(message.data(), packet.data.data(), read_bytes);
175 std::copy(packet.data.begin(), packet.data.end(), std::back_inserter(message));
176 message.resize(max_length);
177 if (!peek) { 173 if (!peek) {
178 received_packets.pop(); 174 received_packets.pop();
179 } 175 }
@@ -293,6 +289,11 @@ Errno ProxySocket::SetNonBlock(bool enable) {
293 return Errno::SUCCESS; 289 return Errno::SUCCESS;
294} 290}
295 291
292std::pair<Errno, Errno> ProxySocket::GetPendingError() {
293 LOG_DEBUG(Network, "(STUBBED) called");
294 return {Errno::SUCCESS, Errno::SUCCESS};
295}
296
296bool ProxySocket::IsOpened() const { 297bool ProxySocket::IsOpened() const {
297 return fd != INVALID_SOCKET; 298 return fd != INVALID_SOCKET;
298} 299}
diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h
index 6e991fa38..70500cf4a 100644
--- a/src/core/internal_network/socket_proxy.h
+++ b/src/core/internal_network/socket_proxy.h
@@ -10,10 +10,12 @@
10 10
11#include "common/common_funcs.h" 11#include "common/common_funcs.h"
12#include "core/internal_network/sockets.h" 12#include "core/internal_network/sockets.h"
13#include "network/network.h" 13#include "network/room_member.h"
14 14
15namespace Network { 15namespace Network {
16 16
17class RoomNetwork;
18
17class ProxySocket : public SocketBase { 19class ProxySocket : public SocketBase {
18public: 20public:
19 explicit ProxySocket(RoomNetwork& room_network_) noexcept; 21 explicit ProxySocket(RoomNetwork& room_network_) noexcept;
@@ -39,11 +41,11 @@ public:
39 41
40 Errno Shutdown(ShutdownHow how) override; 42 Errno Shutdown(ShutdownHow how) override;
41 43
42 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) override; 44 std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
43 45
44 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override; 46 std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) override;
45 47
46 std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr, 48 std::pair<s32, Errno> ReceivePacket(int flags, std::span<u8> message, SockAddrIn* addr,
47 std::size_t max_length); 49 std::size_t max_length);
48 50
49 std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override; 51 std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
@@ -74,6 +76,8 @@ public:
74 template <typename T> 76 template <typename T>
75 Errno SetSockOpt(SOCKET fd, int option, T value); 77 Errno SetSockOpt(SOCKET fd, int option, T value);
76 78
79 std::pair<Errno, Errno> GetPendingError() override;
80
77 bool IsOpened() const override; 81 bool IsOpened() const override;
78 82
79private: 83private:
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index 11e479e50..4ba51f62c 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -15,12 +15,13 @@
15 15
16#include "common/common_types.h" 16#include "common/common_types.h"
17#include "core/internal_network/network.h" 17#include "core/internal_network/network.h"
18#include "network/network.h"
19 18
20// TODO: C++20 Replace std::vector usages with std::span 19// TODO: C++20 Replace std::vector usages with std::span
21 20
22namespace Network { 21namespace Network {
23 22
23struct ProxyPacket;
24
24class SocketBase { 25class SocketBase {
25public: 26public:
26#ifdef YUZU_UNIX 27#ifdef YUZU_UNIX
@@ -59,10 +60,9 @@ public:
59 60
60 virtual Errno Shutdown(ShutdownHow how) = 0; 61 virtual Errno Shutdown(ShutdownHow how) = 0;
61 62
62 virtual std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) = 0; 63 virtual std::pair<s32, Errno> Recv(int flags, std::span<u8> message) = 0;
63 64
64 virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, 65 virtual std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) = 0;
65 SockAddrIn* addr) = 0;
66 66
67 virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0; 67 virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0;
68 68
@@ -87,6 +87,8 @@ public:
87 87
88 virtual Errno SetNonBlock(bool enable) = 0; 88 virtual Errno SetNonBlock(bool enable) = 0;
89 89
90 virtual std::pair<Errno, Errno> GetPendingError() = 0;
91
90 virtual bool IsOpened() const = 0; 92 virtual bool IsOpened() const = 0;
91 93
92 virtual void HandleProxyPacket(const ProxyPacket& packet) = 0; 94 virtual void HandleProxyPacket(const ProxyPacket& packet) = 0;
@@ -126,9 +128,9 @@ public:
126 128
127 Errno Shutdown(ShutdownHow how) override; 129 Errno Shutdown(ShutdownHow how) override;
128 130
129 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) override; 131 std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
130 132
131 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override; 133 std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) override;
132 134
133 std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override; 135 std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
134 136
@@ -156,6 +158,11 @@ public:
156 template <typename T> 158 template <typename T>
157 Errno SetSockOpt(SOCKET fd, int option, T value); 159 Errno SetSockOpt(SOCKET fd, int option, T value);
158 160
161 std::pair<Errno, Errno> GetPendingError() override;
162
163 template <typename T>
164 std::pair<T, Errno> GetSockOpt(SOCKET fd, int option);
165
159 bool IsOpened() const override; 166 bool IsOpened() const override;
160 167
161 void HandleProxyPacket(const ProxyPacket& packet) override; 168 void HandleProxyPacket(const ProxyPacket& packet) override;
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 3be9b71cf..e04ad19db 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -153,7 +153,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
153 153
154 // Load NSO modules 154 // Load NSO modules
155 modules.clear(); 155 modules.clear();
156 const VAddr base_address{GetInteger(process.PageTable().GetCodeRegionStart())}; 156 const VAddr base_address{GetInteger(process.GetPageTable().GetCodeRegionStart())};
157 VAddr next_load_addr{base_address}; 157 VAddr next_load_addr{base_address};
158 const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), 158 const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(),
159 system.GetContentProvider()}; 159 system.GetContentProvider()};
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 709e2564f..ffe976b94 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -96,7 +96,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
96 } 96 }
97 97
98 codeset.memory = std::move(program_image); 98 codeset.memory = std::move(program_image);
99 const VAddr base_address = GetInteger(process.PageTable().GetCodeRegionStart()); 99 const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart());
100 process.LoadModule(std::move(codeset), base_address); 100 process.LoadModule(std::move(codeset), base_address);
101 101
102 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); 102 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 7b43f70ed..7a2a52fd4 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -79,6 +79,8 @@ enum class ResultStatus : u16 {
79 ErrorBadPFSHeader, 79 ErrorBadPFSHeader,
80 ErrorIncorrectPFSFileSize, 80 ErrorIncorrectPFSFileSize,
81 ErrorBadNCAHeader, 81 ErrorBadNCAHeader,
82 ErrorCompressedNCA,
83 ErrorSparseNCA,
82 ErrorMissingProductionKeyFile, 84 ErrorMissingProductionKeyFile,
83 ErrorMissingHeaderKey, 85 ErrorMissingHeaderKey,
84 ErrorIncorrectHeaderKey, 86 ErrorIncorrectHeaderKey,
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 7be6cf5f3..506808b5d 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -203,7 +203,7 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
203 203
204 // Load codeset for current process 204 // Load codeset for current process
205 codeset.memory = std::move(program_image); 205 codeset.memory = std::move(program_image);
206 process.LoadModule(std::move(codeset), process.PageTable().GetCodeRegionStart()); 206 process.LoadModule(std::move(codeset), process.GetPageTable().GetCodeRegionStart());
207 207
208 return true; 208 return true;
209} 209}
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 79639f5e4..74cc9579f 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -167,7 +167,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S
167 modules.clear(); 167 modules.clear();
168 168
169 // Load module 169 // Load module
170 const VAddr base_address = GetInteger(process.PageTable().GetCodeRegionStart()); 170 const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart());
171 if (!LoadModule(process, system, *file, base_address, true, true)) { 171 if (!LoadModule(process, system, *file, base_address, true, true)) {
172 return {ResultStatus::ErrorLoadingNSO, {}}; 172 return {ResultStatus::ErrorLoadingNSO, {}};
173 } 173 }
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 257406f09..e1fbe8e00 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -31,10 +31,10 @@ struct Memory::Impl {
31 explicit Impl(Core::System& system_) : system{system_} {} 31 explicit Impl(Core::System& system_) : system{system_} {}
32 32
33 void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { 33 void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
34 current_page_table = &process.PageTable().PageTableImpl(); 34 current_page_table = &process.GetPageTable().PageTableImpl();
35 current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer(); 35 current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
36 36
37 const std::size_t address_space_width = process.PageTable().GetAddressSpaceWidth(); 37 const std::size_t address_space_width = process.GetPageTable().GetAddressSpaceWidth();
38 38
39 system.ArmInterface(core_id).PageTableChanged(*current_page_table, address_space_width); 39 system.ArmInterface(core_id).PageTableChanged(*current_page_table, address_space_width);
40 } 40 }
@@ -186,7 +186,7 @@ struct Memory::Impl {
186 void WalkBlock(const Kernel::KProcess& process, const Common::ProcessAddress addr, 186 void WalkBlock(const Kernel::KProcess& process, const Common::ProcessAddress addr,
187 const std::size_t size, auto on_unmapped, auto on_memory, auto on_rasterizer, 187 const std::size_t size, auto on_unmapped, auto on_memory, auto on_rasterizer,
188 auto increment) { 188 auto increment) {
189 const auto& page_table = process.PageTable().PageTableImpl(); 189 const auto& page_table = process.GetPageTable().PageTableImpl();
190 std::size_t remaining_size = size; 190 std::size_t remaining_size = size;
191 std::size_t page_index = addr >> YUZU_PAGEBITS; 191 std::size_t page_index = addr >> YUZU_PAGEBITS;
192 std::size_t page_offset = addr & YUZU_PAGEMASK; 192 std::size_t page_offset = addr & YUZU_PAGEMASK;
@@ -266,6 +266,22 @@ struct Memory::Impl {
266 ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size); 266 ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size);
267 } 267 }
268 268
269 const u8* GetSpan(const VAddr src_addr, const std::size_t size) const {
270 if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] ==
271 current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) {
272 return GetPointerSilent(src_addr);
273 }
274 return nullptr;
275 }
276
277 u8* GetSpan(const VAddr src_addr, const std::size_t size) {
278 if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] ==
279 current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) {
280 return GetPointerSilent(src_addr);
281 }
282 return nullptr;
283 }
284
269 template <bool UNSAFE> 285 template <bool UNSAFE>
270 void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr, 286 void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr,
271 const void* src_buffer, const std::size_t size) { 287 const void* src_buffer, const std::size_t size) {
@@ -559,7 +575,7 @@ struct Memory::Impl {
559 } 575 }
560 } 576 }
561 577
562 const Common::ProcessAddress end = base + size; 578 const auto end = base + size;
563 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", 579 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
564 base + page_table.pointers.size()); 580 base + page_table.pointers.size());
565 581
@@ -570,14 +586,18 @@ struct Memory::Impl {
570 while (base != end) { 586 while (base != end) {
571 page_table.pointers[base].Store(nullptr, type); 587 page_table.pointers[base].Store(nullptr, type);
572 page_table.backing_addr[base] = 0; 588 page_table.backing_addr[base] = 0;
573 589 page_table.blocks[base] = 0;
574 base += 1; 590 base += 1;
575 } 591 }
576 } else { 592 } else {
593 auto orig_base = base;
577 while (base != end) { 594 while (base != end) {
578 page_table.pointers[base].Store( 595 auto host_ptr =
579 system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS), type); 596 system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS);
580 page_table.backing_addr[base] = GetInteger(target) - (base << YUZU_PAGEBITS); 597 auto backing = GetInteger(target) - (base << YUZU_PAGEBITS);
598 page_table.pointers[base].Store(host_ptr, type);
599 page_table.backing_addr[base] = backing;
600 page_table.blocks[base] = orig_base << YUZU_PAGEBITS;
581 601
582 ASSERT_MSG(page_table.pointers[base].Pointer(), 602 ASSERT_MSG(page_table.pointers[base].Pointer(),
583 "memory mapping base yield a nullptr within the table"); 603 "memory mapping base yield a nullptr within the table");
@@ -747,6 +767,14 @@ struct Memory::Impl {
747 VAddr last_address; 767 VAddr last_address;
748 }; 768 };
749 769
770 void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) {
771 system.GPU().InvalidateRegion(GetInteger(dest_addr), size);
772 }
773
774 void FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
775 system.GPU().FlushRegion(GetInteger(dest_addr), size);
776 }
777
750 Core::System& system; 778 Core::System& system;
751 Common::PageTable* current_page_table = nullptr; 779 Common::PageTable* current_page_table = nullptr;
752 std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> 780 std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES>
@@ -780,7 +808,7 @@ void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress b
780 808
781bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { 809bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
782 const Kernel::KProcess& process = *system.ApplicationProcess(); 810 const Kernel::KProcess& process = *system.ApplicationProcess();
783 const auto& page_table = process.PageTable().PageTableImpl(); 811 const auto& page_table = process.GetPageTable().PageTableImpl();
784 const size_t page = vaddr >> YUZU_PAGEBITS; 812 const size_t page = vaddr >> YUZU_PAGEBITS;
785 if (page >= page_table.pointers.size()) { 813 if (page >= page_table.pointers.size()) {
786 return false; 814 return false;
@@ -881,6 +909,14 @@ void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_b
881 impl->ReadBlockUnsafe(src_addr, dest_buffer, size); 909 impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
882} 910}
883 911
912const u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) const {
913 return impl->GetSpan(src_addr, size);
914}
915
916u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) {
917 return impl->GetSpan(src_addr, size);
918}
919
884void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, 920void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
885 const std::size_t size) { 921 const std::size_t size) {
886 impl->WriteBlock(dest_addr, src_buffer, size); 922 impl->WriteBlock(dest_addr, src_buffer, size);
@@ -924,4 +960,12 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug)
924 impl->MarkRegionDebug(GetInteger(vaddr), size, debug); 960 impl->MarkRegionDebug(GetInteger(vaddr), size, debug);
925} 961}
926 962
963void Memory::InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) {
964 impl->InvalidateRegion(dest_addr, size);
965}
966
967void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
968 impl->FlushRegion(dest_addr, size);
969}
970
927} // namespace Core::Memory 971} // namespace Core::Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index ea01824f8..ea33c769c 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -5,8 +5,12 @@
5 5
6#include <cstddef> 6#include <cstddef>
7#include <memory> 7#include <memory>
8#include <optional>
8#include <span> 9#include <span>
9#include <string> 10#include <string>
11#include <vector>
12
13#include "common/scratch_buffer.h"
10#include "common/typed_address.h" 14#include "common/typed_address.h"
11#include "core/hle/result.h" 15#include "core/hle/result.h"
12 16
@@ -24,6 +28,10 @@ class PhysicalMemory;
24class KProcess; 28class KProcess;
25} // namespace Kernel 29} // namespace Kernel
26 30
31namespace Tegra {
32class MemoryManager;
33}
34
27namespace Core::Memory { 35namespace Core::Memory {
28 36
29/** 37/**
@@ -343,6 +351,9 @@ public:
343 */ 351 */
344 void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); 352 void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size);
345 353
354 const u8* GetSpan(const VAddr src_addr, const std::size_t size) const;
355 u8* GetSpan(const VAddr src_addr, const std::size_t size);
356
346 /** 357 /**
347 * Writes a range of bytes into the current process' address space at the specified 358 * Writes a range of bytes into the current process' address space at the specified
348 * virtual address. 359 * virtual address.
@@ -461,6 +472,8 @@ public:
461 void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); 472 void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug);
462 473
463 void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); 474 void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
475 void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size);
476 void FlushRegion(Common::ProcessAddress dest_addr, size_t size);
464 477
465private: 478private:
466 Core::System& system; 479 Core::System& system;
@@ -469,4 +482,203 @@ private:
469 std::unique_ptr<Impl> impl; 482 std::unique_ptr<Impl> impl;
470}; 483};
471 484
485enum GuestMemoryFlags : u32 {
486 Read = 1 << 0,
487 Write = 1 << 1,
488 Safe = 1 << 2,
489 Cached = 1 << 3,
490
491 SafeRead = Read | Safe,
492 SafeWrite = Write | Safe,
493 SafeReadWrite = SafeRead | SafeWrite,
494 SafeReadCachedWrite = SafeReadWrite | Cached,
495
496 UnsafeRead = Read,
497 UnsafeWrite = Write,
498 UnsafeReadWrite = UnsafeRead | UnsafeWrite,
499 UnsafeReadCachedWrite = UnsafeReadWrite | Cached,
500};
501
502namespace {
503template <typename M, typename T, GuestMemoryFlags FLAGS>
504class GuestMemory {
505 using iterator = T*;
506 using const_iterator = const T*;
507 using value_type = T;
508 using element_type = T;
509 using iterator_category = std::contiguous_iterator_tag;
510
511public:
512 GuestMemory() = delete;
513 explicit GuestMemory(M& memory_, u64 addr_, std::size_t size_,
514 Common::ScratchBuffer<T>* backup = nullptr)
515 : memory{memory_}, addr{addr_}, size{size_} {
516 static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
517 if constexpr (FLAGS & GuestMemoryFlags::Read) {
518 Read(addr, size, backup);
519 }
520 }
521
522 ~GuestMemory() = default;
523
524 T* data() noexcept {
525 return data_span.data();
526 }
527
528 const T* data() const noexcept {
529 return data_span.data();
530 }
531
532 [[nodiscard]] T* begin() noexcept {
533 return data();
534 }
535
536 [[nodiscard]] const T* begin() const noexcept {
537 return data();
538 }
539
540 [[nodiscard]] T* end() noexcept {
541 return data() + size;
542 }
543
544 [[nodiscard]] const T* end() const noexcept {
545 return data() + size;
546 }
547
548 T& operator[](size_t index) noexcept {
549 return data_span[index];
550 }
551
552 const T& operator[](size_t index) const noexcept {
553 return data_span[index];
554 }
555
556 void SetAddressAndSize(u64 addr_, std::size_t size_) noexcept {
557 addr = addr_;
558 size = size_;
559 addr_changed = true;
560 }
561
562 std::span<T> Read(u64 addr_, std::size_t size_,
563 Common::ScratchBuffer<T>* backup = nullptr) noexcept {
564 addr = addr_;
565 size = size_;
566 if (size == 0) {
567 is_data_copy = true;
568 return {};
569 }
570
571 if (TrySetSpan()) {
572 if constexpr (FLAGS & GuestMemoryFlags::Safe) {
573 memory.FlushRegion(addr, size * sizeof(T));
574 }
575 } else {
576 if (backup) {
577 backup->resize_destructive(size);
578 data_span = *backup;
579 } else {
580 data_copy.resize(size);
581 data_span = std::span(data_copy);
582 }
583 is_data_copy = true;
584 span_valid = true;
585 if constexpr (FLAGS & GuestMemoryFlags::Safe) {
586 memory.ReadBlock(addr, data_span.data(), size * sizeof(T));
587 } else {
588 memory.ReadBlockUnsafe(addr, data_span.data(), size * sizeof(T));
589 }
590 }
591 return data_span;
592 }
593
594 void Write(std::span<T> write_data) noexcept {
595 if constexpr (FLAGS & GuestMemoryFlags::Cached) {
596 memory.WriteBlockCached(addr, write_data.data(), size * sizeof(T));
597 } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
598 memory.WriteBlock(addr, write_data.data(), size * sizeof(T));
599 } else {
600 memory.WriteBlockUnsafe(addr, write_data.data(), size * sizeof(T));
601 }
602 }
603
604 bool TrySetSpan() noexcept {
605 if (u8* ptr = memory.GetSpan(addr, size * sizeof(T)); ptr) {
606 data_span = {reinterpret_cast<T*>(ptr), size};
607 span_valid = true;
608 return true;
609 }
610 return false;
611 }
612
613protected:
614 bool IsDataCopy() const noexcept {
615 return is_data_copy;
616 }
617
618 bool AddressChanged() const noexcept {
619 return addr_changed;
620 }
621
622 M& memory;
623 u64 addr;
624 size_t size;
625 std::span<T> data_span{};
626 std::vector<T> data_copy;
627 bool span_valid{false};
628 bool is_data_copy{false};
629 bool addr_changed{false};
630};
631
632template <typename M, typename T, GuestMemoryFlags FLAGS>
633class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
634public:
635 GuestMemoryScoped() = delete;
636 explicit GuestMemoryScoped(M& memory_, u64 addr_, std::size_t size_,
637 Common::ScratchBuffer<T>* backup = nullptr)
638 : GuestMemory<M, T, FLAGS>(memory_, addr_, size_, backup) {
639 if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
640 if (!this->TrySetSpan()) {
641 if (backup) {
642 this->data_span = *backup;
643 this->span_valid = true;
644 this->is_data_copy = true;
645 }
646 }
647 }
648 }
649
650 ~GuestMemoryScoped() {
651 if constexpr (FLAGS & GuestMemoryFlags::Write) {
652 if (this->size == 0) [[unlikely]] {
653 return;
654 }
655
656 if (this->AddressChanged() || this->IsDataCopy()) {
657 ASSERT(this->span_valid);
658 if constexpr (FLAGS & GuestMemoryFlags::Cached) {
659 this->memory.WriteBlockCached(this->addr, this->data_span.data(),
660 this->size * sizeof(T));
661 } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
662 this->memory.WriteBlock(this->addr, this->data_span.data(),
663 this->size * sizeof(T));
664 } else {
665 this->memory.WriteBlockUnsafe(this->addr, this->data_span.data(),
666 this->size * sizeof(T));
667 }
668 } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
669 this->memory.InvalidateRegion(this->addr, this->size * sizeof(T));
670 }
671 }
672 }
673};
674} // namespace
675
676template <typename T, GuestMemoryFlags FLAGS>
677using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>;
678template <typename T, GuestMemoryFlags FLAGS>
679using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>;
680template <typename T, GuestMemoryFlags FLAGS>
681using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>;
682template <typename T, GuestMemoryFlags FLAGS>
683using GpuGuestMemoryScoped = GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>;
472} // namespace Core::Memory 684} // namespace Core::Memory
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 8742dd164..7b52f61a7 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -199,7 +199,7 @@ void CheatEngine::Initialize() {
199 metadata.process_id = system.ApplicationProcess()->GetProcessId(); 199 metadata.process_id = system.ApplicationProcess()->GetProcessId();
200 metadata.title_id = system.GetApplicationProcessProgramID(); 200 metadata.title_id = system.GetApplicationProcessProgramID();
201 201
202 const auto& page_table = system.ApplicationProcess()->PageTable(); 202 const auto& page_table = system.ApplicationProcess()->GetPageTable();
203 metadata.heap_extents = { 203 metadata.heap_extents = {
204 .base = GetInteger(page_table.GetHeapRegionStart()), 204 .base = GetInteger(page_table.GetHeapRegionStart()),
205 .size = page_table.GetHeapRegionSize(), 205 .size = page_table.GetHeapRegionSize(),
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 6c3dc7369..b5b3e7eda 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -117,8 +117,8 @@ json GetProcessorStateDataAuto(Core::System& system) {
117 arm.SaveContext(context); 117 arm.SaveContext(context);
118 118
119 return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32", 119 return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32",
120 GetInteger(process->PageTable().GetCodeRegionStart()), context.sp, 120 GetInteger(process->GetPageTable().GetCodeRegionStart()),
121 context.pc, context.pstate, context.cpu_registers); 121 context.sp, context.pc, context.pstate, context.cpu_registers);
122} 122}
123 123
124json GetBacktraceData(Core::System& system) { 124json GetBacktraceData(Core::System& system) {
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 9f26392b1..66e3ae9af 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -523,6 +523,8 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
523 } 523 }
524 524
525 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); 525 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1");
526 // Share the same button mapping with non-Nintendo controllers
527 SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0");
526 528
527 // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native 529 // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
528 // driver on Linux. 530 // driver on Linux.
@@ -800,16 +802,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
800 802
801 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. 803 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
802 // We will add those afterwards 804 // We will add those afterwards
803 // This list also excludes Screenshot since there's not really a mapping for that
804 ButtonBindings switch_to_sdl_button; 805 ButtonBindings switch_to_sdl_button;
805 806
806 if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO || 807 switch_to_sdl_button = GetDefaultButtonBinding(joystick);
807 SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
808 SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) {
809 switch_to_sdl_button = GetNintendoButtonBinding(joystick);
810 } else {
811 switch_to_sdl_button = GetDefaultButtonBinding();
812 }
813 808
814 // Add the missing bindings for ZL/ZR 809 // Add the missing bindings for ZL/ZR
815 static constexpr ZButtonBindings switch_to_sdl_axis{{ 810 static constexpr ZButtonBindings switch_to_sdl_axis{{
@@ -830,32 +825,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
830 return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); 825 return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis);
831} 826}
832 827
833ButtonBindings SDLDriver::GetDefaultButtonBinding() const { 828ButtonBindings SDLDriver::GetDefaultButtonBinding(
834 return {
835 std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
836 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
837 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
838 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
839 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
840 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
841 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
842 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
843 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
844 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
845 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
846 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
847 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
848 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
849 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
850 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
851 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
852 {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
853 };
854}
855
856ButtonBindings SDLDriver::GetNintendoButtonBinding(
857 const std::shared_ptr<SDLJoystick>& joystick) const { 829 const std::shared_ptr<SDLJoystick>& joystick) const {
858 // Default SL/SR mapping for pro controllers 830 // Default SL/SR mapping for other controllers
859 auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; 831 auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
860 auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; 832 auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
861 833
@@ -869,10 +841,10 @@ ButtonBindings SDLDriver::GetNintendoButtonBinding(
869 } 841 }
870 842
871 return { 843 return {
872 std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A}, 844 std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
873 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B}, 845 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
874 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X}, 846 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
875 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y}, 847 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
876 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, 848 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
877 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, 849 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
878 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, 850 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index ffde169b3..fcba4e3c6 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -100,11 +100,8 @@ private:
100 int axis_y, float offset_x, 100 int axis_y, float offset_x,
101 float offset_y) const; 101 float offset_y) const;
102 102
103 /// Returns the default button bindings list for generic controllers 103 /// Returns the default button bindings list
104 ButtonBindings GetDefaultButtonBinding() const; 104 ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
105
106 /// Returns the default button bindings list for nintendo controllers
107 ButtonBindings GetNintendoButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
108 105
109 /// Returns the button mappings from a single controller 106 /// Returns the button mappings from a single controller
110 ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, 107 ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 3b2fe01da..7f79111e0 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -274,6 +274,7 @@ add_library(video_core STATIC
274 vulkan_common/vulkan_wrapper.h 274 vulkan_common/vulkan_wrapper.h
275 vulkan_common/nsight_aftermath_tracker.cpp 275 vulkan_common/nsight_aftermath_tracker.cpp
276 vulkan_common/nsight_aftermath_tracker.h 276 vulkan_common/nsight_aftermath_tracker.h
277 vulkan_common/vma.cpp
277) 278)
278 279
279create_target_directory_groups(video_core) 280create_target_directory_groups(video_core)
@@ -291,7 +292,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
291 292
292add_dependencies(video_core host_shaders) 293add_dependencies(video_core host_shaders)
293target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) 294target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
294target_link_libraries(video_core PRIVATE sirit Vulkan::Headers vma) 295target_link_libraries(video_core PRIVATE sirit Vulkan::Headers GPUOpen::VulkanMemoryAllocator)
295 296
296if (ENABLE_NSIGHT_AFTERMATH) 297if (ENABLE_NSIGHT_AFTERMATH)
297 if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) 298 if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
@@ -324,6 +325,9 @@ else()
324 325
325 # xbyak 326 # xbyak
326 set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow") 327 set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow")
328
329 # VMA
330 set_source_files_properties(vulkan_common/vma.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-unused-variable;-Wno-unused-parameter;-Wno-missing-field-initializers")
327endif() 331endif()
328 332
329if (ARCHITECTURE_x86_64) 333if (ARCHITECTURE_x86_64)
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index b5ed3380f..f0f450edb 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -234,9 +234,10 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
234 if (has_new_downloads) { 234 if (has_new_downloads) {
235 memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); 235 memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount);
236 } 236 }
237 tmp_buffer.resize_destructive(amount); 237
238 cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount); 238 Core::Memory::CpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadWrite> tmp(
239 cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount); 239 cpu_memory, *cpu_src_address, amount, &tmp_buffer);
240 tmp.SetAddressAndSize(*cpu_dest_address, amount);
240 return true; 241 return true;
241} 242}
242 243
@@ -441,6 +442,11 @@ void BufferCache<P>::UnbindComputeStorageBuffers() {
441template <class P> 442template <class P>
442void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset, 443void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
443 bool is_written) { 444 bool is_written) {
445 if (ssbo_index >= channel_state->compute_storage_buffers.size()) [[unlikely]] {
446 LOG_ERROR(HW_GPU, "Storage buffer index {} exceeds maximum storage buffer count",
447 ssbo_index);
448 return;
449 }
444 channel_state->enabled_compute_storage_buffers |= 1U << ssbo_index; 450 channel_state->enabled_compute_storage_buffers |= 1U << ssbo_index;
445 channel_state->written_compute_storage_buffers |= (is_written ? 1U : 0U) << ssbo_index; 451 channel_state->written_compute_storage_buffers |= (is_written ? 1U : 0U) << ssbo_index;
446 452
@@ -463,6 +469,11 @@ void BufferCache<P>::UnbindComputeTextureBuffers() {
463template <class P> 469template <class P>
464void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, 470void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size,
465 PixelFormat format, bool is_written, bool is_image) { 471 PixelFormat format, bool is_written, bool is_image) {
472 if (tbo_index >= channel_state->compute_texture_buffers.size()) [[unlikely]] {
473 LOG_ERROR(HW_GPU, "Texture buffer index {} exceeds maximum texture buffer count",
474 tbo_index);
475 return;
476 }
466 channel_state->enabled_compute_texture_buffers |= 1U << tbo_index; 477 channel_state->enabled_compute_texture_buffers |= 1U << tbo_index;
467 channel_state->written_compute_texture_buffers |= (is_written ? 1U : 0U) << tbo_index; 478 channel_state->written_compute_texture_buffers |= (is_written ? 1U : 0U) << tbo_index;
468 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { 479 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index 460fc7551..0b7135d49 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -67,7 +67,7 @@ constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
67constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18; 67constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
68constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8; 68constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
69constexpr u32 NUM_STORAGE_BUFFERS = 16; 69constexpr u32 NUM_STORAGE_BUFFERS = 16;
70constexpr u32 NUM_TEXTURE_BUFFERS = 16; 70constexpr u32 NUM_TEXTURE_BUFFERS = 32;
71constexpr u32 NUM_STAGES = 5; 71constexpr u32 NUM_STAGES = 5;
72 72
73using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; 73using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>;
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 551929824..9f1b340a9 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -5,6 +5,7 @@
5#include "common/microprofile.h" 5#include "common/microprofile.h"
6#include "common/settings.h" 6#include "common/settings.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/memory.h"
8#include "video_core/dma_pusher.h" 9#include "video_core/dma_pusher.h"
9#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
10#include "video_core/gpu.h" 11#include "video_core/gpu.h"
@@ -12,6 +13,8 @@
12 13
13namespace Tegra { 14namespace Tegra {
14 15
16constexpr u32 MacroRegistersStart = 0xE00;
17
15DmaPusher::DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_, 18DmaPusher::DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_,
16 Control::ChannelState& channel_state_) 19 Control::ChannelState& channel_state_)
17 : gpu{gpu_}, system{system_}, memory_manager{memory_manager_}, puller{gpu_, memory_manager_, 20 : gpu{gpu_}, system{system_}, memory_manager{memory_manager_}, puller{gpu_, memory_manager_,
@@ -74,25 +77,16 @@ bool DmaPusher::Step() {
74 } 77 }
75 78
76 // Push buffer non-empty, read a word 79 // Push buffer non-empty, read a word
77 command_headers.resize_destructive(command_list_header.size); 80 if (dma_state.method >= MacroRegistersStart) {
78 constexpr u32 MacroRegistersStart = 0xE00;
79 if (dma_state.method < MacroRegistersStart) {
80 if (Settings::IsGPULevelHigh()) {
81 memory_manager.ReadBlock(dma_state.dma_get, command_headers.data(),
82 command_list_header.size * sizeof(u32));
83 } else {
84 memory_manager.ReadBlockUnsafe(dma_state.dma_get, command_headers.data(),
85 command_list_header.size * sizeof(u32));
86 }
87 } else {
88 const size_t copy_size = command_list_header.size * sizeof(u32);
89 if (subchannels[dma_state.subchannel]) { 81 if (subchannels[dma_state.subchannel]) {
90 subchannels[dma_state.subchannel]->current_dirty = 82 subchannels[dma_state.subchannel]->current_dirty = memory_manager.IsMemoryDirty(
91 memory_manager.IsMemoryDirty(dma_state.dma_get, copy_size); 83 dma_state.dma_get, command_list_header.size * sizeof(u32));
92 } 84 }
93 memory_manager.ReadBlockUnsafe(dma_state.dma_get, command_headers.data(), copy_size);
94 } 85 }
95 ProcessCommands(command_headers); 86 Core::Memory::GpuGuestMemory<Tegra::CommandHeader,
87 Core::Memory::GuestMemoryFlags::UnsafeRead>
88 headers(memory_manager, dma_state.dma_get, command_list_header.size, &command_headers);
89 ProcessCommands(headers);
96 } 90 }
97 91
98 return true; 92 return true;
diff --git a/src/video_core/engines/engine_upload.cpp b/src/video_core/engines/engine_upload.cpp
index 7f5a0c29d..bc64d4486 100644
--- a/src/video_core/engines/engine_upload.cpp
+++ b/src/video_core/engines/engine_upload.cpp
@@ -5,6 +5,7 @@
5 5
6#include "common/algorithm.h" 6#include "common/algorithm.h"
7#include "common/assert.h" 7#include "common/assert.h"
8#include "core/memory.h"
8#include "video_core/engines/engine_upload.h" 9#include "video_core/engines/engine_upload.h"
9#include "video_core/memory_manager.h" 10#include "video_core/memory_manager.h"
10#include "video_core/rasterizer_interface.h" 11#include "video_core/rasterizer_interface.h"
@@ -46,15 +47,11 @@ void State::ProcessData(const u32* data, size_t num_data) {
46void State::ProcessData(std::span<const u8> read_buffer) { 47void State::ProcessData(std::span<const u8> read_buffer) {
47 const GPUVAddr address{regs.dest.Address()}; 48 const GPUVAddr address{regs.dest.Address()};
48 if (is_linear) { 49 if (is_linear) {
49 if (regs.line_count == 1) { 50 for (size_t line = 0; line < regs.line_count; ++line) {
50 rasterizer->AccelerateInlineToMemory(address, copy_size, read_buffer); 51 const GPUVAddr dest_line = address + line * regs.dest.pitch;
51 } else { 52 std::span<const u8> buffer(read_buffer.data() + line * regs.line_length_in,
52 for (size_t line = 0; line < regs.line_count; ++line) { 53 regs.line_length_in);
53 const GPUVAddr dest_line = address + line * regs.dest.pitch; 54 rasterizer->AccelerateInlineToMemory(dest_line, regs.line_length_in, buffer);
54 std::span<const u8> buffer(read_buffer.data() + line * regs.line_length_in,
55 regs.line_length_in);
56 rasterizer->AccelerateInlineToMemory(dest_line, regs.line_length_in, buffer);
57 }
58 } 55 }
59 } else { 56 } else {
60 u32 width = regs.dest.width; 57 u32 width = regs.dest.width;
@@ -70,13 +67,14 @@ void State::ProcessData(std::span<const u8> read_buffer) {
70 const std::size_t dst_size = Tegra::Texture::CalculateSize( 67 const std::size_t dst_size = Tegra::Texture::CalculateSize(
71 true, bytes_per_pixel, width, regs.dest.height, regs.dest.depth, 68 true, bytes_per_pixel, width, regs.dest.height, regs.dest.depth,
72 regs.dest.BlockHeight(), regs.dest.BlockDepth()); 69 regs.dest.BlockHeight(), regs.dest.BlockDepth());
73 tmp_buffer.resize_destructive(dst_size); 70
74 memory_manager.ReadBlock(address, tmp_buffer.data(), dst_size); 71 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
75 Tegra::Texture::SwizzleSubrect(tmp_buffer, read_buffer, bytes_per_pixel, width, 72 tmp(memory_manager, address, dst_size, &tmp_buffer);
76 regs.dest.height, regs.dest.depth, x_offset, regs.dest.y, 73
77 x_elements, regs.line_count, regs.dest.BlockHeight(), 74 Tegra::Texture::SwizzleSubrect(tmp, read_buffer, bytes_per_pixel, width, regs.dest.height,
75 regs.dest.depth, x_offset, regs.dest.y, x_elements,
76 regs.line_count, regs.dest.BlockHeight(),
78 regs.dest.BlockDepth(), regs.line_length_in); 77 regs.dest.BlockDepth(), regs.line_length_in);
79 memory_manager.WriteBlockCached(address, tmp_buffer.data(), dst_size);
80 } 78 }
81} 79}
82 80
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 601095f03..a38d9528a 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -84,7 +84,6 @@ Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
84 84
85 Texture::TICEntry tic_entry; 85 Texture::TICEntry tic_entry;
86 memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry)); 86 memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
87
88 return tic_entry; 87 return tic_entry;
89} 88}
90 89
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 62d70e9f3..c3696096d 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -9,6 +9,7 @@
9#include "common/settings.h" 9#include "common/settings.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/core_timing.h" 11#include "core/core_timing.h"
12#include "core/memory.h"
12#include "video_core/dirty_flags.h" 13#include "video_core/dirty_flags.h"
13#include "video_core/engines/draw_manager.h" 14#include "video_core/engines/draw_manager.h"
14#include "video_core/engines/maxwell_3d.h" 15#include "video_core/engines/maxwell_3d.h"
@@ -679,17 +680,14 @@ void Maxwell3D::ProcessCBData(u32 value) {
679Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { 680Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
680 const GPUVAddr tic_address_gpu{regs.tex_header.Address() + 681 const GPUVAddr tic_address_gpu{regs.tex_header.Address() +
681 tic_index * sizeof(Texture::TICEntry)}; 682 tic_index * sizeof(Texture::TICEntry)};
682
683 Texture::TICEntry tic_entry; 683 Texture::TICEntry tic_entry;
684 memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry)); 684 memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
685
686 return tic_entry; 685 return tic_entry;
687} 686}
688 687
689Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const { 688Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const {
690 const GPUVAddr tsc_address_gpu{regs.tex_sampler.Address() + 689 const GPUVAddr tsc_address_gpu{regs.tex_sampler.Address() +
691 tsc_index * sizeof(Texture::TSCEntry)}; 690 tsc_index * sizeof(Texture::TSCEntry)};
692
693 Texture::TSCEntry tsc_entry; 691 Texture::TSCEntry tsc_entry;
694 memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry)); 692 memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry));
695 return tsc_entry; 693 return tsc_entry;
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index f8598fd98..cd8e24b0b 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -7,6 +7,7 @@
7#include "common/microprofile.h" 7#include "common/microprofile.h"
8#include "common/settings.h" 8#include "common/settings.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/memory.h"
10#include "video_core/engines/maxwell_3d.h" 11#include "video_core/engines/maxwell_3d.h"
11#include "video_core/engines/maxwell_dma.h" 12#include "video_core/engines/maxwell_dma.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
@@ -130,11 +131,12 @@ void MaxwellDMA::Launch() {
130 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); 131 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0);
131 read_buffer.resize_destructive(16); 132 read_buffer.resize_destructive(16);
132 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { 133 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) {
133 memory_manager.ReadBlock( 134 Core::Memory::GpuGuestMemoryScoped<
134 convert_linear_2_blocklinear_addr(regs.offset_in + offset), 135 u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
135 read_buffer.data(), read_buffer.size()); 136 tmp_write_buffer(memory_manager,
136 memory_manager.WriteBlockCached(regs.offset_out + offset, read_buffer.data(), 137 convert_linear_2_blocklinear_addr(regs.offset_in + offset),
137 read_buffer.size()); 138 16, &read_buffer);
139 tmp_write_buffer.SetAddressAndSize(regs.offset_out + offset, 16);
138 } 140 }
139 } else if (is_src_pitch && !is_dst_pitch) { 141 } else if (is_src_pitch && !is_dst_pitch) {
140 UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); 142 UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0);
@@ -142,20 +144,19 @@ void MaxwellDMA::Launch() {
142 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); 144 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0);
143 read_buffer.resize_destructive(16); 145 read_buffer.resize_destructive(16);
144 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { 146 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) {
145 memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(), 147 Core::Memory::GpuGuestMemoryScoped<
146 read_buffer.size()); 148 u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
147 memory_manager.WriteBlockCached( 149 tmp_write_buffer(memory_manager, regs.offset_in + offset, 16, &read_buffer);
148 convert_linear_2_blocklinear_addr(regs.offset_out + offset), 150 tmp_write_buffer.SetAddressAndSize(
149 read_buffer.data(), read_buffer.size()); 151 convert_linear_2_blocklinear_addr(regs.offset_out + offset), 16);
150 } 152 }
151 } else { 153 } else {
152 if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { 154 if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
153 read_buffer.resize_destructive(regs.line_length_in); 155 Core::Memory::GpuGuestMemoryScoped<
154 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), 156 u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
155 regs.line_length_in, 157 tmp_write_buffer(memory_manager, regs.offset_in, regs.line_length_in,
156 VideoCommon::CacheType::NoBufferCache); 158 &read_buffer);
157 memory_manager.WriteBlockCached(regs.offset_out, read_buffer.data(), 159 tmp_write_buffer.SetAddressAndSize(regs.offset_out, regs.line_length_in);
158 regs.line_length_in);
159 } 160 }
160 } 161 }
161 } 162 }
@@ -222,17 +223,15 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
222 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); 223 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
223 224
224 const size_t dst_size = dst_operand.pitch * regs.line_count; 225 const size_t dst_size = dst_operand.pitch * regs.line_count;
225 read_buffer.resize_destructive(src_size);
226 write_buffer.resize_destructive(dst_size);
227 226
228 memory_manager.ReadBlock(src_operand.address, read_buffer.data(), src_size); 227 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
229 memory_manager.ReadBlock(dst_operand.address, write_buffer.data(), dst_size); 228 memory_manager, src_operand.address, src_size, &read_buffer);
229 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
230 tmp_write_buffer(memory_manager, dst_operand.address, dst_size, &write_buffer);
230 231
231 UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, 232 UnswizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth,
232 src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, 233 x_offset, src_params.origin.y, x_elements, regs.line_count, block_height,
233 dst_operand.pitch); 234 block_depth, dst_operand.pitch);
234
235 memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
236} 235}
237 236
238void MaxwellDMA::CopyPitchToBlockLinear() { 237void MaxwellDMA::CopyPitchToBlockLinear() {
@@ -287,18 +286,17 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
287 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); 286 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
288 const size_t src_size = static_cast<size_t>(regs.pitch_in) * regs.line_count; 287 const size_t src_size = static_cast<size_t>(regs.pitch_in) * regs.line_count;
289 288
290 read_buffer.resize_destructive(src_size); 289 GPUVAddr src_addr = regs.offset_in;
291 write_buffer.resize_destructive(dst_size); 290 GPUVAddr dst_addr = regs.offset_out;
292 291 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
293 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); 292 memory_manager, src_addr, src_size, &read_buffer);
294 memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); 293 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
295 294 tmp_write_buffer(memory_manager, dst_addr, dst_size, &write_buffer);
296 // If the input is linear and the output is tiled, swizzle the input and copy it over. 295
297 SwizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, 296 // If the input is linear and the output is tiled, swizzle the input and copy it over.
298 dst_params.origin.y, x_elements, regs.line_count, block_height, block_depth, 297 SwizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth,
299 regs.pitch_in); 298 x_offset, dst_params.origin.y, x_elements, regs.line_count, block_height,
300 299 block_depth, regs.pitch_in);
301 memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
302} 300}
303 301
304void MaxwellDMA::CopyBlockLinearToBlockLinear() { 302void MaxwellDMA::CopyBlockLinearToBlockLinear() {
@@ -342,23 +340,20 @@ void MaxwellDMA::CopyBlockLinearToBlockLinear() {
342 const u32 pitch = x_elements * bytes_per_pixel; 340 const u32 pitch = x_elements * bytes_per_pixel;
343 const size_t mid_buffer_size = pitch * regs.line_count; 341 const size_t mid_buffer_size = pitch * regs.line_count;
344 342
345 read_buffer.resize_destructive(src_size);
346 write_buffer.resize_destructive(dst_size);
347
348 intermediate_buffer.resize_destructive(mid_buffer_size); 343 intermediate_buffer.resize_destructive(mid_buffer_size);
349 344
350 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); 345 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
351 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); 346 memory_manager, regs.offset_in, src_size, &read_buffer);
347 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
348 tmp_write_buffer(memory_manager, regs.offset_out, dst_size, &write_buffer);
352 349
353 UnswizzleSubrect(intermediate_buffer, read_buffer, bytes_per_pixel, src_width, src.height, 350 UnswizzleSubrect(intermediate_buffer, tmp_read_buffer, bytes_per_pixel, src_width, src.height,
354 src.depth, src_x_offset, src.origin.y, x_elements, regs.line_count, 351 src.depth, src_x_offset, src.origin.y, x_elements, regs.line_count,
355 src.block_size.height, src.block_size.depth, pitch); 352 src.block_size.height, src.block_size.depth, pitch);
356 353
357 SwizzleSubrect(write_buffer, intermediate_buffer, bytes_per_pixel, dst_width, dst.height, 354 SwizzleSubrect(tmp_write_buffer, intermediate_buffer, bytes_per_pixel, dst_width, dst.height,
358 dst.depth, dst_x_offset, dst.origin.y, x_elements, regs.line_count, 355 dst.depth, dst_x_offset, dst.origin.y, x_elements, regs.line_count,
359 dst.block_size.height, dst.block_size.depth, pitch); 356 dst.block_size.height, dst.block_size.depth, pitch);
360
361 memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
362} 357}
363 358
364void MaxwellDMA::ReleaseSemaphore() { 359void MaxwellDMA::ReleaseSemaphore() {
diff --git a/src/video_core/engines/sw_blitter/blitter.cpp b/src/video_core/engines/sw_blitter/blitter.cpp
index ff88cd03d..3a599f466 100644
--- a/src/video_core/engines/sw_blitter/blitter.cpp
+++ b/src/video_core/engines/sw_blitter/blitter.cpp
@@ -159,11 +159,11 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
159 const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); 159 const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
160 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format)); 160 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format));
161 const size_t src_size = get_surface_size(src, src_bytes_per_pixel); 161 const size_t src_size = get_surface_size(src, src_bytes_per_pixel);
162 impl->tmp_buffer.resize_destructive(src_size);
163 memory_manager.ReadBlock(src.Address(), impl->tmp_buffer.data(), src_size);
164 162
165 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel; 163 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_buffer(
164 memory_manager, src.Address(), src_size, &impl->tmp_buffer);
166 165
166 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel;
167 const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel; 167 const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel;
168 168
169 impl->src_buffer.resize_destructive(src_copy_size); 169 impl->src_buffer.resize_destructive(src_copy_size);
@@ -200,12 +200,11 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
200 200
201 impl->dst_buffer.resize_destructive(dst_copy_size); 201 impl->dst_buffer.resize_destructive(dst_copy_size);
202 if (src.linear == Fermi2D::MemoryLayout::BlockLinear) { 202 if (src.linear == Fermi2D::MemoryLayout::BlockLinear) {
203 UnswizzleSubrect(impl->src_buffer, impl->tmp_buffer, src_bytes_per_pixel, src.width, 203 UnswizzleSubrect(impl->src_buffer, tmp_buffer, src_bytes_per_pixel, src.width, src.height,
204 src.height, src.depth, config.src_x0, config.src_y0, src_extent_x, 204 src.depth, config.src_x0, config.src_y0, src_extent_x, src_extent_y,
205 src_extent_y, src.block_height, src.block_depth, 205 src.block_height, src.block_depth, src_extent_x * src_bytes_per_pixel);
206 src_extent_x * src_bytes_per_pixel);
207 } else { 206 } else {
208 process_pitch_linear(false, impl->tmp_buffer, impl->src_buffer, src_extent_x, src_extent_y, 207 process_pitch_linear(false, tmp_buffer, impl->src_buffer, src_extent_x, src_extent_y,
209 src.pitch, config.src_x0, config.src_y0, src_bytes_per_pixel); 208 src.pitch, config.src_x0, config.src_y0, src_bytes_per_pixel);
210 } 209 }
211 210
@@ -221,20 +220,18 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
221 } 220 }
222 221
223 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel); 222 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel);
224 impl->tmp_buffer.resize_destructive(dst_size); 223 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadWrite>
225 memory_manager.ReadBlock(dst.Address(), impl->tmp_buffer.data(), dst_size); 224 tmp_buffer2(memory_manager, dst.Address(), dst_size, &impl->tmp_buffer);
226 225
227 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) { 226 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) {
228 SwizzleSubrect(impl->tmp_buffer, impl->dst_buffer, dst_bytes_per_pixel, dst.width, 227 SwizzleSubrect(tmp_buffer2, impl->dst_buffer, dst_bytes_per_pixel, dst.width, dst.height,
229 dst.height, dst.depth, config.dst_x0, config.dst_y0, dst_extent_x, 228 dst.depth, config.dst_x0, config.dst_y0, dst_extent_x, dst_extent_y,
230 dst_extent_y, dst.block_height, dst.block_depth, 229 dst.block_height, dst.block_depth, dst_extent_x * dst_bytes_per_pixel);
231 dst_extent_x * dst_bytes_per_pixel);
232 } else { 230 } else {
233 process_pitch_linear(true, impl->dst_buffer, impl->tmp_buffer, dst_extent_x, dst_extent_y, 231 process_pitch_linear(true, impl->dst_buffer, tmp_buffer2, dst_extent_x, dst_extent_y,
234 dst.pitch, config.dst_x0, config.dst_y0, 232 dst.pitch, config.dst_x0, config.dst_y0,
235 static_cast<size_t>(dst_bytes_per_pixel)); 233 static_cast<size_t>(dst_bytes_per_pixel));
236 } 234 }
237 memory_manager.WriteBlock(dst.Address(), impl->tmp_buffer.data(), dst_size);
238 return true; 235 return true;
239} 236}
240 237
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 45141e488..d16040613 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -10,13 +10,13 @@
10#include "core/device_memory.h" 10#include "core/device_memory.h"
11#include "core/hle/kernel/k_page_table.h" 11#include "core/hle/kernel/k_page_table.h"
12#include "core/hle/kernel/k_process.h" 12#include "core/hle/kernel/k_process.h"
13#include "core/memory.h"
14#include "video_core/invalidation_accumulator.h" 13#include "video_core/invalidation_accumulator.h"
15#include "video_core/memory_manager.h" 14#include "video_core/memory_manager.h"
16#include "video_core/rasterizer_interface.h" 15#include "video_core/rasterizer_interface.h"
17#include "video_core/renderer_base.h" 16#include "video_core/renderer_base.h"
18 17
19namespace Tegra { 18namespace Tegra {
19using Core::Memory::GuestMemoryFlags;
20 20
21std::atomic<size_t> MemoryManager::unique_identifier_generator{}; 21std::atomic<size_t> MemoryManager::unique_identifier_generator{};
22 22
@@ -587,13 +587,10 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size,
587 587
588void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, 588void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size,
589 VideoCommon::CacheType which) { 589 VideoCommon::CacheType which) {
590 tmp_buffer.resize_destructive(size); 590 Core::Memory::GpuGuestMemoryScoped<u8, GuestMemoryFlags::SafeReadWrite> data(
591 ReadBlock(gpu_src_addr, tmp_buffer.data(), size, which); 591 *this, gpu_src_addr, size);
592 592 data.SetAddressAndSize(gpu_dest_addr, size);
593 // The output block must be flushed in case it has data modified from the GPU.
594 // Fixes NPC geometry in Zombie Panic in Wonderland DX
595 FlushRegion(gpu_dest_addr, size, which); 593 FlushRegion(gpu_dest_addr, size, which);
596 WriteBlock(gpu_dest_addr, tmp_buffer.data(), size, which);
597} 594}
598 595
599bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { 596bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const {
@@ -758,4 +755,23 @@ void MemoryManager::FlushCaching() {
758 accumulator->Clear(); 755 accumulator->Clear();
759} 756}
760 757
758const u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) const {
759 auto cpu_addr = GpuToCpuAddress(src_addr);
760 if (cpu_addr) {
761 return memory.GetSpan(*cpu_addr, size);
762 }
763 return nullptr;
764}
765
766u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) {
767 if (!IsContinuousRange(src_addr, size)) {
768 return nullptr;
769 }
770 auto cpu_addr = GpuToCpuAddress(src_addr);
771 if (cpu_addr) {
772 return memory.GetSpan(*cpu_addr, size);
773 }
774 return nullptr;
775}
776
761} // namespace Tegra 777} // namespace Tegra
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 4202c26ff..9b311b9e5 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -15,6 +15,7 @@
15#include "common/range_map.h" 15#include "common/range_map.h"
16#include "common/scratch_buffer.h" 16#include "common/scratch_buffer.h"
17#include "common/virtual_buffer.h" 17#include "common/virtual_buffer.h"
18#include "core/memory.h"
18#include "video_core/cache_types.h" 19#include "video_core/cache_types.h"
19#include "video_core/pte_kind.h" 20#include "video_core/pte_kind.h"
20 21
@@ -62,6 +63,20 @@ public:
62 [[nodiscard]] u8* GetPointer(GPUVAddr addr); 63 [[nodiscard]] u8* GetPointer(GPUVAddr addr);
63 [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const; 64 [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const;
64 65
66 template <typename T>
67 [[nodiscard]] T* GetPointer(GPUVAddr addr) {
68 const auto address{GpuToCpuAddress(addr)};
69 if (!address) {
70 return {};
71 }
72 return memory.GetPointer(*address);
73 }
74
75 template <typename T>
76 [[nodiscard]] const T* GetPointer(GPUVAddr addr) const {
77 return GetPointer<T*>(addr);
78 }
79
65 /** 80 /**
66 * ReadBlock and WriteBlock are full read and write operations over virtual 81 * ReadBlock and WriteBlock are full read and write operations over virtual
67 * GPU Memory. It's important to use these when GPU memory may not be continuous 82 * GPU Memory. It's important to use these when GPU memory may not be continuous
@@ -139,6 +154,9 @@ public:
139 154
140 void FlushCaching(); 155 void FlushCaching();
141 156
157 const u8* GetSpan(const GPUVAddr src_addr, const std::size_t size) const;
158 u8* GetSpan(const GPUVAddr src_addr, const std::size_t size);
159
142private: 160private:
143 template <bool is_big_pages, typename FuncMapped, typename FuncReserved, typename FuncUnmapped> 161 template <bool is_big_pages, typename FuncMapped, typename FuncReserved, typename FuncUnmapped>
144 inline void MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, FuncMapped&& func_mapped, 162 inline void MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, FuncMapped&& func_mapped,
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index 2d3f58201..4002fa72b 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -38,8 +38,8 @@ void RendererBase::RequestScreenshot(void* data, std::function<void(bool)> callb
38 LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request"); 38 LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request");
39 return; 39 return;
40 } 40 }
41 auto async_callback{[callback = std::move(callback)](bool invert_y) { 41 auto async_callback{[callback_ = std::move(callback)](bool invert_y) {
42 std::thread t{callback, invert_y}; 42 std::thread t{callback_, invert_y};
43 t.detach(); 43 t.detach();
44 }}; 44 }};
45 renderer_settings.screenshot_bits = data; 45 renderer_settings.screenshot_bits = data;
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index 23a48c6fe..71f720c63 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -231,24 +231,25 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
231 } 231 }
232 const bool in_parallel = thread_worker != nullptr; 232 const bool in_parallel = thread_worker != nullptr;
233 const auto backend = device.GetShaderBackend(); 233 const auto backend = device.GetShaderBackend();
234 auto func{[this, sources = std::move(sources), sources_spirv = std::move(sources_spirv), 234 auto func{[this, sources_ = std::move(sources), sources_spirv_ = std::move(sources_spirv),
235 shader_notify, backend, in_parallel, 235 shader_notify, backend, in_parallel,
236 force_context_flush](ShaderContext::Context*) mutable { 236 force_context_flush](ShaderContext::Context*) mutable {
237 for (size_t stage = 0; stage < 5; ++stage) { 237 for (size_t stage = 0; stage < 5; ++stage) {
238 switch (backend) { 238 switch (backend) {
239 case Settings::ShaderBackend::GLSL: 239 case Settings::ShaderBackend::GLSL:
240 if (!sources[stage].empty()) { 240 if (!sources_[stage].empty()) {
241 source_programs[stage] = CreateProgram(sources[stage], Stage(stage)); 241 source_programs[stage] = CreateProgram(sources_[stage], Stage(stage));
242 } 242 }
243 break; 243 break;
244 case Settings::ShaderBackend::GLASM: 244 case Settings::ShaderBackend::GLASM:
245 if (!sources[stage].empty()) { 245 if (!sources_[stage].empty()) {
246 assembly_programs[stage] = CompileProgram(sources[stage], AssemblyStage(stage)); 246 assembly_programs[stage] =
247 CompileProgram(sources_[stage], AssemblyStage(stage));
247 } 248 }
248 break; 249 break;
249 case Settings::ShaderBackend::SPIRV: 250 case Settings::ShaderBackend::SPIRV:
250 if (!sources_spirv[stage].empty()) { 251 if (!sources_spirv_[stage].empty()) {
251 source_programs[stage] = CreateProgram(sources_spirv[stage], Stage(stage)); 252 source_programs[stage] = CreateProgram(sources_spirv_[stage], Stage(stage));
252 } 253 }
253 break; 254 break;
254 } 255 }
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 0329ed820..7e1d7f92e 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -288,9 +288,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
288 const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { 288 const auto load_compute{[&](std::ifstream& file, FileEnvironment env) {
289 ComputePipelineKey key; 289 ComputePipelineKey key;
290 file.read(reinterpret_cast<char*>(&key), sizeof(key)); 290 file.read(reinterpret_cast<char*>(&key), sizeof(key));
291 queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { 291 queue_work([this, key, env_ = std::move(env), &state, &callback](Context* ctx) mutable {
292 ctx->pools.ReleaseContents(); 292 ctx->pools.ReleaseContents();
293 auto pipeline{CreateComputePipeline(ctx->pools, key, env, true)}; 293 auto pipeline{CreateComputePipeline(ctx->pools, key, env_, true)};
294 std::scoped_lock lock{state.mutex}; 294 std::scoped_lock lock{state.mutex};
295 if (pipeline) { 295 if (pipeline) {
296 compute_cache.emplace(key, std::move(pipeline)); 296 compute_cache.emplace(key, std::move(pipeline));
@@ -305,9 +305,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
305 const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) { 305 const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) {
306 GraphicsPipelineKey key; 306 GraphicsPipelineKey key;
307 file.read(reinterpret_cast<char*>(&key), sizeof(key)); 307 file.read(reinterpret_cast<char*>(&key), sizeof(key));
308 queue_work([this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { 308 queue_work([this, key, envs_ = std::move(envs), &state, &callback](Context* ctx) mutable {
309 boost::container::static_vector<Shader::Environment*, 5> env_ptrs; 309 boost::container::static_vector<Shader::Environment*, 5> env_ptrs;
310 for (auto& env : envs) { 310 for (auto& env : envs_) {
311 env_ptrs.push_back(&env); 311 env_ptrs.push_back(&env);
312 } 312 }
313 ctx->pools.ReleaseContents(); 313 ctx->pools.ReleaseContents();
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 51df18ec3..f8cd2a5d8 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -206,8 +206,8 @@ public:
206 const size_t sub_first_offset = static_cast<size_t>(first % 4) * GetQuadsNum(num_indices); 206 const size_t sub_first_offset = static_cast<size_t>(first % 4) * GetQuadsNum(num_indices);
207 const size_t offset = 207 const size_t offset =
208 (sub_first_offset + GetQuadsNum(first)) * 6ULL * BytesPerIndex(index_type); 208 (sub_first_offset + GetQuadsNum(first)) * 6ULL * BytesPerIndex(index_type);
209 scheduler.Record([buffer = *buffer, index_type_, offset](vk::CommandBuffer cmdbuf) { 209 scheduler.Record([buffer_ = *buffer, index_type_, offset](vk::CommandBuffer cmdbuf) {
210 cmdbuf.BindIndexBuffer(buffer, offset, index_type_); 210 cmdbuf.BindIndexBuffer(buffer_, offset, index_type_);
211 }); 211 });
212 } 212 }
213 213
@@ -528,17 +528,18 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
528 buffer_handles.push_back(handle); 528 buffer_handles.push_back(handle);
529 } 529 }
530 if (device.IsExtExtendedDynamicStateSupported()) { 530 if (device.IsExtExtendedDynamicStateSupported()) {
531 scheduler.Record([bindings = std::move(bindings), 531 scheduler.Record([bindings_ = std::move(bindings),
532 buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { 532 buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
533 cmdbuf.BindVertexBuffers2EXT( 533 cmdbuf.BindVertexBuffers2EXT(bindings_.min_index,
534 bindings.min_index, bindings.max_index - bindings.min_index, buffer_handles.data(), 534 bindings_.max_index - bindings_.min_index,
535 bindings.offsets.data(), bindings.sizes.data(), bindings.strides.data()); 535 buffer_handles_.data(), bindings_.offsets.data(),
536 bindings_.sizes.data(), bindings_.strides.data());
536 }); 537 });
537 } else { 538 } else {
538 scheduler.Record([bindings = std::move(bindings), 539 scheduler.Record([bindings_ = std::move(bindings),
539 buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { 540 buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
540 cmdbuf.BindVertexBuffers(bindings.min_index, bindings.max_index - bindings.min_index, 541 cmdbuf.BindVertexBuffers(bindings_.min_index, bindings_.max_index - bindings_.min_index,
541 buffer_handles.data(), bindings.offsets.data()); 542 buffer_handles_.data(), bindings_.offsets.data());
542 }); 543 });
543 } 544 }
544} 545}
@@ -573,11 +574,11 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<
573 for (u32 index = 0; index < bindings.buffers.size(); ++index) { 574 for (u32 index = 0; index < bindings.buffers.size(); ++index) {
574 buffer_handles.push_back(bindings.buffers[index]->Handle()); 575 buffer_handles.push_back(bindings.buffers[index]->Handle());
575 } 576 }
576 scheduler.Record([bindings = std::move(bindings), 577 scheduler.Record([bindings_ = std::move(bindings),
577 buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { 578 buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
578 cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles.size()), 579 cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles_.size()),
579 buffer_handles.data(), bindings.offsets.data(), 580 buffer_handles_.data(), bindings_.offsets.data(),
580 bindings.sizes.data()); 581 bindings_.sizes.data());
581 }); 582 });
582} 583}
583 584
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index d600c4e61..4f84d8497 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -469,9 +469,9 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
469 ComputePipelineCacheKey key; 469 ComputePipelineCacheKey key;
470 file.read(reinterpret_cast<char*>(&key), sizeof(key)); 470 file.read(reinterpret_cast<char*>(&key), sizeof(key));
471 471
472 workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { 472 workers.QueueWork([this, key, env_ = std::move(env), &state, &callback]() mutable {
473 ShaderPools pools; 473 ShaderPools pools;
474 auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)}; 474 auto pipeline{CreateComputePipeline(pools, key, env_, state.statistics.get(), false)};
475 std::scoped_lock lock{state.mutex}; 475 std::scoped_lock lock{state.mutex};
476 if (pipeline) { 476 if (pipeline) {
477 compute_cache.emplace(key, std::move(pipeline)); 477 compute_cache.emplace(key, std::move(pipeline));
@@ -500,10 +500,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
500 (key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) { 500 (key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) {
501 return; 501 return;
502 } 502 }
503 workers.QueueWork([this, key, envs = std::move(envs), &state, &callback]() mutable { 503 workers.QueueWork([this, key, envs_ = std::move(envs), &state, &callback]() mutable {
504 ShaderPools pools; 504 ShaderPools pools;
505 boost::container::static_vector<Shader::Environment*, 5> env_ptrs; 505 boost::container::static_vector<Shader::Environment*, 5> env_ptrs;
506 for (auto& env : envs) { 506 for (auto& env : envs_) {
507 env_ptrs.push_back(&env); 507 env_ptrs.push_back(&env);
508 } 508 }
509 auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), 509 auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs),
@@ -702,8 +702,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
702 if (!pipeline || pipeline_cache_filename.empty()) { 702 if (!pipeline || pipeline_cache_filename.empty()) {
703 return pipeline; 703 return pipeline;
704 } 704 }
705 serialization_thread.QueueWork([this, key, env = std::move(env)] { 705 serialization_thread.QueueWork([this, key, env_ = std::move(env)] {
706 SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env}, 706 SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env_},
707 pipeline_cache_filename, CACHE_VERSION); 707 pipeline_cache_filename, CACHE_VERSION);
708 }); 708 });
709 return pipeline; 709 return pipeline;
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index d67490449..29e0b797b 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -98,10 +98,10 @@ HostCounter::HostCounter(QueryCache& cache_, std::shared_ptr<HostCounter> depend
98 : HostCounterBase{std::move(dependency_)}, cache{cache_}, type{type_}, 98 : HostCounterBase{std::move(dependency_)}, cache{cache_}, type{type_},
99 query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} { 99 query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} {
100 const vk::Device* logical = &cache.GetDevice().GetLogical(); 100 const vk::Device* logical = &cache.GetDevice().GetLogical();
101 cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { 101 cache.GetScheduler().Record([logical, query_ = query](vk::CommandBuffer cmdbuf) {
102 const bool use_precise = Settings::IsGPULevelHigh(); 102 const bool use_precise = Settings::IsGPULevelHigh();
103 logical->ResetQueryPool(query.first, query.second, 1); 103 logical->ResetQueryPool(query_.first, query_.second, 1);
104 cmdbuf.BeginQuery(query.first, query.second, 104 cmdbuf.BeginQuery(query_.first, query_.second,
105 use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0); 105 use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0);
106 }); 106 });
107} 107}
@@ -111,8 +111,9 @@ HostCounter::~HostCounter() {
111} 111}
112 112
113void HostCounter::EndQuery() { 113void HostCounter::EndQuery() {
114 cache.GetScheduler().Record( 114 cache.GetScheduler().Record([query_ = query](vk::CommandBuffer cmdbuf) {
115 [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); }); 115 cmdbuf.EndQuery(query_.first, query_.second);
116 });
116} 117}
117 118
118u64 HostCounter::BlockingQuery(bool async) const { 119u64 HostCounter::BlockingQuery(bool async) const {
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 3aac3cfab..bf6ad6c79 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1412,7 +1412,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS
1412 } 1412 }
1413 scheduler->RequestOutsideRenderPassOperationContext(); 1413 scheduler->RequestOutsideRenderPassOperationContext();
1414 scheduler->Record([buffers = std::move(buffers_vector), image = *original_image, 1414 scheduler->Record([buffers = std::move(buffers_vector), image = *original_image,
1415 aspect_mask = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { 1415 aspect_mask_ = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
1416 const VkImageMemoryBarrier read_barrier{ 1416 const VkImageMemoryBarrier read_barrier{
1417 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 1417 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1418 .pNext = nullptr, 1418 .pNext = nullptr,
@@ -1424,7 +1424,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS
1424 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 1424 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1425 .image = image, 1425 .image = image,
1426 .subresourceRange{ 1426 .subresourceRange{
1427 .aspectMask = aspect_mask, 1427 .aspectMask = aspect_mask_,
1428 .baseMipLevel = 0, 1428 .baseMipLevel = 0,
1429 .levelCount = VK_REMAINING_MIP_LEVELS, 1429 .levelCount = VK_REMAINING_MIP_LEVELS,
1430 .baseArrayLayer = 0, 1430 .baseArrayLayer = 0,
@@ -1456,7 +1456,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS
1456 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 1456 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1457 .image = image, 1457 .image = image,
1458 .subresourceRange{ 1458 .subresourceRange{
1459 .aspectMask = aspect_mask, 1459 .aspectMask = aspect_mask_,
1460 .baseMipLevel = 0, 1460 .baseMipLevel = 0,
1461 .levelCount = VK_REMAINING_MIP_LEVELS, 1461 .levelCount = VK_REMAINING_MIP_LEVELS,
1462 .baseArrayLayer = 0, 1462 .baseArrayLayer = 0,
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 3a859139c..4457b366f 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -8,6 +8,7 @@
8 8
9#include "common/alignment.h" 9#include "common/alignment.h"
10#include "common/settings.h" 10#include "common/settings.h"
11#include "core/memory.h"
11#include "video_core/control/channel_state.h" 12#include "video_core/control/channel_state.h"
12#include "video_core/dirty_flags.h" 13#include "video_core/dirty_flags.h"
13#include "video_core/engines/kepler_compute.h" 14#include "video_core/engines/kepler_compute.h"
@@ -1026,19 +1027,19 @@ void TextureCache<P>::UploadImageContents(Image& image, StagingBuffer& staging)
1026 runtime.AccelerateImageUpload(image, staging, uploads); 1027 runtime.AccelerateImageUpload(image, staging, uploads);
1027 return; 1028 return;
1028 } 1029 }
1029 const size_t guest_size_bytes = image.guest_size_bytes; 1030
1030 swizzle_data_buffer.resize_destructive(guest_size_bytes); 1031 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data(
1031 gpu_memory->ReadBlockUnsafe(gpu_addr, swizzle_data_buffer.data(), guest_size_bytes); 1032 *gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
1032 1033
1033 if (True(image.flags & ImageFlagBits::Converted)) { 1034 if (True(image.flags & ImageFlagBits::Converted)) {
1034 unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes); 1035 unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
1035 auto copies = UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data_buffer, 1036 auto copies =
1036 unswizzle_data_buffer); 1037 UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, unswizzle_data_buffer);
1037 ConvertImage(unswizzle_data_buffer, image.info, mapped_span, copies); 1038 ConvertImage(unswizzle_data_buffer, image.info, mapped_span, copies);
1038 image.UploadMemory(staging, copies); 1039 image.UploadMemory(staging, copies);
1039 } else { 1040 } else {
1040 const auto copies = 1041 const auto copies =
1041 UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data_buffer, mapped_span); 1042 UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, mapped_span);
1042 image.UploadMemory(staging, copies); 1043 image.UploadMemory(staging, copies);
1043 } 1044 }
1044} 1045}
@@ -1231,11 +1232,12 @@ void TextureCache<P>::QueueAsyncDecode(Image& image, ImageId image_id) {
1231 decode->image_id = image_id; 1232 decode->image_id = image_id;
1232 async_decodes.push_back(std::move(decode)); 1233 async_decodes.push_back(std::move(decode));
1233 1234
1234 Common::ScratchBuffer<u8> local_unswizzle_data_buffer(image.unswizzled_size_bytes); 1235 static Common::ScratchBuffer<u8> local_unswizzle_data_buffer;
1235 const size_t guest_size_bytes = image.guest_size_bytes; 1236 local_unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
1236 swizzle_data_buffer.resize_destructive(guest_size_bytes); 1237 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data(
1237 gpu_memory->ReadBlockUnsafe(image.gpu_addr, swizzle_data_buffer.data(), guest_size_bytes); 1238 *gpu_memory, image.gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
1238 auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data_buffer, 1239
1240 auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data,
1239 local_unswizzle_data_buffer); 1241 local_unswizzle_data_buffer);
1240 const size_t out_size = MapSizeBytes(image); 1242 const size_t out_size = MapSizeBytes(image);
1241 1243
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 0de6ed09d..a83f5d41c 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -20,6 +20,7 @@
20#include "common/div_ceil.h" 20#include "common/div_ceil.h"
21#include "common/scratch_buffer.h" 21#include "common/scratch_buffer.h"
22#include "common/settings.h" 22#include "common/settings.h"
23#include "core/memory.h"
23#include "video_core/compatible_formats.h" 24#include "video_core/compatible_formats.h"
24#include "video_core/engines/maxwell_3d.h" 25#include "video_core/engines/maxwell_3d.h"
25#include "video_core/memory_manager.h" 26#include "video_core/memory_manager.h"
@@ -544,17 +545,15 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
544 tile_size.height, info.tile_width_spacing); 545 tile_size.height, info.tile_width_spacing);
545 const size_t subresource_size = sizes[level]; 546 const size_t subresource_size = sizes[level];
546 547
547 tmp_buffer.resize_destructive(subresource_size);
548 const std::span<u8> dst(tmp_buffer);
549
550 for (s32 layer = 0; layer < info.resources.layers; ++layer) { 548 for (s32 layer = 0; layer < info.resources.layers; ++layer) {
551 const std::span<const u8> src = input.subspan(host_offset); 549 const std::span<const u8> src = input.subspan(host_offset);
552 gpu_memory.ReadBlockUnsafe(gpu_addr + guest_offset, dst.data(), dst.size_bytes()); 550 {
553 551 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadWrite>
554 SwizzleTexture(dst, src, bytes_per_block, num_tiles.width, num_tiles.height, 552 dst(gpu_memory, gpu_addr + guest_offset, subresource_size, &tmp_buffer);
555 num_tiles.depth, block.height, block.depth);
556 553
557 gpu_memory.WriteBlockUnsafe(gpu_addr + guest_offset, dst.data(), dst.size_bytes()); 554 SwizzleTexture(dst, src, bytes_per_block, num_tiles.width, num_tiles.height,
555 num_tiles.depth, block.height, block.depth);
556 }
558 557
559 host_offset += host_bytes_per_layer; 558 host_offset += host_bytes_per_layer;
560 guest_offset += layer_stride; 559 guest_offset += layer_stride;
@@ -837,6 +836,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
837 const Extent3D size = info.size; 836 const Extent3D size = info.size;
838 837
839 if (info.type == ImageType::Linear) { 838 if (info.type == ImageType::Linear) {
839 ASSERT(output.size_bytes() >= guest_size_bytes);
840 gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), guest_size_bytes); 840 gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), guest_size_bytes);
841 841
842 ASSERT((info.pitch >> bpp_log2) << bpp_log2 == info.pitch); 842 ASSERT((info.pitch >> bpp_log2) << bpp_log2 == info.pitch);
@@ -904,16 +904,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
904 return copies; 904 return copies;
905} 905}
906 906
907BufferCopy UploadBufferCopy(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr,
908 const ImageBase& image, std::span<u8> output) {
909 gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), image.guest_size_bytes);
910 return BufferCopy{
911 .src_offset = 0,
912 .dst_offset = 0,
913 .size = image.guest_size_bytes,
914 };
915}
916
917void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, 907void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output,
918 std::span<BufferImageCopy> copies) { 908 std::span<BufferImageCopy> copies) {
919 u32 output_offset = 0; 909 u32 output_offset = 0;
diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h
index ab45a43c4..5a0649d24 100644
--- a/src/video_core/texture_cache/util.h
+++ b/src/video_core/texture_cache/util.h
@@ -66,9 +66,6 @@ struct OverlapResult {
66 Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, 66 Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info,
67 std::span<const u8> input, std::span<u8> output); 67 std::span<const u8> input, std::span<u8> output);
68 68
69[[nodiscard]] BufferCopy UploadBufferCopy(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr,
70 const ImageBase& image, std::span<u8> output);
71
72void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, 69void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output,
73 std::span<BufferImageCopy> copies); 70 std::span<BufferImageCopy> copies);
74 71
diff --git a/externals/vma/vma.cpp b/src/video_core/vulkan_common/vma.cpp
index 1fe2cf52b..1fe2cf52b 100644
--- a/externals/vma/vma.cpp
+++ b/src/video_core/vulkan_common/vma.cpp
diff --git a/src/web_service/announce_room_json.cpp b/src/web_service/announce_room_json.cpp
index 4c3195efd..f1020a5b8 100644
--- a/src/web_service/announce_room_json.cpp
+++ b/src/web_service/announce_room_json.cpp
@@ -135,11 +135,11 @@ void RoomJson::Delete() {
135 LOG_ERROR(WebService, "Room must be registered to be deleted"); 135 LOG_ERROR(WebService, "Room must be registered to be deleted");
136 return; 136 return;
137 } 137 }
138 Common::DetachedTasks::AddTask( 138 Common::DetachedTasks::AddTask([host_{this->host}, username_{this->username},
139 [host{this->host}, username{this->username}, token{this->token}, room_id{this->room_id}]() { 139 token_{this->token}, room_id_{this->room_id}]() {
140 // create a new client here because the this->client might be destroyed. 140 // create a new client here because the this->client might be destroyed.
141 Client{host, username, token}.DeleteJson(fmt::format("/lobby/{}", room_id), "", false); 141 Client{host_, username_, token_}.DeleteJson(fmt::format("/lobby/{}", room_id_), "", false);
142 }); 142 });
143} 143}
144 144
145} // namespace WebService 145} // namespace WebService
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 63326968b..5c910c9e0 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -235,7 +235,7 @@ GameListWorker::~GameListWorker() = default;
235void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { 235void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
236 using namespace FileSys; 236 using namespace FileSys;
237 237
238 const auto& cache = dynamic_cast<ContentProviderUnion&>(system.GetContentProvider()); 238 const auto& cache = system.GetContentProviderUnion();
239 239
240 auto installed_games = cache.ListEntriesFilterOrigin(std::nullopt, TitleType::Application, 240 auto installed_games = cache.ListEntriesFilterOrigin(std::nullopt, TitleType::Application,
241 ContentRecordType::Program); 241 ContentRecordType::Program);