diff options
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}" |
| 57 | done | 57 | done |
| 58 | 58 | ||
| 59 | pip3 install pefile | ||
| 60 | python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/" | 59 | python3 .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 | |||
| 11 | echo "Downloading Vulkan SDK $VulkanSDKVer from $Uri" | ||
| 12 | $WebClient = New-Object System.Net.WebClient | ||
| 13 | $WebClient.DownloadFile($Uri, $Destination) | ||
| 14 | echo "Finished downloading $ExeFile" | ||
| 15 | |||
| 16 | $VULKAN_SDK = "C:/VulkanSDK/$VulkanSDKVer" | ||
| 17 | $Arguments = "--root `"$VULKAN_SDK`" --accept-licenses --default-answer --confirm-command install" | ||
| 18 | |||
| 19 | echo "Installing Vulkan SDK $VulkanSDKVer" | ||
| 20 | $InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -Wait -ArgumentList $Arguments | ||
| 21 | $ExitCode = $InstallProcess.ExitCode | ||
| 22 | |||
| 23 | if ($ExitCode -ne 0) { | ||
| 24 | echo "Error installing Vulkan SDK $VulkanSDKVer (Error: $ExitCode)" | ||
| 25 | Exit $ExitCode | ||
| 26 | } | ||
| 27 | |||
| 28 | echo "Finished installing Vulkan SDK $VulkanSDKVer" | ||
| 29 | |||
| 30 | if ("$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 | ||
| 9 | steps: | 9 | steps: |
| 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: | |||
| 10 | jobs: | 10 | jobs: |
| 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 | ||
| 64 | CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF) | 64 | CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF) |
| 65 | 65 | ||
| 66 | set(DEFAULT_ENABLE_OPENSSL ON) | ||
| 67 | if (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) | ||
| 75 | endif() | ||
| 76 | option(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 |
| 67 | if (ANDROID) | 79 | if (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) | |||
| 277 | find_package(enet 1.3 MODULE) | 289 | find_package(enet 1.3 MODULE) |
| 278 | find_package(fmt 9 REQUIRED) | 290 | find_package(fmt 9 REQUIRED) |
| 279 | find_package(inih 52 MODULE COMPONENTS INIReader) | 291 | find_package(inih 52 MODULE COMPONENTS INIReader) |
| 280 | find_package(LLVM MODULE COMPONENTS Demangle) | 292 | find_package(LLVM 17 MODULE COMPONENTS Demangle) |
| 281 | find_package(lz4 REQUIRED) | 293 | find_package(lz4 REQUIRED) |
| 282 | find_package(nlohmann_json 3.8 REQUIRED) | 294 | find_package(nlohmann_json 3.8 REQUIRED) |
| 283 | find_package(Opus 1.3 MODULE) | 295 | find_package(Opus 1.3 MODULE) |
| 296 | find_package(VulkanMemoryAllocator CONFIG) | ||
| 284 | find_package(ZLIB 1.2 REQUIRED) | 297 | find_package(ZLIB 1.2 REQUIRED) |
| 285 | find_package(zstd 1.5 REQUIRED) | 298 | find_package(zstd 1.5 REQUIRED) |
| 286 | 299 | ||
| 287 | if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS) | 300 | if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS) |
| 288 | find_package(Vulkan 1.3.246 REQUIRED) | 301 | find_package(Vulkan 1.3.256 REQUIRED) |
| 289 | endif() | 302 | endif() |
| 290 | 303 | ||
| 291 | if (ENABLE_LIBUSB) | 304 | if (ENABLE_LIBUSB) |
| @@ -322,6 +335,10 @@ if (MINGW) | |||
| 322 | find_library(MSWSOCK_LIBRARY mswsock REQUIRED) | 335 | find_library(MSWSOCK_LIBRARY mswsock REQUIRED) |
| 323 | endif() | 336 | endif() |
| 324 | 337 | ||
| 338 | if(ENABLE_OPENSSL) | ||
| 339 | find_package(OpenSSL 1.1.1 REQUIRED) | ||
| 340 | endif() | ||
| 341 | |||
| 325 | # Please consider this as a stub | 342 | # Please consider this as a stub |
| 326 | if(ENABLE_QT6 AND Qt6_LOCATION) | 343 | if(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() | |||
| 144 | add_subdirectory(nx_tzdb) | 144 | add_subdirectory(nx_tzdb) |
| 145 | 145 | ||
| 146 | # VMA | 146 | # VMA |
| 147 | add_library(vma vma/vma.cpp) | 147 | if (NOT TARGET GPUOpen::VulkanMemoryAllocator) |
| 148 | target_include_directories(vma PUBLIC ./vma/VulkanMemoryAllocator/include) | 148 | add_subdirectory(VulkanMemoryAllocator) |
| 149 | target_link_libraries(vma PRIVATE Vulkan::Headers) | 149 | endif() |
| 150 | 150 | ||
| 151 | if (NOT TARGET LLVM::Demangle) | 151 | if (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 | ||
| 27 | using namespace llvm; | 25 | using namespace llvm; |
| 28 | using namespace llvm::itanium_demangle; | 26 | using 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 | ||
| 335 | using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; | 367 | using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; |
| 336 | 368 | ||
| 337 | char *llvm::itaniumDemangle(const char *MangledName, char *Buf, | 369 | char *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 | ||
| 369 | ItaniumPartialDemangler::ItaniumPartialDemangler() | 386 | ItaniumPartialDemangler::ItaniumPartialDemangler() |
| @@ -396,14 +413,12 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { | |||
| 396 | } | 413 | } |
| 397 | 414 | ||
| 398 | static char *printNode(const Node *RootNode, char *Buf, size_t *N) { | 415 | static 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 | ||
| 409 | char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { | 424 | char *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 | ||
| 484 | char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { | 497 | char *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 | ||
| 510 | char *ItaniumPartialDemangler::getFunctionReturnType( | 521 | char *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 | ||
| 529 | char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { | 538 | char *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 | ||
| 16 | namespace llvm { | 17 | namespace 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 | ||
| 32 | char *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. | |
| 36 | char *itaniumDemangle(std::string_view mangled_name); | ||
| 35 | 37 | ||
| 36 | enum MSDemangleFlags { | 38 | enum 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 | }; |
| 44 | char *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. | ||
| 55 | char *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. | ||
| 59 | char *rustDemangle(std::string_view MangledName); | ||
| 60 | |||
| 61 | // Demangles a D mangled symbol. | ||
| 62 | char *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. | ||
| 69 | std::string demangle(std::string_view MangledName); | ||
| 70 | |||
| 71 | bool 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 | |||
| 98 | private: | 125 | private: |
| 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 | |||
| 110 | DEMANGLE_NAMESPACE_BEGIN | 35 | DEMANGLE_NAMESPACE_BEGIN |
| 111 | 36 | ||
| 37 | template <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 | |||
| 71 | public: | ||
| 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. |
| 114 | class Node { | 159 | class Node { |
| 115 | public: | 160 | public: |
| 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 | |||
| 126 | private: | 195 | private: |
| 127 | Kind K; | 196 | Kind K; |
| 128 | 197 | ||
| 198 | Prec Precedence : 6; | ||
| 199 | |||
| 129 | // FIXME: Make these protected. | 200 | // FIXME: Make these protected. |
| 130 | public: | 201 | public: |
| 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 | ||
| 143 | public: | 214 | public: |
| 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 | ||
| 262 | class DotSuffix final : public Node { | 349 | class DotSuffix final : public Node { |
| 263 | const Node *Prefix; | 350 | const Node *Prefix; |
| 264 | const StringView Suffix; | 351 | const std::string_view Suffix; |
| 265 | 352 | ||
| 266 | public: | 353 | public: |
| 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 | ||
| 280 | class VendorExtQualType final : public Node { | 367 | class 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 | ||
| 284 | public: | 372 | public: |
| 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 | ||
| 328 | public: | 422 | public: |
| @@ -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 | ||
| 354 | class ConversionOperatorType final : public Node { | 451 | class 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 | ||
| 369 | class PostfixQualifiedType final : public Node { | 466 | class PostfixQualifiedType final : public Node { |
| 370 | const Node *Ty; | 467 | const Node *Ty; |
| 371 | const StringView Postfix; | 468 | const std::string_view Postfix; |
| 372 | 469 | ||
| 373 | public: | 470 | public: |
| 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 | ||
| 385 | class NameType final : public Node { | 482 | class NameType final : public Node { |
| 386 | const StringView Name; | 483 | const std::string_view Name; |
| 387 | 484 | ||
| 388 | public: | 485 | public: |
| 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 | |||
| 496 | class BitIntType final : public Node { | ||
| 497 | const Node *Size; | ||
| 498 | bool Signed; | ||
| 499 | |||
| 500 | public: | ||
| 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 | ||
| 399 | class ElaboratedTypeSpefType : public Node { | 516 | class ElaboratedTypeSpefType : public Node { |
| 400 | StringView Kind; | 517 | std::string_view Kind; |
| 401 | Node *Child; | 518 | Node *Child; |
| 402 | public: | 519 | public: |
| 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 | ||
| 415 | struct AbiTagAttr : Node { | 532 | struct 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 | ||
| 449 | class ObjCProtoName : public Node { | 568 | class 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 | ||
| 455 | public: | 574 | public: |
| 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 | |||
| 611 | class NodeOrString { | ||
| 612 | const void *First; | ||
| 613 | const void *Second; | ||
| 614 | |||
| 615 | public: | ||
| 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 | ||
| 647 | class ArrayType final : public Node { | 751 | class ArrayType final : public Node { |
| 648 | const Node *Base; | 752 | const Node *Base; |
| 649 | NodeOrString Dimension; | 753 | Node *Dimension; |
| 650 | 754 | ||
| 651 | public: | 755 | public: |
| 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 | ||
| 847 | class SpecialName final : public Node { | 951 | class SpecialName final : public Node { |
| 848 | const StringView Special; | 952 | const std::string_view Special; |
| 849 | const Node *Child; | 953 | const Node *Child; |
| 850 | 954 | ||
| 851 | public: | 955 | public: |
| 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 | |||
| 1004 | struct 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 | |||
| 1026 | struct 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 | ||
| 936 | class VectorType final : public Node { | 1080 | class VectorType final : public Node { |
| 937 | const Node *BaseType; | 1081 | const Node *BaseType; |
| 938 | const NodeOrString Dimension; | 1082 | const Node *Dimension; |
| 939 | 1083 | ||
| 940 | public: | 1084 | public: |
| 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 | ||
| 958 | class PixelVectorType final : public Node { | 1102 | class PixelVectorType final : public Node { |
| 959 | const NodeOrString Dimension; | 1103 | const Node *Dimension; |
| 960 | 1104 | ||
| 961 | public: | 1105 | public: |
| 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 | |||
| 1119 | class BinaryFPType final : public Node { | ||
| 1120 | const Node *Dimension; | ||
| 1121 | |||
| 1122 | public: | ||
| 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: | |||
| 1104 | class ParameterPack final : public Node { | 1256 | class 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 | |||
| 1366 | struct 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 | ||
| 1390 | class ExpandedSpecialSubstitution final : public Node { | 1527 | class SpecialSubstitution; |
| 1528 | class ExpandedSpecialSubstitution : public Node { | ||
| 1529 | protected: | ||
| 1391 | SpecialSubKind SSK; | 1530 | SpecialSubKind SSK; |
| 1392 | 1531 | ||
| 1532 | ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_) | ||
| 1533 | : Node(K_), SSK(SSK_) {} | ||
| 1393 | public: | 1534 | public: |
| 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 { | 1541 | protected: |
| 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 { | 1564 | private: |
| 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 | ||
| 1442 | class SpecialSubstitution final : public Node { | 1576 | class SpecialSubstitution final : public ExpandedSpecialSubstitution { |
| 1443 | public: | 1577 | public: |
| 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 | ||
| 1598 | inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution( | ||
| 1599 | SpecialSubstitution const *SS) | ||
| 1600 | : ExpandedSpecialSubstitution(SS->SSK) {} | ||
| 1601 | |||
| 1493 | class CtorDtorName final : public Node { | 1602 | class 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 | ||
| 1526 | class UnnamedTypeName : public Node { | 1635 | class UnnamedTypeName : public Node { |
| 1527 | const StringView Count; | 1636 | const std::string_view Count; |
| 1528 | 1637 | ||
| 1529 | public: | 1638 | public: |
| 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 | ||
| 1541 | class ClosureTypeName : public Node { | 1651 | class 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 | ||
| 1546 | public: | 1656 | public: |
| 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 | ||
| 1592 | class BinaryExpr : public Node { | 1703 | class 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 | ||
| 1597 | public: | 1708 | public: |
| 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 | ||
| 1627 | public: | 1741 | public: |
| 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 | ||
| 1642 | class PostfixExpr : public Node { | 1757 | class PostfixExpr : public Node { |
| 1643 | const Node *Child; | 1758 | const Node *Child; |
| 1644 | const StringView Operator; | 1759 | const std::string_view Operator; |
| 1645 | 1760 | ||
| 1646 | public: | 1761 | public: |
| 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 | ||
| 1665 | public: | 1780 | public: |
| 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 | ||
| 1682 | class MemberExpr : public Node { | 1798 | class 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 | ||
| 1687 | public: | 1803 | public: |
| 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 | |||
| 1819 | class 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); } | 1826 | public: |
| 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 | ||
| 1700 | class EnclosingExpr : public Node { | 1854 | class 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 | ||
| 1705 | public: | 1859 | public: |
| 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 | ||
| 1719 | class CastExpr : public Node { | 1877 | class 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 | ||
| 1725 | public: | 1883 | public: |
| 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 | ||
| 1762 | public: | 1928 | public: |
| 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[] ? |
| 1783 | public: | 1951 | public: |
| 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 | ||
| 1820 | public: | 1987 | public: |
| 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 | ||
| 1836 | class PrefixExpr : public Node { | 2007 | class PrefixExpr : public Node { |
| 1837 | StringView Prefix; | 2008 | std::string_view Prefix; |
| 1838 | Node *Child; | 2009 | Node *Child; |
| 1839 | 2010 | ||
| 1840 | public: | 2011 | public: |
| 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 | ||
| 1854 | class FunctionParam : public Node { | 2025 | class FunctionParam : public Node { |
| 1855 | StringView Number; | 2026 | std::string_view Number; |
| 1856 | 2027 | ||
| 1857 | public: | 2028 | public: |
| 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 | ||
| 1872 | public: | 2044 | public: |
| 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 | |||
| 2062 | class PointerToMemberConversionExpr : public Node { | ||
| 2063 | const Node *Type; | ||
| 2064 | const Node *SubExpr; | ||
| 2065 | std::string_view Offset; | ||
| 2066 | |||
| 2067 | public: | ||
| 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 | ||
| 1952 | class FoldExpr : public Node { | 2152 | class 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 | ||
| 1957 | public: | 2157 | public: |
| 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. | ||
| 2022 | class UUIDOfExpr : public Node { | ||
| 2023 | Node *Operand; | ||
| 2024 | public: | ||
| 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 | ||
| 2080 | class IntegerCastExpr : public Node { | 2257 | class 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 | ||
| 2085 | public: | 2262 | public: |
| 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 | ||
| 2099 | class IntegerLiteral : public Node { | 2280 | class IntegerLiteral : public Node { |
| 2100 | StringView Type; | 2281 | std::string_view Type; |
| 2101 | StringView Value; | 2282 | std::string_view Value; |
| 2102 | 2283 | ||
| 2103 | public: | 2284 | public: |
| 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 | ||
| 2141 | template <class Float> class FloatLiteralImpl : public Node { | 2321 | template <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 | ||
| 2147 | public: | 2327 | public: |
| 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>; | |||
| 2190 | template<typename Fn> | 2367 | template<typename Fn> |
| 2191 | void Node::visit(Fn F) const { | 2368 | void 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. |
| 2201 | template<typename NodeT> struct NodeKind; | 2379 | template<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 | }; |
| 2207 | FOR_EACH_NODE_KIND(SPECIALIZATION) | 2385 | #include "ItaniumNodes.def" |
| 2208 | #undef SPECIALIZATION | ||
| 2209 | |||
| 2210 | #undef FOR_EACH_NODE_KIND | ||
| 2211 | |||
| 2212 | template <class T, size_t N> | ||
| 2213 | class 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 | |||
| 2247 | public: | ||
| 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 | ||
| 2331 | template <typename Derived, typename Alloc> struct AbstractManglingParser { | 2387 | template <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> |
| 2552 | template <typename Derived, typename Alloc> | 2674 | template <typename Derived, typename Alloc> |
| 2553 | Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) { | 2675 | Node *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 |
| 2630 | template <typename Derived, typename Alloc> | 2746 | template <typename Derived, typename Alloc> |
| 2631 | Node * | 2747 | Node * |
| 2632 | AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) { | 2748 | AbstractManglingParser<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 | ||
| 2647 | template <typename Derived, typename Alloc> | 2787 | template <typename Derived, typename Alloc> |
| 2648 | Node * | 2788 | Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName( |
| 2649 | AbstractManglingParser<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> | ||
| 2834 | template <typename Derived, typename Alloc> | ||
| 2835 | bool 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) | 2950 | template <typename Derived, typename Alloc> |
| 2773 | // ::= an # & | 2951 | const 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 | }; | ||
| 3031 | template <typename Derived, typename Alloc> | ||
| 3032 | const 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. | ||
| 3037 | template <typename Derived, typename Alloc> | ||
| 3038 | const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo * | ||
| 3039 | AbstractManglingParser<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 | ||
| 2822 | template <typename Derived, typename Alloc> | 3063 | template <typename Derived, typename Alloc> |
| 2823 | Node * | 3064 | Node * |
| 2824 | AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { | 3065 | AbstractManglingParser<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 * | |||
| 3071 | AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, | 3128 | AbstractManglingParser<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> |
| 3329 | template <typename Derived, typename Alloc> | 3367 | template <typename Derived, typename Alloc> |
| 3330 | Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() { | 3368 | Node *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() { | |||
| 3419 | template <typename Derived, typename Alloc> | 3455 | template <typename Derived, typename Alloc> |
| 3420 | Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) { | 3456 | Node *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> |
| 3433 | template <typename Alloc, typename Derived> | 3469 | template <typename Alloc, typename Derived> |
| 3434 | StringView | 3470 | std::string_view |
| 3435 | AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) { | 3471 | AbstractManglingParser<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 | ||
| 3459 | template <typename Alloc, typename Derived> | 3495 | template <typename Alloc, typename Derived> |
| 3460 | StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() { | 3496 | std::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' |
| 3642 | template <typename Derived, typename Alloc> | 3682 | template <typename Derived, typename Alloc> |
| 3643 | Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() { | 3683 | Node *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() { | |||
| 3665 | template <typename Derived, typename Alloc> | 3705 | template <typename Derived, typename Alloc> |
| 3666 | Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() { | 3706 | Node *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 | ||
| 4059 | template <typename Derived, typename Alloc> | 4134 | template <typename Derived, typename Alloc> |
| 4060 | Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) { | 4135 | Node * |
| 4136 | AbstractManglingParser<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 | ||
| 4067 | template <typename Derived, typename Alloc> | 4144 | template <typename Derived, typename Alloc> |
| 4068 | Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) { | 4145 | Node * |
| 4146 | AbstractManglingParser<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 | ||
| 4078 | template <typename Derived, typename Alloc> | 4157 | template <typename Derived, typename Alloc> |
| 4079 | Node * | 4158 | Node *AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral( |
| 4080 | AbstractManglingParser<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?) | ||
| 4104 | template <typename Derived, typename Alloc> | 4184 | template <typename Derived, typename Alloc> |
| 4105 | Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { | 4185 | Node *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 | ||
| 4132 | template <typename Derived, typename Alloc> | ||
| 4133 | Node *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 |
| 4166 | template <typename Derived, typename Alloc> | 4211 | template <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 | ||
| 4468 | template <typename Derived, typename Alloc> | ||
| 4469 | Node * | ||
| 4470 | AbstractManglingParser<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 | ||
| 4488 | template <typename Derived, typename Alloc> | ||
| 4489 | Node *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() { | |||
| 4475 | template <typename Derived, typename Alloc> | 4555 | template <typename Derived, typename Alloc> |
| 4476 | Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { | 4556 | Node *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 | ||
| 4997 | template <typename Derived, typename Alloc> | 4883 | template <typename Derived, typename Alloc> |
| 4998 | Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { | 4884 | Node *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> |
| 5121 | template <typename Derived, typename Alloc> | 5027 | template <typename Derived, typename Alloc> |
| 5122 | Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { | 5028 | Node *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 <> | |||
| 5204 | struct FloatData<long double> | 5130 | struct 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. | ||
| 5267 | template <typename Derived, typename Alloc> | 5199 | template <typename Derived, typename Alloc> |
| 5268 | Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { | 5200 | Node *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 | |||
| 16 | NODE(NodeArrayNode) | ||
| 17 | NODE(DotSuffix) | ||
| 18 | NODE(VendorExtQualType) | ||
| 19 | NODE(QualType) | ||
| 20 | NODE(ConversionOperatorType) | ||
| 21 | NODE(PostfixQualifiedType) | ||
| 22 | NODE(ElaboratedTypeSpefType) | ||
| 23 | NODE(NameType) | ||
| 24 | NODE(AbiTagAttr) | ||
| 25 | NODE(EnableIfAttr) | ||
| 26 | NODE(ObjCProtoName) | ||
| 27 | NODE(PointerType) | ||
| 28 | NODE(ReferenceType) | ||
| 29 | NODE(PointerToMemberType) | ||
| 30 | NODE(ArrayType) | ||
| 31 | NODE(FunctionType) | ||
| 32 | NODE(NoexceptSpec) | ||
| 33 | NODE(DynamicExceptionSpec) | ||
| 34 | NODE(FunctionEncoding) | ||
| 35 | NODE(LiteralOperator) | ||
| 36 | NODE(SpecialName) | ||
| 37 | NODE(CtorVtableSpecialName) | ||
| 38 | NODE(QualifiedName) | ||
| 39 | NODE(NestedName) | ||
| 40 | NODE(LocalName) | ||
| 41 | NODE(ModuleName) | ||
| 42 | NODE(ModuleEntity) | ||
| 43 | NODE(VectorType) | ||
| 44 | NODE(PixelVectorType) | ||
| 45 | NODE(BinaryFPType) | ||
| 46 | NODE(BitIntType) | ||
| 47 | NODE(SyntheticTemplateParamName) | ||
| 48 | NODE(TypeTemplateParamDecl) | ||
| 49 | NODE(NonTypeTemplateParamDecl) | ||
| 50 | NODE(TemplateTemplateParamDecl) | ||
| 51 | NODE(TemplateParamPackDecl) | ||
| 52 | NODE(ParameterPack) | ||
| 53 | NODE(TemplateArgumentPack) | ||
| 54 | NODE(ParameterPackExpansion) | ||
| 55 | NODE(TemplateArgs) | ||
| 56 | NODE(ForwardTemplateReference) | ||
| 57 | NODE(NameWithTemplateArgs) | ||
| 58 | NODE(GlobalQualifiedName) | ||
| 59 | NODE(ExpandedSpecialSubstitution) | ||
| 60 | NODE(SpecialSubstitution) | ||
| 61 | NODE(CtorDtorName) | ||
| 62 | NODE(DtorName) | ||
| 63 | NODE(UnnamedTypeName) | ||
| 64 | NODE(ClosureTypeName) | ||
| 65 | NODE(StructuredBindingName) | ||
| 66 | NODE(BinaryExpr) | ||
| 67 | NODE(ArraySubscriptExpr) | ||
| 68 | NODE(PostfixExpr) | ||
| 69 | NODE(ConditionalExpr) | ||
| 70 | NODE(MemberExpr) | ||
| 71 | NODE(SubobjectExpr) | ||
| 72 | NODE(EnclosingExpr) | ||
| 73 | NODE(CastExpr) | ||
| 74 | NODE(SizeofParamPackExpr) | ||
| 75 | NODE(CallExpr) | ||
| 76 | NODE(NewExpr) | ||
| 77 | NODE(DeleteExpr) | ||
| 78 | NODE(PrefixExpr) | ||
| 79 | NODE(FunctionParam) | ||
| 80 | NODE(ConversionExpr) | ||
| 81 | NODE(PointerToMemberConversionExpr) | ||
| 82 | NODE(InitListExpr) | ||
| 83 | NODE(FoldExpr) | ||
| 84 | NODE(ThrowExpr) | ||
| 85 | NODE(BoolExpr) | ||
| 86 | NODE(StringLiteral) | ||
| 87 | NODE(LambdaExpr) | ||
| 88 | NODE(EnumLiteral) | ||
| 89 | NODE(IntegerLiteral) | ||
| 90 | NODE(FloatLiteral) | ||
| 91 | NODE(DoubleLiteral) | ||
| 92 | NODE(LongDoubleLiteral) | ||
| 93 | NODE(BracedExpr) | ||
| 94 | NODE(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 | ||
| 120 | inline bool operator==(const StringView &LHS, const StringView &RHS) { | 116 | inline 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 | ||
| 125 | DEMANGLE_NAMESPACE_END | 121 | DEMANGLE_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 | |||
| 23 | DEMANGLE_NAMESPACE_BEGIN | ||
| 24 | |||
| 25 | inline bool starts_with(std::string_view self, char C) noexcept { | ||
| 26 | return !self.empty() && *self.begin() == C; | ||
| 27 | } | ||
| 28 | |||
| 29 | inline 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 | |||
| 37 | DEMANGLE_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 | ||
| 24 | DEMANGLE_NAMESPACE_BEGIN | 31 | DEMANGLE_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. |
| 28 | class OutputStream { | 35 | class 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 | ||
| 66 | public: | 75 | public: |
| 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 | ||
| 144 | template <class T> class SwapAndRestore { | 188 | template <class T> class ScopedOverride { |
| 145 | T &Restore; | 189 | T &Loc; |
| 146 | T OriginalValue; | 190 | T Original; |
| 147 | bool ShouldRestore = true; | ||
| 148 | 191 | ||
| 149 | public: | 192 | public: |
| 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 | ||
| 175 | inline 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 | |||
| 190 | DEMANGLE_NAMESPACE_END | 204 | DEMANGLE_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 | |||
| 12 | import androidx.recyclerview.widget.RecyclerView | 12 | import androidx.recyclerview.widget.RecyclerView |
| 13 | import org.yuzu.yuzu_emu.R | 13 | import org.yuzu.yuzu_emu.R |
| 14 | import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding | 14 | import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding |
| 15 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment | ||
| 15 | import org.yuzu.yuzu_emu.model.HomeSetting | 16 | import org.yuzu.yuzu_emu.model.HomeSetting |
| 16 | 17 | ||
| 17 | class HomeSettingAdapter(private val activity: AppCompatActivity, var options: List<HomeSetting>) : | 18 | class 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}; | |||
| 28 | template <typename T> | 28 | template <typename T> |
| 29 | static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | 29 | static 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 | */ |
| 102 | static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | 101 | static 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() { | |||
| 30 | void DetachedTasks::AddTask(std::function<void()> task) { | 30 | void 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 | ||
| 8 | namespace Network { | 11 | namespace Network { |
| 9 | 12 | ||
| 10 | /// Address families | 13 | /// Address families |
| 11 | enum class Domain : u8 { | 14 | enum 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 |
| 16 | enum class Type { | 20 | enum 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 |
| 24 | enum class Protocol : u8 { | 29 | enum 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; | |||
| 48 | constexpr u32 FLAG_MSG_DONTWAIT = 0x80; | 54 | constexpr u32 FLAG_MSG_DONTWAIT = 0x80; |
| 49 | constexpr u32 FLAG_O_NONBLOCK = 0x800; | 55 | constexpr u32 FLAG_O_NONBLOCK = 0x800; |
| 50 | 56 | ||
| 57 | /// Cross-platform addrinfo structure | ||
| 58 | struct 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 | ||
| 16 | namespace Common::TimeZone { | 16 | namespace Common::TimeZone { |
| @@ -33,32 +33,29 @@ std::string GetDefaultTimeZone() { | |||
| 33 | return "GMT"; | 33 | return "GMT"; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | static std::string GetOsTimeZoneOffset() { | 36 | // Results are not comparable to seconds since Epoch |
| 37 | const std::time_t t{std::time(nullptr)}; | 37 | static 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 | |
| 43 | static 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 | ||
| 55 | std::chrono::seconds GetCurrentOffsetSeconds() { | 48 | std::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 | ||
| 73 | std::string FindSystemTimeZone() { | 70 | std::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) |
| 864 | endif() | 866 | endif() |
| 865 | 867 | ||
| 868 | if(ENABLE_OPENSSL) | ||
| 869 | target_sources(core PRIVATE | ||
| 870 | hle/service/ssl/ssl_backend_openssl.cpp) | ||
| 871 | target_link_libraries(core PRIVATE OpenSSL::SSL) | ||
| 872 | elseif (APPLE) | ||
| 873 | target_sources(core PRIVATE | ||
| 874 | hle/service/ssl/ssl_backend_securetransport.cpp) | ||
| 875 | target_link_libraries(core PRIVATE "-framework Security") | ||
| 876 | elseif (WIN32) | ||
| 877 | target_sources(core PRIVATE | ||
| 878 | hle/service/ssl/ssl_backend_schannel.cpp) | ||
| 879 | target_link_libraries(core PRIVATE crypt32 secur32) | ||
| 880 | else() | ||
| 881 | target_sources(core PRIVATE | ||
| 882 | hle/service/ssl/ssl_backend_none.cpp) | ||
| 883 | endif() | ||
| 884 | |||
| 866 | if (YUZU_USE_PRECOMPILED_HEADERS) | 885 | if (YUZU_USE_PRECOMPILED_HEADERS) |
| 867 | target_precompile_headers(core PRIVATE precompiled_headers.h) | 886 | target_precompile_headers(core PRIVATE precompiled_headers.h) |
| 868 | endif() | 887 | endif() |
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 | ||
| 348 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, | 348 | ARM_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 | ||
| 355 | ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; | 355 | ARM_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 | ||
| 17 | namespace Core::Memory { | 17 | namespace Core::Memory { |
| 18 | class Memory; | 18 | class Memory; |
| @@ -28,8 +28,8 @@ class System; | |||
| 28 | 28 | ||
| 29 | class ARM_Dynarmic_32 final : public ARM_Interface { | 29 | class ARM_Dynarmic_32 final : public ARM_Interface { |
| 30 | public: | 30 | public: |
| 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 | ||
| 407 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, | 407 | ARM_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 | ||
| 414 | ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; | 414 | ARM_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 | ||
| 16 | namespace Core::Memory { | 16 | namespace Core::Memory { |
| 17 | class Memory; | 17 | class Memory; |
| @@ -25,8 +25,8 @@ class System; | |||
| 25 | 25 | ||
| 26 | class ARM_Dynarmic_64 final : public ARM_Interface { | 26 | class ARM_Dynarmic_64 final : public ARM_Interface { |
| 27 | public: | 27 | public: |
| 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 | ||
| 13 | namespace Core::Memory { | 11 | namespace Core::Memory { |
| @@ -16,6 +14,9 @@ class Memory; | |||
| 16 | 14 | ||
| 17 | namespace Core { | 15 | namespace Core { |
| 18 | 16 | ||
| 17 | class ARM_Dynarmic_32; | ||
| 18 | class ARM_Dynarmic_64; | ||
| 19 | |||
| 19 | class DynarmicExclusiveMonitor final : public ExclusiveMonitor { | 20 | class DynarmicExclusiveMonitor final : public ExclusiveMonitor { |
| 20 | public: | 21 | public: |
| 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 | ||
| 883 | FileSys::ContentProviderUnion& System::GetContentProviderUnion() { | ||
| 884 | return *impl->content_provider; | ||
| 885 | } | ||
| 886 | |||
| 887 | const FileSys::ContentProviderUnion& System::GetContentProviderUnion() const { | ||
| 888 | return *impl->content_provider; | ||
| 889 | } | ||
| 890 | |||
| 883 | Service::FileSystem::FileSystemController& System::GetFileSystemController() { | 891 | Service::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 | }; |
| 58 | static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); | 58 | static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); |
| 59 | 59 | ||
| 60 | struct NCABucketInfo { | ||
| 61 | u64 table_offset; | ||
| 62 | u64 table_size; | ||
| 63 | std::array<u8, 0x10> table_header; | ||
| 64 | }; | ||
| 65 | static_assert(sizeof(NCABucketInfo) == 0x20, "NCABucketInfo has incorrect size."); | ||
| 66 | |||
| 67 | struct NCASparseInfo { | ||
| 68 | NCABucketInfo bucket; | ||
| 69 | u64 physical_offset; | ||
| 70 | u16 generation; | ||
| 71 | INSERT_PADDING_BYTES_NOINIT(0x6); | ||
| 72 | }; | ||
| 73 | static_assert(sizeof(NCASparseInfo) == 0x30, "NCASparseInfo has incorrect size."); | ||
| 74 | |||
| 75 | struct NCACompressionInfo { | ||
| 76 | NCABucketInfo bucket; | ||
| 77 | INSERT_PADDING_BYTES_NOINIT(0x8); | ||
| 78 | }; | ||
| 79 | static_assert(sizeof(NCACompressionInfo) == 0x28, "NCACompressionInfo has incorrect size."); | ||
| 80 | |||
| 60 | struct NCASectionRaw { | 81 | struct 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 | }; |
| 66 | static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size."); | 89 | static_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 | ||
| 440 | public: | 415 | public: |
| 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 | */ |
| 39 | void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, | 39 | void 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 | ||
| 27 | namespace Kernel { | 28 | namespace Kernel { |
| 28 | 29 | ||
| 30 | namespace { | ||
| 31 | |||
| 32 | template <bool MoveHandleAllowed> | ||
| 33 | Result 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 | |||
| 113 | void 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 | |||
| 29 | using ThreadQueueImplForKServerSessionRequest = KThreadQueue; | 149 | using ThreadQueueImplForKServerSessionRequest = KThreadQueue; |
| 30 | 150 | ||
| 31 | KServerSession::KServerSession(KernelCore& kernel) | 151 | KServerSession::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 | ||
| 97 | Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address, | 97 | Result 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 | ||
| 38 | Result KThreadLocalPage::Finalize() { | 38 | Result 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 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | constexpr inline size_t MessageBufferSize = 0x100; | ||
| 13 | |||
| 14 | class MessageBuffer { | ||
| 15 | public: | ||
| 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 | |||
| 418 | private: | ||
| 419 | u32* m_buffer; | ||
| 420 | size_t m_size; | ||
| 421 | |||
| 422 | public: | ||
| 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) { | |||
| 506 | void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { | 506 | void 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 | ||
| 331 | std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { | 331 | std::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 | ||
| 182 | void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, | 182 | void 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 |
| 77 | void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, | 77 | void 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 |
| 81 | void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output); | 81 | void 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 | ||
| 40 | namespace Service::NFC { | 38 | namespace Service::NFC { |
| 41 | NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, | 39 | NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, |
| @@ -1486,6 +1484,7 @@ DeviceState NfcDevice::GetCurrentState() const { | |||
| 1486 | } | 1484 | } |
| 1487 | 1485 | ||
| 1488 | Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const { | 1486 | Result 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 | ||
| 14 | namespace Service::NFC { | 17 | namespace Service::NFC { |
| 15 | 18 | ||
| @@ -51,22 +54,53 @@ Result DeviceManager::Finalize() { | |||
| 51 | return ResultSuccess; | 54 | return ResultSuccess; |
| 52 | } | 55 | } |
| 53 | 56 | ||
| 54 | Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, | 57 | Result 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 | ||
| 72 | DeviceState DeviceManager::GetDeviceState(u64 device_handle) const { | 106 | DeviceState 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 | ||
| 85 | Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const { | 119 | Result 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 | ||
| 131 | Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const { | 165 | Result 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 | ||
| 145 | Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const { | 179 | Result 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 | ||
| 155 | Kernel::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 | ||
| 200 | Result 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 | ||
| 165 | Result DeviceManager::ReadMifare(u64 device_handle, | 221 | Result 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 | ||
| 256 | Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const { | 312 | Result 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 | ||
| 327 | Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const { | 383 | Result 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 | ||
| 341 | Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const { | 397 | Result 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 | ||
| 355 | Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const { | 411 | Result 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 | ||
| 402 | Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const { | 458 | Result 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 | ||
| 416 | Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle, | 472 | Result 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 | ||
| 474 | Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const { | 530 | Result 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 | ||
| 488 | Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const { | 544 | Result 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 | ||
| 544 | Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const { | 600 | Result 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 | ||
| 652 | Result 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 | |||
| 596 | Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device, | 665 | Result 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 | ||
| 649 | Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device, | 718 | Result 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 | ||
| 198 | void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) { | 202 | void 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 | ||
| 208 | void NfcInterface::ReadMifare(HLERequestContext& ctx) { | 216 | void 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); | |||
| 17 | constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80); | 17 | constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80); |
| 18 | constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88); | 18 | constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88); |
| 19 | constexpr Result ResultTagRemoved(ErrorModule::NFC, 97); | 19 | constexpr Result ResultTagRemoved(ErrorModule::NFC, 97); |
| 20 | constexpr Result ResultUnknown112(ErrorModule::NFC, 112); | ||
| 20 | constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113); | 21 | constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113); |
| 22 | constexpr Result ResultUnknown114(ErrorModule::NFC, 114); | ||
| 23 | constexpr Result ResultUnknown115(ErrorModule::NFC, 115); | ||
| 21 | constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120); | 24 | constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120); |
| 22 | constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128); | 25 | constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128); |
| 23 | constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136); | 26 | constexpr 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 | ||
| 11 | namespace { | 12 | namespace { |
| 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 | ||
| 11 | namespace Core { | 8 | namespace Core { |
| 12 | class System; | 9 | class System; |
| 13 | } | 10 | } |
| 14 | 11 | ||
| 12 | namespace Network { | ||
| 13 | class RoomNetwork; | ||
| 14 | } | ||
| 15 | |||
| 15 | namespace Service::NIFM { | 16 | namespace Service::NIFM { |
| 16 | 17 | ||
| 17 | void LoopProcess(Core::System& system); | 18 | void 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 | ||
| 23 | using Common::Expected; | ||
| 24 | using Common::Unexpected; | ||
| 25 | |||
| 23 | namespace Service::Sockets { | 26 | namespace Service::Sockets { |
| 24 | 27 | ||
| 25 | namespace { | 28 | namespace { |
| @@ -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 | ||
| 445 | void 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 | |||
| 439 | void BSD::EventFd(HLERequestContext& ctx) { | 470 | void 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 | ||
| 674 | Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { | 707 | Errno 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 | ||
| 738 | Errno 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 | ||
| 914 | Expected<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 | |||
| 929 | std::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 | |||
| 844 | s32 BSD::FindFreeFileDescriptorHandle() noexcept { | 936 | s32 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 | |||
| 32 | private: | 40 | private: |
| 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 | |||
| 6 | namespace Service::Sockets { | 9 | namespace Service::Sockets { |
| 7 | 10 | ||
| 11 | constexpr Result ResultOverflow{ErrorModule::NSD, 6}; | ||
| 12 | |||
| 13 | // This is nn::oe::ServerEnvironmentType | ||
| 14 | enum class ServerEnvironmentType : u8 { | ||
| 15 | Dd, | ||
| 16 | Lp, | ||
| 17 | Sd, | ||
| 18 | Sp, | ||
| 19 | Dp, | ||
| 20 | }; | ||
| 21 | |||
| 8 | NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { | 22 | NSD::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 | ||
| 57 | static 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 | |||
| 65 | static 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 | |||
| 77 | void 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 | |||
| 88 | void 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 | |||
| 106 | void NSD::GetApplicationServerEnvironmentType(HLERequestContext& ctx) { | ||
| 107 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 108 | rb.Push(ResultSuccess); | ||
| 109 | rb.Push(static_cast<u32>(ServerEnvironmentType::Lp)); | ||
| 110 | } | ||
| 111 | |||
| 43 | NSD::~NSD() = default; | 112 | NSD::~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> { | |||
| 15 | public: | 15 | public: |
| 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 | |||
| 19 | private: | ||
| 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 | |||
| 27 | namespace Service::Sockets { | 18 | namespace Service::Sockets { |
| 28 | 19 | ||
| 29 | SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} { | 20 | SFDNSRES::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 | ||
| 62 | static NetDbError AddrInfoErrorToNetDbError(s32 result) { | 53 | static 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 | ||
| 76 | static std::vector<u8> SerializeAddrInfo(const addrinfo* addrinfo, s32 result_code, | 70 | static 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 | |||
| 89 | template <typename T> | ||
| 90 | static 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 | |||
| 96 | static 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. | ||
| 106 | static 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 | |||
| 133 | static 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 | |||
| 165 | void 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 | |||
| 184 | void 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 | |||
| 203 | static 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 | ||
| 188 | static std::pair<u32, s32> GetAddrInfoRequestImpl(HLERequestContext& ctx) { | 242 | static 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 | ||
| 224 | void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) { | 284 | void 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 | ||
| 234 | void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) { | 303 | void 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 | |||
| 325 | void 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 | ||
| 19 | private: | 19 | private: |
| 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 | |||
| 28 | enum 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 | ||
| 27 | enum class Domain : u32 { | 47 | enum class Domain : u32 { |
| 48 | Unspecified = 0, | ||
| 28 | INET = 2, | 49 | INET = 2, |
| 29 | }; | 50 | }; |
| 30 | 51 | ||
| 31 | enum class Type : u32 { | 52 | enum 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 | ||
| 38 | enum class Protocol : u32 { | 60 | enum 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 | ||
| 67 | enum class SocketLevel : u32 { | ||
| 68 | SOCKET = 0xffff, // i.e. SOL_SOCKET | ||
| 69 | }; | ||
| 70 | |||
| 45 | enum class OptName : u32 { | 71 | enum 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 | ||
| 56 | enum class ShutdownHow : s32 { | 84 | enum 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 | ||
| 85 | DECLARE_ENUM_FLAG_OPERATORS(PollEvents); | 116 | DECLARE_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 | ||
| 44 | GetAddrInfoError 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 | |||
| 42 | Network::Domain Translate(Domain domain) { | 84 | Network::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 | ||
| 52 | Domain Translate(Network::Domain domain) { | 96 | Domain 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 | ||
| 62 | Network::Type Translate(Type type) { | 108 | Network::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 | ||
| 74 | Network::Protocol Translate(Type type, Protocol protocol) { | 126 | Type 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 | |||
| 144 | Network::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 | |||
| 158 | Protocol 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 | ||
| 96 | Network::PollEvents TranslatePollEventsToHost(PollEvents flags) { | 172 | Network::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 | ||
| 115 | PollEvents TranslatePollEventsToGuest(Network::PollEvents flags) { | 194 | PollEvents 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 | ||
| 135 | Network::SockAddrIn Translate(SockAddrIn value) { | 217 | Network::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 |
| 18 | std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value); | 18 | std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value); |
| 19 | 19 | ||
| 20 | /// Translate abstract getaddrinfo error to guest getaddrinfo error | ||
| 21 | GetAddrInfoError Translate(Network::GetAddrInfoError value); | ||
| 22 | |||
| 20 | /// Translate guest domain to abstract domain | 23 | /// Translate guest domain to abstract domain |
| 21 | Network::Domain Translate(Domain domain); | 24 | Network::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 |
| 27 | Network::Type Translate(Type type); | 30 | Network::Type Translate(Type type); |
| 28 | 31 | ||
| 32 | /// Translate abstract type to guest type | ||
| 33 | Type Translate(Network::Type type); | ||
| 34 | |||
| 29 | /// Translate guest protocol to abstract protocol | 35 | /// Translate guest protocol to abstract protocol |
| 30 | Network::Protocol Translate(Type type, Protocol protocol); | 36 | Network::Protocol Translate(Protocol protocol); |
| 31 | 37 | ||
| 32 | /// Translate abstract poll event flags to guest poll event flags | 38 | /// Translate abstract protocol to guest protocol |
| 33 | Network::PollEvents TranslatePollEventsToHost(PollEvents flags); | 39 | Protocol 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 |
| 36 | PollEvents TranslatePollEventsToGuest(Network::PollEvents flags); | 42 | Network::PollEvents Translate(PollEvents flags); |
| 43 | |||
| 44 | /// Translate abstract poll event flags to guest poll event flags | ||
| 45 | PollEvents 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 |
| 39 | Network::SockAddrIn Translate(SockAddrIn value); | 48 | Network::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 | ||
| 9 | namespace Service::SSL { | 17 | namespace 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 | ||
| 32 | enum class IoMode : u32 { | ||
| 33 | Blocking = 1, | ||
| 34 | NonBlocking = 2, | ||
| 35 | }; | ||
| 36 | |||
| 37 | // This is nn::ssl::sf::OptionType | ||
| 38 | enum 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 |
| 24 | struct SslVersion { | 44 | struct SslVersion { |
| 25 | union { | 45 | union { |
| @@ -34,35 +54,42 @@ struct SslVersion { | |||
| 34 | }; | 54 | }; |
| 35 | }; | 55 | }; |
| 36 | 56 | ||
| 57 | struct SslContextSharedData { | ||
| 58 | u32 connection_count = 0; | ||
| 59 | }; | ||
| 60 | |||
| 37 | class ISslConnection final : public ServiceFramework<ISslConnection> { | 61 | class ISslConnection final : public ServiceFramework<ISslConnection> { |
| 38 | public: | 62 | public: |
| 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 | ||
| 85 | private: | 133 | private: |
| 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 | ||
| 89 | class ISslContext final : public ServiceFramework<ISslContext> { | 393 | class ISslContext final : public ServiceFramework<ISslContext> { |
| 90 | public: | 394 | public: |
| 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 | ||
| 112 | private: | 417 | private: |
| 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 | |||
| 15 | namespace Network { | ||
| 16 | class SocketBase; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Service::SSL { | ||
| 20 | |||
| 21 | constexpr Result ResultNoSocket{ErrorModule::SSLSrv, 103}; | ||
| 22 | constexpr Result ResultInvalidSocket{ErrorModule::SSLSrv, 106}; | ||
| 23 | constexpr Result ResultTimeout{ErrorModule::SSLSrv, 205}; | ||
| 24 | constexpr 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). | ||
| 30 | constexpr Result ResultWouldBlock{ErrorModule::SSLSrv, 204}; | ||
| 31 | |||
| 32 | class SSLConnectionBackend { | ||
| 33 | public: | ||
| 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 | |||
| 43 | ResultVal<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 | |||
| 8 | namespace Service::SSL { | ||
| 9 | |||
| 10 | ResultVal<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 | |||
| 19 | using namespace Common::FS; | ||
| 20 | |||
| 21 | namespace Service::SSL { | ||
| 22 | |||
| 23 | // Import OpenSSL's `SSL` type into the namespace. This is needed because the | ||
| 24 | // namespace is also named `SSL`. | ||
| 25 | using ::SSL; | ||
| 26 | |||
| 27 | namespace { | ||
| 28 | |||
| 29 | std::once_flag one_time_init_flag; | ||
| 30 | bool one_time_init_success = false; | ||
| 31 | |||
| 32 | SSL_CTX* ssl_ctx; | ||
| 33 | IOFile key_log_file; // only open if SSLKEYLOGFILE set in environment | ||
| 34 | BIO_METHOD* bio_meth; | ||
| 35 | |||
| 36 | Result CheckOpenSSLErrors(); | ||
| 37 | void OneTimeInit(); | ||
| 38 | void OneTimeInitLogFile(); | ||
| 39 | bool OneTimeInitBIO(); | ||
| 40 | |||
| 41 | } // namespace | ||
| 42 | |||
| 43 | class SSLConnectionBackendOpenSSL final : public SSLConnectionBackend { | ||
| 44 | public: | ||
| 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 | |||
| 256 | ResultVal<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 | |||
| 265 | namespace { | ||
| 266 | |||
| 267 | Result 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 | |||
| 297 | void 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 | |||
| 322 | void 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 | |||
| 336 | bool 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 | |||
| 15 | namespace { | ||
| 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 | |||
| 25 | std::once_flag one_time_init_flag; | ||
| 26 | bool one_time_init_success = false; | ||
| 27 | |||
| 28 | SCHANNEL_CRED schannel_cred{}; | ||
| 29 | CredHandle cred_handle; | ||
| 30 | |||
| 31 | static 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 | |||
| 63 | namespace Service::SSL { | ||
| 64 | |||
| 65 | class SSLConnectionBackendSchannel final : public SSLConnectionBackend { | ||
| 66 | public: | ||
| 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 | |||
| 535 | ResultVal<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 | |||
| 20 | namespace { | ||
| 21 | |||
| 22 | template <typename T> | ||
| 23 | struct 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 | |||
| 39 | std::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 | |||
| 47 | std::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 | |||
| 57 | namespace Service::SSL { | ||
| 58 | |||
| 59 | class SSLConnectionBackendSecureTransport final : public SSLConnectionBackend { | ||
| 60 | public: | ||
| 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 | |||
| 206 | private: | ||
| 207 | CFReleaser<SSLContextRef> context = nullptr; | ||
| 208 | bool got_read_eof = false; | ||
| 209 | |||
| 210 | std::shared_ptr<Network::SocketBase> socket; | ||
| 211 | }; | ||
| 212 | |||
| 213 | ResultVal<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 | ||
| 98 | Errno TranslateNativeError(int e) { | 99 | Errno 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 | ||
| 196 | Errno TranslateNativeError(int e) { | 201 | Errno 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 | ||
| 244 | int TranslateDomain(Domain domain) { | 255 | GetAddrInfoError 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 | |||
| 308 | Domain 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 | |||
| 320 | int 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 | ||
| 254 | int TranslateType(Type type) { | 332 | Type 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 | |||
| 350 | int 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 | ||
| 266 | int TranslateProtocol(Protocol protocol) { | 366 | Protocol 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 | |||
| 380 | int 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 | ||
| 278 | SockAddrIn TranslateToSockAddrIn(sockaddr input_) { | 394 | SockAddrIn 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_) { | |||
| 301 | short TranslatePollEvents(PollEvents events) { | 406 | short 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 | ||
| 486 | std::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 | |||
| 492 | u32 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 | |||
| 497 | Common::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 | |||
| 369 | std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { | 528 | std::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 | ||
| 413 | template <typename T> | 572 | template <typename T> |
| 414 | Errno Socket::SetSockOpt(SOCKET fd_, int option, T value) { | 573 | std::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 | |||
| 584 | template <typename T> | ||
| 585 | Errno 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 | ||
| 423 | Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { | 594 | Errno 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 | ||
| 432 | std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() { | 604 | std::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 | ||
| 460 | std::pair<SockAddrIn, Errno> Socket::GetPeerName() { | 630 | std::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 | ||
| 471 | std::pair<SockAddrIn, Errno> Socket::GetSockName() { | 640 | std::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 | ||
| 482 | Errno Socket::Bind(SockAddrIn addr) { | 650 | Errno Socket::Bind(SockAddrIn addr) { |
| @@ -519,7 +687,7 @@ Errno Socket::Shutdown(ShutdownHow how) { | |||
| 519 | return GetAndLogLastError(); | 687 | return GetAndLogLastError(); |
| 520 | } | 688 | } |
| 521 | 689 | ||
| 522 | std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { | 690 | std::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 | ||
| 535 | std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { | 703 | std::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 | ||
| 767 | std::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 | |||
| 600 | Errno Socket::SetLinger(bool enable, u32 linger) { | 772 | Errno 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 | ||
| 20 | namespace Common { | ||
| 21 | template <typename T, typename E> | ||
| 22 | class Expected; | ||
| 23 | } | ||
| 24 | |||
| 19 | namespace Network { | 25 | namespace Network { |
| 20 | 26 | ||
| 21 | class SocketBase; | 27 | class 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 | |||
| 49 | enum 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 | ||
| 54 | DECLARE_ENUM_FLAG_OPERATORS(PollEvents); | 83 | DECLARE_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 |
| 83 | std::optional<IPv4Address> GetHostIPv4Address(); | 112 | std::optional<IPv4Address> GetHostIPv4Address(); |
| 84 | 113 | ||
| 114 | std::string IPv4AddressToString(IPv4Address ip_addr); | ||
| 115 | u32 IPv4AddressToInteger(IPv4Address ip_addr); | ||
| 116 | |||
| 117 | // named to avoid name collision with Windows macro | ||
| 118 | Common::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 | ||
| 101 | std::pair<s32, Errno> ProxySocket::Recv(int flags, std::vector<u8>& message) { | 102 | std::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 | ||
| 109 | std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { | 110 | std::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 | ||
| 143 | std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& message, | 144 | std::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 | ||
| 292 | std::pair<Errno, Errno> ProxySocket::GetPendingError() { | ||
| 293 | LOG_DEBUG(Network, "(STUBBED) called"); | ||
| 294 | return {Errno::SUCCESS, Errno::SUCCESS}; | ||
| 295 | } | ||
| 296 | |||
| 296 | bool ProxySocket::IsOpened() const { | 297 | bool 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 | ||
| 15 | namespace Network { | 15 | namespace Network { |
| 16 | 16 | ||
| 17 | class RoomNetwork; | ||
| 18 | |||
| 17 | class ProxySocket : public SocketBase { | 19 | class ProxySocket : public SocketBase { |
| 18 | public: | 20 | public: |
| 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 | ||
| 79 | private: | 83 | private: |
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 | ||
| 22 | namespace Network { | 21 | namespace Network { |
| 23 | 22 | ||
| 23 | struct ProxyPacket; | ||
| 24 | |||
| 24 | class SocketBase { | 25 | class SocketBase { |
| 25 | public: | 26 | public: |
| 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 | ||
| 781 | bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { | 809 | bool 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 | ||
| 912 | const u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) const { | ||
| 913 | return impl->GetSpan(src_addr, size); | ||
| 914 | } | ||
| 915 | |||
| 916 | u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) { | ||
| 917 | return impl->GetSpan(src_addr, size); | ||
| 918 | } | ||
| 919 | |||
| 884 | void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, | 920 | void 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 | ||
| 963 | void Memory::InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { | ||
| 964 | impl->InvalidateRegion(dest_addr, size); | ||
| 965 | } | ||
| 966 | |||
| 967 | void 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; | |||
| 24 | class KProcess; | 28 | class KProcess; |
| 25 | } // namespace Kernel | 29 | } // namespace Kernel |
| 26 | 30 | ||
| 31 | namespace Tegra { | ||
| 32 | class MemoryManager; | ||
| 33 | } | ||
| 34 | |||
| 27 | namespace Core::Memory { | 35 | namespace 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 | ||
| 465 | private: | 478 | private: |
| 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 | ||
| 485 | enum 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 | |||
| 502 | namespace { | ||
| 503 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 504 | class 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 | |||
| 511 | public: | ||
| 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 | |||
| 613 | protected: | ||
| 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 | |||
| 632 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 633 | class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> { | ||
| 634 | public: | ||
| 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 | |||
| 676 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 677 | using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>; | ||
| 678 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 679 | using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>; | ||
| 680 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 681 | using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>; | ||
| 682 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 683 | using 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 | ||
| 124 | json GetBacktraceData(Core::System& system) { | 124 | json 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 | ||
| 833 | ButtonBindings SDLDriver::GetDefaultButtonBinding() const { | 828 | ButtonBindings 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 | |||
| 856 | ButtonBindings 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 | ||
| 279 | create_target_directory_groups(video_core) | 280 | create_target_directory_groups(video_core) |
| @@ -291,7 +292,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS}) | |||
| 291 | 292 | ||
| 292 | add_dependencies(video_core host_shaders) | 293 | add_dependencies(video_core host_shaders) |
| 293 | target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) | 294 | target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) |
| 294 | target_link_libraries(video_core PRIVATE sirit Vulkan::Headers vma) | 295 | target_link_libraries(video_core PRIVATE sirit Vulkan::Headers GPUOpen::VulkanMemoryAllocator) |
| 295 | 296 | ||
| 296 | if (ENABLE_NSIGHT_AFTERMATH) | 297 | if (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") | ||
| 327 | endif() | 331 | endif() |
| 328 | 332 | ||
| 329 | if (ARCHITECTURE_x86_64) | 333 | if (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() { | |||
| 441 | template <class P> | 442 | template <class P> |
| 442 | void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset, | 443 | void 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() { | |||
| 463 | template <class P> | 469 | template <class P> |
| 464 | void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, | 470 | void 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; | |||
| 67 | constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18; | 67 | constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18; |
| 68 | constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8; | 68 | constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8; |
| 69 | constexpr u32 NUM_STORAGE_BUFFERS = 16; | 69 | constexpr u32 NUM_STORAGE_BUFFERS = 16; |
| 70 | constexpr u32 NUM_TEXTURE_BUFFERS = 16; | 70 | constexpr u32 NUM_TEXTURE_BUFFERS = 32; |
| 71 | constexpr u32 NUM_STAGES = 5; | 71 | constexpr u32 NUM_STAGES = 5; |
| 72 | 72 | ||
| 73 | using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; | 73 | using 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 | ||
| 13 | namespace Tegra { | 14 | namespace Tegra { |
| 14 | 15 | ||
| 16 | constexpr u32 MacroRegistersStart = 0xE00; | ||
| 17 | |||
| 15 | DmaPusher::DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_, | 18 | DmaPusher::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) { | |||
| 46 | void State::ProcessData(std::span<const u8> read_buffer) { | 47 | void 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) { | |||
| 679 | Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { | 680 | Texture::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 | ||
| 689 | Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const { | 688 | Texture::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 | ||
| 238 | void MaxwellDMA::CopyPitchToBlockLinear() { | 237 | void 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 | ||
| 304 | void MaxwellDMA::CopyBlockLinearToBlockLinear() { | 302 | void 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 | ||
| 364 | void MaxwellDMA::ReleaseSemaphore() { | 359 | void 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 | ||
| 19 | namespace Tegra { | 18 | namespace Tegra { |
| 19 | using Core::Memory::GuestMemoryFlags; | ||
| 20 | 20 | ||
| 21 | std::atomic<size_t> MemoryManager::unique_identifier_generator{}; | 21 | std::atomic<size_t> MemoryManager::unique_identifier_generator{}; |
| 22 | 22 | ||
| @@ -587,13 +587,10 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size, | |||
| 587 | 587 | ||
| 588 | void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, | 588 | void 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 | ||
| 599 | bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { | 596 | bool 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 | ||
| 758 | const 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 | |||
| 766 | u8* 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 | |||
| 142 | private: | 160 | private: |
| 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 | ||
| 113 | void HostCounter::EndQuery() { | 113 | void 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 | ||
| 118 | u64 HostCounter::BlockingQuery(bool async) const { | 119 | u64 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 | ||
| 907 | BufferCopy 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 | |||
| 917 | void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, | 907 | void 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 | |||
| 72 | void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, | 69 | void 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; | |||
| 235 | void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { | 235 | void 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); |