1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00
Beef/IDEHelper/Backend/BeCOFFObject.cpp

2572 lines
71 KiB
C++
Raw Normal View History

2019-08-23 11:56:54 -07:00
#include "BeCOFFObject.h"
#include "BeMCContext.h"
#include "BeLibManger.h"
#include "../COFFData.h"
#include "BeefySysLib/MemStream.h"
#include "codeview/cvinfo.h"
#include "BeefySysLib/util/BeefPerf.h"
2024-05-01 06:26:14 -04:00
#include "llvm/IR/DIBuilder.h"
2019-08-23 11:56:54 -07:00
#include "BeefySysLib/util/AllocDebug.h"
#pragma warning(disable:4996)
USING_NS_BF;
//////////////////////////////////////////////////////////////////////////
BeInlineLineBuilder::BeInlineLineBuilder()
{
mCurLine = 0;
mCurCodePos = 0;
mStartDbgLoc = NULL;
mEnded = false;
}
void BeInlineLineBuilder::Compress(int val)
{
if (val <= 0x7F)
{
mData.push_back((uint8)val);
return;
}
if (val <= 0x3FFF)
{
mData.push_back((uint8)(val >> 8) | 0x80);
mData.push_back((uint8)(val & 0xFF));
return;
}
if (val <= 0x1FFFFFFF)
{
mData.push_back((uint8)(val >> 24) | 0xC0);
mData.push_back((uint8)((val >> 16) & 0xFF));
mData.push_back((uint8)((val >> 8) & 0xFF));
mData.push_back((uint8)(val & 0xFF));
return;
}
}
void BeInlineLineBuilder::WriteSigned(int val)
{
if (val < 0)
Compress(-val * 2 + 1);
else
Compress(val * 2);
}
void BeInlineLineBuilder::Update(BeDbgCodeEmission* codeEmission)
{
BF_ASSERT(!mEnded);
int lineOfs = codeEmission->mDbgLoc->mLine - mCurLine;
int codeOfs = codeEmission->mPos - mCurCodePos;
if (codeOfs != 0)
{
mData.push_back(CodeViewInfo::BA_OP_ChangeLineOffset);
WriteSigned(lineOfs);
mData.push_back(CodeViewInfo::BA_OP_ChangeCodeOffset);
Compress(codeOfs);
mCurLine = codeEmission->mDbgLoc->mLine;
mCurCodePos = codeEmission->mPos;
}
}
void BeInlineLineBuilder::Start(BeDbgCodeEmission* codeEmission)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
//mCurLine = codeEmission->mDbgLoc->mDbgInlinedAt->mLine;
int lineOfs = codeEmission->mDbgLoc->mLine - mCurLine;
int codeOfs = codeEmission->mPos - mCurCodePos;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
auto usingFile = codeEmission->mDbgLoc->mDbgInlinedAt->GetDbgFile();
auto wantFile = codeEmission->mDbgLoc->GetDbgFile();
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
mData.push_back(CodeViewInfo::BA_OP_ChangeLineOffset);
WriteSigned(lineOfs);
/*if (wantFile != usingFile)
{
mData.push_back(CodeViewInfo::BA_OP_ChangeFile);
Compress(wantFile->mIdx * 8);
}*/
mData.push_back(CodeViewInfo::BA_OP_ChangeCodeOffset);
2022-07-27 12:26:36 -04:00
Compress(codeOfs);
2019-08-23 11:56:54 -07:00
mCurLine = codeEmission->mDbgLoc->mLine;
2022-07-27 12:26:36 -04:00
mCurCodePos = codeEmission->mPos;
2019-08-23 11:56:54 -07:00
/*mData.push_back(CodeViewInfo::BA_OP_ChangeLineOffset);
WriteSigned(-mStartDbgLoc->mDbgInlinedAt->mLine - 1);
mData.push_back(CodeViewInfo::BA_OP_ChangeCodeOffset);
Compress(codeEmission->mPos);
mCurLine = -1;
mCurCodePos = codeEmission->mPos;*/
}
void BeInlineLineBuilder::End(BeDbgCodeEmission* codeEmission)
{
BF_ASSERT(!mEnded);
int codeOfs = codeEmission->mPos - mCurCodePos;
mData.push_back(CodeViewInfo::BA_OP_ChangeCodeLength);
Compress(codeOfs);
mCurCodePos = codeEmission->mPos;
mEnded = true;
}
//////////////////////////////////////////////////////////////////////////
BeCOFFObject::BeCOFFObject()
{
mWriteToLib = false;
2022-07-27 12:26:36 -04:00
mBSSPos = 0;
2019-08-23 11:56:54 -07:00
mCurTagId = 0x1000;
mCurStringId = 0;
mCurJumpTableIdx = 0;
mBeModule = NULL;
mTTagStartPos = -1;
mSTagStartPos = -1;
2022-07-27 12:26:36 -04:00
mSectionStartPos = -1;
2019-08-23 11:56:54 -07:00
mTypesLocked = false;
mTimestamp = 0;
mPerfManager = NULL;
mStream = NULL;
}
void BeCOFFObject::ToString(BeMDNode* mdNode, String& str)
{
if (auto dbgStruct = BeValueDynCast<BeDbgStructType>(mdNode))
{
if (auto dbgNamespace = BeValueDynCast<BeDbgNamespace>(dbgStruct->mScope))
{
ToString(dbgNamespace, str);
str += "::";
}
else if (auto dbgOuterType = BeValueDynCast<BeDbgType>(dbgStruct->mScope))
{
ToString(dbgOuterType, str);
str += "::";
}
str += dbgStruct->mName;
}
else if (auto dbgStruct = BeValueDynCast<BeDbgEnumType>(mdNode))
{
if (auto dbgNamespace = BeValueDynCast<BeDbgNamespace>(dbgStruct->mScope))
{
ToString(dbgNamespace, str);
str += "::";
}
else if (auto dbgOuterType = BeValueDynCast<BeDbgType>(dbgStruct->mScope))
{
ToString(dbgOuterType, str);
str += "::";
}
str += dbgStruct->mName;
}
else if (auto dbgNamespace = BeValueDynCast<BeDbgNamespace>(mdNode))
{
if (auto outerNamespace = BeValueDynCast<BeDbgNamespace>(dbgNamespace->mScope))
{
ToString(outerNamespace, str);
str += "::";
}
str += dbgNamespace->mName;
}
else
{
BF_FATAL("err");
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
}
int BeCOFFObject::GetCVRegNum(X64CPURegister reg, int bits)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
if (bits == 8)
{
switch (reg)
{
case X64Reg_RAX: return CV_AMD64_AL;
case X64Reg_RDX: return CV_AMD64_DL;
case X64Reg_RCX: return CV_AMD64_CL;
case X64Reg_RBX: return CV_AMD64_BL;
case X64Reg_RSI: return CV_AMD64_SIL;
case X64Reg_RDI: return CV_AMD64_DIL;
case X64Reg_R8: return CV_AMD64_R8B;
case X64Reg_R9: return CV_AMD64_R9B;
case X64Reg_R10: return CV_AMD64_R10B;
case X64Reg_R11: return CV_AMD64_R11B;
case X64Reg_R12: return CV_AMD64_R12B;
case X64Reg_R13: return CV_AMD64_R13B;
case X64Reg_R14: return CV_AMD64_R14B;
case X64Reg_R15: return CV_AMD64_R15B;
}
}
if (bits == 16)
{
switch (reg)
{
case X64Reg_RAX: return CV_AMD64_AX;
case X64Reg_RDX: return CV_AMD64_DX;
case X64Reg_RCX: return CV_AMD64_CX;
case X64Reg_RBX: return CV_AMD64_BX;
case X64Reg_RSI: return CV_AMD64_SI;
case X64Reg_RDI: return CV_AMD64_DI;
case X64Reg_R8: return CV_AMD64_R8W;
case X64Reg_R9: return CV_AMD64_R9W;
case X64Reg_R10: return CV_AMD64_R10W;
case X64Reg_R11: return CV_AMD64_R11W;
case X64Reg_R12: return CV_AMD64_R12W;
case X64Reg_R13: return CV_AMD64_R13W;
case X64Reg_R14: return CV_AMD64_R14W;
case X64Reg_R15: return CV_AMD64_R15W;
}
}
if (bits == 32)
{
switch (reg)
{
case X64Reg_RAX: return CV_AMD64_EAX;
case X64Reg_RDX: return CV_AMD64_EDX;
case X64Reg_RCX: return CV_AMD64_ECX;
case X64Reg_RBX: return CV_AMD64_EBX;
case X64Reg_RSI: return CV_AMD64_ESI;
case X64Reg_RDI: return CV_AMD64_EDI;
case X64Reg_R8: return CV_AMD64_R8D;
case X64Reg_R9: return CV_AMD64_R9D;
case X64Reg_R10: return CV_AMD64_R10D;
case X64Reg_R11: return CV_AMD64_R11D;
case X64Reg_R12: return CV_AMD64_R12D;
case X64Reg_R13: return CV_AMD64_R13D;
case X64Reg_R14: return CV_AMD64_R14D;
case X64Reg_R15: return CV_AMD64_R15D;
}
}
switch (reg)
{
case X64Reg_RAX: return CV_AMD64_RAX;
case X64Reg_RDX: return CV_AMD64_RDX;
case X64Reg_RCX: return CV_AMD64_RCX;
case X64Reg_RBX: return CV_AMD64_RBX;
case X64Reg_RSI: return CV_AMD64_RSI;
case X64Reg_RDI: return CV_AMD64_RDI;
case X64Reg_RBP: return CV_AMD64_RBP;
case X64Reg_RSP: return CV_AMD64_RSP;
case X64Reg_R8: return CV_AMD64_R8;
case X64Reg_R9: return CV_AMD64_R9;
case X64Reg_R10: return CV_AMD64_R10;
case X64Reg_R11: return CV_AMD64_R11;
case X64Reg_R12: return CV_AMD64_R12;
case X64Reg_R13: return CV_AMD64_R13;
case X64Reg_R14: return CV_AMD64_R14;
case X64Reg_R15: return CV_AMD64_R15;
case X64Reg_RIP: return CV_AMD64_RIP;
case X64Reg_EAX: return CV_AMD64_EAX;
case X64Reg_EDX: return CV_AMD64_EDX;
case X64Reg_ECX: return CV_AMD64_ECX;
case X64Reg_EBX: return CV_AMD64_EBX;
case X64Reg_ESI: return CV_AMD64_ESI;
case X64Reg_EDI: return CV_AMD64_EDI;
case X64Reg_R8D: return CV_AMD64_R8D;
case X64Reg_R9D: return CV_AMD64_R9D;
case X64Reg_R10D: return CV_AMD64_R10D;
case X64Reg_R11D: return CV_AMD64_R11D;
case X64Reg_R12D: return CV_AMD64_R12D;
case X64Reg_R13D: return CV_AMD64_R13D;
case X64Reg_R14D: return CV_AMD64_R14D;
case X64Reg_R15D: return CV_AMD64_R15D;
case X64Reg_AX: return CV_AMD64_AX;
case X64Reg_DX: return CV_AMD64_DX;
case X64Reg_CX: return CV_AMD64_CX;
case X64Reg_BX: return CV_AMD64_BX;
case X64Reg_SI: return CV_AMD64_SI;
case X64Reg_DI: return CV_AMD64_DI;
case X64Reg_R8W: return CV_AMD64_R8W;
case X64Reg_R9W: return CV_AMD64_R9W;
case X64Reg_R10W: return CV_AMD64_R10W;
case X64Reg_R11W: return CV_AMD64_R11W;
case X64Reg_R12W: return CV_AMD64_R12W;
case X64Reg_R13W: return CV_AMD64_R13W;
case X64Reg_R14W: return CV_AMD64_R14W;
case X64Reg_R15W: return CV_AMD64_R15W;
case X64Reg_AL: return CV_AMD64_AL;
case X64Reg_DL: return CV_AMD64_DL;
case X64Reg_CL: return CV_AMD64_CL;
case X64Reg_BL: return CV_AMD64_BL;
case X64Reg_SIL: return CV_AMD64_SIL;
case X64Reg_DIL: return CV_AMD64_DIL;
case X64Reg_R8B: return CV_AMD64_R8B;
case X64Reg_R9B: return CV_AMD64_R9B;
case X64Reg_R10B: return CV_AMD64_R10B;
case X64Reg_R11B: return CV_AMD64_R11B;
case X64Reg_R12B: return CV_AMD64_R12B;
case X64Reg_R13B: return CV_AMD64_R13B;
case X64Reg_R14B: return CV_AMD64_R14B;
case X64Reg_R15B: return CV_AMD64_R15B;
case X64Reg_XMM0_f32: case X64Reg_XMM0_f64: return CV_AMD64_XMM0_0;
case X64Reg_XMM1_f32: case X64Reg_XMM1_f64: return CV_AMD64_XMM1_0;
case X64Reg_XMM2_f32: case X64Reg_XMM2_f64: return CV_AMD64_XMM2_0;
case X64Reg_XMM3_f32: case X64Reg_XMM3_f64: return CV_AMD64_XMM3_0;
case X64Reg_XMM4_f32: case X64Reg_XMM4_f64: return CV_AMD64_XMM4_0;
case X64Reg_XMM5_f32: case X64Reg_XMM5_f64: return CV_AMD64_XMM5_0;
case X64Reg_XMM6_f32: case X64Reg_XMM6_f64: return CV_AMD64_XMM6_0;
case X64Reg_XMM7_f32: case X64Reg_XMM7_f64: return CV_AMD64_XMM7_0;
case X64Reg_XMM8_f32: case X64Reg_XMM8_f64: return CV_AMD64_XMM8_0;
case X64Reg_XMM9_f32: case X64Reg_XMM9_f64: return CV_AMD64_XMM9_0;
case X64Reg_XMM10_f32: case X64Reg_XMM10_f64: return CV_AMD64_XMM10_0;
case X64Reg_XMM11_f32: case X64Reg_XMM11_f64: return CV_AMD64_XMM11_0;
case X64Reg_XMM12_f32: case X64Reg_XMM12_f64: return CV_AMD64_XMM12_0;
case X64Reg_XMM13_f32: case X64Reg_XMM13_f64: return CV_AMD64_XMM13_0;
case X64Reg_XMM14_f32: case X64Reg_XMM14_f64: return CV_AMD64_XMM14_0;
case X64Reg_XMM15_f32: case X64Reg_XMM15_f64: return CV_AMD64_XMM15_0;
case X64Reg_XMM00: return CV_AMD64_XMM0_0;
case X64Reg_XMM01: return CV_AMD64_XMM0_1;
case X64Reg_XMM02: return CV_AMD64_XMM0_2;
case X64Reg_XMM03: return CV_AMD64_XMM0_3;
case X64Reg_XMM10: return CV_AMD64_XMM1_0;
case X64Reg_XMM11: return CV_AMD64_XMM1_1;
case X64Reg_XMM12: return CV_AMD64_XMM1_2;
case X64Reg_XMM13: return CV_AMD64_XMM1_3;
case X64Reg_XMM20: return CV_AMD64_XMM2_0;
case X64Reg_XMM21: return CV_AMD64_XMM2_1;
case X64Reg_XMM22: return CV_AMD64_XMM2_2;
case X64Reg_XMM23: return CV_AMD64_XMM2_3;
case X64Reg_XMM30: return CV_AMD64_XMM3_0;
case X64Reg_XMM31: return CV_AMD64_XMM3_1;
case X64Reg_XMM32: return CV_AMD64_XMM3_2;
case X64Reg_XMM33: return CV_AMD64_XMM3_3;
case X64Reg_XMM40: return CV_AMD64_XMM4_0;
case X64Reg_XMM41: return CV_AMD64_XMM4_1;
case X64Reg_XMM42: return CV_AMD64_XMM4_2;
case X64Reg_XMM43: return CV_AMD64_XMM4_3;
case X64Reg_XMM50: return CV_AMD64_XMM5_0;
case X64Reg_XMM51: return CV_AMD64_XMM5_1;
case X64Reg_XMM52: return CV_AMD64_XMM5_2;
case X64Reg_XMM53: return CV_AMD64_XMM5_3;
case X64Reg_XMM60: return CV_AMD64_XMM6_0;
case X64Reg_XMM61: return CV_AMD64_XMM6_1;
case X64Reg_XMM62: return CV_AMD64_XMM6_2;
case X64Reg_XMM63: return CV_AMD64_XMM6_3;
case X64Reg_XMM70: return CV_AMD64_XMM7_0;
case X64Reg_XMM71: return CV_AMD64_XMM7_1;
case X64Reg_XMM72: return CV_AMD64_XMM7_2;
case X64Reg_XMM73: return CV_AMD64_XMM7_3;
}
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
return 0;
}
void BeCOFFObject::DbgEncodeConstant(DynMemStream& memStream, int64 val)
{
if ((val >= 0) && (val <= 0x7FFF))
{
memStream.Write((int16)val);
return;
}
if ((val >= -0x80) && (val <= 0x7F))
{
memStream.Write((int16)LF_CHAR);
memStream.Write((int8)val);
return;
}
if ((val >= -0x8000) && (val <= 0x7FFF))
{
memStream.Write((int16)LF_SHORT);
memStream.Write((int16)val);
return;
}
if ((val >= -0x80000000LL) && (val <= 0x7FFFFFFF))
{
memStream.Write((int16)LF_LONG);
memStream.Write((int32)val);
return;
}
memStream.Write((int16)LF_QUADWORD);
memStream.Write((int64)val);
}
void BeCOFFObject::DbgEncodeString(DynMemStream& memStream, const StringImpl& str)
{
memStream.Write((char*)str.c_str(), str.length() + 1);
}
void BeCOFFObject::DbgMakeFuncType(BeDbgFunction* dbgFunc)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
if (dbgFunc->mCvTypeId != -1)
return;
/*auto funcTypeResultPair = mFuncTypeSet.insert(dbgFunc);
if (!funcTypeResultPair.second)
{
// This matchesInlineScope another signature so we don't need to redefine it
dbgFunc->mCvTypeId = (*funcTypeResultPair.first)->mCvTypeId;
return;
}*/
COFFFuncTypeRef* funcTypeRefPtr = NULL;
if (!mFuncTypeSet.TryAdd(dbgFunc, &funcTypeRefPtr))
{
// This matchesInlineScope another signature so we don't need to redefine it
dbgFunc->mCvTypeId = funcTypeRefPtr->mFunc->mCvTypeId;
return;
}
auto dbgType = BeValueDynCast<BeDbgType>(dbgFunc->mScope);
auto& outT = mDebugTSect.mData;
for (auto genericArgType : dbgFunc->mGenericArgs)
DbgGetTypeId(genericArgType);
auto parentType = BeValueDynCast<BeDbgType>(dbgFunc->mScope);
DbgGetTypeId(parentType);
for (auto funcParam : dbgFunc->mType->mParams)
DbgGetTypeId(funcParam);
DbgGetTypeId(dbgFunc->mType->mReturnType);
for (auto paramType : dbgFunc->mType->mParams)
DbgGetTypeId(paramType);
2022-07-27 12:26:36 -04:00
bool hasThis = dbgFunc->HasThis();
2019-08-23 11:56:54 -07:00
/*auto argListResultPair = mArgListSet.insert(dbgFunc);
if (!argListResultPair.second)
2022-07-27 12:26:36 -04:00
{
dbgFunc->mCvArgListId = (*argListResultPair.first)->mCvArgListId;
2019-08-23 11:56:54 -07:00
}
else*/
COFFArgListRef* argListRefPtr = NULL;
if (!mArgListSet.TryAdd(dbgFunc, &argListRefPtr))
{
dbgFunc->mCvArgListId = argListRefPtr->mFunc->mCvArgListId;
}
else
{
dbgFunc->mCvArgListId = mCurTagId++;
DbgTStartTag();
outT.Write((int16)LF_ARGLIST);
outT.Write((int32)(dbgFunc->mType->mParams.size() - (hasThis ? 1 : 0)));
for (int paramIdx = hasThis ? 1 : 0; paramIdx < (int)dbgFunc->mType->mParams.size(); paramIdx++)
{
2022-07-27 12:26:36 -04:00
BeDbgType* dbgType = dbgFunc->mType->mParams[paramIdx];
2019-08-23 11:56:54 -07:00
outT.Write(DbgGetTypeId(dbgType));
}
DbgTEndTag();
}
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
dbgFunc->mCvTypeId = mCurTagId++;
DbgTStartTag();
if (dbgType != NULL)
{
outT.Write((int16)LF_MFUNCTION);
outT.Write(DbgGetTypeId(dbgFunc->mType->mReturnType));
outT.Write(DbgGetTypeId(parentType));
if (hasThis)
{
if ((dbgFunc->mVariables.size() > 0) && (dbgFunc->mVariables[0] == NULL))
2022-03-08 06:27:06 -08:00
outT.Write(DbgGetTypeId(BeValueDynCast<BeDbgType>(dbgFunc->GetParamType(1)))); // 0 is sret, 1 = this
2019-08-23 11:56:54 -07:00
else
2022-03-08 06:27:06 -08:00
outT.Write(DbgGetTypeId(BeValueDynCast<BeDbgType>(dbgFunc->GetParamType(0)))); // 0 = this
2019-08-23 11:56:54 -07:00
}
else
outT.Write((int32)T_VOID);
outT.Write((uint8)0); // calltype
CV_funcattr_t attr = { 0 };
outT.Write(*(uint8*)&attr);
outT.Write((int16)(dbgFunc->mType->mParams.size() - (hasThis ? 1 : 0)));
outT.Write((int32)dbgFunc->mCvArgListId);
outT.Write((int32)0); // thisadjust
}
else
{
outT.Write((int16)LF_PROCEDURE);
outT.Write(DbgGetTypeId(dbgFunc->mType->mReturnType));
outT.Write((uint8)0); // calltype
CV_funcattr_t attr = { 0 };
outT.Write(*(uint8*)&attr);
outT.Write((int16)(dbgFunc->mType->mParams.size() - (hasThis ? 1 : 0)));
outT.Write((int32)dbgFunc->mCvArgListId);
}
DbgTEndTag();
}
void BeCOFFObject::DbgMakeFunc(BeDbgFunction* dbgFunc)
{
auto& outT = mDebugTSect.mData;
2022-07-27 12:26:36 -04:00
BF_ASSERT(dbgFunc->mCvTypeId == -1);
2019-08-23 11:56:54 -07:00
DbgMakeFuncType(dbgFunc);
auto dbgType = BeValueDynCast<BeDbgType>(dbgFunc->mScope);
if (dbgType != NULL)
{
dbgFunc->mCvFuncId = mCurTagId++;
DbgTStartTag();
outT.Write((int16)LF_MFUNC_ID);
outT.Write(dbgType->mCvDeclTypeId);
outT.Write(dbgFunc->mCvTypeId);
DbgEncodeString(outT, dbgFunc->mName);
DbgTEndTag();
}
else
{
dbgFunc->mCvFuncId = mCurTagId++;
DbgTStartTag();
outT.Write((int16)LF_FUNC_ID);
outT.Write((int32)0); // ScopeID (global)
outT.Write(dbgFunc->mCvTypeId);
DbgEncodeString(outT, dbgFunc->mName);
DbgTEndTag();
}
}
void BeCOFFObject::DbgTAlign()
{
int curPos = mDebugTSect.mData.GetPos();
2022-07-27 12:26:36 -04:00
// Perform alignment
2019-08-23 11:56:54 -07:00
int addPadding = (4 - (curPos & 3)) % 4;
while (addPadding > 0)
{
mDebugTSect.mData.Write((uint8)(0xF0 + addPadding));
addPadding--;
}
}
void BeCOFFObject::DbgTStartTag()
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
BF_ASSERT(mTTagStartPos == -1);
mTTagStartPos = mDebugTSect.mData.GetPos();
mDebugTSect.mData.Write((int16)0);
}
void BeCOFFObject::DbgTEndTag()
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
BF_ASSERT(mTTagStartPos != -1);
DbgTAlign();
2022-07-27 12:26:36 -04:00
int tagSize = mDebugTSect.mData.GetPos() - mTTagStartPos;
BF_ASSERT(tagSize <= 0xFFFF);
2019-08-23 11:56:54 -07:00
*((int16*)&mDebugTSect.mData.mData[mTTagStartPos]) = (int16)(tagSize - 2);
mTTagStartPos = -1;
}
int BeCOFFObject::DbgGetTypeId(BeDbgType* dbgType, bool doDefine)
{
if (dbgType == NULL)
return 0;
if ((!doDefine && (dbgType->mCvDeclTypeId != -1)))
{
if (dbgType->mCvDefTypeId != -1)
return dbgType->mCvDefTypeId;
return dbgType->mCvDeclTypeId;
}
if ((doDefine) && (dbgType->mCvDefTypeId != -1))
return dbgType->mCvDefTypeId;
auto& outT = mDebugTSect.mData;
auto structType = BeValueDynCast<BeDbgStructType>(dbgType);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
if (structType != NULL)
{
2022-07-27 12:26:36 -04:00
//lfClass classInfo;
2019-08-23 11:56:54 -07:00
//BF_CLEAR_VALUE(classInfo);
2022-07-27 12:26:36 -04:00
//classInfo.leaf = LF_STRUCTURE;
CV_prop_t structProp = { 0 };
2019-08-23 11:56:54 -07:00
if (structType->mAlign == 1)
structProp.packed = true;
int fieldListTag = 0;
2022-07-27 12:26:36 -04:00
int memberCount = 0;
2019-08-23 11:56:54 -07:00
if (doDefine)
{
// Pass over all needed types first to make sure we generate any forward references we'll need
// because we're locked in inbetween DbgTStartTag and DbgTEndTag
DbgGetTypeId(dbgType);
DbgGetTypeId(structType->mDerivedFrom);
for (auto member : structType->mMembers)
{
2022-07-27 12:26:36 -04:00
auto type = member->mType;
2019-08-23 11:56:54 -07:00
DbgGetTypeId(type);
}
for (auto func : structType->mMethods)
2022-07-27 12:26:36 -04:00
DbgMakeFuncType(func);
2019-08-23 11:56:54 -07:00
fieldListTag = mCurTagId++;
//int tagStartPos = -1;
DbgTStartTag();
outT.Write((int16)LF_FIELDLIST);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
if (structType->mDerivedFrom != NULL)
{
outT.Write((int16)LF_BCLASS);
CV_fldattr_t attr = { 0 };
attr.access = 3; // public
outT.Write(*(int16*)&attr);
outT.Write(DbgGetTypeId(structType->mDerivedFrom));
DbgEncodeConstant(outT, 0); // Offset
DbgTAlign();
}
auto _CheckFieldOverflow = [&]()
{
int tagSize = mDebugTSect.mData.GetPos() - mTTagStartPos;
if (tagSize >= 0xE000)
2019-08-23 11:56:54 -07:00
{
int extFieldListTag = mCurTagId++;
outT.Write((int16)LF_INDEX);
2022-07-27 12:26:36 -04:00
outT.Write((int16)0); // Padding
2019-08-23 11:56:54 -07:00
outT.Write((int32)extFieldListTag); // Padding
DbgTEndTag();
DbgTStartTag();
outT.Write((int16)LF_FIELDLIST);
}
};
for (auto member : structType->mMembers)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
_CheckFieldOverflow();
if (member->mIsStatic)
outT.Write((int16)LF_STMEMBER);
else
outT.Write((int16)LF_MEMBER);
CV_fldattr_t attr = { 0 };
if ((member->mFlags & 3) == llvm::DINode::FlagPrivate)
attr.access = 1;
else if ((member->mFlags & 3) == llvm::DINode::FlagProtected)
attr.access = 2;
else
attr.access = 3;
outT.Write(*(int16*)&attr);
outT.Write(DbgGetTypeId(member->mType));
if (!member->mIsStatic)
2022-07-27 12:26:36 -04:00
DbgEncodeConstant(outT, member->mOffset);
2019-08-23 11:56:54 -07:00
DbgEncodeString(outT, member->mName);
memberCount++;
DbgTAlign();
}
for (auto func : structType->mMethods)
{
_CheckFieldOverflow();
//TODO: Handle static methods
outT.Write((int16)LF_ONEMETHOD);
CV_fldattr_t attr = { 0 };
if ((func->mFlags & 3) == llvm::DINode::FlagPrivate)
attr.access = 1;
else if ((func->mFlags & 3) == llvm::DINode::FlagProtected)
attr.access = 2;
else
attr.access = 3;
if ((func->mFlags & llvm::DINode::FlagArtificial) != 0)
attr.compgenx = 1;
bool isVirt = func->mVK > 0;
if (isVirt)
attr.mprop = CV_MTintro;
outT.Write(*(int16*)&attr);
outT.Write(func->mCvTypeId);
if (isVirt)
outT.Write((int32)func->mVIndex * mBeModule->mContext->mPointerSize);
2019-08-23 11:56:54 -07:00
DbgEncodeString(outT, func->mName);
memberCount++;
DbgTAlign();
}
// LF_FIELDLIST
DbgTEndTag();
}
else
{
structProp.fwdref = 1;
}
DbgTStartTag();
outT.Write((int16)LF_STRUCTURE);
outT.Write((int16)memberCount);
outT.Write(*(int16*)&structProp);
outT.Write((int32)fieldListTag);
outT.Write((int32)0); //derivedfrom - should we ever set this?
outT.Write((int32)0); //vshape
if (doDefine)
2022-07-27 12:26:36 -04:00
DbgEncodeConstant(outT, structType->mSize);
2019-08-23 11:56:54 -07:00
else
DbgEncodeConstant(outT, 0);
String fullName;
2022-07-27 12:26:36 -04:00
ToString(structType, fullName);
2019-08-23 11:56:54 -07:00
2022-07-27 12:26:36 -04:00
DbgEncodeString(outT, fullName);
2019-08-23 11:56:54 -07:00
DbgTEndTag(); // LF_STRUCTURE
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
if (doDefine)
dbgType->mCvDefTypeId = mCurTagId++;
else
dbgType->mCvDeclTypeId = mCurTagId++;
if (doDefine)
{
int strId = mCurTagId++;
DbgTStartTag();
outT.Write((int16)LF_STRING_ID);
outT.Write(0);
String fullPath;
structType->mDefFile->ToString(fullPath);
DbgEncodeString(outT, fullPath);
DbgTEndTag();
mCurTagId++;
DbgTStartTag();
outT.Write((int16)LF_UDT_SRC_LINE);
outT.Write(structType->mCvDefTypeId);
outT.Write(strId);
outT.Write(structType->mDefLine + 1);
DbgTEndTag();
/*for (auto func : structType->mMethods)
{
// Yes, using declTypeId is correct here
DbgTStartTag();
outT.Write((int16)LF_MFUNC_ID);
outT.Write(declTypeId);
outT.Write(func->mCvTypeId);
DbgEncodeString(outT, func->mName);
DbgTEndTag();
func->mCvFuncId = mCurTagId++;
}*/
return dbgType->mCvDefTypeId;
}
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
return dbgType->mCvDeclTypeId;
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
else if (auto enumType = BeValueDynCast<BeDbgEnumType>(dbgType))
{
int fieldListId = 0;
if (enumType->mIsFullyDefined)
{
fieldListId = mCurTagId++;
//int tagStartPos = -1;
DbgTStartTag();
outT.Write((int16)LF_FIELDLIST);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
for (auto member : enumType->mMembers)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
outT.Write((int16)LF_ENUMERATE);
CV_fldattr_t attr = { 0 };
attr.access = 3; // public
2022-07-27 12:26:36 -04:00
outT.Write(*(int16*)&attr);
2019-08-23 11:56:54 -07:00
DbgEncodeConstant(outT, member->mValue);
DbgEncodeString(outT, member->mName);
DbgTAlign();
}
// LF_FIELDLIST
DbgTEndTag();
}
int32 elementId = T_VOID;
if (enumType->mElementType != NULL)
elementId = DbgGetTypeId(enumType->mElementType);
//int32 elementId = DbgGetTypeId(enumType->mElementType);
2022-07-27 12:26:36 -04:00
CV_prop_t structProp = { 0 };
2019-08-23 11:56:54 -07:00
if (!enumType->mIsFullyDefined)
structProp.fwdref = 1;
DbgTStartTag();
outT.Write((int16)LF_ENUM);
2022-07-27 12:26:36 -04:00
outT.Write((int16)enumType->mMembers.size());
2019-08-23 11:56:54 -07:00
outT.Write(*(int16*)&structProp);
outT.Write(elementId);
outT.Write((int32)fieldListId);
String fullName;
ToString(dbgType, fullName);
DbgEncodeString(outT, fullName);
DbgTEndTag();
dbgType->mCvDeclTypeId = dbgType->mCvDefTypeId = mCurTagId++;
return dbgType->mCvDefTypeId;
}
else if (auto dbgBasicType = BeValueDynCast<BeDbgBasicType>(dbgType))
{
switch (dbgBasicType->mEncoding)
{
case llvm::dwarf::DW_ATE_address:
dbgBasicType->mCvDefTypeId = 0;
break;
case llvm::dwarf::DW_ATE_signed:
switch (dbgBasicType->mSize)
{
case 1: dbgBasicType->mCvDefTypeId = T_INT1; break;
case 2: dbgBasicType->mCvDefTypeId = T_SHORT; break;
case 4: dbgBasicType->mCvDefTypeId = T_INT4; break;
case 8: dbgBasicType->mCvDefTypeId = T_QUAD; break;
}
break;
case llvm::dwarf::DW_ATE_unsigned:
switch (dbgBasicType->mSize)
{
case 1: dbgBasicType->mCvDefTypeId = T_UINT1; break;
case 2: dbgBasicType->mCvDefTypeId = T_USHORT; break;
case 4: dbgBasicType->mCvDefTypeId = T_UINT4; break;
case 8: dbgBasicType->mCvDefTypeId = T_UQUAD; break;
}
break;
case llvm::dwarf::DW_ATE_float:
switch (dbgBasicType->mSize)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
case 4: dbgBasicType->mCvDefTypeId = T_REAL32; break;
case 8: dbgBasicType->mCvDefTypeId = T_REAL64; break;
}
break;
case llvm::dwarf::DW_ATE_unsigned_char:
switch (dbgBasicType->mSize)
{
case 1: dbgBasicType->mCvDefTypeId = T_CHAR; break;
case 2: dbgBasicType->mCvDefTypeId = T_CHAR16; break;
case 4: dbgBasicType->mCvDefTypeId = T_CHAR32; break;
}
break;
case llvm::dwarf::DW_ATE_boolean:
dbgBasicType->mCvDefTypeId = T_BOOL08;
break;
}
dbgBasicType->mCvDeclTypeId = dbgBasicType->mCvDefTypeId;
return dbgBasicType->mCvDeclTypeId;
}
else if (auto ptrType = BeValueDynCast<BeDbgPointerType>(dbgType))
{
if (auto innerBasicType = BeValueDynCast<BeDbgBasicType>(ptrType->mElement))
{
switch (innerBasicType->mEncoding)
{
case llvm::dwarf::DW_ATE_address:
ptrType->mCvDefTypeId = T_PVOID;
break;
case llvm::dwarf::DW_ATE_signed:
switch (innerBasicType->mSize)
{
case 1: ptrType->mCvDefTypeId = T_64PINT1; break;
case 2: ptrType->mCvDefTypeId = T_64PSHORT; break;
case 4: ptrType->mCvDefTypeId = T_64PINT4; break;
case 8: ptrType->mCvDefTypeId = T_64PINT8; break;
}
break;
case llvm::dwarf::DW_ATE_unsigned:
switch (innerBasicType->mSize)
{
case 1: ptrType->mCvDefTypeId = T_64PUINT1; break;
case 2: ptrType->mCvDefTypeId = T_64PUSHORT; break;
case 4: ptrType->mCvDefTypeId = T_64PUINT4; break;
case 8: ptrType->mCvDefTypeId = T_64PUINT8; break;
}
break;
case llvm::dwarf::DW_ATE_float:
switch (innerBasicType->mSize)
{
case 4: ptrType->mCvDefTypeId = T_64PREAL32; break;
case 8: ptrType->mCvDefTypeId = T_64PREAL64; break;
}
break;
case llvm::dwarf::DW_ATE_unsigned_char:
switch (innerBasicType->mSize)
{
case 1: ptrType->mCvDefTypeId = T_64PUCHAR; break;
case 2: ptrType->mCvDefTypeId = T_64PCHAR16; break;
case 4: ptrType->mCvDefTypeId = T_64PCHAR32; break;
}
break;
case llvm::dwarf::DW_ATE_boolean:
ptrType->mCvDefTypeId = T_64PBOOL08;
break;
}
if (ptrType->mCvDefTypeId != -1)
{
ptrType->mCvDeclTypeId = ptrType->mCvDefTypeId;
return ptrType->mCvDefTypeId;
}
}
lfPointerBody::lfPointerAttr attr = { 0 };
attr.ptrtype = CV_PTR_64;
attr.ptrmode = CV_PTR_MODE_PTR;
attr.size = 8;
int32 elementId = DbgGetTypeId(ptrType->mElement);
DbgTStartTag();
2022-07-27 12:26:36 -04:00
outT.Write((int16)LF_POINTER);
2019-08-23 11:56:54 -07:00
outT.Write(elementId);
outT.Write(*(int32*)&attr);
2022-07-27 12:26:36 -04:00
DbgTEndTag();
2019-08-23 11:56:54 -07:00
dbgType->mCvDeclTypeId = dbgType->mCvDefTypeId = mCurTagId++;
return dbgType->mCvDefTypeId;
}
else if (auto refType = BeValueDynCast<BeDbgReferenceType>(dbgType))
{
lfPointerBody::lfPointerAttr attr = { 0 };
attr.ptrtype = CV_PTR_64;
attr.ptrmode = CV_PTR_MODE_LVREF;
attr.size = 8;
int32 elementId = DbgGetTypeId(refType->mElement);
DbgTStartTag();
2022-07-27 12:26:36 -04:00
outT.Write((int16)LF_POINTER);
2019-08-23 11:56:54 -07:00
outT.Write(elementId);
2022-07-27 12:26:36 -04:00
outT.Write(*(int32*)&attr);
2019-08-23 11:56:54 -07:00
DbgTEndTag();
dbgType->mCvDeclTypeId = dbgType->mCvDefTypeId = mCurTagId++;
return dbgType->mCvDefTypeId;
}
else if (auto constType = BeValueDynCast<BeDbgConstType>(dbgType))
2022-07-27 12:26:36 -04:00
{
CV_modifier_t attr = { 0 };
2019-08-23 11:56:54 -07:00
attr.MOD_const = 1;
2022-03-08 06:27:06 -08:00
int32 elementId = DbgGetTypeId(BeValueDynCast<BeDbgType>(constType->mElement));
2019-08-23 11:56:54 -07:00
DbgTStartTag();
2022-07-27 12:26:36 -04:00
outT.Write((int16)LF_MODIFIER);
2019-08-23 11:56:54 -07:00
outT.Write(elementId);
2022-07-27 12:26:36 -04:00
outT.Write(*(int16*)&attr);
2019-08-23 11:56:54 -07:00
DbgTEndTag();
dbgType->mCvDeclTypeId = dbgType->mCvDefTypeId = mCurTagId++;
return dbgType->mCvDefTypeId;
}
else if (auto artificialType = BeValueDynCast<BeDbgArtificialType>(dbgType))
{
return DbgGetTypeId(artificialType->mElement);
}
else if (auto arrayType = BeValueDynCast<BeDbgArrayType>(dbgType))
{
int32 elementId = DbgGetTypeId(arrayType->mElement);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
DbgTStartTag();
outT.Write((int16)LF_ARRAY);
outT.Write((int32)elementId);
outT.Write((int32)0x23/*int64*/);
DbgEncodeConstant(outT, BF_ALIGN(arrayType->mSize, arrayType->mAlign));
DbgEncodeString(outT, "");
DbgTEndTag();
dbgType->mCvDeclTypeId = dbgType->mCvDefTypeId = mCurTagId++;
return dbgType->mCvDefTypeId;
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
else
BF_FATAL("NotImpl");
BF_FATAL("Invalid type");
return -1;
}
void BeCOFFObject::DbgGenerateTypeInfo()
{
BP_ZONE("BeCOFFObject::DbgGenerateTypeInfo");
AutoPerf perf("BeCOFFObject::DbgGenerateTypeInfo", mPerfManager);
auto& outT = mDebugTSect.mData;
outT.Write((int)CV_SIGNATURE_C13);
2022-03-08 06:27:06 -08:00
for (auto mdNode : mBeModule->mDbgModule->mTypes)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
bool defineType = true;
2022-03-08 06:27:06 -08:00
if (auto dbgStructType = BeValueDynCast<BeDbgStructType>(mdNode))
2019-08-23 11:56:54 -07:00
{
if (!dbgStructType->mIsFullyDefined)
2022-07-27 12:26:36 -04:00
defineType = false;
2019-08-23 11:56:54 -07:00
}
if (defineType)
{
2022-03-08 06:27:06 -08:00
if (auto dbgType = BeValueDynCast<BeDbgType>(mdNode))
DbgGetTypeId(dbgType, true);
2019-08-23 11:56:54 -07:00
}
}
for (auto dbgFunc : mBeModule->mDbgModule->mFuncs)
{
if (dbgFunc->mValue != NULL)
DbgMakeFunc(dbgFunc);
}
}
void BeCOFFObject::DbgStartSection(int sectionNum)
{
2022-07-27 12:26:36 -04:00
auto& outS = mDebugSSect.mData;
BF_ASSERT(mSectionStartPos == -1);
2019-08-23 11:56:54 -07:00
outS.Write((int32)sectionNum);
outS.Write(0); // Temporary - size
mSectionStartPos = outS.GetPos();
}
void BeCOFFObject::DbgEndSection()
{
2022-07-27 12:26:36 -04:00
auto& outS = mDebugSSect.mData;
int totalLen = outS.GetPos() - mSectionStartPos;
*((int32*)&outS.mData[mSectionStartPos - 4]) = totalLen;
2019-08-23 11:56:54 -07:00
mSectionStartPos = -1;
while ((outS.GetPos() & 3) != 0)
outS.Write((uint8)0);
}
void BeCOFFObject::DbgStartVarDefRange(BeDbgFunction* dbgFunc, BeDbgVariable* dbgVar, const BeDbgVariableLoc& varLoc, int offset, int range)
{
BF_ASSERT(range >= 0);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
auto funcSym = GetSymbol(dbgFunc->mValue);
2022-03-08 06:27:06 -08:00
auto varType = BeValueDynCast<BeDbgType>(dbgVar->mType);
2022-07-27 12:26:36 -04:00
auto& outS = mDebugSSect.mData;
2019-08-23 11:56:54 -07:00
if (varLoc.mKind == BeDbgVariableLoc::Kind_SymbolAddr)
{
BF_FATAL("Not supported");
}
else if (varLoc.mKind == BeDbgVariableLoc::Kind_Reg)
{
if (varLoc.mOfs == 0)
{
outS.Write((int16)S_DEFRANGE_REGISTER);
2022-03-08 06:27:06 -08:00
outS.Write((int16)GetCVRegNum(varLoc.mReg, varType->mSize * 8));
2019-08-23 11:56:54 -07:00
CV_RANGEATTR rangeAttr = { 0 };
outS.Write(*(int16*)&rangeAttr); // offset to register
}
else
{
outS.Write((int16)S_DEFRANGE_REGISTER_REL);
2022-03-08 06:27:06 -08:00
outS.Write((int16)GetCVRegNum(varLoc.mReg, varType->mSize * 8));
2019-08-23 11:56:54 -07:00
outS.Write((int16)0);
outS.Write((int32)varLoc.mOfs);
// CV_RANGEATTR rangeAttr = { 0 };
// outS.Write(*(int16*)&rangeAttr); // offset to register
}
}
else //if (varLoc.mKind == BeDbgVariableLoc::Kind_Indexed)
{
outS.Write((int16)S_DEFRANGE_REGISTER_REL);
outS.Write((int16)GetCVRegNum(varLoc.mReg, 64));
outS.Write((int16)0); // offset in parent
outS.Write((int32)varLoc.mOfs); // offset to register
}
BeMCRelocation reloc;
reloc.mKind = BeMCRelocationKind_SECREL;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = funcSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int32)offset); // offset start
reloc.mKind = BeMCRelocationKind_SECTION;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = funcSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int16)0); // section
2022-07-27 12:26:36 -04:00
outS.Write((int16)range); // Range
2019-08-23 11:56:54 -07:00
}
void BeCOFFObject::DbgEndLineBlock(BeDbgFunction* dbgFunc, const Array<BeDbgCodeEmission>& emissions, int blockStartPos, int emissionStartIdx, int lineCount)
{
auto& outS = mDebugSSect.mData;
int addLineCount = 0;
if ((emissionStartIdx == 0) && (dbgFunc->mLine != -1))
{
outS.Write((int16)0);
outS.Write((int16)0);
addLineCount++;
}
for (int emissionIdx = emissionStartIdx; emissionIdx < emissionStartIdx + lineCount; emissionIdx++)
{
auto& codeEmission = emissions[emissionIdx];
// Start column
outS.Write((int16)(codeEmission.mDbgLoc->mColumn + 1));
// End column
outS.Write((int16)(codeEmission.mDbgLoc->mColumn + 1));
}
*(int*)(&outS.mData[blockStartPos] + 4) = lineCount + addLineCount;
*(int*)(&outS.mData[blockStartPos] + 8) = outS.GetPos() - blockStartPos;
}
void BeCOFFObject::DbgSAlign()
{
int curPos = mDebugSSect.mData.GetPos();
2022-07-27 12:26:36 -04:00
// Perform alignment
2019-08-23 11:56:54 -07:00
int addPadding = (4 - (curPos & 3)) % 4;
while (addPadding > 0)
{
mDebugSSect.mData.Write((uint8)0);
addPadding--;
}
}
void BeCOFFObject::DbgSStartTag()
{
BF_ASSERT(mSTagStartPos == -1);
mSTagStartPos = mDebugSSect.mData.GetPos();
mDebugSSect.mData.Write((int16)0);
}
void BeCOFFObject::DbgSEndTag()
{
BF_ASSERT(mSTagStartPos != -1);
int tagSize = mDebugSSect.mData.GetPos() - mSTagStartPos;
BF_ASSERT(tagSize <= 0xFFFF);
2019-08-23 11:56:54 -07:00
*((uint16*)&mDebugSSect.mData.mData[mSTagStartPos]) = (uint16)(tagSize - 2);
mSTagStartPos = -1;
}
void BeCOFFObject::DbgOutputLocalVar(BeDbgFunction* dbgFunc, BeDbgVariable* dbgVar)
2022-07-27 12:26:36 -04:00
{
2022-03-08 06:27:06 -08:00
auto varType = BeValueDynCast<BeDbgType>(dbgVar->mType);
2019-08-23 11:56:54 -07:00
// CodeView only allows 16-bit lengths, so we need to split ranges for very long spans
if (dbgVar->mDeclEnd - dbgVar->mDeclStart > 0xFFFF)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
int splitPos = dbgVar->mDeclStart + 0xFFFF;
BeDbgVariable varStart = *dbgVar;
varStart.mDeclEnd = splitPos;
Array<BeDbgVariableRange>* startArrs[2] = { &varStart.mSavedRanges, &varStart.mGaps };
for (auto& arr : startArrs)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
for (int arrIdx = 0; arrIdx < (int)arr->size(); arrIdx++)
{
auto& gap = (*arr)[arrIdx];
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
int gapStart = gap.mOffset;
int gapEnd = gap.mOffset + gap.mLength;
if (gapStart > splitPos)
gapStart = splitPos;
if (gapEnd > splitPos)
gapEnd = splitPos;
if (gapStart == gapEnd)
{
arr->RemoveAt(arrIdx);
arrIdx--;
}
else
{
gap.mOffset = gapStart;
gap.mLength = gapEnd - gapStart;
BF_ASSERT(gap.mLength > 0);
}
}
}
DbgOutputLocalVar(dbgFunc, &varStart);
BeDbgVariable varEnd = *dbgVar;
varEnd.mDeclStart = splitPos;
Array<BeDbgVariableRange>* endArrs[2] = { &varEnd.mSavedRanges, &varEnd.mGaps };
for (auto& arr : endArrs)
{
for (int arrIdx = 0; arrIdx < (int)arr->size(); arrIdx++)
{
auto& gap = (*arr)[arrIdx];
2022-07-27 12:26:36 -04:00
int gapStart = gap.mOffset;
2019-08-23 11:56:54 -07:00
if (gapStart < splitPos)
gapStart = splitPos;
if (gap.mLength == -1)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
gap.mOffset = gapStart;
continue;
}
2022-07-27 12:26:36 -04:00
int gapEnd = gap.mOffset + gap.mLength;
2019-08-23 11:56:54 -07:00
if (gapEnd < splitPos)
gapEnd = splitPos;
if (gapStart == gapEnd)
{
arr->RemoveAt(arrIdx);
arrIdx--;
}
else
{
gap.mOffset = gapStart;
gap.mLength = gapEnd - gapStart;
BF_ASSERT(gap.mLength > 0);
}
}
}
DbgOutputLocalVar(dbgFunc, &varEnd);
}
auto& outS = mDebugSSect.mData;
DbgSStartTag();
outS.Write((int16)S_LOCAL);
2022-03-08 06:27:06 -08:00
outS.Write(DbgGetTypeId(varType));
2019-08-23 11:56:54 -07:00
CV_LVARFLAGS flags = { 0 };
if (dbgVar->mParamNum != -1)
flags.fIsParam = 1;
outS.Write(*(int16*)&flags);
bool isConst = false;
2022-07-27 12:26:36 -04:00
String varName = dbgVar->mName;
2019-08-23 11:56:54 -07:00
bool isGlobal = false;
//
{
auto checkVal = dbgVar->mValue;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
if (auto beCast = BeValueDynCast<BeCastConstant>(checkVal))
checkVal = beCast->mTarget;
if (auto beGlobal = BeValueDynCast<BeGlobalVariable>(checkVal))
{
isGlobal = true;
}
}
if (!isGlobal)
{
if (auto beConst = BeValueDynCast<BeConstant>(dbgVar->mValue))
{
if ((beConst->mType != NULL) && (!beConst->mType->IsPointer()))
2019-08-23 11:56:54 -07:00
{
int64 writeVal = beConst->mInt64;
2022-02-06 08:35:25 -05:00
if (beConst->mType->mTypeCode == BeTypeCode_Float)
{
// We need to do this because Singles are stored in mDouble, so we need to reduce here
float floatVal = (float)beConst->mDouble;
writeVal = *(uint32*)&floatVal;
}
if (writeVal < 0)
varName += StrFormat("$_%llu", -writeVal);
else
varName += StrFormat("$%llu", writeVal);
isConst = true;
2019-08-23 11:56:54 -07:00
}
}
}
DbgEncodeString(outS, varName);
DbgSEndTag();
// TODO: Split these up into multiple variables if we cover more than 0xF000 bytes...
DbgSStartTag();
/*if (dbgVar->mDeclEnd == -1)
dbgVar->mDeclEnd = dbgFunc->mCodeLen;*/
int declEnd = dbgVar->mDeclEnd;
if (declEnd == -1)
{
declEnd = dbgFunc->mCodeLen;
if ((dbgVar->mGaps.size() == 1) && (dbgVar->mGaps[0].mOffset == dbgVar->mDeclStart) && (dbgVar->mGaps[0].mLength == -1) && (!isConst))
2022-07-27 12:26:36 -04:00
{
// Variable not used
2019-08-23 11:56:54 -07:00
declEnd = dbgVar->mDeclStart;
}
}
else if (dbgVar->mDeclLifetimeExtend)
declEnd++;
DbgStartVarDefRange(dbgFunc, dbgVar, dbgVar->mPrimaryLoc, dbgVar->mDeclStart, declEnd - dbgVar->mDeclStart);
if (!isConst)
{
for (auto gap : dbgVar->mGaps)
{
if (gap.mLength == 0)
continue;
if (gap.mLength == -1)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
// Not a real gap, and not an unused variable indicator
if (gap.mOffset > dbgVar->mDeclStart)
continue;
if (gap.mOffset == dbgVar->mDeclEnd)
continue;
}
outS.Write((int16)(gap.mOffset - dbgVar->mDeclStart));
if (gap.mLength == -1)
{
// This means we never even used the variable
BF_ASSERT(gap.mOffset == dbgVar->mDeclStart);
outS.Write((int16)(declEnd - gap.mOffset));
}
else
{
outS.Write((int16)gap.mLength);
}
}
}
DbgSEndTag(); // S_DEFRANGE_X
if (!dbgVar->mSavedRanges.empty())
{
auto& lastSavedRange = dbgVar->mSavedRanges.back();
if (lastSavedRange.mLength == -1)
{
// This can happen if our variable dies before a saved register restore
lastSavedRange.mLength = dbgFunc->mCodeLen - lastSavedRange.mOffset;
}
auto savedDeclStart = dbgVar->mSavedRanges[0].mOffset;
// If there is only one value in mSavedRanges, then encode this as just that single span with no gaps
// Otherwise add gap information for the space between the mSavedRanges values
DbgSStartTag();
DbgStartVarDefRange(dbgFunc, dbgVar, dbgVar->mSavedLoc, savedDeclStart,
(lastSavedRange.mOffset + lastSavedRange.mLength) - savedDeclStart);
for (int saveGapIdx = 0; saveGapIdx < (int)dbgVar->mSavedRanges.size() - 1; saveGapIdx++)
{
auto& saveRange0 = dbgVar->mSavedRanges[saveGapIdx];
auto& saveRange1 = dbgVar->mSavedRanges[saveGapIdx + 1];
outS.Write((int16)(saveRange0.mOffset + saveRange0.mLength - savedDeclStart));
outS.Write((int16)(saveRange1.mOffset - (saveRange0.mOffset + saveRange0.mLength)));
}
DbgSEndTag(); // S_DEFRANGE_X
}
}
void BeCOFFObject::DbgOutputLocalVars(BeInlineLineBuilder* curInlineBuilder, BeDbgFunction* dbgFunc)
{
auto& outS = mDebugSSect.mData;
for (auto dbgVar : curInlineBuilder->mVariables)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
if (dbgVar == NULL)
continue;
DbgOutputLocalVar(dbgFunc, dbgVar);
}
}
void BeCOFFObject::DbgGenerateModuleInfo()
{
BP_ZONE("BeCOFFObject::DbgGenerateModuleInfo");
AutoPerf perf("BeCOFFObject::DbgGenerateModuleInfo", mPerfManager);
auto& outS = mDebugSSect.mData;
outS.Write((int)CV_SIGNATURE_C13);
2022-07-27 12:26:36 -04:00
2020-03-30 09:53:44 -07:00
Array<int> fileDataPositions;
2019-08-23 11:56:54 -07:00
Array<BeDbgFunction*> inlinees;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
// Funcs
for (auto dbgFunc : mBeModule->mDbgModule->mFuncs)
{
if (dbgFunc->mValue == NULL)
2022-07-27 12:26:36 -04:00
continue;
2019-08-23 11:56:54 -07:00
if (dbgFunc->mCvFuncId == -1)
continue;
BF_ASSERT(dbgFunc->mCvFuncId != -1);
auto funcSym = GetSymbol(dbgFunc->mValue, false);
if (funcSym == NULL)
continue;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
DbgStartSection(DEBUG_S_SYMBOLS);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
DbgSStartTag();
if (dbgFunc->mValue->mLinkageType == BfIRLinkageType_Internal)
outS.Write((int16)S_LPROC32_ID);
else
outS.Write((int16)S_GPROC32_ID);
outS.Write((int32)0); // PtrParent
outS.Write((int32)0); // PtrEnd
outS.Write((int32)0); // PtrNext
outS.Write((int32)BF_MAX(dbgFunc->mCodeLen, 0)); // CodeSize
outS.Write((int32)0); // DbgStart
outS.Write((int32)0); // DbgEnd
2022-07-27 12:26:36 -04:00
outS.Write(dbgFunc->mCvFuncId);
2019-08-23 11:56:54 -07:00
BeMCRelocation reloc;
reloc.mKind = BeMCRelocationKind_SECREL;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = funcSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int32)0); // off
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
reloc.mKind = BeMCRelocationKind_SECTION;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = funcSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int16)0); // seg
CV_PROCFLAGS procFlags = { 0 };
outS.Write(*(uint8*)&procFlags);
String fullName;
if ((BeValueDynCast<BeDbgNamespace>(dbgFunc->mScope) != NULL) ||
(BeValueDynCast<BeDbgStructType>(dbgFunc->mScope) != NULL))
ToString(dbgFunc->mScope, fullName);
if (!fullName.empty())
fullName += "::";
fullName += dbgFunc->mName;
DbgEncodeString(outS, fullName);
2022-07-27 12:26:36 -04:00
DbgSEndTag();
2019-08-23 11:56:54 -07:00
BeInlineLineBuilder* curInlineBuilder = NULL;
BeDbgLoc* curDbgLoc = NULL;
OwnedVector<BeInlineLineBuilder> inlineBuilders;
Array<BeInlineLineBuilder*> inlineStack;
Dictionary<BeDbgLoc*, BeInlineLineBuilder*> inlineMap;
// Build inline table
for (int emissionIdx = 0; emissionIdx < (int)dbgFunc->mEmissions.size(); emissionIdx++)
{
auto& codeEmission = dbgFunc->mEmissions[emissionIdx];
auto newDbgLoc = codeEmission.mDbgLoc;
if (curDbgLoc != newDbgLoc)
{
curDbgLoc = newDbgLoc;
2022-07-27 12:26:36 -04:00
int newInlineDepth = newDbgLoc->GetInlineDepth();
2019-08-23 11:56:54 -07:00
int curInlineDepth = 0;
if (curInlineBuilder != NULL)
curInlineDepth = curInlineBuilder->mStartDbgLoc->GetInlineDepth();
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
int depthMatch = 0;
if (curInlineBuilder != NULL)
2022-07-27 12:26:36 -04:00
depthMatch = curDbgLoc->GetInlineMatchDepth(curInlineBuilder->mStartDbgLoc);
2019-08-23 11:56:54 -07:00
while (curInlineDepth > depthMatch)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
curInlineBuilder->End(&codeEmission);
inlineStack.pop_back();
if (inlineStack.empty())
curInlineBuilder = NULL;
else
2022-07-27 12:26:36 -04:00
curInlineBuilder = inlineStack.back();
2019-08-23 11:56:54 -07:00
curInlineDepth--;
}
// Check for new inlines
while (newInlineDepth > curInlineDepth)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
auto inlineBuilder = inlineBuilders.Alloc<BeInlineLineBuilder>();
// If we add more than one inline depth at a time then we need to set startDbgLoc appropriately
int inlineIdx = newInlineDepth - curInlineDepth - 2;
if (inlineIdx == -1)
inlineBuilder->mStartDbgLoc = codeEmission.mDbgLoc;
else
inlineBuilder->mStartDbgLoc = codeEmission.mDbgLoc->GetInlinedAt(inlineIdx);
auto dbgFunc = inlineBuilder->mStartDbgLoc->GetDbgFunc();
if (!inlinees.Contains(dbgFunc))
inlinees.Add(dbgFunc);
inlineBuilder->mCurLine = dbgFunc->mLine;
2022-07-27 12:26:36 -04:00
inlineBuilder->Start(&codeEmission);
2019-08-23 11:56:54 -07:00
curInlineBuilder = inlineBuilder;
inlineStack.push_back(curInlineBuilder);
curInlineDepth++;
BF_ASSERT(inlineBuilder->mStartDbgLoc->mDbgInlinedAt != NULL);
inlineMap[inlineBuilder->mStartDbgLoc->mDbgInlinedAt] = inlineBuilder;
}
if (curInlineBuilder != NULL)
2022-07-27 12:26:36 -04:00
curInlineBuilder->Update(&codeEmission);
}
2019-08-23 11:56:54 -07:00
}
BF_ASSERT(inlineStack.empty());
for (auto dbgVar : dbgFunc->mVariables)
{
2022-07-27 12:26:36 -04:00
if ((dbgVar == NULL) || (dbgVar->mDeclDbgLoc == NULL))
2019-08-23 11:56:54 -07:00
continue;
if (dbgVar->mDeclDbgLoc->mDbgInlinedAt == NULL)
continue;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
BeInlineLineBuilder* inlineBuilder = NULL;
if (inlineMap.TryGetValue(dbgVar->mDeclDbgLoc->mDbgInlinedAt, &inlineBuilder))
{
//auto inlineBuilder = itr->second;
inlineBuilder->mVariables.push_back(dbgVar);
}
}
// Emit inlines and variables
int inlineBuilderIdx = 0;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
curInlineBuilder = NULL;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
for (auto dbgVar : dbgFunc->mVariables)
2022-07-27 12:26:36 -04:00
{
if ((dbgVar == NULL) || (dbgVar->mDeclDbgLoc == NULL))
2019-08-23 11:56:54 -07:00
continue;
if (dbgVar->mDeclDbgLoc->mDbgInlinedAt == NULL)
DbgOutputLocalVar(dbgFunc, dbgVar);
}
while ((inlineBuilderIdx < (int)inlineBuilders.size()) || (curInlineBuilder != NULL) /*|| (varIdx < (int)dbgFunc->mVariables.size())*/)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
BeInlineLineBuilder* newInlineBuilder = NULL;
int curInlineDepth = 0;
if (curInlineBuilder != NULL)
curInlineDepth = curInlineBuilder->mStartDbgLoc->GetInlineDepth();
int newInlineDepth = 0;
if (inlineBuilderIdx < (int)inlineBuilders.size())
{
newInlineBuilder = inlineBuilders[inlineBuilderIdx++];
newInlineDepth = newInlineBuilder->mStartDbgLoc->GetInlineDepth();
}
int depthMatch = 0;
if ((curInlineBuilder != NULL) && (newInlineBuilder != NULL))
depthMatch = curInlineBuilder->mStartDbgLoc->GetInlineMatchDepth(newInlineBuilder->mStartDbgLoc);
if ((curInlineDepth == newInlineDepth) && (depthMatch == newInlineDepth) && (depthMatch > 0))
{
// If we inline two of the same methods on the same line then its possible they share the same inlined position
// But we know there is a unique item here
depthMatch--;
}
while (curInlineDepth > depthMatch)
{
DbgSStartTag();
outS.Write((int16)S_INLINESITE_END);
DbgSEndTag();
curInlineDepth--;
inlineStack.pop_back();
if (inlineStack.empty())
curInlineBuilder = NULL;
else
2022-07-27 12:26:36 -04:00
curInlineBuilder = inlineStack.back();
2019-08-23 11:56:54 -07:00
}
if (newInlineDepth > curInlineDepth)
{
BF_ASSERT(newInlineDepth == curInlineDepth + 1);
DbgSStartTag();
outS.Write((int16)S_INLINESITE);
outS.Write((int32)0); // pParent
outS.Write((int32)0); // pEnd
auto inlinedDbgFunc = newInlineBuilder->mStartDbgLoc->GetDbgFunc();
if (inlinedDbgFunc->mCvFuncId == -1)
DbgMakeFunc(inlinedDbgFunc);
2022-07-27 12:26:36 -04:00
outS.Write(inlinedDbgFunc->mCvFuncId);
2019-08-23 11:56:54 -07:00
outS.Write(&newInlineBuilder->mData[0], (int)newInlineBuilder->mData.size());
DbgSEndTag();
newInlineDepth++;
inlineStack.push_back(newInlineBuilder);
curInlineBuilder = newInlineBuilder;
DbgOutputLocalVars(curInlineBuilder, dbgFunc);
}
// This can fail if an inlined method is not emitted contiguously, or if multiple copies of the same method
// get inlined at exactly the same DbgLoc -- which isn't possible in Beef
2022-06-01 11:01:13 -07:00
//BF_ASSERT(curInlineBuilder == newInlineBuilder);
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
DbgSStartTag();
outS.Write((int16)S_PROC_ID_END);
DbgSEndTag();
DbgEndSection(); // DEBUG_S_SYMBOLS
if (dbgFunc->mEmissions.empty())
continue;
DbgStartSection(DEBUG_S_LINES);
reloc.mKind = BeMCRelocationKind_SECREL;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = funcSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int32)0x0); // offset contribution
reloc.mKind = BeMCRelocationKind_SECTION;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = funcSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int16)0); // section contribution
int16 flags = CV_LINES_HAVE_COLUMNS;
outS.Write((int16)flags);
outS.Write(dbgFunc->mCodeLen); // contribution size
// Iterate over lines
// int32 offFile (file num)
// int32 nLines
// int32 cbBlock
curDbgLoc = NULL;
BeDbgFile* curFile = NULL;
2022-07-27 12:26:36 -04:00
int lastBlockStartPos = -1;
int lineCount = 0;
2019-08-23 11:56:54 -07:00
Array<BeDbgCodeEmission> emissions;
2022-07-27 12:26:36 -04:00
emissions.Reserve(dbgFunc->mEmissions.size());
2019-08-23 11:56:54 -07:00
for (int emissionIdx = 0; emissionIdx < (int)dbgFunc->mEmissions.size(); emissionIdx++)
{
auto& codeEmission = dbgFunc->mEmissions[emissionIdx];
auto rootDbgLoc = codeEmission.mDbgLoc->GetRoot();
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
bool doEmission = true;
if (!emissions.empty())
{
if (rootDbgLoc == emissions.back().mDbgLoc)
2022-07-27 12:26:36 -04:00
doEmission = false;
2019-08-23 11:56:54 -07:00
}
if (doEmission)
{
BeDbgCodeEmission newEmission;
newEmission.mDbgLoc = rootDbgLoc;
newEmission.mPos = codeEmission.mPos;
emissions.push_back(newEmission);
}
}
2022-07-27 12:26:36 -04:00
2020-03-23 12:07:05 -07:00
///
{
int fileDataPos = 0;
for (auto dbgFile : mBeModule->mDbgModule->mFiles)
{
fileDataPositions.Add(fileDataPos);
fileDataPos += 4;
if (dbgFile->mMD5Hash.IsZero())
fileDataPos += 4;
else
fileDataPos += 20;
}
}
2019-08-23 11:56:54 -07:00
int emissionStartIdx = 0;
BeDbgFile* curDbgFile = NULL;
for (int emissionIdx = 0; emissionIdx < (int)emissions.size(); emissionIdx++)
{
auto& codeEmission = emissions[emissionIdx];
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
auto dbgLoc = codeEmission.mDbgLoc;
BeDbgFile* dbgFile = dbgLoc->GetDbgFile();
if (dbgFile != curDbgFile)
{
if (curDbgLoc != NULL)
{
DbgEndLineBlock(dbgFunc, emissions, lastBlockStartPos, emissionStartIdx, lineCount);
lineCount = 0;
emissionStartIdx = emissionIdx;
}
2022-07-27 12:26:36 -04:00
curDbgLoc = dbgLoc;
2019-08-23 11:56:54 -07:00
curDbgFile = dbgFile;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
lastBlockStartPos = outS.GetPos();
2020-03-23 12:07:05 -07:00
outS.Write((int32)fileDataPositions[dbgFile->mIdx]);
2019-08-23 11:56:54 -07:00
outS.Write((int32)0); // placeholder nLines
outS.Write((int32)0); // placeholder cbBlock
if ((emissionIdx == 0) && (dbgFunc->mLine != -1))
{
outS.Write((int32)0);
outS.Write((int32)dbgFunc->mLine + 1);
}
}
outS.Write((int32)codeEmission.mPos);
outS.Write((int32)codeEmission.mDbgLoc->mLine + 1);
lineCount++;
}
if (curDbgLoc != NULL)
DbgEndLineBlock(dbgFunc, emissions, lastBlockStartPos, emissionStartIdx, lineCount);
DbgEndSection(); // DEBUG_S_LINES
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
if (!inlinees.empty())
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
DbgStartSection(DEBUG_S_INLINEELINES);
outS.Write((int32)0); // Lines type
for (auto inlinedDbgFunc : inlinees)
2022-07-27 12:26:36 -04:00
{
BF_ASSERT(inlinedDbgFunc->mCvFuncId != -1);
2019-08-23 11:56:54 -07:00
outS.Write(inlinedDbgFunc->mCvFuncId);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
auto dbgFile = inlinedDbgFunc->mFile;
2020-03-30 09:53:44 -07:00
outS.Write((int32)fileDataPositions[dbgFile->mIdx]);
2019-08-23 11:56:54 -07:00
outS.Write((int32)inlinedDbgFunc->mLine + 1);
}
DbgEndSection();
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
2022-07-27 12:26:36 -04:00
// Global variables
2019-08-23 11:56:54 -07:00
{
2022-07-27 12:26:36 -04:00
bool startedSymbols = false;
2019-08-23 11:56:54 -07:00
for (auto dbgGlobalVar : mBeModule->mDbgModule->mGlobalVariables)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
auto gvSym = GetSymbol(dbgGlobalVar->mValue);
if (gvSym == NULL)
{
//TODO: Is this an error?
continue;
}
if (!startedSymbols)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
DbgStartSection(DEBUG_S_SYMBOLS);
startedSymbols = true;
}
DbgSStartTag();
bool isTLS = false;
2022-07-27 12:26:36 -04:00
if (auto beGlobalVar = BeValueDynCast<BeGlobalVariable>(dbgGlobalVar->mValue))
2019-08-23 11:56:54 -07:00
isTLS = beGlobalVar->mIsTLS;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
if (isTLS)
outS.Write(dbgGlobalVar->mIsLocalToUnit ? (int16)S_LTHREAD32 : (int16)S_GTHREAD32);
else
outS.Write(dbgGlobalVar->mIsLocalToUnit ? (int16)S_LDATA32 : (int16)S_GDATA32);
2022-07-27 12:26:36 -04:00
2022-03-08 06:27:06 -08:00
outS.Write(DbgGetTypeId(BeValueDynCast<BeDbgType>(dbgGlobalVar->mType)));
2019-08-23 11:56:54 -07:00
2022-07-27 12:26:36 -04:00
BF_ASSERT(dbgGlobalVar->mValue != NULL);
2019-08-23 11:56:54 -07:00
BeMCRelocation reloc;
reloc.mKind = BeMCRelocationKind_SECREL;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = gvSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int32)0x0); // offset contribution
reloc.mKind = BeMCRelocationKind_SECTION;
reloc.mOffset = outS.GetPos();
reloc.mSymTableIdx = gvSym->mIdx;
mDebugSSect.mRelocs.push_back(reloc);
outS.Write((int16)0); // section contribution
DbgEncodeString(outS, dbgGlobalVar->mName);
DbgSEndTag();
}
if (startedSymbols)
DbgEndSection(); // DEBUG_S_SYMBOLS
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
bool startedUDT = false;
for (auto dbgType : mBeModule->mDbgModule->mTypes)
{
if (auto dbgStructType = BeValueDynCast<BeDbgStructType>(dbgType))
{
if (dbgStructType->mIsFullyDefined)
{
if (!startedUDT)
{
DbgStartSection(DEBUG_S_SYMBOLS);
startedUDT = true;
}
DbgSStartTag();
outS.Write((int16)S_UDT);
outS.Write(DbgGetTypeId(dbgStructType));
String fullName;
ToString(dbgStructType, fullName);
DbgEncodeString(outS, fullName);
DbgSEndTag();
}
}
}
if (startedUDT)
DbgEndSection();
DbgStartSection(DEBUG_S_FILECHKSMS);
Array<char> strTable;
strTable.push_back(0);
for (auto dbgFile : mBeModule->mDbgModule->mFiles)
{
outS.Write((int32)strTable.size());
2020-03-23 12:07:05 -07:00
if (dbgFile->mMD5Hash.IsZero())
{
2022-07-27 12:26:36 -04:00
outS.Write((int32)0); // hashLen, hashType, padding
2020-03-23 12:07:05 -07:00
}
else
{
outS.Write((uint8)16); // hashLen
outS.Write((uint8)1); // hashType
outS.Write(&dbgFile->mMD5Hash, 16);
outS.Write((int8)0); // padding
outS.Write((int8)0);
}
2019-08-23 11:56:54 -07:00
String fullPath;
dbgFile->ToString(fullPath);
strTable.Insert(strTable.size(), &fullPath[0], fullPath.length());
strTable.push_back(0);
}
DbgEndSection();
DbgStartSection(DEBUG_S_STRINGTABLE);
outS.Write(&strTable[0], (int)strTable.size());
DbgSAlign();
DbgEndSection();
}
void BeCOFFObject::InitSect(BeCOFFSection& sect, const StringImpl& name, int characteristics, bool addNow, bool makeSectSymbol)
{
sect.mSectName = name;
sect.mCharacteristics = characteristics;
if (addNow)
MarkSectionUsed(sect, makeSectSymbol);
}
void BeCOFFObject::AlignConst(BeCOFFSection& sect, BeConstant* constVal)
{
2019-08-23 11:56:54 -07:00
auto beType = constVal->GetType();
sect.mAlign = BF_MAX(sect.mAlign, beType->mAlign);
sect.mData.Align(beType->mAlign);
}
2019-08-23 11:56:54 -07:00
void BeCOFFObject::WriteConst(BeCOFFSection& sect, BeConstant* constVal)
2022-07-27 12:26:36 -04:00
{
auto beType = constVal->GetType();
2019-08-23 11:56:54 -07:00
if (auto globalVar = BeValueDynCast<BeGlobalVariable>(constVal))
{
auto sym = GetSymbol(globalVar);
BeMCRelocation reloc;
reloc.mKind = BeMCRelocationKind_ADDR64;
reloc.mOffset = sect.mData.GetPos();
reloc.mSymTableIdx = sym->mIdx;
sect.mRelocs.push_back(reloc);
sect.mData.Write((int64)0);
}
else if (auto beFunc = BeValueDynCast<BeFunction>(constVal))
{
auto sym = GetSymbol(beFunc);
BeMCRelocation reloc;
reloc.mKind = BeMCRelocationKind_ADDR64;
reloc.mOffset = sect.mData.GetPos();
reloc.mSymTableIdx = sym->mIdx;
sect.mRelocs.push_back(reloc);
sect.mData.Write((int64)0);
}
else if (auto constStruct = BeValueDynCast<BeStructConstant>(constVal))
{
int startOfs = sect.mData.GetSize();
if (constStruct->mType->mTypeCode == BeTypeCode_Struct)
{
BeStructType* structType = (BeStructType*)constStruct->mType;
BF_ASSERT(structType->mMembers.size() == constStruct->mMemberValues.size());
for (int memberIdx = 0; memberIdx < (int)constStruct->mMemberValues.size(); memberIdx++)
{
auto& member = structType->mMembers[memberIdx];
// Do any per-member alignment
sect.mData.WriteZeros(member.mByteOffset - (sect.mData.GetSize() - startOfs));
WriteConst(sect, constStruct->mMemberValues[memberIdx]);
}
// Do end padding
sect.mData.WriteZeros(structType->mSize - (sect.mData.GetSize() - startOfs));
}
else if (constStruct->mType->mTypeCode == BeTypeCode_SizedArray)
{
2021-01-31 06:41:09 -08:00
BeSizedArrayType* arrayType = (BeSizedArrayType*)constStruct->mType;
2019-08-23 11:56:54 -07:00
for (auto& memberVal : constStruct->mMemberValues)
2021-01-31 06:41:09 -08:00
{
2019-08-23 11:56:54 -07:00
WriteConst(sect, memberVal);
2021-01-31 06:41:09 -08:00
int padding = arrayType->mElementType->GetStride() - arrayType->mElementType->mSize;
if (padding > 0)
sect.mData.WriteZeros(padding);
}
2019-08-23 11:56:54 -07:00
}
else
BF_FATAL("Invalid StructConst type");
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
else if (auto constStr = BeValueDynCast<BeStringConstant>(constVal))
{
sect.mData.Write((void*)constStr->mString.c_str(), (int)constStr->mString.length() + 1);
}
else if (auto constCast = BeValueDynCast<BeCastConstant>(constVal))
{
WriteConst(sect, constCast->mTarget);
}
2022-03-08 06:27:06 -08:00
else if (auto constGep = BeValueDynCast<BeGEP2Constant>(constVal))
2019-08-23 11:56:54 -07:00
{
if (auto globalVar = BeValueDynCast<BeGlobalVariable>(constGep->mTarget))
{
2022-07-27 12:26:36 -04:00
BF_ASSERT(constGep->mIdx0 == 0);
2019-08-23 11:56:54 -07:00
int64 dataOfs = 0;
if (globalVar->mType->mTypeCode == BeTypeCode_Struct)
{
auto structType = (BeStructType*)globalVar->mType;
dataOfs = structType->mMembers[constGep->mIdx1].mByteOffset;
}
else if (globalVar->mType->mTypeCode == BeTypeCode_SizedArray)
{
auto arrayType = (BeSizedArrayType*)globalVar->mType;
dataOfs = arrayType->mElementType->mSize * constGep->mIdx1;
}
else
{
BF_FATAL("Invalid GEP");
}
auto sym = GetSymbol(globalVar);
BeMCRelocation reloc;
reloc.mKind = BeMCRelocationKind_ADDR64;
reloc.mOffset = sect.mData.GetPos();
reloc.mSymTableIdx = sym->mIdx;
sect.mRelocs.push_back(reloc);
sect.mData.Write((int64)dataOfs);
}
else
{
BF_FATAL("Invalid GEPConstant");
}
}
else if ((beType->IsPointer()) && (constVal->mTarget != NULL))
{
WriteConst(sect, constVal->mTarget);
}
else if (beType->IsComposite())
{
BF_ASSERT(constVal->mInt64 == 0);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
int64 zero = 0;
int sizeLeft = beType->mSize;
while (sizeLeft > 0)
{
int writeSize = BF_MIN(sizeLeft, 8);
sect.mData.Write(&zero, writeSize);
sizeLeft -= writeSize;
}
}
else
{
sect.mData.Write((void*)&constVal->mInt64, beType->mSize);
}
}
namespace BeefyDbg64
{
void TestCoff(void* tdata, int tdataSize, void* cuData, int cuDataSize);
}
void BeCOFFObject::Generate(BeModule* module)
{
mBeModule = module;
bool hasDebugInfo = module->mDbgModule != NULL;
DynMemStream textSegData;
InitSect(mTextSect, ".text", IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ, true, true);
InitSect(mDataSect, ".data", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, true, false);
InitSect(mRDataSect, ".rdata", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, true, false);
InitSect(mBSSSect, ".bss", IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, true, false);
InitSect(mTLSSect, ".tls$", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, true, false);
mBSSSect.mAlign = 4;
InitSect(mXDataSect, ".xdata", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ, true, true);
if (hasDebugInfo)
{
InitSect(mDebugSSect, ".debug$S", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ, true, false);
InitSect(mDebugTSect, ".debug$T", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ, true, false);
}
InitSect(mPDataSect, ".pdata", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ, true, false);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
mTextSect.mData.mData.Reserve(4096);
BfSizedVector<BeMCSymbol*, 32> globalVarSyms;
for (int globalVarIdx = 0; globalVarIdx < (int)module->mGlobalVariables.size(); globalVarIdx++)
{
auto globalVar = module->mGlobalVariables[globalVarIdx];
2021-01-15 14:28:21 -08:00
if ((globalVar->mRefCount == 0) && (globalVar->mInitializer == NULL))
{
globalVarSyms.push_back(NULL);
continue;
}
2019-08-23 11:56:54 -07:00
BeMCSymbol* sym = mSymbols.Alloc();
sym->mType = globalVar->mType;
sym->mName = globalVar->mName;
sym->mIsStatic = globalVar->mLinkageType == BfIRLinkageType_Internal;
sym->mSymKind = BeMCSymbolKind_External;
sym->mIdx = (int)mSymbols.size() - 1;
2022-07-27 12:26:36 -04:00
sym->mIsTLS = globalVar->mIsTLS;
2019-08-23 11:56:54 -07:00
globalVarSyms.push_back(sym);
mSymbolMap[globalVar] = sym;
}
for (int globalVarIdx = 0; globalVarIdx < (int)module->mGlobalVariables.size(); globalVarIdx++)
{
auto globalVar = module->mGlobalVariables[globalVarIdx];
2021-01-15 14:28:21 -08:00
2022-07-27 12:26:36 -04:00
if ((globalVar->mRefCount == 0) && (globalVar->mInitializer == NULL))
2021-01-15 14:28:21 -08:00
continue;
2019-08-23 11:56:54 -07:00
auto sym = globalVarSyms[globalVarIdx];
if (globalVar->mInitializer != NULL)
{
if (globalVar->mAlign == -1)
globalVar->mAlign = globalVar->mType->mAlign;
BF_ASSERT(globalVar->mAlign != -1);
if (globalVar->mIsConstant)
{
auto constVal = BeValueDynCast<BeConstant>(globalVar->mInitializer);
MarkSectionUsed(mRDataSect);
sym->mSectionNum = mRDataSect.mSectionIdx + 1;
mRDataSect.mData.Align(globalVar->mAlign);
mRDataSect.mAlign = BF_MAX(mRDataSect.mAlign, globalVar->mAlign);
AlignConst(mRDataSect, constVal);
2022-07-27 12:26:36 -04:00
sym->mValue = mRDataSect.mData.GetSize();
2019-08-23 11:56:54 -07:00
WriteConst(mRDataSect, constVal);
}
else if (globalVar->mIsTLS)
{
MarkSectionUsed(mTLSSect);
sym->mSectionNum = mTLSSect.mSectionIdx + 1;
mTLSSect.mSizeOverride = (mTLSSect.mSizeOverride + globalVar->mAlign - 1) & ~(globalVar->mAlign - 1);
mTLSSect.mAlign = BF_MAX(mTLSSect.mAlign, globalVar->mAlign);
sym->mValue = mTLSSect.mSizeOverride;
mTLSSect.mSizeOverride += globalVar->mType->mSize;
}
else if (auto funcVal = BeValueDynCast<BeFunction>(globalVar->mInitializer))
{
auto& sect = mDataSect;
MarkSectionUsed(sect);
sym->mSectionNum = sect.mSectionIdx + 1;
sect.mData.Align(globalVar->mAlign);
sect.mAlign = BF_MAX(sect.mAlign, globalVar->mAlign);
sym->mValue = sect.mData.GetSize();
auto sym = GetSymbol(funcVal);
BeMCRelocation reloc;
reloc.mKind = BeMCRelocationKind_ADDR64;
reloc.mOffset = sect.mData.GetPos();
reloc.mSymTableIdx = sym->mIdx;
sect.mRelocs.push_back(reloc);
sect.mData.Write((int64)0);
}
else if (auto constVal = BeValueDynCast<BeConstant>(globalVar->mInitializer))
{
MarkSectionUsed(mDataSect);
sym->mSectionNum = mDataSect.mSectionIdx + 1;
mDataSect.mData.Align(globalVar->mAlign);
mDataSect.mAlign = BF_MAX(mDataSect.mAlign, globalVar->mAlign);
AlignConst(mDataSect, constVal);
sym->mValue = mDataSect.mData.GetSize();
WriteConst(mDataSect, constVal);
}
2019-08-23 11:56:54 -07:00
else
{
MarkSectionUsed(mBSSSect);
sym->mSectionNum = mBSSSect.mSectionIdx + 1;
mBSSSect.mSizeOverride = (mBSSSect.mSizeOverride + globalVar->mAlign - 1) & ~(globalVar->mAlign - 1);
mBSSSect.mAlign = BF_MAX(mBSSSect.mAlign, globalVar->mAlign);
sym->mValue = mBSSSect.mSizeOverride;
2022-07-27 12:26:36 -04:00
mBSSSect.mSizeOverride += globalVar->mType->mSize;
}
2020-09-21 23:38:50 -07:00
}
if (globalVar->mStorageKind == BfIRStorageKind_Export)
{
mDirectives += " ";
mDirectives.Append("/EXPORT:");
mDirectives.Append(globalVar->mName);
2019-08-23 11:56:54 -07:00
}
}
for (int i = 0; i < mTLSSect.mSizeOverride; i++)
mTLSSect.mData.Write((uint8)0);
for (int funcIdx = 0; funcIdx < (int)module->mFunctions.size(); funcIdx++)
{
auto func = module->mFunctions[funcIdx];
if ((!func->IsDecl()) && (func->mLinkageType == BfIRLinkageType_External))
{
GetSymbol(func);
}
}
while (!mFuncWorkList.IsEmpty())
{
auto func = mFuncWorkList[0];
mFuncWorkList.RemoveAt(0);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
module->mActiveFunction = func;
if (!func->IsDecl())
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
BeMCSymbol* sym = GetSymbol(func);
BF_ASSERT(sym != NULL);
sym->mValue = mTextSect.mData.GetSize();
BeMCContext context(this);
context.Generate(func);
if (func->mIsDLLExport)
{
mDirectives += " ";
mDirectives.Append("/EXPORT:");
mDirectives.Append(func->mName);
}
2019-08-23 11:56:54 -07:00
}
}
if (!mDirectives.IsEmpty())
{
InitSect(mDirectiveSect, ".drectve", IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_ALIGN_1BYTES, true, false);
mDirectiveSect.mData.Write((void*)mDirectives.c_str(), (int)mDirectives.length());
}
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
if (hasDebugInfo)
{
DbgGenerateTypeInfo();
DbgGenerateModuleInfo();
}
{
//BeefyDbg64::TestCoff(&mDebugTSect.mData.mData[0], mDebugTSect.mData.GetSize(), &mDebugSSect.mData.mData[0], mDebugSSect.mData.GetSize());
}
}
bool BeCOFFObject::Generate(BeModule* module, const StringImpl& fileName)
{
BP_ZONE_F("BeCOFFObject::Generate %s", fileName.c_str());
2022-07-27 12:26:36 -04:00
AutoPerf perf("BeCOFFObject::Generate", mPerfManager);
2019-08-23 11:56:54 -07:00
if (mWriteToLib)
{
DynMemStream memStream;
2019-08-23 11:56:54 -07:00
Generate(module);
mStream = &memStream;
Finish();
mStream = NULL;
BeLibEntry* libEntry = BeLibManager::Get()->AddFile(fileName, memStream.GetPtr(), memStream.GetSize());
if (libEntry == NULL)
return false;
for (auto sym : mSymbols)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
if (sym->mIsStatic)
continue;
if (((sym->mSymKind == BeMCSymbolKind_External) && (sym->mSectionNum != 0)) ||
((sym->mSymKind == BeMCSymbolKind_Function)))
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
libEntry->AddSymbol(sym->mName);
}
}
}
else
{
SysFileStream fileStream;
bool success = fileStream.Open(fileName, BfpFileCreateKind_CreateAlways, BfpFileCreateFlag_Write);
if (!success)
return false;
Generate(module);
mStream = &fileStream;
Finish();
mStream = NULL;
{
BP_ZONE("BeCOFFObject::Generate.fclose");
AutoPerf perf("BeCOFFObject::Generate - fclose", mPerfManager);
fileStream.Close();
}
}
return true;
}
void BeCOFFObject::Finish()
{
BP_ZONE("BeCOFFObject::Finish");
//AutoPerf perf("BeCOFFObject::Finish", mPerfManager);
PEFileHeader header;
memset(&header, 0, sizeof(header));
header.mMachine = PE_MACHINE_X64;
header.mTimeDateStamp = mTimestamp;
header.mNumberOfSections = (int)mUsedSections.size();
SizedArray<PESectionHeader, 16> sectHdrs;
sectHdrs.resize(header.mNumberOfSections);
SizedArray<BeCOFFSection*, 16> sectData;
sectData.resize(header.mNumberOfSections);
int filePos = sizeof(PEFileHeader) + header.mNumberOfSections*sizeof(PESectionHeader);
for (int sectNum = 0; sectNum < header.mNumberOfSections; sectNum++)
{
PESectionHeader& sectHdr = sectHdrs[sectNum];
memset(&sectHdr, 0, sizeof(sectHdr));
BeCOFFSection* sect = mUsedSections[sectNum];
strcpy(sectHdr.mName, sect->mSectName.c_str());
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
int characteristics = sect->mCharacteristics;
if (sect->mAlign != 0)
{
if (sect->mAlign == 8192) characteristics |= IMAGE_SCN_ALIGN_8192BYTES;
else if (sect->mAlign == 4096) characteristics |= IMAGE_SCN_ALIGN_4096BYTES;
else if (sect->mAlign == 2048) characteristics |= IMAGE_SCN_ALIGN_2048BYTES;
else if (sect->mAlign == 1024) characteristics |= IMAGE_SCN_ALIGN_1024BYTES;
else if (sect->mAlign == 512) characteristics |= IMAGE_SCN_ALIGN_512BYTES;
else if (sect->mAlign == 256) characteristics |= IMAGE_SCN_ALIGN_256BYTES;
else if (sect->mAlign == 128) characteristics |= IMAGE_SCN_ALIGN_128BYTES;
else if (sect->mAlign == 64) characteristics |= IMAGE_SCN_ALIGN_64BYTES;
else if (sect->mAlign == 32) characteristics |= IMAGE_SCN_ALIGN_32BYTES;
else if (sect->mAlign == 16) characteristics |= IMAGE_SCN_ALIGN_16BYTES;
else if (sect->mAlign == 8) characteristics |= IMAGE_SCN_ALIGN_8BYTES;
else if (sect->mAlign == 4) characteristics |= IMAGE_SCN_ALIGN_4BYTES;
else if (sect->mAlign == 2) characteristics |= IMAGE_SCN_ALIGN_2BYTES;
}
2022-07-27 12:26:36 -04:00
sectData[sectNum] = sect;
2019-08-23 11:56:54 -07:00
int dataSize = sect->mData.GetSize();
if (dataSize != 0)
{
sectHdr.mPointerToRawData = filePos;
sectHdr.mSizeOfRawData = dataSize;
filePos += dataSize;
if (!sect->mRelocs.empty())
{
sectHdr.mPointerToRelocations = filePos;
if (sect->mRelocs.size() > 0xFFFF)
{
characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL;
// Extended reloc count
sectHdr.mNumberOfRelocations = 0xFFFF;
filePos += sizeof(COFFRelocation);
}
else
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
sectHdr.mNumberOfRelocations = (int)sect->mRelocs.size();
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
filePos += (int)sect->mRelocs.size() * sizeof(COFFRelocation);
}
}
else
{
sectHdr.mSizeOfRawData = sect->mSizeOverride;
}
sectHdr.mCharacteristics = characteristics;
BF_ASSERT(characteristics != 0);
}
2022-07-27 12:26:36 -04:00
header.mPointerToSymbolTable = filePos;
2019-08-23 11:56:54 -07:00
header.mNumberOfSymbols = (int)mSymbols.size();
mStream->WriteT(header);
for (int sectNum = 0; sectNum < header.mNumberOfSections; sectNum++)
{
PESectionHeader& sectHdr = sectHdrs[sectNum];
mStream->WriteT(sectHdr);
}
for (int sectNum = 0; sectNum < header.mNumberOfSections; sectNum++)
{
BeCOFFSection* sect = sectData[sectNum];
if (sect == NULL)
continue;
PESectionHeader& sectHdr = sectHdrs[sectNum];
if (sectHdr.mPointerToRawData != 0)
BF_ASSERT(mStream->GetPos() == sectHdr.mPointerToRawData);
if (sect->mData.GetSize() != 0)
{
mStream->Write((uint8*)sect->mData.GetPtr(), (int)sect->mData.GetSize());
BF_ASSERT(mStream->GetPos() == sectHdr.mPointerToRawData + (int)sect->mData.GetSize());
}
int relocIdx = 0;
if (sect->mRelocs.size() > 0xFFFF)
{
// Extended reloc count
COFFRelocation coffReloc = { 0 };
coffReloc.mVirtualAddress = sect->mRelocs.size() + 1;
mStream->WriteT(coffReloc);
relocIdx++;
}
for (auto& reloc : sect->mRelocs)
{
COFFRelocation coffReloc;
coffReloc.mVirtualAddress = reloc.mOffset;
coffReloc.mSymbolTableIndex = reloc.mSymTableIdx;
coffReloc.mType = IMAGE_REL_AMD64_ABSOLUTE;
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
switch (reloc.mKind)
{
case BeMCRelocationKind_ADDR32NB:
coffReloc.mType = IMAGE_REL_AMD64_ADDR32NB;
break;
case BeMCRelocationKind_ADDR64:
coffReloc.mType = IMAGE_REL_AMD64_ADDR64;
break;
case BeMCRelocationKind_REL32:
coffReloc.mType = IMAGE_REL_AMD64_REL32;
break;
case BeMCRelocationKind_SECREL:
coffReloc.mType = IMAGE_REL_AMD64_SECREL;
break;
case BeMCRelocationKind_SECTION:
coffReloc.mType = IMAGE_REL_AMD64_SECTION;
break;
}
mStream->WriteT(coffReloc);
relocIdx++;
BF_ASSERT(mStream->GetPos() == sectHdr.mPointerToRawData + (int)sect->mData.GetSize() + relocIdx*10);
}
}
BF_ASSERT(mStream->GetPos() == filePos);
2022-07-27 12:26:36 -04:00
2019-08-23 11:56:54 -07:00
SizedArray<PE_SymInfo, 16> symInfoVec;
symInfoVec.reserve(mSymbols.size() + 16);
for (auto& sym : mSymbols)
{
//BP_ZONE("Finish - AddSym");
2022-07-27 12:26:36 -04:00
if (sym->mSymKind == BeMCSymbolKind_AuxPlaceholder)
continue;
2019-08-23 11:56:54 -07:00
PE_SymInfo symInfo;
memset(&symInfo, 0, sizeof(symInfo));
if (sym->mName.length() > 7)
{
int strTablePos = mStrTable.mPos;
mStrTable.Write((uint8*)sym->mName.c_str(), (int)sym->mName.length() + 1);
symInfo.mNameOfs[1] = strTablePos + 4;
}
else
2022-07-27 12:26:36 -04:00
strcpy(symInfo.mName, sym->mName.c_str());
2019-08-23 11:56:54 -07:00
if (sym->mSymKind == BeMCSymbolKind_SectionDef)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
symInfo.mSectionNum = sym->mSectionNum;
symInfo.mStorageClass = IMAGE_SYM_CLASS_STATIC;
symInfo.mNumOfAuxSymbols = 1;
symInfoVec.push_back(symInfo);
static_assert(sizeof(PE_SymInfoAux) == sizeof(PE_SymInfo), "PE_SymInfo size mismatch");
BeCOFFSection& section = mXDataSect;
PE_SymInfoAux auxSymInfo;
auxSymInfo.mLength = section.mData.GetSize();
auxSymInfo.mNumberOfRelocations = (int)section.mRelocs.size();
auxSymInfo.mNumberOfLinenumbers = 0;
auxSymInfo.mCheckSum = 0;
auxSymInfo.mNumber = 0;
auxSymInfo.mSelection = 2; // Pick any (only applicable for COMDAT but ignored elsewhere)
auxSymInfo.mUnused = 0;
auxSymInfo.mUnused2 = 0;
2022-07-27 12:26:36 -04:00
auxSymInfo.mUnused3 = 0;
2019-08-23 11:56:54 -07:00
symInfoVec.push_back(*(PE_SymInfo*)&auxSymInfo);
continue;
}
else if (sym->mSymKind == BeMCSymbolKind_SectionRef)
{
2022-07-27 12:26:36 -04:00
symInfo.mSectionNum = sym->mSectionNum;
symInfo.mStorageClass = IMAGE_SYM_CLASS_SECTION;
2019-08-23 11:56:54 -07:00
}
else if (sym->mSymKind == BeMCSymbolKind_Function)
{
symInfo.mValue = sym->mValue;
2022-07-27 12:26:36 -04:00
symInfo.mSectionNum = mTextSect.mSectionIdx + 1;
2019-08-23 11:56:54 -07:00
symInfo.mType = 0x20; //DT_FUNCTION
if (sym->mIsStatic)
symInfo.mStorageClass = IMAGE_SYM_CLASS_STATIC;
else
symInfo.mStorageClass = IMAGE_SYM_CLASS_EXTERNAL;
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
else if (sym->mSymKind == BeMCSymbolKind_COMDAT)
{
symInfo.mValue = sym->mValue;
2022-07-27 12:26:36 -04:00
symInfo.mSectionNum = sym->mSectionNum;
2019-08-23 11:56:54 -07:00
symInfo.mStorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
else
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
if (sym->mIsStatic)
symInfo.mStorageClass = IMAGE_SYM_CLASS_STATIC;
else
symInfo.mStorageClass = IMAGE_SYM_CLASS_EXTERNAL;
symInfo.mValue = sym->mValue;
symInfo.mSectionNum = sym->mSectionNum;
2022-07-27 12:26:36 -04:00
}
2019-08-23 11:56:54 -07:00
symInfoVec.push_back(symInfo);
}
if (!symInfoVec.IsEmpty())
mStream->Write(&symInfoVec[0], (int)(sizeof(PE_SymInfo)*symInfoVec.size()));
int32 strTableSize = (int32)mStrTable.GetSize();
mStream->Write(strTableSize + 4);
if (strTableSize != 0)
mStream->Write((uint8*)&mStrTable.mData[0], (int)mStrTable.mData.size());
}
BeMCSymbol* BeCOFFObject::GetSymbol(BeValue* value, bool allowCreate)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
/*auto itr = mSymbolMap.find(value);
if (itr != mSymbolMap.end())
return itr->second;*/
BeMCSymbol** symbolPtr = NULL;
if (mSymbolMap.TryGetValue(value, &symbolPtr))
return *symbolPtr;
if (allowCreate)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
if (auto func = BeValueDynCast<BeFunction>(value))
{
mFuncWorkList.Add(func);
BeMCSymbol* sym = mSymbols.Alloc();
sym->mType = func->GetType();
sym->mName = func->mName;
sym->mIsStatic = func->mLinkageType == BfIRLinkageType_Internal;
if (func->mBlocks.empty())
{
sym->mSymKind = BeMCSymbolKind_External;
}
else
{
sym->mSymKind = BeMCSymbolKind_Function;
}
sym->mIdx = (int)mSymbols.size() - 1;
sym->mBeFunction = func;
mSymbolMap[func] = sym;
return sym;
}
}
return NULL;
}
BeMCSymbol* BeCOFFObject::GetSymbolRef(const StringImpl& name)
2022-07-27 12:26:36 -04:00
{
2019-08-23 11:56:54 -07:00
/*auto itr = mNamedSymbolMap.find(name);
if (itr != mNamedSymbolMap.end())
return itr->second;*/
BeMCSymbol** symbolPtr = NULL;
if (mNamedSymbolMap.TryGetValue(name, &symbolPtr))
return *symbolPtr;
auto sym = mSymbols.Alloc();
sym->mName = name;
sym->mSymKind = BeMCSymbolKind_External;
sym->mIdx = (int)mSymbols.size() - 1;
mNamedSymbolMap[name] = sym;
return sym;
}
void BeCOFFObject::MarkSectionUsed(BeCOFFSection& sect, bool getSectSymbol)
{
if (sect.mSectionIdx == -1)
{
sect.mSectionIdx = (int)mUsedSections.size();
mUsedSections.push_back(&sect);
}
if (getSectSymbol)
{
//TODO: We previously only did sectionDefs when we needed the SelectionNum value, but
2022-07-27 12:26:36 -04:00
// omitting this causes the MS linker to throw "multiple '<X>' sections found with different
// attributes (0000000000) errors. This change could potentially break LIB creation in the
2019-08-23 11:56:54 -07:00
// linker. Verify it still works.
if (((sect.mCharacteristics & IMAGE_SCN_LNK_COMDAT) != 0) || (true))
{
if (sect.mSymbolIdx == -1)
{
BeMCSymbol* sym;
sym = mSymbols.Alloc();
sym->mSymKind = BeMCSymbolKind_SectionDef;
sym->mName = sect.mSectName;
sym->mIsStatic = false;
sym->mSectionNum = sect.mSectionIdx + 1;
sym->mIdx = (int)mSymbols.size() - 1;
sect.mSymbolIdx = sym->mIdx;
sym = mSymbols.Alloc();
sym->mSymKind = BeMCSymbolKind_AuxPlaceholder;
}
}
else
{
// It's important for the linker's import library output to include
2022-07-27 12:26:36 -04:00
// section refs and not section defs, even when they aren't an external
2019-08-23 11:56:54 -07:00
// reference
BeMCSymbol* sym;
sym = mSymbols.Alloc();
sym->mSymKind = BeMCSymbolKind_SectionRef;
sym->mName = sect.mSectName;
sym->mIsStatic = false;
sym->mSectionNum = sect.mSectionIdx + 1;
sym->mIdx = (int)mSymbols.size() - 1;
sect.mSymbolIdx = sym->mIdx;
}
}
}
BeMCSymbol* BeCOFFObject::GetCOMDAT(const StringImpl& name, void* data, int size, int align)
{
/*auto itr = mNamedSymbolMap.find(name);
if (itr != mNamedSymbolMap.end())
return itr->second;*/
BeMCSymbol** symbolPtr = NULL;
if (mNamedSymbolMap.TryGetValue(name, &symbolPtr))
return *symbolPtr;
BeCOFFSection mRData8Sect;
auto* rdataSect = mDynSects.Alloc();
2022-07-27 12:26:36 -04:00
int characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_MEM_READ;
InitSect(*rdataSect, ".rdata", characteristics, true, true);
2019-08-23 11:56:54 -07:00
rdataSect->mAlign = align;
auto sym = mSymbols.Alloc();
sym->mName = name;
sym->mSymKind = BeMCSymbolKind_COMDAT;
sym->mIdx = (int)mSymbols.size() - 1;
sym->mSectionNum = rdataSect->mSectionIdx + 1;
sym->mValue = rdataSect->mData.GetPos();
2022-07-27 12:26:36 -04:00
mNamedSymbolMap[name] = sym;
rdataSect->mData.Write(data, size);
return sym;
2019-08-23 11:56:54 -07:00
}
BeCOFFSection* BeCOFFObject::CreateSect(const StringImpl& name, int characteristics, bool makeSectSymbol)
{
auto* sect = mDynSects.Alloc();
sect->mCharacteristics = characteristics;
InitSect(*sect, name, characteristics, true, makeSectSymbol);
return sect;
}