#include "shm_object.h" #include "shm_manager.h" #if defined(__GNUC__) #include #include #define SHM_PATH "/dev/shm" namespace bg { namespace detail { bool GetDirectorySize(const char* path, size_t* const total_size) { bool result = false; char full_path[256]; // [rsp+A0h] [rbp-130h] BYREF DIR* path_dir = opendir(path); if(!path_dir) { return false; } struct dirent64* diren = readdir64(path_dir); if(!diren) { goto RETURN; } while(1) { snprintf(full_path, 0x100uLL, "%s/%s", path, diren->d_name); if(diren->d_type != DT_DIR) break; if(strcmp(diren->d_name, ".") && strcmp(diren->d_name, "..")) { st.st_dev = 0LL; if(!bg::detail::GetDirectorySize(full_path, &st.st_dev)) { goto RETURN; } *total_size += st.st_dev; SHM_INFO("directory entry %s, size: %#lx", full_path, st.st_dev); } READ_DIR: diren = readdir64(path_dir); if(!diren) { result = 1; goto RETURN; } } if(diren->d_type != DT_REG) { SHM_WARN("entry %s, type: %u, ignored.", full_path, v4->d_type); goto READ_DIR; } if(!_lxstat64(1, full_path, (struct stat64*)&st)) { *total_size += st.st_size; SHM_TRACE("file entry %s, size: %#lx", full_path, st.st_size); goto READ_DIR; } SHM_ERROR("lstat() failed, file: % s, error : % s.", full_path, strerror(_errno_location())); RETURN: closedir(v3); return false; } void* ShmObjectCreate(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size) { size_t page_size = sysconf(_SC_PAGESIZE); int fd = shm_open(path, O_CREAT | O_RDWR, 0666); if(fd == -1) { int* error = _errno_location(); v19 = v18; if(*error == 17) { SHM_INFO("shm object(%s) already exists, will be deleted.", path); if(shm_unlink(path)) { SHM_ERROR("shm_unlink() failed, path: %s, error: %s.", path, strerror(*_errno_location())); SHM_ERROR } else { fd = shm_open(path, O_CREAT | O_RDWR, 0666); if(fd != -1) goto OPEN_SUCC; SHM_ERROR("shm_open() failed, path: %s, error: %s.", path, strerror(*_errno_location())); } } else { SHM_ERROR("shm_open() failed, path: %s, error: %s.", path, strerror(*_errno_location())) } return nullptr; } OPEN_SUCC: *real_size = PALIGN_UP(*real_size, page_size); size_t available_size; if(!bg::detail::GetAvailableMemorySize(available_size) || available_size < *real_size) { SHM_ERROR("shared memory not enough, available: %#lx, required: %#lx.", available_size, *real_size); close(fd); shm_unlink(path); return nullptr; } if(!ftruncate64(fd, *real_size)) { int flag; if(*mmap_size < *real_size) { SHM_INFO("mmap size(%#lx) is not enough, revised to real size(%#lx).", *mmap_size, *real_size); *mmap_size = *real_size; } *mmap_size = PALIGN_UP(*mmap_size, page_size); if(fixed_addr) { if(fixed_addr & (page_size - 1)) { uintptr_t new_addr = PALIGN_UP(fixed_addr, page_size); SHM_INFO("ixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", fixed_addr, page_size, new_addr); fixed_addr = new_addr; } flag = MAP_SHARED; } else { flag = MAP_PRIVATE; } LABEL_13: char* mem = mmap64(fixed_addr, mmap_size, PROT_READ | PROT_WRITE, flag, fd, 0); if(mem != MAP_FAILED) { close(fd); return mem; } SHM_ERROR("mmap() failed, addr(% #lx), size(% #lx), error: % s.", old, *mmap_size), strerror(*_errno_location())); } else { SHM_ERROR("ftruncate() failed, path: % s, size : % #lx, error: % s.", path, *real_size, strerror(*_errno_location())); } close(v7); shm_unlink(path); return 0LL; } void* ShmObjectAttach(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size) { size_t page_size = sysconf(_SC_PAGESIZE); int fd = shm_open(path, O_RDWR, 0666); if(fd != -1) { if(_fxstat64(1, fd, (struct stat64*)&st)) { SHM_ERROR("fstat() failed, path: %s, error: %s.", path, strerror(*_errno_location())); LABEL_17: close(v9); return nullptr; } st_size = st.st_size; *real_size = st.st_size; if(st_size > *mmap_size) { SHM_INFO("mmap size(% #lx) is not enough, revised to real size(% #lx).", *mmap_size, st_size, *real_size); *mmap_size = *real_size; } *mmap_size = PALIGN_UP(*mmap_size, page_size); int flag; if(fixed_addr) { if(fixed_addr & (page_size - 1)) { uintptr_t new_addr = PALIGN_UP(fixed_addr, page_size); SHM_INFO("fixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", fixed_addr, page_size, new_addr); } flag = MAP_SHARED; } else { flag = MAP_PRIVATE; } LABEL_9: void* memory = mmap64(fixed_addr, *mmap_size, PROT_READ | PROT_WRITE, flag, fd, 0); if(v1memory5 != (void*)-1LL) { close(fd); return memory; } SHM_ERROR("mmap() failed, addr(%#lx), size(%#lx), error: %s.", memory, *mmap_size, strerror(*_errno_location())); close(fd); return nullptr; } SHM_ERROR("shm_open() failed, path: %s, error: %s.", path, strerror(*_errno_location())); close(fd); return nullptr; } void ShmObjectDelete(void* addr, uintptr_t mmap_size, const char* path) { if(munmap(addr, mmap_size)) { strerror(*v5); SHM_ERROR("munmap() failed, addr(%p), mmap size(%#lx), error: %s.", addr, mmap_size, strerror(_errno_location())); } if(path) { if(shm_unlink(path)) { v4 = _errno_location(); strerror(*v4); SHM_ERROR("shm_unlink() failed, path: %s, error: %s.", path, strerror(_errno_location())); } } } bool ShmObjectResize(const char* path, size_t* new_size) { size_t available_size; // [rsp+8h] [rbp-B8h] BYREF size_t page_size = sysconf(_SC_PAGESIZE); int fd = shm_open(path, O_RDWR, 0666); if(fd != -1) { if(_fxstat64(1, fd, (struct stat64*)&st)) { SHM_ERROR("fstat() failed, path: %s, error: %s.", path, strerror(*_errno_location())); } else { *new_size = PALIGN_UP(*new_size, page_size); st_size = st.st_size; if(st_size >= *new_size) { available_size = 0; if(bg::detail::GetAvailableMemorySize(&available_size)) goto TRUNCAT; } else { available_size = 0; diff = *new_size - st_size; if(bg::detail::GetAvailableMemorySize(&available_size)) { if(diff <= available_size) { TRUNCAT: if(!ftruncate64(fd, *new_size)) { close(v4); return true; } SHM_ERROR("ftruncate() failed, path: %s, size: %#lx, error: %s.", path, *new_size, strerror(*_errno_location())); goto FAIL; } SHM_ERROR("shared memory not enough, available: %#lx, required: %#lx.", available_size, diff); } } } FAIL: close(v4); return false; } SHM_ERROR("shm_open() failed, path: % s, error : % s.", path, strerror(*_errno_location())); return false; } bool GetAvailableMemorySize(size_t* const size) { statvfs st; // [rsp+10h] [rbp-80h] BYREF if(statvfs64("/dev/shm", (struct statvfs64*)&st)) { SHM_ERROR("statvfs() failed, path: %s, error: %s", SHM_PATH, strerror(*_errno_location())); return false; } else { size_t used_size = 0LL; bool ret = bg::detail::GetDirectorySize(SHM_PATH, &used_size); if(ret) { uintptr_t f_bsize = st.f_bsize; uintptr_t f_blocks = st.f_blocks; uintptr_t total_size = st.f_blocks * st.f_bsize; if(total_size < used_size) { return nullptr; } return total_size - used_size; } return ret; } } } } #else #include #include static std::unordered_map g_mapping_handles; namespace bg { namespace detail { bool GetDirectorySize(const char* path, size_t* const total_size) { HANDLE handle = GetCurrentProcess(); if(handle == nullptr) { return false; } PROCESS_MEMORY_COUNTERS pmc; GetProcessMemoryInfo(handle, &pmc, sizeof(pmc)); *total_size = pmc.WorkingSetSize; return true; } void* ShmObjectCreate(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size) { SYSTEM_INFO si; GetSystemInfo(&si); size_t pagesize = si.dwPageSize; size_t align = pagesize - 1; *real_size = PALIGN_UP(*real_size, pagesize); /*size_t available_size; if(!GetAvailableMemorySize(&available_size)) { SHM_ASSERT(false && "ShmObjectCreate GetAvailableMemorySize FAIL"); return nullptr; } if(*real_size > available_size) { SHM_ERROR("shared memory not enough, available: %#lx, required: %#lx.", available_size, *real_size); return nullptr; }*/ HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, (uint32_t)(*real_size >> 32), (uint32_t)(*real_size & 0xffffffff), path); void* addr = nullptr; if(handle == nullptr) { SHM_ERROR("CreateFileMapping(%uz, %s) failed error:%s", *real_size, path, strerror(GetLastError())); return nullptr; } if(GetLastError() == ERROR_ALREADY_EXISTS) { SHM_WARN("shm object(%s) already exists, will be deleted.", path); if(CloseHandle(handle)) { SHM_ERROR("CloseHandle failed, path: %s, error: %s.", path, strerror(GetLastError())); } handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, (uint32_t)(*real_size >> 32), (uint32_t)(*real_size & 0xffffffff), path); if(handle == nullptr) { SHM_ERROR("CreateFileMapping failed, path: %s, error: %s.", strerror(GetLastError())); return nullptr; } if(GetLastError() != NO_ERROR) { goto END; } } if(*mmap_size != *real_size) { SHM_ERROR("mmap size(%#llx) is not enough, revised to real size(%#llx).", *mmap_size, *real_size); *mmap_size = *real_size; } *mmap_size = PALIGN_UP(*mmap_size, pagesize); if(fixed_addr) { uintptr_t base_addr = fixed_addr; if(base_addr & align) { base_addr = PALIGN_UP(fixed_addr, pagesize); SHM_WARN("fixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", base_addr, pagesize, fixed_addr); fixed_addr = base_addr; } } addr = MapViewOfFileEx(handle, FILE_MAP_WRITE, 0, 0, *mmap_size, (void*)fixed_addr); if(addr == nullptr) { SHM_ERROR("CreateFileMapping failed, path: %s, error: %s.", path, strerror(GetLastError())); addr = MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, *mmap_size); } if(addr != nullptr) { g_mapping_handles[path] = handle; return addr; } END: SHM_ERROR("CreateFileMapping failed, path: %s, error: %s.", path, strerror(GetLastError())); CloseHandle(handle); return nullptr; } void* ShmObjectAttach(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size) { SYSTEM_INFO si; GetSystemInfo(&si); size_t pagesize = si.dwPageSize; size_t align = pagesize - 1; HANDLE handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, path); void* addr = nullptr; if(handle == nullptr) { SHM_ERROR("OpenFileMapping(%uz, %s) failed error:%s", *real_size, path, strerror(GetLastError())); return nullptr; } if(*mmap_size < *real_size) { SHM_ERROR("mmap size(%#lx) is not enough, revised to real size(%#lx).", *mmap_size, *real_size); *mmap_size = *real_size; } *mmap_size = PALIGN_UP(*mmap_size, pagesize); if(fixed_addr) { uintptr_t base_addr = fixed_addr; if(base_addr & align) { base_addr = PALIGN_UP(fixed_addr, pagesize); SHM_WARN("fixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", base_addr, pagesize, fixed_addr); fixed_addr = base_addr; } } addr = MapViewOfFileEx(handle, FILE_MAP_WRITE, 0, 0, *mmap_size, (void*)fixed_addr); if(addr == nullptr) { addr = MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, *mmap_size); } if(addr != nullptr) { g_mapping_handles[path] = handle; return addr; } SHM_ERROR("CreateFileMapping failed, path: %s, error: %s.", strerror(GetLastError())); CloseHandle(handle); return nullptr; } void ShmObjectDelete(void* addr, uintptr_t mmap_size, const char* path) { if(UnmapViewOfFile(addr) == 0) { SHM_ERROR("UnmapViewOfFile() failed, addr(%p), mmap size(%#lx), error: %s.", addr, mmap_size, strerror(GetLastError())); } auto itor = g_mapping_handles.find(path); if(itor == g_mapping_handles.end()) { SHM_ASSERT(false); return; } CloseHandle(itor->second); g_mapping_handles.erase(itor); } bool ShmObjectResize(const char* path, size_t* new_size) { return false; } bool GetAvailableMemorySize(size_t* const size) { /*HANDLE handle = GetCurrentProcess(); if(handle == nullptr) { return false; } PROCESS_MEMORY_COUNTERS pmc; GetProcessMemoryInfo(handle, &pmc, sizeof(pmc)); *size = pmc.PeakWorkingSetSize - pmc.WorkingSetSize; return true;*/ return false; } } } #endif