From 67d389712cafd5109d7a7e6147bce82c5064086d Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sun, 11 May 2025 19:40:08 -0700 Subject: [PATCH] Target: implement the Darwin ARM64 support to complete the port This implements the necessary ARM64 specific logic for mmap and munmap syscalls to be able to allocate and deallocate memory in the inferior. This gives us a complete implementation for the Darwin ARM64 target. --- .github/workflows/build.yml | 13 ++- CMakeLists.txt | 2 +- README.md | 2 +- Sources/Target/Darwin/ARM64/ProcessARM64.cpp | 104 ++++++++++++++++--- 4 files changed, 102 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76f82e42..975c1e1a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,10 +143,12 @@ jobs: ${{ github.workspace }}/BinaryCache/ds2/ds2.exe macos: - # The macos-latest runner image runs on an M1 ARM CPU which is not currently - # supported by ds2. Build on macos-13, which is x86_64-based, until Darwin - # on ARM support is implemented. - runs-on: macos-13 + runs-on: macos-latest + + strategy: + fail-fast: false + matrix: + processor: [ arm64, x86_64 ] steps: - uses: actions/checkout@v4 @@ -157,6 +159,7 @@ jobs: cmake -B ${{ github.workspace }}/BinaryCache/ds2 \ -C ${{ github.workspace }}/cmake/caches/ClangWarnings.cmake \ -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_SYSTEM_PROCESSOR="${{ matrix.processor }}" \ -G Ninja \ -S ${{ github.workspace }} - name: Build @@ -164,7 +167,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: macOS-x86_64-ds2 + name: macOS-${{ matrix.processor }}-ds2 path: | ${{ github.workspace }}/BinaryCache/ds2/ds2 diff --git a/CMakeLists.txt b/CMakeLists.txt index ab7b674d..3a45adb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,7 @@ if(DS2_ARCHITECTURE MATCHES "ARM|ARM64") set_source_files_properties( Sources/Architecture/ARM/ThumbBranchInfo.cpp PROPERTIES - COMPILE_OPTIONS $<$:-Wno-error=comma>) + COMPILE_OPTIONS $<$,$>:-Wno-error=comma>) target_sources(ds2 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/Headers/DebugServer2/Architecture/ARM/RegistersDescriptors.h diff --git a/README.md b/README.md index 5b7affa0..c9106d32 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ platforms at various times. - [x] ARM64 - [x] Android - - [ ] Darwin + - [x] Darwin - [x] Linux - [x] MinGW - [ ] Windows diff --git a/Sources/Target/Darwin/ARM64/ProcessARM64.cpp b/Sources/Target/Darwin/ARM64/ProcessARM64.cpp index 5e072de5..db5250f5 100644 --- a/Sources/Target/Darwin/ARM64/ProcessARM64.cpp +++ b/Sources/Target/Darwin/ARM64/ProcessARM64.cpp @@ -1,15 +1,64 @@ -// -// Copyright (c) 2014-present, Saleem Abdulrasool -// All rights reserved. -// -// This source code is licensed under the University of Illinois/NCSA Open -// Source License found in the LICENSE file in the root directory of this -// source tree. An additional grant of patent rights can be found in the -// PATENTS file in the same directory. -// +// Copyright 2024-2025 Saleem Abdulrasool #include "DebugServer2/Target/Process.h" +#include + +#include +#include +#include + +namespace { +template +inline void InsertBytes(ds2::ByteVector &bytes, T value) { + uint8_t *data = reinterpret_cast(&value); + bytes.insert(std::end(bytes), data, data + sizeof(T)); +} + +namespace syscalls { +inline void mmap(size_t size, int protection, ds2::ByteVector &code) { + DS2ASSERT(std::log2(MAP_ANON | MAP_PRIVATE) <= 16); + DS2ASSERT(std::log2(SYS_mmap) <= 16); + DS2ASSERT(std::log2(protection) <= 16); + + for (uint32_t instruction: { + static_cast(0xd2800000), // mov x0, 0 + static_cast(0x580000e1), // ldr x1, .Lsize + static_cast(0xd2800002 | protection << 5), // mov x2, protection + static_cast(0xd2800003 | (MAP_ANON | MAP_PRIVATE) << 5), // mov x3, MAP_ANON | MAP_PRIVATE + static_cast(0x92800004), // mov x4, -1 + static_cast(0xd2800005), // mov x5, 0 + static_cast(0xd2800008 | SYS_mmap << 5), // mov x8, =SYS_mmap + static_cast(0xd4000001), // svc 0 + static_cast(0xd43e0000), // brk #0xf000 + // .Lsize: + // .quad size + }) + InsertBytes(code, instruction); + InsertBytes(code, size); +} + +inline void munmap(uintptr_t address, size_t size, ds2::ByteVector &code) { + DS2ASSERT(std::log2(SYS_munmap) <= 16); + + for (uint32_t instruction: { + static_cast(0x580000a0), // ldr x0, .Laddress + static_cast(0x580000c1), // ldr x1, .Lsize + static_cast(0xd2800008 | SYS_munmap << 5), // mov x8, =SYS_munmap + static_cast(0xd4000001), // svc 0 + static_cast(0xd43e0000), // brk #0xf000 + // .Laddress: + // .quad address + // .Lsize: + // .quad size + }) + InsertBytes(code, instruction); + InsertBytes(code, address); + InsertBytes(code, size); +} +} +} + namespace ds2 { namespace Target { namespace Darwin { @@ -18,12 +67,43 @@ ErrorCode Process::allocateMemory(size_t size, uint32_t protection, if (address == nullptr || size == 0) return kErrorInvalidArgument; - *address = 0; - return kErrorUnsupported; + ProcessInfo info; + ErrorCode error = getInfo(info); + if (error != kSuccess) + return error; + + ByteVector code; + syscalls::mmap(size, convertMemoryProtectionFromPOSIX(protection), code); + + error = ptrace().execute(_pid, info, &code[0], code.size(), *address); + if (error != kSuccess) + return error; + + if (*address == reinterpret_cast(MAP_FAILED)) + return kErrorNoMemory; + return kSuccess; } ErrorCode Process::deallocateMemory(uint64_t address, size_t size) { - return kErrorUnsupported; + if (size == 0) + return kErrorInvalidArgument; + + ProcessInfo info; + ErrorCode error = getInfo(info); + if (error != kSuccess) + return error; + + ByteVector code; + syscalls::munmap(address, size, code); + + uint64_t result = 0; + error = ptrace().execute(_pid, info, &code[0], code.size(), result); + if (error != kSuccess) + return error; + + if (static_cast(result) < 0) + return kErrorInvalidArgument; + return kSuccess; } } }