Skip to content

Commit

Permalink
Continue support for PDB
Browse files Browse the repository at this point in the history
  • Loading branch information
dd86k committed Jan 24, 2024
1 parent 0256b2a commit cc16160
Show file tree
Hide file tree
Showing 7 changed files with 812 additions and 166 deletions.
241 changes: 167 additions & 74 deletions app/dump/pdb70.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import adbg.disassembler.core;
import adbg.object.server;
import adbg.object.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):
Expand All @@ -19,8 +21,8 @@ int dump_pdb70(ref Dumper dump, adbg_object_t *o) {
if (dump.selected_headers())
dump_pdb70_header(dump, o);

//if (dump.selected_debug())
// dump_pdb70_debug(dump, o);
if (dump.selected_debug())
dump_pdb70_debug(dump, o);

return 0;
}
Expand All @@ -32,93 +34,184 @@ void dump_pdb70_header(ref Dumper dump, adbg_object_t *o) {

pdb70_file_header *header = adbg_object_pdb70_header(o);

if (header.PageCount * header.PageSize != o.file_size) {
print_string("error", "Reported size isn't same as actual file size.");
return;
}

print_stringl("Magic", header.Magic.ptr, 24);
print_x32("PageSize", header.PageSize);
print_x32("FreeIndex", header.FreeIndex);
print_x32("PageCount", header.PageCount);
print_x32("DirectorySize", header.DirectorySize);
print_x32("Unknown", header.Unknown2);
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(ref Dumper dump, adbg_object_t *o) {
print_header("Debug");

pdb70_file_header *header = adbg_object_pdb70_header(o);
uint diroff = header.DirectoryOffset * header.PageSize;
uint dircnt = (header.DirectorySize / header.PageSize) + 1;
uint *dir = void;
if (adbg_object_offset(o, cast(void**)&dir, diroff)) {
print_string("error", "Directory offset out of bounds.");
print_section(1, "PDB Stream", 10);
pdb70_pdb_header *pdb = void;
uint s1sz = void;
if (adbg_object_pdb70_stream_open(o, cast(void**)&pdb, &s1sz, PdbStream.pdb)) {
print_string("error", "Couldn't read Stream 1");
return;
}
if (s1sz) {
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);
}
adbg_object_pdb70_stream_close(o, cast(void**)&pdb);

uint nstreams = *dir; /// Number of stream sizes
uint *psize = dir + 1; // Start at first size
uint *ploc = psize + nstreams; // Start at first loc
for (size_t i; i < nstreams; ++i) {
int stream_size = cast(int)psize[i];
print_section(2, "TPI Stream", 10);
pdb70_tpi_header *tpi = void;
uint s2sz = void;
if (adbg_object_pdb70_stream_open(o, cast(void**)&tpi, &s2sz, PdbStream.tpi)) {
print_string("error", "Couldn't read Stream 2");
return;
}
if (s2sz) {
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_section(cast(uint)i);
print_x32("Size", stream_size);
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);

if (stream_size > 0) {
print_x32("Page", ploc[i]);
uint sloc = ploc[i] * header.PageSize;
void *stream = void; // Stream count
if (adbg_object_offsetl(o, &stream, sloc, 4)) {
print_string("warning", "Stream directory outside of bounds.");
continue;
}
int type = cast(int)i + 1;
switch (type) {
case 1:
print_string("Stream Type", "PDB Header");
uint dataoff = (*cast(uint*)stream) * header.PageSize;
pdb70_stream_header *pdbhdr = void;
if (adbg_object_offsetl(o, cast(void**)&pdbhdr, dataoff, 4)) {
print_string("warning", "Stream outside of bounds.");
continue;
}
with (pdbhdr) {
char[UID_TEXTLEN] guid = void;
uid_text(pdbhdr.UniqueId, guid, UID_GUID);
print_x32("Version", Version);
print_x32("Signature", Signature, ctime32(Signature));
print_u32("Age", Age);
print_stringl("UniqueId", guid.ptr, UID_TEXTLEN);
}
break;
case 2:
print_string("Stream Type", "Type manager");
break;
case 3:
print_string("Stream Type", "Debug information");
break;
case 4:
print_string("Stream Type", "NameMap");
break;
default: // >4 -> symbol
print_string("Stream Type", "Unknown");
}
}
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);

uint nlocs = (stream_size / header.PageSize) + 1;
for (size_t n; n < nlocs; ++n) {
++ploc;
print_u32("HashAdjBufferOffset", tpi.HashAdjBufferOffset);
print_u32("HashAdjBufferLength", tpi.HashAdjBufferLength);
}
adbg_object_pdb70_stream_close(o, cast(void**)&tpi);

print_section(3, "DBI Stream", 10);
pdb70_dbi_header *dbi = void;
uint s3sz = void;
if (adbg_object_pdb70_stream_open(o, cast(void**)&dbi, &s3sz, PdbStream.dbi)) {
print_string("error", "Couldn't read Stream 3");
return;
}
if (s3sz) {
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);
}
}
+/
adbg_object_pdb70_stream_close(o, cast(void**)&dbi);

