@@ -614,44 +614,85 @@ static std::optional<std::string> GetFileNameByLoadAddress(HANDLE hProcess,
614614 return dos_path;
615615}
616616
617+ // Determine how many bytes can be read at `addr` in `hProcess` before crossing
618+ // out of the committed memory region containing it. Returns 0 if the address is
619+ // not within a committed region.
620+ static SIZE_T BytesReadableAt (HANDLE hProcess, LPCVOID addr) {
621+ MEMORY_BASIC_INFORMATION mbi{};
622+ if (!::VirtualQueryEx (hProcess, addr, &mbi, sizeof (mbi)))
623+ return 0 ;
624+ if (mbi.State != MEM_COMMIT)
625+ return 0 ;
626+ uintptr_t region_end =
627+ reinterpret_cast <uintptr_t >(mbi.BaseAddress ) + mbi.RegionSize ;
628+ uintptr_t a = reinterpret_cast <uintptr_t >(addr);
629+ assert (a < region_end);
630+ return region_end - a;
631+ }
632+
633+ static std::optional<std::string> ReadRemotePathStringW (HANDLE hProcess,
634+ LPCVOID addr) {
635+ SIZE_T to_read = std::min<SIZE_T>((MAX_PATH + 1 ) * sizeof (wchar_t ),
636+ BytesReadableAt (hProcess, addr));
637+ to_read &= ~SIZE_T (1 ); // round down to a wchar_t boundary
638+ if (to_read < sizeof (wchar_t ))
639+ return std::nullopt ;
640+
641+ std::array<wchar_t , MAX_PATH + 1 > buf{};
642+ SIZE_T bytes_read = 0 ;
643+ if (!::ReadProcessMemory (hProcess, addr, buf.data (), to_read, &bytes_read))
644+ return std::nullopt ;
645+
646+ size_t max_chars = bytes_read / sizeof (wchar_t );
647+ size_t len = ::wcsnlen (buf.data (), max_chars);
648+ if (len == max_chars) // no null terminator found
649+ return std::nullopt ;
650+ if (len == 0 ) // empty string
651+ return std::nullopt ;
652+
653+ std::string result;
654+ llvm::convertWideToUTF8 (std::wstring (buf.data (), len), result);
655+ return result;
656+ }
657+
658+ static std::optional<std::string> ReadRemotePathStringA (HANDLE hProcess,
659+ LPCVOID addr) {
660+ SIZE_T to_read =
661+ std::min<SIZE_T>(MAX_PATH + 1 , BytesReadableAt (hProcess, addr));
662+ if (to_read == 0 )
663+ return std::nullopt ;
664+
665+ std::array<char , MAX_PATH + 1 > buf{};
666+ SIZE_T bytes_read = 0 ;
667+ if (!::ReadProcessMemory (hProcess, addr, buf.data (), to_read, &bytes_read))
668+ return std::nullopt ;
669+
670+ size_t len = ::strnlen (buf.data (), bytes_read);
671+ if (len == bytes_read) // no null terminator found
672+ return std::nullopt ;
673+ if (len == 0 ) // empty string
674+ return std::nullopt ;
675+
676+ return std::string (buf.data (), len);
677+ }
678+
617679// Resolve the LOAD_DLL_DEBUG_INFO::lpImageName field.
618680static std::optional<std::string>
619681GetFileNameFromImageNameField (HANDLE hProcess,
620682 const LOAD_DLL_DEBUG_INFO &info) {
621683 if (info.lpImageName == nullptr )
622684 return std::nullopt ;
623685
624- LPVOID name_addr = nullptr ;
686+ LPVOID string_addr = nullptr ;
625687 SIZE_T bytes_read = 0 ;
626- if (!::ReadProcessMemory (hProcess, info.lpImageName , &name_addr ,
627- sizeof (name_addr ), &bytes_read) ||
628- bytes_read != sizeof (name_addr) || name_addr == nullptr )
688+ if (!::ReadProcessMemory (hProcess, info.lpImageName , &string_addr ,
689+ sizeof (string_addr ), &bytes_read) ||
690+ bytes_read != sizeof (string_addr) )
629691 return std::nullopt ;
630692
631- if (info.fUnicode ) {
632- std::array<wchar_t , MAX_PATH + 1 > wbuf{};
633- if (!::ReadProcessMemory (hProcess, name_addr, wbuf.data (),
634- wbuf.size () * sizeof (wchar_t ), &bytes_read))
635- return std::nullopt ;
636- if (wbuf[MAX_PATH] != L' \0 ' )
637- return std::nullopt ;
638- std::string path_utf8;
639- llvm::convertWideToUTF8 (wbuf.data (), path_utf8);
640- if (path_utf8.empty ())
641- return std::nullopt ;
642- return path_utf8;
643- }
644-
645- std::array<char , MAX_PATH + 1 > abuf{};
646- if (!::ReadProcessMemory (hProcess, name_addr, abuf.data (), abuf.size (),
647- &bytes_read))
648- return std::nullopt ;
649- if (abuf[MAX_PATH] != ' \0 ' )
650- return std::nullopt ;
651- std::string path (abuf.data ());
652- if (path.empty ())
653- return std::nullopt ;
654- return path;
693+ if (info.fUnicode )
694+ return ReadRemotePathStringW (hProcess, string_addr);
695+ return ReadRemotePathStringA (hProcess, string_addr);
655696}
656697
657698DWORD
0 commit comments