Newer
Older
alicedbg / dumper / format / pdb70.d
/// PDB 7.00 dumper
///
/// Authors: dd86k <dd@dax.moe>
/// Copyright: © dd86k <dd@dax.moe>
/// License: BSD-3-Clause-Clear
module format.pdb70;

import adbg.disassembler;
import adbg.object.server;
import adbg.machines;
import adbg.object.format.pdb;
import adbg.object.format.pe : adbg_object_pe_machine_string;
import adbg.utils.uid;
import adbg.utils.date;
import adbg.include.c.stdio : printf, snprintf, putchar;
import dumper;

extern (C):

int dump_pdb70(adbg_object_t *o) {
	if (selected_headers())
		dump_pdb70_header(o);
	
	if (selected_debug())
		dump_pdb70_debug(o);
	
	return 0;
}

private:

void dump_pdb70_header(adbg_object_t *o) {
	print_header("Header");
	
	pdb70_file_header *header = adbg_object_pdb70_header(o);
	
	print_stringl("Magic", header.Magic.ptr, 24);
	print_u32("PageSize", header.PageSize);
	print_u32("FreeIndex", header.FreeIndex);
	print_u32("PageCount", header.PageCount);
	print_u32("DirectorySize", header.DirectorySize);
	print_x32("Unknown", header.Unknown);
	print_x32("DirectoryOffset", header.DirectoryOffset);
	
	print_header("FPM information");
	uint bitcnt = header.PageCount / 8;
	for (uint biti; biti < bitcnt; ++biti) {
		char[48] buf = void;
		uint blocknum = biti * 8;
		snprintf(buf.ptr, 48, "Block %u-%u", blocknum, blocknum + 7);
		print_x8(buf.ptr, o.i.pdb70.fpm[biti]);
	}
	
	print_header("Stream information");
	print_u32("Stream count", o.i.pdb70.strcnt);
	uint strcnt = o.i.pdb70.strcnt;
	uint blkoffi;
	// NOTE: Avoid using internal section map in case it changes
	for (uint stri; stri < strcnt; ++stri) {
		uint size = o.i.pdb70.strsize[stri];
		
		// Print field name
		char[48] buf = void;
		snprintf(buf.ptr, 48, "Stream %u", stri);
		print_name(buf.ptr);
		
		// Skip if empty
		//TODO: Check with FPM?
		if (size == 0 || size == PDB_BLOCK_SIZE_UNUSED) {
			putchar('\n');
			continue;
		}
		
		// Print size + associated blocks
		printf("%u\t(", size);
		uint blkcnt = (size + header.PageSize - 1) / header.PageSize;
		for (uint blki; blki < blkcnt; ++blki) {
			if (blki) putchar(',');
			printf("%u", o.i.pdb70.stroff[blkoffi++]);
		}
		printf(")\n");
	}
}

