Skip to content

Commit 341bc00

Browse files
kjkclaude
andcommitted
pdb: Implement VirtualFunctionTable / VirtualTableShape parsing
Port of getsentry/pdb#141. Implements LF_VTSHAPE (packed 4-bit vtable shape descriptors) and LF_VFTABLE (owner, base, object offset, and method name list). Adds VirtualTableShapeDescriptor enum and VirtualTableShapeType interface. Fixes VirtualFunctionTableType fields to match the Rust struct (owner, base, objectOffset, names). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 170d85d commit 341bc00

3 files changed

Lines changed: 54 additions & 5 deletions

File tree

pdb/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ export type {
7474
BaseClassType,
7575
VirtualBaseClassType,
7676
VirtualFunctionTablePointerType,
77+
VirtualFunctionTableType,
78+
VirtualTableShapeType,
7779
OverloadedMethodType,
7880
MethodType,
7981
EnumerateType,
@@ -95,6 +97,7 @@ export {
9597
CallingConvention,
9698
PointerKind,
9799
PointerMode,
100+
VirtualTableShapeDescriptor,
98101
isStaticMethod,
99102
isVirtualMethod,
100103
isPureVirtualMethod,

pdb/src/tpi/parser.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,34 @@ function parseTypeRecord(buf: ParseBuffer, kind: number): TypeData {
370370
return { kind: "MethodList", methods };
371371
}
372372

373+
case C.LF_VTSHAPE: {
374+
const count = buf.readU16();
375+
const descriptors: number[] = [];
376+
for (let i = 0; i < Math.ceil(count / 2); i++) {
377+
const byte = buf.readU8();
378+
descriptors.push(byte & 0x0f);
379+
if (descriptors.length < count) {
380+
descriptors.push((byte >> 4) & 0x0f);
381+
}
382+
}
383+
return { kind: "VirtualTableShape", descriptors };
384+
}
385+
386+
case C.LF_VFTABLE: {
387+
const owner: TypeIndex = buf.readU32();
388+
const base: TypeIndex = buf.readU32();
389+
const objectOffset = buf.readVariant().value as number;
390+
const namesLength = buf.readVariant().value as number;
391+
const names: string[] = [];
392+
let bytesRead = 0;
393+
while (bytesRead < namesLength) {
394+
const name = buf.readCString();
395+
bytesRead += name.length + 1;
396+
names.push(name);
397+
}
398+
return { kind: "VirtualFunctionTable", owner, base, objectOffset, names };
399+
}
400+
373401
default:
374402
throw PdbError.unimplementedTypeKind(kind);
375403
}

pdb/src/tpi/types.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -396,11 +396,28 @@ export interface EnumerateType {
396396
name: string;
397397
}
398398

399+
/** Virtual table shape descriptor (packed 4-bit values). */
400+
export enum VirtualTableShapeDescriptor {
401+
Near = 0x00,
402+
Far = 0x01,
403+
Thin = 0x02,
404+
Outer = 0x03,
405+
Meta = 0x04,
406+
Near32 = 0x05,
407+
Far32 = 0x06,
408+
Unused = 0x07,
409+
}
410+
411+
export interface VirtualTableShapeType {
412+
kind: "VirtualTableShape";
413+
descriptors: VirtualTableShapeDescriptor[];
414+
}
415+
399416
export interface VirtualFunctionTableType {
400417
kind: "VirtualFunctionTable";
401-
completeClass: TypeIndex;
402-
overriddenVft: TypeIndex;
403-
vftEntries: number;
418+
owner: TypeIndex;
419+
base: TypeIndex;
420+
objectOffset: number;
404421
names: string[];
405422
}
406423

@@ -426,10 +443,11 @@ export type TypeData =
426443
| BaseClassType
427444
| VirtualBaseClassType
428445
| VirtualFunctionTablePointerType
446+
| VirtualFunctionTableType
447+
| VirtualTableShapeType
429448
| OverloadedMethodType
430449
| MethodType
431-
| EnumerateType
432-
| VirtualFunctionTableType;
450+
| EnumerateType;
433451

434452
// ─── Id Data Types ───
435453

0 commit comments

Comments
 (0)