f7699740cc
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>
145 lines
3.9 KiB
C++
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_
|