La PDB es un archivo único que se compone lógicamente de varios subarchivos, llamados flujos. Está diseñado para optimizar el proceso de realizar cambios en la PDB, tal y como se realiza mediante compilaciones y enlaces incrementales. Los flujos pueden ser eliminados, añadidos o reemplazados sin reescribir ningún otro flujo, y los cambios en los metadatos que describen los flujos se minimizan también.
El PDB está organizado en páginas de tamaño fijo, típicamente 1K, 2K o 4K, numeradas consecutivamente comenzando por 0.
Nota: Se supone que toda la información numérica (por ejemplo, números de flujo y de página) se almacena en forma little-endian, la forma nativa de los procesadores basados en Intel x86. El código pdbparse Python hace esta suposición.
StreamEdit
Cada flujo en la PDB ocupa varias páginas, que no están necesariamente numeradas consecutivamente. El flujo tiene un número y una longitud. El contenido del flujo es la concatenación de sus páginas, truncadas a la longitud del flujo.
Formato de los metadatosEditar
La función de los metadatos de la PDB es identificar todos los flujos componentes, dando la longitud, y la secuencia de páginas para cada flujo. Los flujos se numeran consecutivamente empezando por el 0. También hay un flujo raíz, sin numerar, que contiene algunos de los metadatos.
HeaderEdit
El PDB comienza con un encabezado, que consiste en:
- Signature, utilizado para identificar y validar el formato específico. La longitud de la firma varía según el formato específico.
- El resto de la cabecera varía según el formato identificado por la firma.
La cabecera puede ser más larga que una sola página.
Las herramientas de Microsoft utilizan dos formatos PDB:
Versión 7Edit
La firma es "Microsoft C/C++ MSF 7.00\r\n\x1ADS"
(32 bytes).
El resto de la cabecera consta de:
- Tamaño de página, 4 bytes.
- Puntero de tabla de asignación, 4 bytes. El significado de esto es desconocido. Parece que hay una tabla de asignación, una matriz de 65.536 bits (8.192 bytes), situada al final de la PDB, y un 1 bit significa una página que no se está utilizando.
- Número de páginas del archivo, 4 bytes.
- Tamaño del flujo raíz, 4 bytes.
- Reservado, 4 bytes.
- Número de página de la lista de números de página del flujo raíz. No indica la ubicación del flujo raíz en sí mismo, sólo de la página que contiene la estructura que apunta a sus páginas. En esa página, la lista de números de página del flujo raíz indica las páginas donde se almacena el flujo raíz. Contiene 4 bytes por página, suficientes para cubrir el tamaño del Root stream anterior.
Root streamEdit
El Root stream describe todos los streams de la PDB empezando por el stream 0. Su contenido varía con la versión del formato de la PDB.
Versión 2Editar
El flujo raíz consta de:
- Número de flujos, 2 bytes.
- Reservado, 2 bytes.
- Para cada flujo:
- Tamaño del flujo, 4 bytes.
- Reservado, 4 bytes.
- Para cada flujo:
- Lista de números de página del flujo, 2 bytes por página, suficiente para cubrir el tamaño del flujo anterior.
Versión 7Edit
El flujo raíz consiste en:
- Número de flujos, 4 bytes.
- Para cada flujo:
- Tamaño del flujo, 4 bytes.
- Para cada flujo:
- Lista de números de página del flujo, 4 bytes por página, suficiente para cubrir el tamaño del flujo anterior.
Contenido del flujoEditar
Las herramientas de Microsoft almacenan diferentes tipos de información en diferentes flujos numerados. Algunos números de flujo tienen un tipo de información fija asociada a ellos, y otros flujos se identifican en los mencionados flujos de tipo fijo.
El flujo 1 se utiliza para verificar que el PDB es el mismo archivo al que se hace referencia en un flujo de archivo ejecutable u objeto.
- Versión, 4 bytes.
- Fecha de caducidad, 4 bytes.
- Edad, 4 bytes. Es el número de veces que se ha modificado este PDB desde su creación.
- GUID, 16 bytes.
- Longitud total de los nombres siguientes, 4 bytes. Seguido de cadenas de caracteres terminadas en cero.
El flujo 2 y el flujo 4 contienen información sobre los tipos. Los registros de tipos reales definen los tipos utilizados en el programa. La estructura de estos registros se puede encontrar en el archivo cvinfo.h proporcionado por Microsoft. Hay dos tipos de registros, cada uno con su propio conjunto de números de índice: IDs de tipo y tipos; sólo los tipos se almacenan en el flujo 2 y sólo los IDs de tipo se almacenan en el flujo 4. Los índices se utilizan para referirse a estos registros desde dentro de los registros de símbolos y otros registros de tipos.
- Una cabecera:
- Versión, 4 bytes.
- Tamaño de la cabecera, 4 bytes.
- Índice mínimo y máximo (último + 1) para los registros de tipos (4 bytes cada uno).
- Tamaño de los datos siguientes, 4 bytes, hasta el final del flujo.
- Información del Hash:
- Número de flujo, 2 bytes con 2 bytes de relleno.
- Clave del Hash, 4 bytes.
- Buckets, 4 bytes.
- HashVals, TiOff, y HashAdj, cada uno compuesto por un offset y una longitud, cada uno de 4 bytes.
- Registros de tipo, longitud variable, cuenta = (máximo – mínimo) de la cabecera anterior.
El flujo 3 es un directorio para otros flujos. Tenga en cuenta que no está presente en la versión 2, ni en un PDB producido por un compilador. El flujo comienza con una cabecera que se rellena para tener 64 bytes en total
Offset | Size | Name | Description |
---|---|---|---|
0 | 4 | Signature | Header identifier, == 0xFFFFFF |
4 | 4 | HeaderVersion | Versión del encabezado |
8 | 4 | Age | |
12 | 2 | snGSSyms | |
14 | 2 | usVerAll |
union { struct { USHORT usVerPdbDllMin : 8; // minor version and USHORT usVerPdbDllMaj : 7; // major version and USHORT fNewVerFmt : 1; // flag telling us we have rbld stored elsewhere (high bit of original major version) } vernew; // that built this pdb last. struct { USHORT usVerPdbDllRbld: 4; USHORT usVerPdbDllMin : 7; USHORT usVerPdbDllMaj : 5; } verold; USHORT usVerAll; }; |
16 | 2 | snPSSyms | |
18 | 2 | usVerPdbDllBuild | versión del pdb dll que construyó este pdb por última vez |
20 | 2 | snSymRecs | |
22 | 2 | VerPdbDllRBld | versión rbld de la dll pdb que construyó este pdb por última vez |
24 | 4 | cbGpModi | tamaño del subflujo rgmodi |
28 | 4 | cbSC | tamaño del subflujo Section Contribution |
32 | 4 | cbSecMap | tamaño del mapa de sección |
36 | 4 | cbFileInfo | tamaño del flujo de información del archivo |
40 | 4 | cbTSMap | tamaño del subflujo Type Server Map |
44 | 4 | iMFC | MFC Index |
48 | 4 | cbDbgHdr | tamaño de la información DbgHdr opcional añadida al final del flujo |
52 | 4 | cbECInfo | número de bytes en el subflujo EC, o 0 si no hay EC habilitado Mods |
56 | 2 | flags |
struct _flags { USHORT fIncLink:1; // true if linked incrmentally (really just if ilink thunks are present) USHORT fStripped:1; // true if PDB::CopyTo stripped the private data out USHORT fCTypes:1; // true if this PDB is using CTypes. USHORT unused:13; // reserved, must be 0. } flags; |
58 | 2 | wMachine | Identificador de máquina, el mismo que se utiliza en el formato de objeto COFF, por ejemplog., hex 8664 para Intel x86 64-bit |
60 | 4 | RESERVED | expansión futura, relleno de 64 bytes |
- Información del módulo, longitud variable. Tamaño total en la cabecera anterior. Hay uno de estos para cada módulo de objeto utilizado por el enlazador
- Apertura, 4 bytes.
- Información de símbolos.
- Número de sección, 2 bytes + 2 bytes de relleno.
- Desplazamiento y tamaño, 4 bytes cada uno.
- Banderas, 4 bytes.
- Número de módulo, 2 bytes + 2 bytes de relleno.
- CRCs para datos de sección y datos de reubicación, 4 bytes cada uno.
- Flags, 2 bytes.
- Número de flujo, 2 bytes.
- Tamaño de los símbolos, 4 bytes.
- Tamaño de la información del número de línea antiguo y nuevo, 4 bytes cada uno.
- Número de archivos fuente, 2 bytes + 2 bytes de relleno.
- Offsets, 4 bytes.
- niSource y niCompiler, 4 bytes cada uno.
- Nombre del módulo, cadena de bytes con terminación nula.
- Nombre del objeto, cadena de bytes con terminación nula.
- Relleno a múltiplo de 4 bytes.
- Contribuciones de sección, cabeceras de sección, información de archivo, mapa ts e información EC. Sus tamaños se encuentran en la cabecera anterior.
- Cabecera de depuración,
- Números de flujo para omisión de puntero de trama antigua, excepciones, arreglos, mapas de objetos hacia y desde el origen, cabeceras de sección, ID de anillo de tokens, Xdata, Pdata, omisión de puntero de trama nueva y origen de cabecera de sección. 2 bytes cada uno.