Visual Studio 从哪里获取我的 DLL 的散列来查找符号?

Where does Visual Studio get the hash for my DLL for looking up symbols?

我正在设置我们的私有符号服务器。一切都很好。当我使用符号服务器调试我们的 Nuget 包之一时,观察以下 Resharper 日志:

Searching for 'ClassLibrary1.Class1' type sources in C:\SNIPPED\SymbolCache\ClassLibrary1.pdb180103b9def6ca85f41230aaf9a4611\ClassLibrary1.pdb
Downloader: https ://LOCAL_SYMBOL_SVR/app/sources/builds/id-1641/sources/files/ClassLibrary1/Class1.cs -> ok, 268 bytes

看到哈希,91180103b9def6ca85f41230aaf9a4611?请注意,它是 33 位数字。

我认为它可能存储在 PE header 中,但 dumpbin.exe /all DLL 在其输出中不包含哈希。

该哈希从何而来?它是否存储在 DLL 的某处?如果是这样,它是如何存储的,存储在哪里?

if PE 使用调试信息构建 - 必须存在 IMAGE_DEBUG_DIRECTORY in it with IMAGE_DEBUG_TYPE_CODEVIEW. so first debugger search for array of IMAGE_DEBUG_DIRECTORY elements (it can be multiple). this array located at IMAGE_DIRECTORY_ENTRY_DEBUG data directory. for IMAGE_DEBUG_TYPE_CODEVIEW debug info now locate in format RSDS

struct RSDSI                       // RSDS debug info
{
    DWORD   dwSig;                 // RSDSI
    GUID    guidSig;
    DWORD   age;
    char    szPdb[];
};

你所说的 "hash" 这实际上不是从 guidSigage 格式化为 %08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x 的散列

dwSig 必须等于 'SDSR'szPdb 存储为 utf8 字符串 代码示例:

ULONG FormatPdbPath(PWSTR* ppdbPath, PCWSTR SymbolsPath, PCSTR PdbFileName, LPGUID Signature, DWORD Age)
{
    ULONG UTF8StringByteCount = (ULONG)strlen(PdbFileName) + 1;

    ULONG UnicodeStringLen = MultiByteToWideChar(CP_UTF8, 0, PdbFileName, UTF8StringByteCount, 0, 0);

    if (!UnicodeStringLen)
    {
        return ERROR_GEN_FAILURE;
    }

    if (UnicodeStringLen >= MAXSHORT)
    {
        return ERROR_FILENAME_EXCED_RANGE;
    }

    PWSTR FileName = (PWSTR)alloca(UnicodeStringLen * sizeof(WCHAR));

    UnicodeStringLen = MultiByteToWideChar(CP_UTF8, 0, PdbFileName, UTF8StringByteCount, FileName, UnicodeStringLen);

    if (!UnicodeStringLen)
    {
        return ERROR_GEN_FAILURE;
    }

    if (PWSTR pdbPath = new WCHAR[2 * UnicodeStringLen + wcslen(SymbolsPath) + 42])
    {
        *ppdbPath = pdbPath;

        swprintf(pdbPath, L"%s\%s\%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x\%s", 
            SymbolsPath, FileName, 
            Signature->Data1, Signature->Data2, Signature->Data3,
            Signature->Data4[0], Signature->Data4[1], Signature->Data4[2], Signature->Data4[3], 
            Signature->Data4[4], Signature->Data4[5], Signature->Data4[6], Signature->Data4[7], 
            Age, FileName);

        return NOERROR;
    }

    return ERROR_NO_SYSTEM_RESOURCES;
}

ULONG FormatPdbPath(PWSTR* ppdbPath, PCWSTR SymbolsPath, PCWSTR lpszName)
{
    HMODULE hmod = LoadLibraryExW(lpszName, 0, LOAD_LIBRARY_AS_DATAFILE);

    if (!hmod) return GetLastError();

    ULONG status = ERROR_NOT_FOUND;

    DWORD cb;
    BOOLEAN bMappedAsImage = !((DWORD_PTR)hmod & (PAGE_SIZE - 1));

    PIMAGE_DEBUG_DIRECTORY pidd = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(hmod, bMappedAsImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &cb);

    if (pidd && cb && !(cb % sizeof(IMAGE_DEBUG_DIRECTORY)))
    {
        do 
        {
            struct RSDSI                       // RSDS debug info
            {
                DWORD   dwSig;                 // RSDSI
                GUID    guidSig;
                DWORD   age;
                char    szPdb[];
            };

            if (pidd->Type == IMAGE_DEBUG_TYPE_CODEVIEW && pidd->SizeOfData > sizeof(RSDSI))
            {
                if (DWORD PointerToRawData = bMappedAsImage ? pidd->AddressOfRawData : pidd->PointerToRawData)
                {
                    RSDSI* lpcvh = (RSDSI*)RtlOffsetToPointer(PAGE_ALIGN(hmod), PointerToRawData);

                    if (lpcvh->dwSig == 'SDSR')
                    {
                        PCSTR szPdb = lpcvh->szPdb, c = strrchr(szPdb, L'\');

                        if (c)
                        {
                            szPdb = c + 1;
                        }

                        status = FormatPdbPath(ppdbPath, SymbolsPath, szPdb, &lpcvh->guidSig, lpcvh->age);

                        break;
                    }
                }
            }

        } while (pidd++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY));
    }

    FreeLibrary(hmod);

    return status;
}

void test(PCWSTR SymbolsPath, PCWSTR lpszName)
{
    PWSTR pdbPath;
    if (!FormatPdbPath(&pdbPath, SymbolsPath, lpszName))
    {
        DbgPrint("%S\n", pdbPath);
        delete [] pdbPath;
    }
}

void test2(PCWSTR SymbolsPath = L"C:\SNIPPED\SymbolCache")
{
    WCHAR myExe[MAX_PATH];
    GetModuleFileNameW(0, myExe, RTL_NUMBER_OF(myExe));
    test(SymbolsPath, myExe);
    test(SymbolsPath, L"hal.dll");
    test(SymbolsPath, L"drivers/ntfs.sys");
    test(SymbolsPath, L"kernel32.dll");
}