void dump_pdb70_debug(adbg_object_t *o) {
	print_header("Debug");
	
	static immutable string[] StreamNames = [
		"Old MSF Directory",
		"PDB Stream",
		"TPI Stream",
		"DBI Stream",
		"IPI Stream",
	];
	
	void *buffer;
	uint  strsize;
	
	// Stream 0 - Old MSF directory
	
	print_section(0, StreamNames[0].ptr, cast(int)StreamNames[0].length);
	if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.pdb)) {
		print_string("error", "Couldn't read Stream 0");
		return;
	}
	if (strsize) {
		print_hexdump("Stream 0 Data", buffer, strsize);
	}
	adbg_object_pdb70_stream_close(o, &buffer);
	
	// Stream 1
	
	print_section(1, StreamNames[1].ptr, cast(int)StreamNames[1].length);
	if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.pdb)) {
		print_string("error", "Couldn't read Stream 1");
		return;
	}
	if (strsize >= pdb70_pdb_header.sizeof) {
		pdb70_pdb_header *pdb = cast(pdb70_pdb_header*)buffer;
		const(char) *vcver = void;
		switch (pdb.Version) with (PdbRaw_PdbVersion) {
		case vc2:	vcver = "VC2"; break;
		case vc4:	vcver = "VC4"; break;
		case vc41:	vcver = "VC41"; break;
		case vc50:	vcver = "VC50"; break;
		case vc98:	vcver = "VC98"; break;
		case vc70_old:	vcver = "VC70_OLD"; break;
		case vc70:	vcver = "VC70"; break;
		case vc80:	vcver = "VC80"; break;
		case vc110:	vcver = "VC110"; break;
		case vc140:	vcver = "VC140"; break;
		default:	vcver = "Unknown";
		}
		
		char[UID_TEXTLEN] uidstr = void;
		int uidlen = uid_string(pdb.UniqueId, uidstr.ptr, UID_TEXTLEN, UID_GUID);
		print_u32("Version", pdb.Version, vcver);
		print_x32("Signature", pdb.Signature);
		print_u32("Age", pdb.Age);
		print_stringl("UniqueID", uidstr.ptr, uidlen);
		
		/*void *leftover = buffer + pdb70_pdb_header.sizeof;
		size_t leftlen = strsize - pdb70_pdb_header.sizeof;
		
		print_raw("Stream 1 Data", leftover, leftlen);*/
	}
	adbg_object_pdb70_stream_close(o, &buffer);
	
	// Stream 2
	
	print_section(2, StreamNames[2].ptr, cast(int)StreamNames[2].length);
	if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.tpi)) {
		print_string("error", "Couldn't read Stream 2");
		return;
	}
	if (strsize >= pdb70_tpi_header.sizeof) {
		pdb70_tpi_header *tpi = cast(pdb70_tpi_header*)buffer;
		const(char) *vcver = void;
		switch (tpi.Version) with (PdbRaw_TpiVer) {
		case v40:	vcver = "v40"; break;
		case v41:	vcver = "v41"; break;
		case v50:	vcver = "v50"; break;
		case v70:	vcver = "v70"; break;
		case v80:	vcver = "v80"; break;
		default:	vcver = "Unknown";
		}
		
		print_u32("Version", tpi.Version, vcver);
		print_u32("HeaderSize", tpi.HeaderSize);
		print_u32("TypeIndexBegin", tpi.TypeIndexBegin);
		print_u32("TypeIndexEnd", tpi.TypeIndexEnd);
		print_u32("TypeRecordBytes", tpi.TypeRecordBytes);
		
		print_u16("HashStreamIndex", tpi.HashStreamIndex);
		print_u16("HashAuxStreamIndex", tpi.HashAuxStreamIndex);
		print_u32("HashKeySize", tpi.HashKeySize);
		print_u32("NumHashBuckets", tpi.NumHashBuckets);
		
		print_u32("HashValueBufferOffset", tpi.HashValueBufferOffset);
		print_u32("HashValueBufferLength", tpi.HashValueBufferLength);
		
		print_u32("IndexOffsetBufferOffset", tpi.IndexOffsetBufferOffset);
		print_u32("IndexOffsetBufferLength", tpi.IndexOffsetBufferLength);
		
		print_u32("HashAdjBufferOffset", tpi.HashAdjBufferOffset);
		print_u32("HashAdjBufferLength", tpi.HashAdjBufferLength);
		
		/*void *leftover = buffer + pdb70_tpi_header.sizeof;
		size_t leftlen = strsize - pdb70_tpi_header.sizeof;
		
		print_raw("Stream 2 Data", leftover, leftlen);*/
	}
	adbg_object_pdb70_stream_close(o, &buffer);
	
	// Stream 3
	
	print_section(3, StreamNames[3].ptr, cast(int)StreamNames[3].length);
	if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.dbi)) {
		print_string("error", "Couldn't read Stream 3");
		return;
	}
	if (strsize >= pdb70_dbi_header.sizeof) {
		pdb70_dbi_header *dbi = cast(pdb70_dbi_header*)buffer;
		
		const(char) *vcver = void;
		switch (dbi.VersionHeader) with (PdbRaw_DbiVer) {
		case v41:	vcver = "v41"; break;
		case v50:	vcver = "v50"; break;
		case v60:	vcver = "v60"; break;
		case v70:	vcver = "v70"; break;
		case v110:	vcver = "v110"; break;
		default:	vcver = "Unknown";
		}
		
		// 255.127-1
		char[16] buildnum = void;
		snprintf(buildnum.ptr, 16, "%u.%u-%u",
			dbi.BuildNumber >> 8 & 0x7f,	// MajorVersion
			cast(ubyte)dbi.BuildNumber,	// MinorVersion
			dbi.BuildNumber >> 15);	// NewVersionFormat
		
		print_x32("VersonSignature", dbi.VersonSignature);
		print_u32("VersionHeader", dbi.VersionHeader, vcver);
		print_u32("Age", dbi.Age);
		print_u16("GlobalStreamIndex", dbi.GlobalStreamIndex);
		print_x16("BuildNumber", dbi.BuildNumber, buildnum.ptr);
		print_u16("PublicStreamIndex", dbi.PublicStreamIndex);
		print_u16("PdbDllVersion", dbi.PdbDllVersion);
		print_u16("SymRecordStream", dbi.SymRecordStream);
		print_u16("PdbDllRbld", dbi.PdbDllRbld);
		print_u32("ModInfoSize", dbi.ModInfoSize);
		print_u32("SectionContributionSize", dbi.SectionContributionSize);
		print_u32("SectionMapSize", dbi.SectionMapSize);
		print_u32("SourceInfoSize", dbi.SourceInfoSize);
		print_u32("TypeServerMapSize", dbi.TypeServerMapSize);
		print_u32("MFCTypeServerIndex", dbi.MFCTypeServerIndex);
		print_u32("OptionalDbgHeaderSize", dbi.OptionalDbgHeaderSize);
		print_u32("ECSubstreamSize", dbi.ECSubstreamSize);
		print_flags16("Flags", dbi.Flags,
			"IncrementallyLinked".ptr,	PdbRaw_DbiFlags.IncrementallyLinked,
			"PrivateSymbolsStripped".ptr,	PdbRaw_DbiFlags.PrivateSymbolsStripped,
			"ConflictingTypes".ptr,	PdbRaw_DbiFlags.ConflictingTypes,
			null);
		print_x16("Machine", dbi.Machine, adbg_object_pe_machine_string(dbi.Machine));
		print_u32("Padding", dbi.Padding);
		
		/*void *leftover = buffer + pdb70_dbi_header.sizeof;
		size_t leftlen = strsize - pdb70_dbi_header.sizeof;
		
		print_raw("Stream 3 Data", leftover, leftlen);*/
	}
	adbg_object_pdb70_stream_close(o, &buffer);
	
	// Stream 4
	/+print_section(4, StreamNames[4].ptr, cast(int)StreamNames[4].length);
	if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.dbi)) {
		print_string("error", "Couldn't read Stream 3");
		return;
	}
	if (strsize >= pdb70_subsection_header.sizeof) {
		pdb70_subsection_header *ipi = cast(pdb70_subsection_header*)buffer;
		
		enum LIMIT = 200; // Arbitrary
		
		size_t i;
	Lr:
		print_x32("Kind", ipi.Kind);
		print_x32("Length", ipi.Length);
		
		ipi = cast(pdb70_subsection_header*)((cast(void*)ipi) + ipi.Length);
		if (ipi.Kind && ipi.Length && ++i < LIMIT) goto Lr;
	}
	adbg_object_pdb70_stream_close(o, &buffer);+/
	
	/*uint strcnt = o.i.pdb70.strcnt;
	for (uint stridx = 5; stridx < strcnt; ++stridx) {
		char[32] buf = void;
		int l = snprintf(buf.ptr, 32, "Stream %u", stridx);
	}*/
}