diff --git a/syscall.cpp b/syscall.cpp index bb05be4..37a5c55 100644 --- a/syscall.cpp +++ b/syscall.cpp @@ -139,7 +139,7 @@ interp::Result LibcHostImportDelegate::UnimplCallback(const HostFunc* func, printf("call to unimplemented host method: "); WriteCall(self->stdout_, func->module_name, func->field_name, - vec_args, vec_results, interp::Result::Ok); + vec_args, vec_results, interp::Result::TrapHostTrapped); return interp::Result::TrapHostTrapped; } @@ -194,9 +194,11 @@ enum class SyscallNum : int { close = 6, brk = 45, ioctl = 54, + munmap = 91, llseek = 140, readv = 145, writev = 146, + mmap2 = 192, madvise = 219, exit_group = 252, clock_gettime = 265, @@ -268,6 +270,16 @@ interp::Result SyscallHandler::HandleSyscall(int n, interp::TypedValue* args, In num_args - 2, return_value); + case SyscallNum::munmap: + if (num_args != 2) { + std::cout << "munmap called with invalid arguments\n"; + return interp::Result::TrapHostTrapped; + } + + return HandleMunmap(args[0].value.i32, + args[1].value.i32, + return_value); + case SyscallNum::llseek: if (num_args != 5) { std::cout << "llseek called with invalid arguments\n"; @@ -303,6 +315,20 @@ interp::Result SyscallHandler::HandleSyscall(int n, interp::TypedValue* args, In args[2].value.i32, return_value); + case SyscallNum::mmap2: + if (num_args != 6) { + std::cout << "mmap2 called with invalid arguments\n"; + return interp::Result::TrapHostTrapped; + } + + return HandleMmap(args[0].value.i32, + args[1].value.i32, + args[2].value.i32, + args[3].value.i32, + static_cast(args[4].value.i32), + args[5].value.i32, + return_value); + case SyscallNum::madvise: *return_value = static_cast(-1); return interp::Result::Ok; @@ -418,42 +444,60 @@ interp::Result SyscallHandler::HandleClose(int fd, uint32_t* return_value) { } interp::Result SyscallHandler::HandleBrk(uint32_t addr, uint32_t* return_value) { - auto* mem = env_->GetMemory(0); + *return_value = 0; + return interp::Result::Ok; +} - if (!brk_init_) { - brk_ = mem->data.size(); - brk_init_ = true; - } +interp::Result SyscallHandler::HandleIoctl(int fd, int cmd, interp::TypedValue* args, Index num_args, uint32_t* return_value) { + // TODO Implement this? + *return_value = static_cast(-1); + return interp::Result::Ok; +} - if (!addr) { - *return_value = brk_; +interp::Result SyscallHandler::HandleMunmap(uint32_t address, uint32_t size, uint32_t* return_value) { + auto* mem = env_->GetMemory(0); + + if (address + size < address || address + size > mem->data.size()) { + *return_value = static_cast(-1); + return interp::Result::Ok; + } else if ((address & 0xfff) != 0 || (size & 0xfff) != 0) { + *return_value = static_cast(-1); return interp::Result::Ok; } - uint32_t max_pages = mem->page_limits.has_max ? mem->page_limits.max : WABT_MAX_PAGES; - uint32_t cur_pages = mem->page_limits.initial; + MmapFreeRegion r; - uint32_t new_pages = addr / WABT_PAGE_SIZE; - if (addr % WABT_PAGE_SIZE != 0) new_pages++; + r.start = address; + r.size = size; - if (new_pages > max_pages) { - *return_value = brk_; - return interp::Result::Ok; - } + bool continue_coalescing = true; + + while (continue_coalescing) { + continue_coalescing = false; + + for (auto it = mmap_free_regions_.begin(); it != mmap_free_regions_.end(); ++it) { + auto& r2 = *it; + + if (r2.start + r2.size == address) { + r.start = r2.start; + r.size += r2.size; + mmap_free_regions_.erase(it); + + continue_coalescing = true; + break; + } else if (r2.start == address + size) { + r.size += r2.size; + mmap_free_regions_.erase(it); - if (new_pages > cur_pages) { - mem->data.resize(new_pages * WABT_PAGE_SIZE); - mem->page_limits.initial = new_pages; + continue_coalescing = true; + break; + } + } } - brk_ = addr; - *return_value = brk_; - return interp::Result::Ok; -} + mmap_free_regions_.push_back(r); -interp::Result SyscallHandler::HandleIoctl(int fd, int cmd, interp::TypedValue* args, Index num_args, uint32_t* return_value) { - // TODO Implement this? - *return_value = static_cast(-1); + *return_value = 0; return interp::Result::Ok; } @@ -503,6 +547,73 @@ interp::Result SyscallHandler::HandleWritev(int fd, uint32_t vecs, uint32_t num_ return interp::Result::Ok; } +enum class MmapFlags : uint32_t { + Private = 0x02, + Anonymous = 0x20 +}; + +interp::Result SyscallHandler::HandleMmap(uint32_t address, + uint32_t size, + uint32_t prot, + uint32_t flags, + int fd, + uint32_t off, + uint32_t* return_value) { + if (flags != (static_cast(MmapFlags::Private) | static_cast(MmapFlags::Anonymous))) { + *return_value = static_cast(-1); + return interp::Result::Ok; + } else if (address != 0 || (size & 0xfff) != 0) { + *return_value = static_cast(-1); + return interp::Result::Ok; + } + + auto* mem = env_->GetMemory(0); + + for (auto it = mmap_free_regions_.begin(); it != mmap_free_regions_.end(); ++it) { + auto& r = *it; + + if (r.size == size) { + *return_value = r.start; + memset(reinterpret_cast(mem->data.data() + r.start), 0, size); + + mmap_free_regions_.erase(it); + return interp::Result::Ok; + } else if (r.size > size) { + *return_value = r.start; + memset(reinterpret_cast(mem->data.data() + r.start), 0, size); + + r.start += size; + r.size -= size; + return interp::Result::Ok; + } + } + + uint32_t max_pages = mem->page_limits.has_max ? mem->page_limits.max : WABT_MAX_PAGES; + uint32_t cur_pages = mem->page_limits.initial; + + uint32_t new_pages = cur_pages + ((size + WABT_PAGE_SIZE - 1) & -WABT_PAGE_SIZE) / WABT_PAGE_SIZE; + + if (new_pages > max_pages) { + *return_value = static_cast(-1); + return interp::Result::Ok; + } + + mem->data.resize(new_pages * WABT_PAGE_SIZE); + mem->page_limits.initial = new_pages; + + if (size != (new_pages - cur_pages) * WABT_PAGE_SIZE) { + MmapFreeRegion r; + + r.start = cur_pages * WABT_PAGE_SIZE + size; + r.size = (new_pages - cur_pages) * WABT_PAGE_SIZE - size; + + mmap_free_regions_.push_back(r); + } + + *return_value = cur_pages * WABT_PAGE_SIZE; + return interp::Result::Ok; +} + interp::Result SyscallHandler::HandleClockGetTime(uint32_t clock_id, uint32_t res, uint32_t* return_value) { timespec* res_p; diff --git a/syscall.hpp b/syscall.hpp index b1c709c..87f51d1 100644 --- a/syscall.hpp +++ b/syscall.hpp @@ -7,6 +7,11 @@ namespace wabt { +struct MmapFreeRegion { + uint32_t start; + uint32_t size; +}; + class SyscallHandler { public: SyscallHandler(interp::Environment* env) : env_(env) {} @@ -28,10 +33,11 @@ class SyscallHandler { interp::Result HandleLlseek(int fd, uint32_t off_hi, uint32_t off_lo, uint32_t result, uint32_t whence, uint32_t* return_value); interp::Result HandleReadv(int fd, uint32_t vecs, uint32_t num_vecs, uint32_t* return_value); interp::Result HandleWritev(int fd, uint32_t vecs, uint32_t num_vecs, uint32_t* return_value); + interp::Result HandleMmap(uint32_t address, uint32_t length, uint32_t prot, uint32_t flags, int fd, uint32_t off, uint32_t* return_value); + interp::Result HandleMunmap(uint32_t address, uint32_t length, uint32_t* return_value); interp::Result HandleClockGetTime(uint32_t clock_id, uint32_t res, uint32_t* return_value); - bool brk_init_ = false; - uint32_t brk_; + std::vector mmap_free_regions_; interp::Environment* env_; };