This small test project use mspdbcore.dll (v12->) to write pdb.
It reads test2.dbg in test.
Use temporary files in tests.
SYMSRV: C:\code\x64dbg\x64\symbols\hello-msvcrt64.pdb\5BEB47315BE54758B90D5ED6BBE9CD131\hello-msvcrt64.pdb not found
DBGHELP: hello-msvcrt64 - public symbols
C:\code\PellesC\V9\mspdb\test\temp\hello-msvcrt64.pdb
EDIT: another version that needs msobjxx.dll too.
EDIT: analyze pdb with this code:#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdint.h>
//#include "msf.h"
// https://llvm.org/docs/PDB/MsfFile.html
const char Magic[] = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\0\0";
typedef struct SuperBlock {
char FileMagic[32]; //sizeof(Magic)];
uint32_t BlockSize;
uint32_t FreeBlockMapBlock;
uint32_t NumBlocks;
uint32_t NumDirectoryBytes;
uint32_t Unknown;
uint32_t BlockMapAddr;
}SUPERBLOCK,*PSUPERBLOCK;
typedef struct StreamDirectory {
uint32_t NumStreams;
uint32_t StreamSizes; //[NumStreams];
uint32_t StreamBlocks[]; //[NumStreams][];
}STREAMDIRECTORY,*PSTREAMDIRECTORY;
typedef struct PdbStreamHeader {
uint32_t Version; // VC70 20000404 1312E94h
uint32_t Signature;
uint32_t Age;
GUID UniqueId;
}PDBSTREAMHEADER,*PPDBSTREAMHEADER;
typedef struct DbiStreamHeader {
int32_t VersionSignature;
uint32_t VersionHeader;
uint32_t Age;
uint16_t GlobalStreamIndex;
uint16_t BuildNumber;
uint16_t PublicStreamIndex;
uint16_t PdbDllVersion;
uint16_t SymRecordStream;
uint16_t PdbDllRbld;
int32_t ModInfoSize;
int32_t SectionContributionSize;
int32_t SectionMapSize;
int32_t SourceInfoSize;
int32_t TypeServerSize;
uint32_t MFCTypeServerIndex;
int32_t OptionalDbgHeaderSize;
int32_t ECSubstreamSize;
uint16_t Flags;
uint16_t Machine;
uint32_t Padding;
}DBISTREAMHEADER, *PDBISTREAMHEADER;
int ProcessFile(PBYTE pMem);
int main(int argc, char **argv)
{
HANDLE hFile, hMapping;
VOID *pMem;
if (argc < 2) {
puts("Usage: TestMsf.exe <file>");
return 1;
}
hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMapping)
{
pMem = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
if (pMem)
{
ProcessFile(pMem);
UnmapViewOfFile(pMem);
} else
puts("File open error");
CloseHandle(hMapping);
} else
puts("FileMapping error");
CloseHandle(hFile);
}
else
puts("File open error");
return 0;
}
int ProcessFile(PBYTE pMem)
{
SUPERBLOCK *pMsfHdr = (SUPERBLOCK*)pMem;
printf("FileMagic: %s\n", pMsfHdr->FileMagic);
printf("BlockSize: %u\n", pMsfHdr->BlockSize);
printf("FreeBlockMapBlock: %u -> %Xh\n", pMsfHdr->FreeBlockMapBlock,
pMsfHdr->FreeBlockMapBlock*pMsfHdr->BlockSize);
printf("NumBlocks: %u\n", pMsfHdr->NumBlocks);
printf("NumDirectoryBytes: %u\n", pMsfHdr->NumDirectoryBytes);
printf("Unknown: %u\n", pMsfHdr->Unknown);
printf("BlockMapAddr: %u -> %Xh\n", pMsfHdr->BlockMapAddr,
pMsfHdr->BlockMapAddr*pMsfHdr->BlockSize);
printf("\nfilesize: %u\n", pMsfHdr->BlockSize*pMsfHdr->NumBlocks);
DWORD *pIndexes = (DWORD*)(pMem+pMsfHdr->BlockMapAddr*pMsfHdr->BlockSize);
DWORD *pIndex = pIndexes; // the first Index Block
printf("\nStreamDir indexes:");
while (*pIndex)
printf("%04Xh ", *pIndex++);
pIndex = pIndexes; // the first Index Block
printf("\nStreamDir Block %u -> %Xh\n", *pIndex, *pIndex*pMsfHdr->BlockSize);
PSTREAMDIRECTORY pStreamDir = (PSTREAMDIRECTORY)(pMem+*pIndex*pMsfHdr->BlockSize);
printf("NumStreams %u\n", pStreamDir->NumStreams);
DWORD nStreams = pStreamDir->NumStreams;
//DWORD *pDW = (DWORD*)&pStreamDir->StreamSizes;
DWORD *pStreamSizes = &pStreamDir->StreamSizes;
printf("StreamSizes[] = ");
for (DWORD nC=0; nC<nStreams; nC++)
printf("%d ", pStreamSizes[nC]);
printf("\nStreamBlocks[] = ");
DWORD *pStreamBlocks = &pStreamDir->StreamSizes;
pStreamBlocks += nStreams;
for (DWORD nC=0; nC<nStreams; nC++)
printf("%d ", pStreamBlocks[nC]);
printf("\n");
printf("Version VC70 20000404 %Xh\n", 20000404);
for (DWORD nC=0; nC<nStreams; nC++) {
if (pStreamBlocks[nC] && pStreamSizes[nC]) {
DWORD nBlock = pStreamBlocks[nC]*pMsfHdr->BlockSize;
//printf("%p\n", pStreamBlocks[nC]*pMsfHdr->BlockSize);
printf("%02u %p %Xh\n", pStreamBlocks[nC], nBlock, *(DWORD*)(pMem+nBlock));
if (*(DWORD*)(pMem+nBlock) == 0x1312E94) {
PPDBSTREAMHEADER pStreamheader = (PPDBSTREAMHEADER)(pMem+nBlock);
printf("\tPdbStreamHeader Version: %u\n", pStreamheader->Version);
}
if (*(DWORD*)(pMem+nBlock) == 0xFFFFFFFF) {
printf("\t%Xh\n", *(DWORD*)(pMem+nBlock+4));
if (*(DWORD*)(pMem+nBlock+4) == 0x1310977) {
PDBISTREAMHEADER pDBIHdr = (PDBISTREAMHEADER)(pMem+nBlock);
printf("\tDBI V70\n");
printf("\tVersionSignature: %Xh\n", pDBIHdr->VersionSignature);
printf("\tVersionHeader: %Xh\n", pDBIHdr->VersionHeader);
printf("\tGlobalStreamIndex: %u -> %Xh\n", pDBIHdr->GlobalStreamIndex,
pDBIHdr->GlobalStreamIndex*pMsfHdr->BlockSize);
printf("\tPublicStreamIndex: %u -> %Xh\n", pDBIHdr->PublicStreamIndex,
pDBIHdr->PublicStreamIndex*pMsfHdr->BlockSize);
printf("\tSymRecordStream: %u -> %Xh\n", pDBIHdr->SymRecordStream,
pDBIHdr->SymRecordStream*pMsfHdr->BlockSize);
printf("\tFlags: %Xh\n", pDBIHdr->Flags);
printf("\tMachine: %Xh\n", pDBIHdr->Machine);
}
}
}
}
return 0;
}