Files
raddebugger/src/linker/pdb_ext/pdb_builder.h
T

491 lines
19 KiB
C

// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#pragma once
////////////////////////////////
#define PDB_NATURAL_ALIGN 4
#define PDB_SYMBOL_ALIGN PDB_NATURAL_ALIGN
////////////////////////////////
// Hash table
#define PDB_HASH_TABLE_PACK_FUNC(name) void name(Arena *arena, String8List *local_data_srl, String8List *key_value_srl, String8 key, String8 value, void *ud)
typedef PDB_HASH_TABLE_PACK_FUNC(PDB_HashTablePackFunc);
#define PDB_HASH_TABLE_UNPACK_FUNC(name) B32 name(void *ud, String8 local_data, String8 key_value_data, U64 *key_value_cursor, String8 *key_out, String8 *value_out)
typedef PDB_HASH_TABLE_UNPACK_FUNC(PDB_HashTableUnpackFunc);
typedef struct PDB_HashTableBucket
{
String8 key;
String8 value;
} PDB_HashTableBucket;
typedef struct PDB_HashTable
{
Arena *arena;
PDB_HashTableBucket *bucket_arr;
U32Array present_bits;
U32Array deleted_bits;
U32 max;
U32 count;
} PDB_HashTable;
typedef enum
{
PDB_HashTableParseError_OK,
PDB_HashTableParseError_OUT_OF_BYTES,
PDB_HashTableParseError_CORRUPTED
} PDB_HashTableParseError;
////////////////////////////////
// String Table
typedef struct PDB_StringTableBucket
{
String8 data;
PDB_StringOffset offset;
PDB_StringIndex istr;
} PDB_StringTableBucket;
typedef struct PDB_StringTable
{
Arena *arena;
U32 version;
U32 size;
U32 bucket_count;
U32 bucket_max;
U32 *ibucket_array;
PDB_StringTableBucket **bucket_array;
} PDB_StringTable;
typedef enum
{
PDB_StringTableOpenError_OK,
PDB_StringTableOpenError_BAD_MAGIC,
PDB_StringTableOpenError_UNKNOWN_VERSION,
PDB_StringTableOpenError_CORRUPTED,
PDB_StringTableOpenError_STRING_OFFSET_OUT_OF_BOUNDS,
PDB_StringTableOpenError_OFFSETS_EXCEED_BUCKET_COUNT
} PDB_StringTableOpenError;
////////////////////////////////
// Type Server
#define PDB_TYPE_HINT_STEP 128
#define PDB_LEAF_ALIGN PDB_NATURAL_ALIGN
typedef enum
{
PDB_OpenTypeServerError_OK,
PDB_OpenTypeServerError_UNKNOWN,
PDB_OpenTypeServerError_INVALID_BUCKET_COUNT,
PDB_OpenTypeServerError_INVALID_TI_RANGE,
PDB_OpenTypeServerError_UNSUPPORTED_VERSION,
} PDB_OpenTypeServerError;
typedef struct PDB_TypeBucket
{
struct PDB_TypeBucket *next;
String8 raw_leaf;
CV_TypeIndex type_index;
} PDB_TypeBucket;
typedef struct PDB_TypeServer
{
Arena *arena;
CV_TypeIndex ti_lo;
String8List leaf_list;
U64 bucket_cap;
PDB_TypeBucket **buckets;
MSF_StreamNumber hash_sn;
PDB_HashTable hash_adj;
} PDB_TypeServer;
typedef struct PDB_TypeHashStreamInfo
{
PDB_OffsetSize hash_vals;
PDB_OffsetSize ti_offs;
PDB_OffsetSize hash_adj;
} PDB_TypeHashStreamInfo;
typedef struct PDB_TypeServerParse
{
Rng1U64 ti_range;
String8 leaf_data;
} PDB_TypeServerParse;
typedef struct
{
CV_DebugT debug_t;
U64 *udt_counts;
U64 *udt_offsets;
Rng1U64 *ranges;
PDB_TypeServer *type_server;
PDB_TypeBucket *udt_buckets;
} PDB_PushLeafTask;
typedef struct
{
PDB_TypeServer *ts;
U32 *map;
} PDB_WriteTypeToBucketMap;
typedef struct
{
CV_TypeIndex ti_lo;
CV_TypeIndex ti_hi;
U64 hint_count;
PDB_TpiOffHint *hint_arr;
String8Node **lf_arr;
Rng1U64 *lf_range_arr;
U64 *lf_cursor_arr;
U8 *lf_buf;
U64 lf_buf_size;
} PDB_WriteTypesTask;
////////////////////////////////
// Info
typedef struct PDB_InfoParse
{
PDB_TpiVersion version;
COFF_TimeStamp time_stamp;
U32 age;
Guid guid;
String8 extra_info;
} PDB_InfoParse;
typedef struct PDB_InfoContext
{
Arena *arena;
COFF_TimeStamp time_stamp;
U32 age;
Guid guid;
PDB_FeatureFlags flags;
PDB_HashTable named_stream_ht;
PDB_HashTable src_header_block_ht;
PDB_StringTable strtab;
} PDB_InfoContext;
////////////////////////////////
// SRC Header Block
typedef enum
{
PDB_SrcError_OK,
PDB_SrcError_DUPLICATE_NAME_STREAM,
PDB_SrcError_DUPLICATE_ENTRY,
PDB_SrcError_UNABLE_TO_WRITE_DATA,
PDB_SrcError_UNSUPPORTED_COMPRESSION,
PDB_SrcError_UNKNOWN
} PDB_SrcError;
////////////////////////////////
// GSI
#define PDB_GSI_V70_SYMBOL_ALIGN 4
#define PDB_GSI_V70_WORD_SIZE 32
#define PDB_GSI_V70_BUCKET_COUNT 4096
#define PDB_GSI_V70_BITMAP_COUNT ((PDB_GSI_V70_BUCKET_COUNT / PDB_GSI_V70_WORD_SIZE) + 1)
#define PDB_GSI_V70_BITMAP_SIZE (PDB_GSI_V70_BITMAP_COUNT * sizeof(U32))
typedef struct PDB_GsiContext
{
Arena *arena;
U64 word_size;
U64 symbol_align;
U64 bucket_count;
U64 symbol_count;
CV_SymbolList *bucket_arr;
} PDB_GsiContext;
typedef struct PDB_GsiSortRecord
{
ISectOff isect_off;
String8 name;
U64 offset;
} PDB_GsiSortRecord;
typedef struct PDB_GsiBuildResult
{
PDB_GsiHeader header;
U64 hash_record_count;
PDB_GsiHashRecord *hash_record_arr;
PDB_GsiSortRecord *sort_record_arr;
U64 bitmap_count;
U32 *bitmap;
U64 compressed_bucket_count;
U32 *compressed_bucket_arr;
U64 total_hash_size;
String8 symbol_data;
} PDB_GsiBuildResult;
typedef struct PDB_GsiSerializeSymbolsTask
{
U64 symbol_align;
CV_SymbolList *bucket_arr;
U64 *bucket_size_arr;
U64 *bucket_off_arr;
U8 *buffer;
PDB_GsiSortRecord **sort_record_arr_arr;
PDB_GsiSortRecord *sort_record_arr;
} PDB_GsiSerializeSymbolsTask;
////////////////////////////////
// PSI
typedef struct PDB_PsiContext
{
Arena *arena;
PDB_GsiContext *gsi;
} PDB_PsiContext;
////////////////////////////////
// DBI
#define PDB_MODULE_ALIGN PDB_NATURAL_ALIGN
typedef struct PDB_DbiModule
{
struct PDB_DbiModule *next;
MSF_StreamNumber sn;
CV_ModIndex imod;
PDB_DbiSectionContrib first_sc;
U64 sym_data_size;
U64 c11_data_size;
U64 c13_data_size;
U64 globrefs_size; // TODO: what is this for?
String8 obj_path;
String8 lib_path;
String8List source_file_list;
} PDB_DbiModule;
typedef struct PDB_DbiModuleList
{
PDB_DbiModule *first;
PDB_DbiModule *last;
U64 count;
} PDB_DbiModuleList;
typedef struct PDB_DbiSectionContribNode
{
struct PDB_DbiSectionContribNode *next;
PDB_DbiSectionContrib data;
} PDB_DbiSectionContribNode;
typedef struct PDB_DbiSectionContribList
{
PDB_DbiSectionContribNode *first;
PDB_DbiSectionContribNode *last;
U64 count;
} PDB_DbiSectionContribList;
typedef struct PDB_DbiSectionNode
{
struct PDB_DbiSectionNode *next;
COFF_SectionHeader data;
} PDB_DbiSectionNode;
typedef struct PDB_DbiSectionList
{
U64 count;
PDB_DbiSectionNode *first;
PDB_DbiSectionNode *last;
} PDB_DbiSectionList;
typedef struct PDB_DbiContext
{
Arena *arena;
U32 age;
COFF_MachineType machine;
MSF_StreamNumber globals_sn;
MSF_StreamNumber publics_sn;
MSF_StreamNumber symbols_sn;
PDB_DbiModuleList module_list;
PDB_DbiSectionContribList sec_contrib_list;
PDB_DbiSectionList section_list;
PDB_StringTable ec_names;
MSF_StreamNumber dbg_streams[PDB_DbiStream_COUNT];
} PDB_DbiContext;
////////////////////////////////
// PDB
typedef struct PDB_Context
{
Arena *arena;
MSF_Context *msf;
PDB_InfoContext *info;
PDB_DbiContext *dbi;
PDB_GsiContext *gsi;
PDB_PsiContext *psi;
PDB_TypeServer *type_servers[CV_TypeIndexSource_COUNT];
} PDB_Context;
////////////////////////////////
typedef struct
{
PDB_GsiContext *gsi;
Rng1U64 *ranges;
CV_SymbolNode **symbols;
U32 *hashes;
} GSI_SymbolHasherTask;
typedef struct
{
CV_StringHashTable string_ht;
PDB_DbiModule **mod_arr;
U16 *imod_arr;
U16 *source_file_name_count_arr;
U32 **source_file_name_offset_arr;
} PDB_DbiBuildFileInfoTask;
////////////////////////////////
// PDB
internal PDB_Context * pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, Guid guid);
internal PDB_Context * pdb_open(String8 data);
internal void pdb_release(PDB_Context **pdb_ptr);
internal void pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht);
internal void pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine);
internal void pdb_set_guid(PDB_Context *pdb, Guid guid);
internal void pdb_set_time_stamp(PDB_Context *pdb, COFF_TimeStamp time_stamp);
internal void pdb_set_age(PDB_Context *pdb, U32 age);
internal COFF_MachineType pdb_get_machine(PDB_Context *pdb);
internal COFF_TimeStamp pdb_get_time_stamp(PDB_Context *pdb);
internal U32 pdb_get_age(PDB_Context *pdb);
internal Guid pdb_get_guid(PDB_Context *pdb);
////////////////////////////////
// Info
internal PDB_InfoContext * pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, Guid guid);
internal void pdb_info_parse_from_data(String8 data, PDB_InfoParse *parse_out);
internal PDB_InfoContext * pdb_info_open(MSF_Context *msf, MSF_StreamNumber sn);
internal void pdb_info_build(PDB_InfoContext *info, MSF_Context *msf, MSF_StreamNumber sn);
internal void pdb_info_release(PDB_InfoContext **info_ptr);
internal MSF_StreamNumber pdb_push_named_stream(PDB_HashTable *named_stream_ht, MSF_Context *msf, String8 name);
internal MSF_StreamNumber pdb_find_named_stream(PDB_HashTable *named_stream_ht, String8 name);
internal PDB_SrcError pdb_add_src(PDB_InfoContext *info, MSF_Context *msf, String8 file_path, String8 file_data, PDB_SrcCompType comp);
////////////////////////////////
// GSI
internal PDB_GsiContext * gsi_alloc(void);
internal PDB_GsiContext * gsi_open(MSF_Context *msf, MSF_StreamNumber sn, String8 symbol_data);
internal void gsi_build(TP_Context *tp, PDB_GsiContext *gsi, MSF_Context *msf, MSF_StreamNumber gsi_sn, MSF_StreamNumber symbols_sn);
internal void gsi_release(PDB_GsiContext **gsi_ptr);
internal void gsi_write_build_result(TP_Context *tp, PDB_GsiBuildResult build, MSF_Context *msf, MSF_StreamNumber sn, MSF_StreamNumber symbols_sn);
internal PDB_GsiBuildResult gsi_build_ex(TP_Context *tp, Arena *arena, PDB_GsiContext *gsi, U64 symbol_data_base, B32 export_symbol_ptr_arr, U64 msf_page_size);
internal U32 gsi_hash(PDB_GsiContext *gsi, String8 input);
internal CV_SymbolNode * gsi_push(PDB_GsiContext *gsi, CV_Symbol *symbol);
internal void gsi_push_many_arr(TP_Context *tp, PDB_GsiContext *gsi, U64 count, CV_SymbolNode **symbol_arr);
internal void gsi_push_many_list(PDB_GsiContext *gsi, U64 count, U32 *hash_arr, CV_SymbolList *list);
internal CV_SymbolNode * gsi_search(PDB_GsiContext *gsi, CV_Symbol *symbol);
////////////////////////////////
// PSI
internal PDB_PsiContext * psi_alloc(void);
internal PDB_PsiContext * psi_open(MSF_Context *msf, MSF_StreamNumber sn, String8 symbol_data);
internal void psi_build(TP_Context *tp, PDB_PsiContext *psi, MSF_Context *msf, MSF_StreamNumber sn, MSF_StreamNumber symbols_sn);
internal void psi_release(PDB_PsiContext **psi_ptr);
internal CV_SymbolNode * psi_push(PDB_PsiContext *psi, CV_Pub32Flags flags, U32 offset, U16 isect, String8 name);
// TODO:
//internal CV_Symbol psi_neareset_symbol(PDB_PsiContext *psi, U16 isect, U32 off);
//internal void psi_push_thunk_map(PDB_PsiContext *psi, U32 *thunk_map, U32 thunk_count, U32 thunk_size, PDB_SO *sect_map, U32 sect_count, ISectOff thunk_table);
////////////////////////////////
// DBI
internal PDB_DbiContext * dbi_alloc(COFF_MachineType machine, U32 age);
internal PDB_DbiContext * dbi_open(MSF_Context *msf, MSF_StreamNumber sn);
internal void dbi_build(TP_Context *tp, PDB_DbiContext *dbi, MSF_Context *msf, MSF_StreamNumber dbi_sn, CV_StringHashTable string_ht);
internal void dbi_release(PDB_DbiContext **dbi_ptr);
internal PDB_DbiModule * dbi_push_module(PDB_DbiContext *dbi, String8 obj_path, String8 lib_path);
internal String8 dbi_module_read_symbol_data(Arena *arena, MSF_Context *msf, PDB_DbiModule *mod);
internal String8 dbi_module_read_c11_data(Arena *arena, MSF_Context *msf, PDB_DbiModule *mod);
internal String8 dbi_module_read_c13_data(Arena *arena, MSF_Context *msf, PDB_DbiModule *mod);
internal void dbi_module_push_section_contrib(PDB_DbiContext *dbi, PDB_DbiModule *mod, ISectOff isect_off, U32 size, U32 data_crc, U32 reloc_crc, COFF_SectionFlags flags);
internal String8List * dbi_open_file_info(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal PDB_DbiModuleList dbi_open_module_info(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header, String8List *file_info);
internal PDB_DbiSectionContribList dbi_open_sec_contrib(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal PDB_StringTable dbi_open_ec_names(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal void dbi_open_dbg_streams(MSF_StreamNumber *dbg_streams, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal PDB_DbiSectionList dbi_open_section_headers(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn);
internal void dbi_build_section_header_stream(PDB_DbiContext *dbi, MSF_Context *msf, MSF_StreamNumber sn);
////////////////////////////////
// Hash Table
internal void pdb_hash_table_alloc(PDB_HashTable *ht, U32 max);
internal void pdb_hash_table_release(PDB_HashTable *ht);
internal PDB_HashTableParseError pdb_hash_table_from_data(PDB_HashTable *ht, String8 data, B32 has_local_data, PDB_HashTableUnpackFunc *unpack_func, void *unpack_ud, U64 *read_bytes_out);
internal String8 pdb_data_from_hash_table(Arena *arena, PDB_HashTable *ht, B32 has_local_data, PDB_HashTablePackFunc *pack_func, void *pack_ud);
internal void pdb_hash_table_set(PDB_HashTable *ht, String8 key, String8 value);
internal B32 pdb_hash_table_get(PDB_HashTable *ht, String8 key, String8 *value_out);
internal void pdb_hash_table_delete(PDB_HashTable *ht, String8 key);
internal B32 pdb_hash_table_try_set(PDB_HashTable *ht, String8 key, String8 value);
internal B32 pdb_hash_table_is_present(PDB_HashTable *ht, U32 k);
internal B32 pdb_hash_table_is_deleted(PDB_HashTable *ht, U32 k);
internal U32 pdb_hash_table_hash(String8 key);
internal void pdb_hash_table_grow(PDB_HashTable *ht, U64 new_capacity);
internal void pdb_hash_table_get_present_keys_and_values(Arena *arena, PDB_HashTable *ht, String8Array *keys_out, String8Array *values_out);
////////////////////////////////
internal PDB_HashTableParseError pdb_hash_adj_hash_table_from_data(PDB_HashTable *ht, String8 data, PDB_StringTable *strtab, U64 *read_bytes_out);
internal PDB_HashTableParseError pdb_src_header_block_ht_from_data(PDB_HashTable *ht, String8 data, PDB_StringTable *strtab, U64 *read_bytes_out);
internal PDB_HashTableParseError pdb_named_stream_ht_from_data(PDB_HashTable *ht, String8 data, U64 *read_bytes_out);
internal String8 pdb_data_from_hash_adj_hash_table(Arena *arena, PDB_HashTable *ht, PDB_StringTable *strtab);
internal String8 pdb_data_from_src_header_block_ht(Arena *arena, PDB_HashTable *ht, PDB_StringTable *strtab);
internal String8 pdb_data_from_named_stream_ht(Arena *arena, PDB_HashTable *ht);
////////////////////////////////
// String Table
internal void pdb_strtab_alloc(PDB_StringTable *strtab, U32 max);
internal PDB_StringTableOpenError pdb_strtab_open(PDB_StringTable *strtab, MSF_Context *msf, MSF_StreamNumber sn);
internal void pdb_strtab_build(PDB_StringTable *strtab, MSF_Context *msf, MSF_StreamNumber sn);
internal void pdb_strtab_release(PDB_StringTable *strtab);
internal PDB_StringIndex pdb_strtab_add(PDB_StringTable *strtab, String8 string);
internal B32 pdb_strtab_search(PDB_StringTable *strtab, String8 string, PDB_StringIndex *index_out);
internal String8 pdb_strtab_string_from_offset(PDB_StringTable *strtab, PDB_StringOffset offset);
internal PDB_StringOffset pdb_strtab_string_to_offset(PDB_StringTable *strtab, PDB_StringIndex stridx);
internal U32 pdb_strtab_get_serialized_size(PDB_StringTable *strtab);
internal B32 pdb_strtab_try_add(PDB_StringTable *strtab, String8 string, PDB_StringIndex *index_out);
internal void pdb_strtab_grow(PDB_StringTable *strtab, U64 new_max);
internal U32 pdb_strtab_hash(PDB_StringTable *strtab, String8 string);
////////////////////////////////
// Type Server
internal PDB_OpenTypeServerError pdb_type_server_parse_from_data_v80(String8 data, PDB_TypeServerParse *parse_out);
internal PDB_OpenTypeServerError pdb_type_server_parse_from_data(String8 data, PDB_TypeServerParse *parse_out);
internal PDB_TypeServer * pdb_type_server_alloc(U64 bucket_count);
internal PDB_TypeServer * pdb_type_server_open_v80(MSF_Context *msf, MSF_StreamNumber sn, PDB_StringTable *strtab);
internal PDB_TypeServer * pdb_type_server_open(MSF_Context *msf, MSF_StreamNumber sn, PDB_StringTable *strtab);
internal void pdb_type_server_build(TP_Context *tp, PDB_TypeServer *ts, PDB_StringTable *strtab, MSF_Context *msf, MSF_StreamNumber sn);
internal void pdb_type_server_release(PDB_TypeServer **serv_ptr);
internal void pdb_type_server_push(PDB_TypeServer *ts, String8 raw_leaf);
internal void pdb_type_server_push_parallel(TP_Context *tp, PDB_TypeServer *ts, CV_DebugT types);
//internal CV_LeafNode * pdb_type_server_leaf_from_string(PDB_TypeServer *ts, String8 string);
internal String8Node * pdb_type_server_reserve(PDB_TypeServer *ts, U64 count);
internal String8Node * pdb_type_server_make_leaf(PDB_TypeServer *ts, CV_LeafKind kind, String8 data);
internal void pdb_type_server_push_bucket(PDB_TypeServer *ts, CV_Leaf *leaf);
internal PDB_TypeHashStreamInfo pdb_type_hash_stream_build(TP_Context *tp, PDB_TypeServer *ts, PDB_StringTable *strtab, MSF_Context *msf, PDB_TpiOffHint *hint_arr, U64 hint_count);
////////////////////////////////
// Enum -> String
internal String8 pdb_string_from_src_error(PDB_SrcError error);
internal String8 pdb_string_from_open_type_server_error(PDB_OpenTypeServerError error);