You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
298 lines
8.8 KiB
C++
298 lines
8.8 KiB
C++
// Copyright 2011-2019 Molecular Matters GmbH, all rights reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreTypes.h"
|
|
#include "LC_PointerUtil.h"
|
|
#include "LC_Platform.h"
|
|
#include <inttypes.h>
|
|
#include "Windows/WindowsHWrapper.h"
|
|
|
|
namespace coffDetail
|
|
{
|
|
struct CoffType
|
|
{
|
|
enum Enum
|
|
{
|
|
COFF, // regular COFF/OBJ files
|
|
BIGOBJ, // OBJ files compiled with /bigobj
|
|
IMPORT_LIBRARY, // import libraries (DLL stubs)
|
|
UNKNOWN
|
|
};
|
|
|
|
// template helper to map from CoffType::Enum values to types
|
|
template <Enum>
|
|
struct TypeMap {};
|
|
|
|
template <>
|
|
struct TypeMap<Enum::COFF>
|
|
{
|
|
typedef IMAGE_FILE_HEADER HeaderType;
|
|
typedef IMAGE_SYMBOL SymbolType;
|
|
typedef IMAGE_AUX_SYMBOL AuxSymbolType;
|
|
};
|
|
|
|
template <>
|
|
struct TypeMap<Enum::BIGOBJ>
|
|
{
|
|
typedef ANON_OBJECT_HEADER_BIGOBJ HeaderType;
|
|
typedef IMAGE_SYMBOL_EX SymbolType;
|
|
typedef IMAGE_AUX_SYMBOL_EX AuxSymbolType;
|
|
};
|
|
};
|
|
|
|
CoffType::Enum GetCoffType(const void* imageBase);
|
|
|
|
// returns the number of relocations
|
|
unsigned int GetRelocationCount(const void* imageBase, const IMAGE_SECTION_HEADER* section);
|
|
|
|
|
|
template <typename SymbolType>
|
|
inline uint32_t GetSectionIndex(const SymbolType* symbol)
|
|
{
|
|
// according to COFF spec, section number is a one-based (because zero is taken by UNDEFINED symbols)
|
|
// signed integer, and signed values like 0, -1 and -2 have special meaning. note that
|
|
// in cases where the index is a negative value that does not correspond to any of
|
|
// the special values, the section number *must* be treated as an unsigned value, which is not
|
|
// stated in the spec.
|
|
// e.g. some non-bigobj COFF files that have more than 32767 sections will have symbols with
|
|
// section numbers like 0x8000, 0x8001, etc. which need to be treated as unsigned values.
|
|
typedef std::make_unsigned<decltype(symbol->SectionNumber)>::type UnsignedSectionNumberType;
|
|
|
|
const uint32_t sectionIndex = static_cast<uint32_t>(static_cast<UnsignedSectionNumberType>(symbol->SectionNumber) - 1u);
|
|
return sectionIndex;
|
|
}
|
|
|
|
|
|
template <typename AuxSymbolType>
|
|
inline uint32_t GetAssociatedComdatSectionIndex(const AuxSymbolType* symbol)
|
|
{
|
|
static_assert(false, "Invalid function overload.");
|
|
return 0u;
|
|
}
|
|
|
|
template <>
|
|
inline uint32_t GetAssociatedComdatSectionIndex(const IMAGE_AUX_SYMBOL* symbol)
|
|
{
|
|
typedef std::make_unsigned<decltype(symbol->Section.Number)>::type UnsignedSectionNumberType;
|
|
const uint32_t sectionIndex = static_cast<uint32_t>(static_cast<UnsignedSectionNumberType>(symbol->Section.Number) - 1u);
|
|
return sectionIndex;
|
|
}
|
|
|
|
template <>
|
|
inline uint32_t GetAssociatedComdatSectionIndex(const IMAGE_AUX_SYMBOL_EX* symbol)
|
|
{
|
|
typedef std::make_unsigned<decltype(symbol->Section.Number)>::type UnsignedSectionNumberType;
|
|
typedef std::make_unsigned<decltype(symbol->Section.HighNumber)>::type UnsignedHighSectionNumberType;
|
|
|
|
const uint32_t sectionIndex = static_cast<uint32_t>(static_cast<UnsignedSectionNumberType>(symbol->Section.Number) - 1u);
|
|
const uint32_t highSectionIndex = static_cast<uint32_t>(static_cast<UnsignedHighSectionNumberType>(symbol->Section.HighNumber) - 1u);
|
|
|
|
return (highSectionIndex << 16u) | sectionIndex;
|
|
}
|
|
|
|
|
|
template <typename SymbolType>
|
|
inline bool IsFunctionSymbol(const SymbolType* symbol)
|
|
{
|
|
return ISFCN(symbol->Type);
|
|
}
|
|
|
|
|
|
/*
|
|
From the COFF spec: 5.4.2 Section Number Values
|
|
Normally, the Section Value field in a symbol table entry is a one-based index into the section table.
|
|
However, this field is a signed integer and can take negative values. The following values, less than one,
|
|
have special meanings.
|
|
|
|
IMAGE_SYM_UNDEFINED The symbol record is not yet assigned a section. A value of zero indicates that a reference
|
|
to an external symbol is defined elsewhere. A value of non-zero is a common symbol with a size that is specified
|
|
by the value.
|
|
|
|
IMAGE_SYM_ABSOLUTE The symbol has an absolute (non-relocatable) value and is not an address.
|
|
|
|
IMAGE_SYM_DEBUG The symbol provides general type or debugging information but does not correspond to a section.
|
|
Microsoft tools use this setting along with .file records (storage class FILE).
|
|
*/
|
|
|
|
template <typename SymbolType>
|
|
inline bool IsUndefinedSymbol(const SymbolType* symbol)
|
|
{
|
|
return (symbol->SectionNumber == IMAGE_SYM_UNDEFINED);
|
|
}
|
|
|
|
template <typename SymbolType>
|
|
inline bool IsAbsoluteSymbol(const SymbolType* symbol)
|
|
{
|
|
return (symbol->SectionNumber == IMAGE_SYM_ABSOLUTE);
|
|
}
|
|
|
|
template <typename SymbolType>
|
|
inline bool IsDebugSymbol(const SymbolType* symbol)
|
|
{
|
|
return (symbol->SectionNumber == IMAGE_SYM_DEBUG);
|
|
}
|
|
|
|
|
|
template <typename SymbolType>
|
|
inline bool IsSectionSymbol(const SymbolType* symbol)
|
|
{
|
|
/*
|
|
From the COFF spec: 5.5.5 Auxiliary Format 5: Section Definitions
|
|
Follows a symbol-table record that defines a section. The auxiliary record provides information
|
|
about the section to which it refers.
|
|
*/
|
|
if (symbol->NumberOfAuxSymbols > 0u)
|
|
{
|
|
/*
|
|
From the COFF spec: 5.4.4 Storage Class
|
|
IMAGE_SYM_CLASS_STATIC: The offset of the symbol within the section. If the Value field is zero,
|
|
then the symbol represents a section name.
|
|
*/
|
|
if ((symbol->StorageClass == IMAGE_SYM_CLASS_STATIC) && (symbol->Value == 0u))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
template <typename SymbolType>
|
|
inline bool IsLabelSymbol(const SymbolType* symbol)
|
|
{
|
|
if (symbol->StorageClass == IMAGE_SYM_CLASS_LABEL)
|
|
{
|
|
return true;
|
|
}
|
|
else if (symbol->StorageClass == IMAGE_SYM_CLASS_UNDEFINED_LABEL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
From the COFF spec: 5.2.1 Type Indicators
|
|
*/
|
|
inline bool IsDebugRelocation(const IMAGE_RELOCATION* relocation)
|
|
{
|
|
#if LC_64_BIT
|
|
return (relocation->Type == IMAGE_REL_AMD64_SECTION);
|
|
#else
|
|
return (relocation->Type == IMAGE_REL_I386_SECTION);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
From the COFF spec: 4.1 Section Flags
|
|
*/
|
|
inline bool IsDiscardableSection(const IMAGE_SECTION_HEADER* section)
|
|
{
|
|
return (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0u;
|
|
}
|
|
|
|
inline bool IsPartOfImage(const IMAGE_SECTION_HEADER* section)
|
|
{
|
|
// if the LNK_REMOVE flag is not set, the section becomes part of the final image
|
|
return (section->Characteristics & IMAGE_SCN_LNK_REMOVE) == 0u;
|
|
}
|
|
|
|
inline bool IsComdatSection(const IMAGE_SECTION_HEADER* section)
|
|
{
|
|
return (section->Characteristics & IMAGE_SCN_LNK_COMDAT) != 0u;
|
|
}
|
|
|
|
inline bool IsDirectiveSection(const IMAGE_SECTION_HEADER* section)
|
|
{
|
|
// sections containing info/comments/directives are mostly named ".drectve", but are more
|
|
// easily identified using IMAGE_SCN_LNK_INFO.
|
|
return (section->Characteristics & IMAGE_SCN_LNK_INFO) != 0u;
|
|
}
|
|
|
|
inline bool IsCodeSection(uint32_t characteristics)
|
|
{
|
|
return (characteristics & IMAGE_SCN_MEM_EXECUTE) != 0u;
|
|
}
|
|
|
|
inline bool IsReadSection(uint32_t characteristics)
|
|
{
|
|
return (characteristics & IMAGE_SCN_MEM_READ) != 0u;
|
|
}
|
|
|
|
inline bool IsWriteSection(uint32_t characteristics)
|
|
{
|
|
return (characteristics & IMAGE_SCN_MEM_WRITE) != 0u;
|
|
}
|
|
|
|
|
|
template <typename HeaderType>
|
|
inline uint32_t GetNumberOfSections(const void* imageBase)
|
|
{
|
|
const HeaderType* header = pointer::As<const HeaderType*>(imageBase);
|
|
return header->NumberOfSections;
|
|
}
|
|
|
|
|
|
template <typename HeaderType>
|
|
inline uint32_t GetNumberOfSymbols(const void* imageBase)
|
|
{
|
|
const HeaderType* header = pointer::As<const HeaderType*>(imageBase);
|
|
return header->NumberOfSymbols;
|
|
}
|
|
|
|
|
|
template <typename HeaderType>
|
|
inline const IMAGE_SECTION_HEADER* GetSectionHeader(const void* imageBase)
|
|
{
|
|
return pointer::Offset<const IMAGE_SECTION_HEADER*>(imageBase, sizeof(HeaderType));
|
|
}
|
|
|
|
|
|
template <typename HeaderType>
|
|
inline const void* GetSymbolTable(const void* imageBase)
|
|
{
|
|
const HeaderType* header = pointer::As<const HeaderType*>(imageBase);
|
|
return pointer::Offset<const void*>(imageBase, header->PointerToSymbolTable);
|
|
}
|
|
|
|
|
|
template <typename SymbolType>
|
|
inline const char* GetStringTable(const void* symbolTable, uint32_t symbolCount)
|
|
{
|
|
// string table comes after the symbol table
|
|
return pointer::Offset<const char*>(symbolTable, sizeof(SymbolType)*symbolCount);
|
|
}
|
|
|
|
|
|
template <typename SymbolType>
|
|
inline const SymbolType* GetSymbol(const void* symbolTable, size_t index)
|
|
{
|
|
return pointer::Offset<const SymbolType*>(symbolTable, index * sizeof(SymbolType));
|
|
}
|
|
|
|
|
|
// archives/libraries
|
|
inline uint32_t GetArchiveMemberSize(const IMAGE_ARCHIVE_MEMBER_HEADER* header)
|
|
{
|
|
// COFF Spec, 7.2. Archive Member Headers:
|
|
// Field "Size" at offset 48: An ASCII decimal representation of the total size of the archive member, not including the size of the header.
|
|
uint32_t size = 0u;
|
|
sscanf_s(reinterpret_cast<const char*>(header->Size), "%" SCNu32, &size);
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
inline uint32_t PadArchiveMemberSize(uint32_t size)
|
|
{
|
|
// COFF Spec, 7.2. Archive Member Headers:
|
|
// "Each member header starts on the first even address after the end of the previous archive member."
|
|
return size + (size & 1u);
|
|
}
|
|
}
|