Files
Tess Strickland f7699740cc [vm] Allow manual loading of Mach-O dynamic library snapshots.
Adds a Mach-O loader, similar to the existing ELF loader, that
can be used on platforms that do not support loading Mach-O dynamic
libraries via dlopen().

Other changes:

* Renames the --force-load-elf-from-memory command line argument
  to --force-load-from-memory.
* Use CPU_TYPE_ANY and CPU_SUBTYPE_ANY for architectures that do
  not have specific constants in <mach/machine.h> (e.g., RISCV),
  as the snapshot header check after loading also catches architecture
  mismatches.
* Emit the unwinding information at the end of the text segment
  for Windows Mach-O snapshots as is done for ELF ones.

TEST=vm/dart/unobfuscated_static_symbols_test
     vm/dart/use_dwarf_stack_traces_flag_test

Issue: https://github.com/dart-lang/sdk/issues/60307
Change-Id: I34a2a334f47d18d5c4f4a712956e71fd0ac94024
Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-x64-try,vm-mac-release-arm64-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-dwarf-linux-product-x64-try,vm-linux-debug-x64-try,vm-mac-debug-arm64-try,vm-fuchsia-release-x64-try,vm-fuchsia-release-arm64-try,vm-linux-debug-ia32-try,vm-aot-linux-debug-simarm_x64-try,vm-aot-linux-debug-simriscv32-try,vm-aot-linux-debug-simriscv64-try,vm-aot-linux-release-simarm_x64-try,vm-gcc-linux-try,vm-ubsan-linux-release-arm64-try,vm-aot-win-release-arm64-try,vm-aot-win-release-x64-try,vm-win-release-x64-try,vm-win-release-arm64-try,vm-aot-win-debug-arm64-try,vm-win-debug-arm64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430100
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2025-06-03 05:56:59 -07:00

145 lines
3.9 KiB
C++

// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_BIN_MAPPABLE_H_
#define RUNTIME_BIN_MAPPABLE_H_
#include "platform/globals.h"
#include "bin/file.h"
#include "bin/virtual_memory.h"
namespace dart {
namespace bin {
class Mappable {
public:
static Mappable* FromPath(const char* path);
#if defined(DART_HOST_OS_FUCHSIA) || defined(DART_HOST_OS_LINUX)
static Mappable* FromFD(int fd);
#endif
static Mappable* FromMemory(const uint8_t* memory, size_t size);
virtual MappedMemory* Map(File::MapType type,
uint64_t position,
uint64_t length,
void* start = nullptr) = 0;
virtual bool SetPosition(uint64_t position) = 0;
virtual bool ReadFully(void* dest, int64_t length) = 0;
virtual ~Mappable() {}
protected:
Mappable() {}
private:
DISALLOW_COPY_AND_ASSIGN(Mappable);
};
class FileMappable : public Mappable {
public:
explicit FileMappable(File* file) : Mappable(), file_(file) {}
~FileMappable() override { file_->Release(); }
MappedMemory* Map(File::MapType type,
uint64_t position,
uint64_t length,
void* start = nullptr) override {
return file_->Map(type, position, length, start);
}
bool SetPosition(uint64_t position) override {
return file_->SetPosition(position);
}
bool ReadFully(void* dest, int64_t length) override {
return file_->ReadFully(dest, length);
}
private:
File* const file_;
DISALLOW_COPY_AND_ASSIGN(FileMappable);
};
class MemoryMappable : public Mappable {
public:
MemoryMappable(const uint8_t* memory, size_t size)
: Mappable(), memory_(memory), size_(size), position_(memory) {}
~MemoryMappable() override {}
MappedMemory* Map(File::MapType type,
uint64_t position,
uint64_t length,
void* start = nullptr) override {
if (position > size_) return nullptr;
MappedMemory* result = nullptr;
const uword map_size = Utils::RoundUp(length, VirtualMemory::PageSize());
if (start == nullptr) {
auto* memory = VirtualMemory::Allocate(
map_size, type == File::kReadExecute, "dart-compiled-image");
if (memory == nullptr) return nullptr;
result = new MappedMemory(memory->address(), memory->size());
memory->release();
delete memory;
} else {
result = new MappedMemory(start, map_size,
/*should_unmap=*/false);
}
size_t remainder = 0;
if ((position + length) > size_) {
remainder = position + length - size_;
length = size_ - position;
}
memcpy(result->address(), memory_ + position, length); // NOLINT
memset(reinterpret_cast<uint8_t*>(result->address()) + length, 0,
remainder);
auto mode = VirtualMemory::kReadOnly;
switch (type) {
case File::kReadExecute:
mode = VirtualMemory::kReadExecute;
break;
case File::kReadWrite:
mode = VirtualMemory::kReadWrite;
break;
case File::kReadOnly:
mode = VirtualMemory::kReadOnly;
break;
default:
UNREACHABLE();
}
VirtualMemory::Protect(result->address(), result->size(), mode);
return result;
}
bool SetPosition(uint64_t position) override {
if (position > size_) return false;
position_ = memory_ + position;
return true;
}
bool ReadFully(void* dest, int64_t length) override {
if ((position_ + length) > (memory_ + size_)) return false;
memcpy(dest, position_, length);
return true;
}
private:
const uint8_t* const memory_;
const size_t size_;
const uint8_t* position_;
DISALLOW_COPY_AND_ASSIGN(MemoryMappable);
};
} // namespace bin
} // namespace dart
#endif // RUNTIME_BIN_MAPPABLE_H_