// Copyright 2011-2020 Molecular Matters GmbH, all rights reserved. #pragma once #if LC_VERSION == 1 // BEGIN EPIC MOD #include "CoreTypes.h" // END EPIC MOD #include "LC_ImmutableString.h" #include "LC_ProcessTypes.h" #include "LC_Types.h" #include "LC_Executable.h" #include "LC_ChangeNotification.h" #include "LC_DirectoryCache.h" // BEGIN EPIC MOD #include // END EPIC MOD template class CoffCache; namespace coff { struct CoffDB; } namespace symbols { struct Symbol { ImmutableString name; uint32_t rva; // BEGIN EPIC MOD Symbol(ImmutableString _name, uint32_t _rva) : name(_name), rva(_rva) {} // END EPIC MOD LC_DISABLE_ASSIGNMENT(Symbol); LC_DISABLE_COPY(Symbol); }; struct SymbolDB { // symbols accessibly by name or RVA types::StringMap symbolsByName; types::unordered_map symbolsByRva; // a set of symbols that need to be ignored upon reconstruction types::StringSet symbolsWithoutRva; // public function symbols that can be patched types::vector patchableFunctionSymbols; // symbols that contain an anonymous namespace in their mangled name types::vector ansSymbols; }; struct Contribution { // index of the name of the compiland (.obj file) that contributed this uint32_t compilandNameIndex; uint32_t rva; uint32_t size; }; struct ContributionDB { // string table that stores the name of a compiland (.obj file). // indexed by a contribution's compiland name index. // this is loaded initially when gathering contributions. types::vector originalStringTable; // string table that stores the name of an .obj file on disk. // indexed by a contribution's compiland name index. // this is filled after both contributions and compilands have been loaded. types::vector objOnDiskStringTable; // stores all contributions gathered from a .PDB file, ordered by ascending RVA types::vector contributions; // array of all contributions per compiland name index, each ordered by ascending RVA. // indexed by a contribution's compiland name index. typedef types::vector ContributionsPerCompiland; types::vector contributionsPerCompilandNameIndex; // lookup-table from compiland name to corresponding compiland name index types::StringMap compilandNameToCompilandNameIndex; }; struct CompilandSourceFiles { // source files used by compilands types::vector files; }; struct Compiland { struct Type { enum Enum : uint8_t { SINGLE_FILE, AMALGAMATION, PART_OF_AMALGAMATION }; }; ImmutableString originalObjPath; // full path to the original, non-normalized .obj file ImmutableString srcPath; // full path to source file ImmutableString pdbPath; // full path to .pdb file ImmutableString compilerPath; // full path to compiler used to compile the compiland ImmutableString commandLine; // command line arguments passed to the compiler ImmutableString workingDirectory; // full path to working directory ImmutableString amalgamationPath; // full path to the amalgamation .obj in case this is part of an amalgamation CompilandSourceFiles* sourceFiles; uint32_t uniqueId; Type::Enum type; bool isPartOfLibrary; bool wasRecompiled; // BEGIN EPIC MOD Compiland(ImmutableString _originalObjPath, ImmutableString _srcPath, ImmutableString _pdbPath, ImmutableString _compilerPath, ImmutableString _commandLine, ImmutableString _workingDirectory, ImmutableString _amalgamationPath, CompilandSourceFiles* _sourceFiles, uint32_t _uniqueId, Type::Enum _type, bool _isPartOfLibrary, bool _wasRecompiled) : originalObjPath(_originalObjPath), srcPath(_srcPath), pdbPath(_pdbPath), compilerPath(_compilerPath), commandLine(_commandLine), workingDirectory(_workingDirectory), amalgamationPath(_amalgamationPath), sourceFiles(_sourceFiles), uniqueId(_uniqueId), type(_type), isPartOfLibrary(_isPartOfLibrary), wasRecompiled(_wasRecompiled) { } // END EPIC MOD LC_DISABLE_ASSIGNMENT(Compiland); LC_DISABLE_COPY(Compiland); }; struct AmalgamatedCompiland { types::vector singleParts; // .obj of the single files that make up an amalgamation bool isSplit; }; struct ModifiedObjFile { std::wstring objPath; std::wstring amalgamatedObjPath; // optional }; // full path to .obj file typedef ImmutableString ObjPath; // full path to any file typedef ImmutableString FilePath; typedef uint64_t TimeStamp; struct Dependency { DirectoryCache::Directory* parentDirectory; TimeStamp lastModification; types::vector objPaths; bool hadInitialChange; }; struct CompilandDB { // stores a compiland for each .obj file that contributed to a module and has its source available types::StringMap compilands; // stores an array of .obj files which are part of amalgamated compilands types::StringMap amalgamatedCompilands; // stores an array of .obj files that need to be recompiled when a certain file changes types::StringMap dependencies; // stores the real name of the .obj on disk for each original DIA compiland name. // this lookup table is needed because DIA compilands coming from static libraries often don't contain the full path, // but a path that is relative to the project instead, e.g. obj\x64\Debug\SimpleFunction.obj types::StringMap compilandNameToObjOnDisk; }; struct DiaCompilandDB { types::vector symbols; }; struct ModuleDB { types::vector modules; // relative path to .exe or .dll }; struct LibraryDB { // full path to all .lib files that need to be used for linking types::vector libraries; }; struct LinkerDB { ImmutableString pdbPath; // full path to .pdb file ImmutableString linkerPath; // full path to linker used to link the executable ImmutableString commandLine; // command line arguments passed to the linker (emitted by VS2015 and later) ImmutableString workingDirectory; // full path to working directory LC_DISABLE_ASSIGNMENT(LinkerDB); }; struct ThunkDB { // stores thunks from table entry RVA to target RVA. types::unordered_map thunksFromTableEntryToTarget; // stores thunks from target RVA to table entry RVA // there can be several different thunks referring to the same RVA! types::unordered_map> thunksFromTargetToTableEntries; }; struct ImageSection { uint32_t nameIndex; uint32_t rva; uint32_t size; }; struct ImageSectionDB { types::vector sectionNames; types::vector sections; // sorted by RVA types::StringMap sectionsByName; }; struct Provider { IDiaDataSource* diaDataSource; IDiaSession* diaSession; IDiaSymbol* globalScope; TimeStamp lastModificationTime; }; struct DynamicInitializerDB { // no symbol ownership types::vector dynamicInitializers; }; struct UserDefinedTypesDB { types::unordered_set typeIds; }; // LIFETIME struct OpenOptions { enum Enum : uint32_t { NONE = 0u, ACCUMULATE_SIZE = 1u << 0u, USE_SYMBOL_SERVER = 1u << 1u }; }; // TODO: helper function to make fixing and refactoring easier for now Symbol* CreateNewSymbol(const ImmutableString& name, uint32_t rva, SymbolDB* db); Provider* OpenEXE(const wchar_t* filename, uint32_t openOptions); void Close(Provider* provider); // BEGIN EPIC MOD - Static grouping of compilands by unity blobs void ResetCachedUnityManifests(); bool TryGetCompilandIdFromUnityManifest(const std::wstring& objPath, uint32_t& compilandId); uint32_t GetCompilandIdFromPath(const std::wstring& objPath); // END EPIC MOD // UPDATE // CACHE: must be kept per module SymbolDB* GatherSymbols(Provider* provider); // CACHE: must be kept per module ContributionDB* GatherContributions(Provider* provider); // converts the string table of .obj files to a string table of real .obj files on disk, // and builds a per-compiland array of contributions. void FinalizeContributions(const CompilandDB* compilandDb, ContributionDB* db); // CACHE: temporary, throw away after use DiaCompilandDB* GatherDiaCompilands(Provider* provider); struct CompilandOptions { enum Enum : uint32_t { NONE = 0u, GENERATE_LOGS = 1u << 0u, FORCE_PCH_PDBS = 1u << 1u, TRACK_OBJ_ONLY = 1u << 2u }; }; // CACHE: stored only ONCE, after initial load, cannot change CompilandDB* GatherCompilands(const Provider* provider, const DiaCompilandDB* diaCompilandDb, unsigned int splitAmalgamatedFilesThreshold, uint32_t compilandOptions); // CACHE: stored only ONCE, after initial load, cannot change LibraryDB* GatherLibraries(const DiaCompilandDB* diaCompilandDb); // CACHE: temporary, throw away after use IDiaSymbol* FindLinkerSymbol(const DiaCompilandDB* diaCompilandDb); // CACHE: stored only ONCE, after initial load, cannot change LinkerDB* GatherLinker(IDiaSymbol* linkerSymbol); // CACHE: must be kept per module ThunkDB* GatherThunks(IDiaSymbol* linkerSymbol); // CACHE: must be kept per module ImageSectionDB* GatherImageSections(IDiaSymbol* linkerSymbol); // CACHE: must be kept per module, stores symbols directly into the given symbol database DynamicInitializerDB GatherDynamicInitializers(const Provider* provider, const executable::Image* image, const executable::ImageSectionDB* imageSections, const ImageSectionDB* imageSectionDb, const ContributionDB* contributionDb, const CompilandDB* compilandDb, const CoffCache* coffCache, SymbolDB* symbolDb); void DestroyLinkerSymbol(IDiaSymbol* symbol); void DestroyDiaCompilandDB(DiaCompilandDB* db); void DestroyModuleDB(ModuleDB* db); void DestroyCompilandDB(CompilandDB* db); void MergeCompilandsAndDependencies(CompilandDB* existingDb, CompilandDB* mergedDb); void MarkCompilandAsRecompiled(Compiland* compiland); void ClearCompilandAsRecompiled(Compiland* compiland); bool IsCompilandRecompiled(const Compiland* compiland); // ACCESS Compiland* FindCompiland(CompilandDB* db, const ObjPath& objPath); const Compiland* FindCompiland(const CompilandDB* db, const ObjPath& objPath); AmalgamatedCompiland* FindAmalgamatedCompiland(CompilandDB* db, const ObjPath& objPath); const AmalgamatedCompiland* FindAmalgamatedCompiland(const CompilandDB* db, const ObjPath& objPath); bool IsAmalgamation(const Compiland* compiland); bool IsPartOfAmalgamation(const Compiland* compiland); // finds a symbol by name. must match exactly const Symbol* FindSymbolByName(const SymbolDB* db, const ImmutableString& name); const Symbol* FindSymbolByRVA(const SymbolDB* db, uint32_t rva); // finds a section by name. must match exactly const ImageSection* FindImageSectionByName(const ImageSectionDB* db, const ImmutableString& name); // finds a section by RVA, binary search. RVA need not be exact, only must lie inside any of the sections const ImageSection* FindImageSectionByRVA(const ImageSectionDB* db, uint32_t rva); // finds a thunk using the table entry RVA, returns the target RVA uint32_t FindThunkTargetByRVA(const ThunkDB* db, uint32_t tableEntryRva); // finds thunks using the target RVA, returns all thunks that point to the target RVA types::vector FindThunkTableEntriesByRVA(const ThunkDB* db, uint32_t targetRva); // takes into account that symbol names might contain COFF suffixes std::string UndecorateSymbolName(const ImmutableString& symbolName); // finds a contribution by RVA, binary search. RVA need not be exact, only must lie inside any of the contributions const Contribution* FindContributionByRVA(const ContributionDB* db, uint32_t rva); // returns the compiland name of a given contribution ImmutableString GetContributionCompilandName(const ContributionDB* db, const Contribution* contribution); // returns all contributions for a certain compiland name const ContributionDB::ContributionsPerCompiland* GetContributionsForCompilandName(const ContributionDB* db, const ImmutableString& compilandName); // returns all contributions for a certain compiland name index const ContributionDB::ContributionsPerCompiland* GetContributionsForCompilandNameIndex(const ContributionDB* db, uint32_t compilandNameIndex); const ImmutableString& GetImageSectionName(const ImageSectionDB* db, const ImageSection* imageSection); // helper function that returns or generates the unique ID of an optional compiland. // for files split off from amalgamated files, we need to use the original object path of the amalgamated file here, // otherwise names of symbols would differ, leading to constructors of global instances being called again. uint32_t GetCompilandId(const Compiland* compiland, const wchar_t* const objPath, const types::vector& modifiedObjFiles); ImmutableString TransformAnonymousNamespacePattern(const ImmutableString& immutableString, uint32_t uniqueId); void TransformAnonymousNamespaceSymbols(SymbolDB* symbolDb, ContributionDB* contributionDb, CompilandDB* compilandDb, const types::vector& modifiedObjFiles); bool IsPchSymbol(const ImmutableString& symbolName); bool IsVTable(const ImmutableString& symbolName); bool IsRttiObjectLocator(const ImmutableString& symbolName); bool IsDynamicInitializer(const ImmutableString& functionSymbolName); bool IsDynamicAtexitDestructor(const ImmutableString& functionSymbolName); bool IsPointerToDynamicInitializer(const ImmutableString& symbolName); bool IsStringLiteral(const ImmutableString& symbolName); bool IsLineNumber(const ImmutableString& symbolName); bool IsFloatingPointSseAvxConstant(const ImmutableString& symbolName); bool IsExceptionRelatedSymbol(const ImmutableString& symbolName); bool IsExceptionClauseSymbol(const ImmutableString& symbolName); bool IsExceptionUnwindSymbolForDynamicInitializer(const ImmutableString& symbolName); bool IsRuntimeCheckRelatedSymbol(const ImmutableString& symbolName); bool IsSdlCheckRelatedSymbol(const ImmutableString& symbolName); bool IsControlFlowGuardRelatedSymbol(const ImmutableString& symbolName); bool IsImageBaseRelatedSymbol(const ImmutableString& symbolName); bool IsTlsArrayRelatedSymbol(const ImmutableString& symbolName); bool IsTlsIndexRelatedSymbol(const ImmutableString& symbolName); bool IsTlsInitRelatedSymbol(const ImmutableString& symbolName); bool IsTlsStaticsRelatedSymbol(const ImmutableString& symbolName); bool IsSectionSymbol(const ImmutableString& symbolName); // BEGIN EPIC MOD bool IsUERegisterSymbol(const ImmutableString& symbolName, const char*& name, size_t& nameLength); bool IsUERegisterSymbol(const ImmutableString& symbolName); bool IsUENoStripSymbol(const ImmutableString& symbolName); bool IsUEInitializerSymbol(const ImmutableString& symbolName); bool IsUEReversePatchSymbol(const ImmutableString& symbolName); bool IsUEStaticsSymbol(const ImmutableString& symbolName); // END EPIC MOD } #endif