/*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);
}*/
}
6 changes: 6 additions & 0 deletions app/dumper.d
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ void print_header(const(char)* name) {
printf("\n# %s\n", name);
}

// Field name only
void print_name(const(char)* name) {
printf("%*s: ", __field_padding, name);
}

void print_section(uint i, const(char) *name = null, int len = 0) {
putchar('\n');
print_u32("index", i);
Expand Down Expand Up @@ -263,6 +268,7 @@ void print_string(const(char)* name, const(char)* val) {
void print_stringl(const(char)* name, const(char)* val, int len) {
printf("%*s: %.*s\n", __field_padding, name, len, val);
}
//TODO: print_stringf

void print_flags16(const(char) *section, ushort flags, ...) {
printf("%*s: 0x%04x\t(", __field_padding, section, flags);
Expand Down
2 changes: 2 additions & 0 deletions app/main.d
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ struct option_t {
//TODO: --dump-length/--dump-end: Length or end
//TODO: --dump-imports-all: Dependency walker
//TODO: --dump-section=name: Hex or raw dump section
//TODO: --dump-stats: File statistics?
// pdb: stream count, positions, etc.
immutable option_t[] options = [
// general
{ 'a', "arch", "Select architecture for disassembler (default=platform)", true, fa: &cli_march },
Expand Down
38 changes: 25 additions & 13 deletions src/adbg/debugger/process.d
Original file line number Diff line number Diff line change
Expand Up @@ -834,32 +834,38 @@ int adbg_process_get_pid(adbg_process_t *tracee) {
}

/// Get the process file path.
///
/// The string is null-terminated.
/// Params:
/// pid = Process ID.
/// buffer = Buffer.
/// bufsize = Size of the buffer.
/// basename = Request for basename; Otherwise full file path.
/// Returns: Error code.
int adbg_process_get_name(int pid, char *buffer, size_t bufsize, bool basename) {
/// Returns: String length; Or zero on error.
size_t adbg_process_get_name(int pid, char *buffer, size_t bufsize, bool basename) {
if (pid <= 0 || buffer == null || bufsize == 0)
return adbg_oops(AdbgError.nullArgument);

version (Windows) {
// Get process handle
HANDLE hand = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pid);
if (hand == null)
return adbg_oops(AdbgError.os);
if (hand == null) {
adbg_oops(AdbgError.os);
return 0;
}
scope(exit) CloseHandle(hand);

// Get filename or basename
uint bf = cast(uint)bufsize;
uint r = basename ?
GetModuleBaseNameA(hand, null, buffer, bf) :
GetModuleFileNameA(hand, buffer, bf);
buffer[r] = 0;
if (r == 0)
return adbg_oops(AdbgError.os);
return 0;
adbg_oops(AdbgError.os);
return r;
} else version (linux) {
enum TBUFSZ = 32;
char[TBUFSZ] pathbuf = void; // Path buffer
Expand All @@ -877,12 +883,16 @@ int adbg_process_get_name(int pid, char *buffer, size_t bufsize, bool basename)
if (r <= 0) {
snprintf(pathbuf.ptr, TBUFSZ, "/proc/%d/comm", pid);
int commfd = open(pathbuf.ptr, O_RDONLY);
if (commfd == -1)
return adbg_oops(AdbgError.os);
if (commfd == -1) {
adbg_oops(AdbgError.os);
return 0;
}
scope(exit) close(commfd);
r = read(commfd, buffer, bufsize);
if (r < 0)
return adbg_oops(AdbgError.os);
if (r < 0) {
adbg_oops(AdbgError.os);
return 0;
}
buffer[r - 1] = 0; // Delete newline
}

Expand All @@ -905,9 +915,11 @@ int adbg_process_get_name(int pid, char *buffer, size_t bufsize, bool basename)
}*/

return r;
} else {
adbg_oops(AdbgError.unimplemented);
return 0;
} else
return adbg_oops(AdbgError.unimplemented);
}
}

/// Get the current runtime machine platform.
Expand Down Expand Up @@ -957,7 +969,7 @@ struct adbg_process_list_t {
}

//TODO: Redo adbg_process_enumerate
// int adbg_process_list(adbg_process_list_t*)
// int* adbg_process_list(size_t *count, ...)
// - List of PIDs instead, use adbg_process_get_name for file path.

// NOTE: For the C vararg to work, list is a parameter instead of a return value.
Expand Down
Loading

0 comments on commit cc16160

Please sign in to comment.