/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "FileUtilsWin.h" #include #include #include "base/process_util.h" #include "mozilla/ProfilerLabels.h" #include "mozilla/ScopeExit.h" #include "mozilla/Unused.h" #include "nsWindowsHelpers.h" namespace mozilla { bool HandleToFilename(HANDLE aHandle, const LARGE_INTEGER& aOffset, nsAString& aFilename) { AUTO_PROFILER_LABEL("HandletoFilename", OTHER); aFilename.Truncate(); // This implementation is nice because it uses fully documented APIs that // are available on all Windows versions that we support. nsAutoHandle fileMapping( CreateFileMapping(aHandle, nullptr, PAGE_READONLY, 0, 1, nullptr)); if (!fileMapping) { return false; } const auto view = MapViewOfFile(fileMapping, FILE_MAP_READ, aOffset.HighPart, aOffset.LowPart, 1); if (!view) { return false; } const auto cleanup = MakeScopeExit([&]() { mozilla::Unused << UnmapViewOfFile(view); }); nsAutoString mappedFilename; DWORD len = 0; SetLastError(ERROR_SUCCESS); do { mappedFilename.SetLength(mappedFilename.Length() + MAX_PATH); len = GetMappedFileNameW(GetCurrentProcess(), view, mappedFilename.get(), mappedFilename.Length()); } while (!len && GetLastError() == ERROR_INSUFFICIENT_BUFFER); if (!len) { return false; } mappedFilename.Truncate(len); return NtPathToDosPath(mappedFilename, aFilename); } template struct RVAMap { RVAMap(HANDLE map, DWORD offset) { SYSTEM_INFO info; GetSystemInfo(&info); DWORD alignedOffset = (offset / info.dwAllocationGranularity) * info.dwAllocationGranularity; MOZ_ASSERT(offset - alignedOffset < info.dwAllocationGranularity, "Wtf"); mRealView = ::MapViewOfFile(map, FILE_MAP_READ, 0, alignedOffset, sizeof(T) + (offset - alignedOffset)); mMappedView = mRealView ? reinterpret_cast((char*)mRealView + (offset - alignedOffset)) : nullptr; } ~RVAMap() { if (mRealView) { ::UnmapViewOfFile(mRealView); } } operator const T*() const { return mMappedView; } const T* operator->() const { return mMappedView; } private: const T* mMappedView; void* mRealView; }; uint32_t GetExecutableArchitecture(const wchar_t* aPath) { nsAutoHandle file(::CreateFileW(aPath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); if (!file) { return base::PROCESS_ARCH_INVALID; } nsAutoHandle map( ::CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr)); if (!map) { return base::PROCESS_ARCH_INVALID; } RVAMap peHeader(map, 0); if (!peHeader) { return base::PROCESS_ARCH_INVALID; } RVAMap ntHeader(map, peHeader->e_lfanew); if (!ntHeader) { return base::PROCESS_ARCH_INVALID; } switch (ntHeader->FileHeader.Machine) { case IMAGE_FILE_MACHINE_I386: return base::PROCESS_ARCH_I386; case IMAGE_FILE_MACHINE_AMD64: return base::PROCESS_ARCH_X86_64; case IMAGE_FILE_MACHINE_ARM64: return base::PROCESS_ARCH_ARM_64; case IMAGE_FILE_MACHINE_ARM: case IMAGE_FILE_MACHINE_ARMNT: case IMAGE_FILE_MACHINE_THUMB: return base::PROCESS_ARCH_ARM; default: return base::PROCESS_ARCH_INVALID; } } } // namespace mozilla