mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 03:28:20 +02:00

Throwing error on member references with ".." cascade token outside invocations (ie: "ts..mA = 123") Fixed 'Thread.ModuleTLSIndex' error - which caused us TLS lookup failures in Beef DLLs Fixed some hotswap errors Made BeefPerf shut down properly Fixed an 'int literal' FixIntUnknown issue where rhs was System.Object which caused an illegal boxing Fixed COFF::LocateSymbol issues with Win32 and also with linking to static libraries - showed up with hot-linking in fmod when hot-adding a floating point mod Fixed a couple memory leaks Fixed alignment issue in COFF::ParseCompileUnit
1699 lines
43 KiB
C++
1699 lines
43 KiB
C++
#include "DebugManager.h"
|
|
#include "BeefySysLib/util/CritSect.h"
|
|
#include "Compiler/BfSystem.h"
|
|
#include "Compiler/BfParser.h"
|
|
#include "Compiler/MemReporter.h"
|
|
#include "Debugger.h"
|
|
#include "DebugVisualizers.h"
|
|
#include "RadixMap.h"
|
|
#include "Compiler/BfDemangler.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "BeefySysLib/util/BeefPerf.h"
|
|
#include "NetManager.h"
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
#include "DbgMiniDump.h"
|
|
#endif
|
|
|
|
#include <iostream>
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4141)
|
|
#pragma warning(disable:4146)
|
|
#pragma warning(disable:4291)
|
|
#pragma warning(disable:4244)
|
|
#pragma warning(disable:4267)
|
|
#pragma warning(disable:4624)
|
|
#pragma warning(disable:4800)
|
|
#pragma warning(disable:4996)
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IRReader/IRReader.h"
|
|
//#include "llvm/Bitcode/ReaderWriter.h"
|
|
#pragma warning(pop)
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
#include <psapi.h>
|
|
#include <shlobj.h>
|
|
#endif
|
|
|
|
#include "BeefySysLib/util/AllocDebug.h"
|
|
|
|
#define ENABLE_DBG_32
|
|
|
|
//#define BF_DBG_32
|
|
//#include "WinDebugger.h"
|
|
//#undef BF_DBG_32
|
|
|
|
/*#define BF_DBG_64
|
|
#include "WinDebugger.h"
|
|
#undef BF_DBG_64*/
|
|
|
|
int Beefy::sRadixMapCount = 0;
|
|
int Beefy::sRootSize = 0;
|
|
int Beefy::sMidSize = 0;
|
|
int Beefy::sLeafSize = 0;
|
|
|
|
USING_NS_BF;
|
|
|
|
DebugManager* Beefy::gDebugManager = NULL;
|
|
Debugger* Beefy::gDebugger = NULL;
|
|
PerfManager* Beefy::gDbgPerfManager = NULL;
|
|
|
|
int64 gBfAllocCount = 0;
|
|
int64 gBfFreeCount = 0;
|
|
|
|
static Dictionary<long, int> gBfAllocMap;
|
|
static Dictionary<void*, long> gBfAllocAddrMap;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
DebugManager::DebugManager()
|
|
{
|
|
gDbgPerfManager = new PerfManager();
|
|
|
|
mDebugVisualizers = new DebugVisualizers();
|
|
mStepFilterVersion = 0;
|
|
mStepOverExternalFiles = false;
|
|
|
|
mDebugger32 = NULL;
|
|
mDebugger64 = NULL;
|
|
mNetManager = new NetManager();
|
|
mNetManager->mDebugManager = this;
|
|
|
|
mSymSrvOptions.mCacheDir = "C:\\SymCache";
|
|
|
|
mSymSrvOptions.mSymbolServers.Add("C:\\BeefSyms");
|
|
mSymSrvOptions.mSymbolServers.Add("https://msdl.microsoft.com/download/symbols");
|
|
mSymSrvOptions.mSymbolServers.Add("http://wintest.beefy2d.com/symbols/");
|
|
mSymSrvOptions.mSymbolServers.Add("https://chromium-browser-symsrv.commondatastorage.googleapis.com");
|
|
//TODO: Just for testing
|
|
mSymSrvOptions.mSymbolServers.Add("http://127.0.0.1/symbols");
|
|
|
|
SetSourceServerCacheDir();
|
|
}
|
|
|
|
DebugManager::~DebugManager()
|
|
{
|
|
delete mNetManager;
|
|
delete mDebugger64;
|
|
delete mDebugger32;
|
|
/*for (auto stepFilter : mStepFilters)
|
|
{
|
|
|
|
}*/
|
|
delete mDebugVisualizers;
|
|
}
|
|
|
|
void DebugManager::OutputMessage(const StringImpl& msg)
|
|
{
|
|
AutoCrit autoCrit(mCritSect);
|
|
mOutMessages.push_back("msg " + msg);
|
|
}
|
|
|
|
void DebugManager::OutputRawMessage(const StringImpl& msg)
|
|
{
|
|
AutoCrit autoCrit(mCritSect);
|
|
mOutMessages.push_back(msg);
|
|
}
|
|
|
|
void DebugManager::SetSourceServerCacheDir()
|
|
{
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
AutoCrit autoCrit(mCritSect);
|
|
|
|
WCHAR appDataPath[MAX_PATH] = { 0 };
|
|
SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, appDataPath);
|
|
mSymSrvOptions.mSourceServerCacheDir = UTF8Encode(appDataPath);
|
|
mSymSrvOptions.mSourceServerCacheDir += "\\SourceServer";
|
|
|
|
if (mSymSrvOptions.mFlags & BfSymSrvFlag_TempCache)
|
|
{
|
|
mSymSrvOptions.mSourceServerCacheDir += "\\temp";
|
|
RecursiveDeleteDirectory(mSymSrvOptions.mSourceServerCacheDir);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
//#define CAPTURE_ALLOC_BACKTRACE
|
|
//#define CAPTURE_ALLOC_SOURCES
|
|
|
|
#ifdef CAPTURE_ALLOC_BACKTRACE
|
|
const int sNumAllocAddrs = 0x300000;
|
|
const int sCaptureDepth = 14;
|
|
const int sCaptureOffset = 4;
|
|
static intptr gAllocAddrs[sNumAllocAddrs][sCaptureDepth];
|
|
#endif
|
|
|
|
#ifdef CAPTURE_ALLOC_SOURCES
|
|
#include <Dbghelp.h>
|
|
#pragma comment(lib, "dbghelp.lib")
|
|
|
|
struct CaptureAllocLocation
|
|
{
|
|
public:
|
|
char* mSymName;
|
|
int mTotalSize;
|
|
bool mIsEndpoint;
|
|
};
|
|
|
|
struct CaptureAllocEntry
|
|
{
|
|
public:
|
|
CaptureAllocLocation* mLoc;
|
|
int mAllocSize;
|
|
};
|
|
|
|
std::map<long, CaptureAllocEntry> gBfCaptureSourceAllocMap;
|
|
//std::map<void*, CaptureAllocLocation> gBfCaptureAllocLocation;
|
|
|
|
#define CAPTURE_ALLOC_POOL_SIZE 0x100000
|
|
CaptureAllocLocation* gHashCaptureAllocSize[CAPTURE_ALLOC_POOL_SIZE] = { 0 };
|
|
|
|
static void ReallocEntry(long oldRequest, long newRequest, int newSize)
|
|
{
|
|
auto itr = gBfCaptureSourceAllocMap.find(oldRequest);
|
|
if (itr != gBfCaptureSourceAllocMap.end())
|
|
{
|
|
CaptureAllocEntry* entry = &itr->second;
|
|
entry->mLoc->mTotalSize -= entry->mAllocSize;
|
|
entry->mLoc->mTotalSize += newSize;
|
|
entry->mAllocSize = newSize;
|
|
gBfCaptureSourceAllocMap[newRequest] = *entry;
|
|
gBfCaptureSourceAllocMap.erase(itr);
|
|
}
|
|
}
|
|
|
|
static void RemoveAllocEntry(long lRequest)
|
|
{
|
|
auto itr = gBfCaptureSourceAllocMap.find(lRequest);
|
|
if (itr != gBfCaptureSourceAllocMap.end())
|
|
{
|
|
CaptureAllocEntry* entry = &itr->second;
|
|
|
|
entry->mLoc->mTotalSize -= entry->mAllocSize;
|
|
gBfCaptureSourceAllocMap.erase(itr);
|
|
}
|
|
}
|
|
|
|
|
|
//const LOC_HASHES
|
|
|
|
|
|
#endif
|
|
|
|
static int gBfNumAllocs = 0;
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
|
|
static bool gBgTrackingAllocs = false; ///// Leave false most of the time
|
|
CritSect gBfCritSect;
|
|
static bool gInsideAlloc = false;
|
|
static int gLastReqId = 0;
|
|
static int BfAllocHook(int nAllocType, void *pvData,
|
|
size_t nSize, int nBlockUse, long lRequest,
|
|
const unsigned char * szFileName, int nLine)
|
|
{
|
|
#ifdef CAPTURE_ALLOC_SOURCES
|
|
if (gInsideAlloc)
|
|
return TRUE;
|
|
|
|
gInsideAlloc = true;
|
|
|
|
intptr stackTrace[20];
|
|
int traceCount = (int)RtlCaptureStackBackTrace(1, 20, (void**)&stackTrace, 0);
|
|
|
|
/*intptr ebpVal;
|
|
__asm
|
|
{
|
|
mov ebpVal, ebp
|
|
}*/
|
|
|
|
//intptr ebp = ebpVal;
|
|
//intptr eip = 0;
|
|
|
|
static HANDLE hProcess = 0;
|
|
if (hProcess == NULL)
|
|
{
|
|
hProcess = GetCurrentProcess();
|
|
BOOL worked = SymInitialize(hProcess, NULL, TRUE);
|
|
}
|
|
|
|
if (nAllocType == _HOOK_ALLOC)
|
|
{
|
|
for (int i = 0; i < traceCount; i++)
|
|
{
|
|
/*__try
|
|
{
|
|
ebp = *((intptr*)ebp + 0);
|
|
if (ebp < 0x100000)
|
|
break;
|
|
eip = *((intptr*)ebp + 1);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
break;
|
|
}*/
|
|
|
|
intptr curAddr = stackTrace[i];
|
|
|
|
const char* name = "?";
|
|
|
|
int hashVal = (curAddr & 0x7FFFFFFF) % CAPTURE_ALLOC_POOL_SIZE;
|
|
if (gHashCaptureAllocSize[hashVal] == NULL)
|
|
{
|
|
//static HPROCESS hProc = GEtProcessH
|
|
char symData[4096];
|
|
DWORD64 disp = 0;
|
|
SYMBOL_INFO* symInfo = (SYMBOL_INFO*)&symData;
|
|
memset(symInfo, 0, sizeof(SYMBOL_INFO));
|
|
symInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
symInfo->MaxNameLen = sizeof(symData) - sizeof(SYMBOL_INFO);
|
|
bool foundSym = false;
|
|
if (SymFromAddr(hProcess, (DWORD64)curAddr, &disp, symInfo))
|
|
{
|
|
name = symInfo->Name;
|
|
foundSym = true;
|
|
}
|
|
|
|
CaptureAllocLocation* captureAllocLoc = new CaptureAllocLocation();
|
|
captureAllocLoc->mSymName = strdup(name);
|
|
captureAllocLoc->mTotalSize = 0;
|
|
captureAllocLoc->mIsEndpoint = (!foundSym) || (strncmp(name, "Beefy::", 7) == 0) || (strncmp(name, "llvm::", 6) == 0);
|
|
if (strstr(name, "operator new") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
if (strstr(name, "::allocateBuckets") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
if (strstr(name, "::grow") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
if (strstr(name, "::DenseMap") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
/*if (strstr(name, "::Allocate") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;*/
|
|
if (strstr(name, "::Alloc") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
/*if (strstr(name, "::AllocBytes") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
if (strstr(name, "::AllocMemoryBlock") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;*/
|
|
if (strstr(name, "::GrowPool") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
|
|
// Testing COnstantInt::get
|
|
if (strstr(name, "::CreateConst") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
if (strstr(name, "::get") != NULL)
|
|
captureAllocLoc->mIsEndpoint = false;
|
|
|
|
if ((captureAllocLoc->mIsEndpoint) && (foundSym))
|
|
{
|
|
|
|
}
|
|
|
|
gHashCaptureAllocSize[hashVal] = captureAllocLoc;
|
|
}
|
|
|
|
CaptureAllocLocation* captureAllocLoc = gHashCaptureAllocSize[hashVal];
|
|
|
|
if ((i < 19) && (!captureAllocLoc->mIsEndpoint))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
captureAllocLoc->mTotalSize += (int)nSize;
|
|
|
|
CaptureAllocEntry entry;
|
|
entry.mAllocSize = (int)nSize;
|
|
entry.mLoc = captureAllocLoc;
|
|
gBfCaptureSourceAllocMap[lRequest] = entry;
|
|
break;
|
|
//if (i >= sCaptureOffset)
|
|
//gAllocAddrs[lRequest][i - sCaptureOffset] = eip;
|
|
}
|
|
}
|
|
else if (nAllocType == _HOOK_REALLOC)
|
|
{
|
|
long oldRequest = ((int*)pvData)[-2];
|
|
ReallocEntry(oldRequest, lRequest, nSize);
|
|
}
|
|
else if (nAllocType == _HOOK_FREE)
|
|
{
|
|
lRequest = ((int*)pvData)[-2];
|
|
RemoveAllocEntry(lRequest);
|
|
}
|
|
|
|
gInsideAlloc = false;
|
|
#endif
|
|
|
|
#ifdef CAPTURE_ALLOC_BACKTRACE
|
|
if (lRequest < sNumAllocAddrs)
|
|
{
|
|
gAllocAddrs[lRequest][0] = 1;
|
|
|
|
intptr ebpVal;
|
|
__asm
|
|
{
|
|
mov ebpVal, ebp
|
|
}
|
|
|
|
intptr ebp = ebpVal;
|
|
intptr eip = 0;
|
|
|
|
for (int i = 0; i < sCaptureDepth + sCaptureOffset; i++)
|
|
{
|
|
__try
|
|
{
|
|
ebp = *((intptr*)ebp + 0);
|
|
if (ebp < 0x100000)
|
|
break;
|
|
eip = *((intptr*)ebp + 1);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (i >= sCaptureOffset)
|
|
gAllocAddrs[lRequest][i - sCaptureOffset] = eip;
|
|
}
|
|
}
|
|
#else
|
|
|
|
if (!gBgTrackingAllocs)
|
|
return TRUE;
|
|
|
|
/*AutoCrit critSect(gBfCritSect);
|
|
|
|
if (gLastReqId == lRequest)
|
|
return TRUE;
|
|
if (!gInsideAlloc)
|
|
{
|
|
gInsideAlloc = true;
|
|
if (nAllocType == _HOOK_ALLOC)
|
|
{
|
|
gBfNumAllocs++;
|
|
gBfAllocCount += nSize;
|
|
gBfAllocMap[lRequest] = nSize;
|
|
}
|
|
if (nAllocType == _HOOK_FREE)
|
|
{
|
|
lRequest = ((int*)pvData)[-2];
|
|
|
|
auto itr = gBfAllocMap.find(lRequest);
|
|
if (itr != gBfAllocMap.end())
|
|
{
|
|
gBfFreeCount += itr->second;
|
|
gBfAllocMap.erase(itr);
|
|
}
|
|
}
|
|
gInsideAlloc = false;
|
|
}
|
|
|
|
gLastReqId = lRequest;
|
|
if (szFileName == NULL)
|
|
return TRUE; */
|
|
|
|
/*char str[1024];
|
|
sprintf(str, "Alloc: %d File: %s Line: %d\n", lRequest, szFileName, nLine);
|
|
OutputDebugStringA(str);*/
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
#endif //BF_PLATFORM_WINDOWS
|
|
|
|
|
|
void BfReportMemory()
|
|
{
|
|
BfLogDbg("Used: %.2fM NumAllocs: %d Allocs: %.2fM\n", (gBfAllocCount - gBfFreeCount) / (1024.0 * 1024.0), gBfNumAllocs, gBfAllocCount / (1024.0 * 1024.0));
|
|
}
|
|
|
|
void BfFullReportMemory()
|
|
{
|
|
/*OutputDebugStrF("Testing OOB\n");
|
|
char* str = new char[12];
|
|
delete str;
|
|
char c = str[1];*/
|
|
|
|
if (gBfParserCache != NULL)
|
|
{
|
|
MemReporter memReporter;
|
|
memReporter.BeginSection("ParserCache");
|
|
gBfParserCache->ReportMemory(&memReporter);
|
|
memReporter.EndSection();
|
|
memReporter.Report();
|
|
}
|
|
|
|
OutputDebugStrF("Used: %.2fM NumAllocs: %d Allocs: %.2fM\n", (gBfAllocCount - gBfFreeCount) / (1024.0 * 1024.0), gBfNumAllocs, gBfAllocCount / (1024.0 * 1024.0));
|
|
OutputDebugStrF("ChunkedDataBuffer allocated blocks: %d\n", ChunkedDataBuffer::sBlocksAllocated);
|
|
|
|
if (gDebugManager != NULL)
|
|
{
|
|
MemReporter memReporter;
|
|
if (gDebugManager->mDebugger32 != NULL)
|
|
{
|
|
memReporter.BeginSection("Debugger32");
|
|
gDebugManager->mDebugger32->ReportMemory(&memReporter);
|
|
memReporter.EndSection();
|
|
}
|
|
memReporter.BeginSection("Debugger64");
|
|
gDebugManager->mDebugger64->ReportMemory(&memReporter);
|
|
memReporter.EndSection();
|
|
memReporter.Report();
|
|
}
|
|
|
|
BpDump();
|
|
|
|
#ifdef CAPTURE_ALLOC_SOURCES
|
|
int memTotal = 0;
|
|
std::map<String, int> byNameMap;
|
|
for (int i = 0; i < CAPTURE_ALLOC_POOL_SIZE; i++)
|
|
{
|
|
CaptureAllocLocation* allocLoc = gHashCaptureAllocSize[i];
|
|
if ((allocLoc != NULL) && (allocLoc->mTotalSize > 0))
|
|
{
|
|
auto itr = byNameMap.insert(std::map<String, int>::value_type(allocLoc->mSymName, 0));
|
|
itr.first->second += allocLoc->mTotalSize;
|
|
memTotal += allocLoc->mTotalSize;
|
|
}
|
|
}
|
|
|
|
std::multimap<int, String> bySizeMap;
|
|
|
|
for (auto kv : byNameMap)
|
|
{
|
|
//OutputDebugStrF("%dk %s\n", (kv.second + 1023) / 1024, kv.first.c_str());
|
|
bySizeMap.insert(std::multimap<int, String>::value_type(-kv.second, kv.first));
|
|
}
|
|
|
|
for (auto kv : bySizeMap)
|
|
{
|
|
OutputDebugStrF("%dk %s\n", (-kv.first + 1023) / 1024, kv.second.c_str());
|
|
}
|
|
|
|
OutputDebugStrF("Total %dk\n", memTotal / 1024);
|
|
#endif
|
|
}
|
|
|
|
struct _CrtMemBlockHeader
|
|
{
|
|
_CrtMemBlockHeader* _block_header_next;
|
|
_CrtMemBlockHeader* _block_header_prev;
|
|
char const* _file_name;
|
|
int _line_number;
|
|
|
|
int _block_use;
|
|
size_t _data_size;
|
|
|
|
long _request_number;
|
|
//unsigned char _gap[no_mans_land_size];
|
|
|
|
// Followed by:
|
|
// unsigned char _data[_data_size];
|
|
// unsigned char _another_gap[no_mans_land_size];
|
|
};
|
|
|
|
//static _CrtMemBlockHeader* __acrt_first_block;
|
|
//static _CrtMemBlockHeader* __acrt_last_block;
|
|
|
|
void ShowMemoryUsage()
|
|
{
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
PROCESS_MEMORY_COUNTERS processMemCounters;
|
|
processMemCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS);
|
|
GetProcessMemoryInfo(GetCurrentProcess(), &processMemCounters, sizeof(PROCESS_MEMORY_COUNTERS));
|
|
OutputDebugStrF("WorkingSet : %dk\n", (int)(processMemCounters.WorkingSetSize / 1024));
|
|
OutputDebugStrF("VirtualMem : %dk\n", (int)(processMemCounters.PagefileUsage/1024));
|
|
|
|
static bool hasCheckpoint = true;
|
|
_CrtMemState memState;
|
|
_CrtMemCheckpoint(&memState);
|
|
//OutputDebugStrF("Crt Size: %dk\n", (int)(memState.lTotalCount / 1024));
|
|
|
|
char* names[6] = { "_FREE_BLOCK", "_NORMAL_BLOCK", "_CRT_BLOCK", "_IGNORE_BLOCK", "_CLIENT_BLOCK", "_MAX_BLOCKS" };
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
OutputDebugStrF("%s : %d %dk\n", names[i], memState.lCounts[i], memState.lSizes[i] / 1024);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
// int64 totalCrtSize = 0;
|
|
// int64 totalUseCrtSize = 0;
|
|
// _CrtMemBlockHeader* blockPtr = memState.pBlockHeader;
|
|
// while (blockPtr != NULL)
|
|
// {
|
|
// totalCrtSize += blockPtr->_data_size;
|
|
// if (blockPtr->_block_use != _FREE_BLOCK)
|
|
// totalUseCrtSize += blockPtr->_data_size;
|
|
// blockPtr = blockPtr->_block_header_next;
|
|
// }
|
|
// OutputDebugStrF("Crt Size: %dk Used: %dk\n", (int)(totalCrtSize / 1024), (int)(totalUseCrtSize / 1024));
|
|
#endif
|
|
|
|
_HEAPINFO heapInfo = {0};
|
|
int64 heapSize = 0;
|
|
|
|
int heapStatus;
|
|
while ((heapStatus = _heapwalk(&heapInfo)) == _HEAPOK)
|
|
{
|
|
heapSize += (int64)heapInfo._size;
|
|
}
|
|
OutputDebugStrF("WALKED HEAP SIZE: %dk\n", heapSize / 1024);
|
|
|
|
//_CrtMemDumpStatistics(&memState);
|
|
#endif
|
|
}
|
|
|
|
/*void* TestHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)
|
|
{
|
|
return HeapAlloc(hHeap, dwFlags, dwBytes);
|
|
}*/
|
|
|
|
static void BfFatalErrorHandler(void *user_data, const std::string& reason, bool gen_crash_diag)
|
|
{
|
|
BF_FATAL(reason.c_str());
|
|
OutputDebugStrF("LLVM ERROR: %s\n", reason.c_str());
|
|
}
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
BOOL WINAPI DllMain(
|
|
HANDLE hDllHandle,
|
|
DWORD dwReason,
|
|
LPVOID lpreserved)
|
|
{
|
|
//::MessageBoxA(NULL, "A", "B", MB_OK);
|
|
|
|
// MemReporter memReporter;
|
|
// memReporter.mShowInKB = false;
|
|
// {
|
|
// memReporter.BeginSection("A");
|
|
// {
|
|
// memReporter.BeginSection("B");
|
|
// memReporter.Add(10);
|
|
//
|
|
// memReporter.Add("C", 1);
|
|
// memReporter.Add("D", 2);
|
|
//
|
|
// memReporter.EndSection();
|
|
// }
|
|
// memReporter.EndSection();
|
|
// }
|
|
//
|
|
// memReporter.Report();
|
|
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
BpInit("127.0.0.1", "Beef IDE");
|
|
BpSetThreadName("Main");
|
|
BfpThread_SetName(NULL, "Main", NULL);
|
|
|
|
llvm::install_fatal_error_handler(BfFatalErrorHandler, NULL);
|
|
|
|
//_CRTDBG_CHECK_EVERY_16_DF
|
|
//_CRTDBG_CHECK_ALWAYS_DF
|
|
//_CRTDBG_DELAY_FREE_MEM_DF
|
|
|
|
//_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/);
|
|
_CrtSetAllocHook(BfAllocHook);
|
|
}
|
|
|
|
if (dwReason == -123)
|
|
{
|
|
BpDump();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#endif //BF_PLATFORM_WINDOWS
|
|
|
|
//////
|
|
|
|
void SleepTest()
|
|
{
|
|
BfpThread_Sleep(3000);
|
|
}
|
|
|
|
void WdAllocTest();
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
static _CrtMemState gStartMemCheckpoint;
|
|
#endif
|
|
BF_EXPORT void BF_CALLTYPE Debugger_Create()
|
|
{
|
|
String outStr = BfDemangler::Demangle(
|
|
"??0?$_String_alloc@U?$_String_base_types@DV?$allocator@D@std@@@std@@@std@@QEAA@AEBV?$allocator@D@1@@Z"
|
|
//"?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAX_N_K@Z"
|
|
//"?gamma@Class1@@2PAY04NA"
|
|
//"?alpha@@3HA"
|
|
//"?Fis_i@myclass@@SAHH@Z"
|
|
//"??$?0AEBV?$allocator@D@std@@$$V@?$_Compressed_pair@U?$_Wrap_alloc@V?$allocator@D@std@@@std@@V?$_String_val@U?$_Simple_types@D@std@@@2@$00@std@@QEAA@U_One_then_variadic_args_t@1@AEBV?$allocator@D@1@@Z"
|
|
|
|
//"??0?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IU?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@I@std@@@2@@std@@QEAA@XZ"
|
|
//"??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV01@PEBD@Z"
|
|
//"??0?$allocator@_W@std@@QEAA@XZ"
|
|
//"??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@XZ"
|
|
, DbgLanguage_C);
|
|
|
|
/*{
|
|
|
|
struct TestStruct
|
|
{
|
|
TestStruct* mNext;
|
|
int mInt;
|
|
|
|
TestStruct(int i)
|
|
{
|
|
mNext = NULL;
|
|
mInt = i;
|
|
}
|
|
};
|
|
|
|
TestStruct tsArr[5] = { 1, 2, 3, 4, 5 };
|
|
SLIList<TestStruct*> sliList;
|
|
|
|
sliList.PushBack(&tsArr[0]);
|
|
//sliList.PushBack(&tsArr[1]);
|
|
//sliList.PushBack(&tsArr[2]);
|
|
|
|
auto itr = sliList.begin();
|
|
auto* val = *itr;
|
|
//++itr;
|
|
//val = *itr;
|
|
//++itr;
|
|
//val = *itr;
|
|
sliList.erase(itr);
|
|
bool isEnd = itr == sliList.end();
|
|
}*/
|
|
|
|
String str = StrFormat("%d:%@:%l@", 123, (intptr)0x1234567890LL, 0xABCDEF7890LL);
|
|
//String str = StrFormat("%l@", "Yo");
|
|
|
|
//TODO: Very slow, remove
|
|
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF);
|
|
|
|
//TODO: _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_EVERY_16_DF*/);
|
|
//_CrtSetAllocHook(BfAllocHook);
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
_CrtMemCheckpoint(&gStartMemCheckpoint);
|
|
#endif
|
|
//_CrtSetBreakAlloc(621);
|
|
|
|
gDebugManager = new DebugManager();
|
|
#ifdef ENABLE_DBG_32
|
|
gDebugManager->mDebugger32 = CreateDebugger32(gDebugManager, NULL);
|
|
#else
|
|
gDebugManager->mDebugger32 = NULL;
|
|
#endif
|
|
|
|
#ifdef BF32
|
|
gDebugManager->mDebugger64 = NULL;
|
|
#else
|
|
gDebugManager->mDebugger64 = CreateDebugger64(gDebugManager, NULL);
|
|
#endif
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
::AllowSetForegroundWindow(ASFW_ANY);
|
|
#endif
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_SetCallbacks(void* callback)
|
|
{
|
|
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_FullReportMemory()
|
|
{
|
|
//WdAllocTest();
|
|
ShowMemoryUsage();
|
|
BfFullReportMemory();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_Delete()
|
|
{
|
|
delete gDebugManager;
|
|
gDebugManager = NULL;
|
|
|
|
delete gPerfManager;
|
|
gPerfManager = NULL;
|
|
|
|
//OutputDebugStrF("Deleting Debugger\n");
|
|
//BfReportMemory();
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
gBgTrackingAllocs = false;
|
|
#endif
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_ProgramDone()
|
|
{
|
|
//TODO:
|
|
//::MessageBoxA(NULL, "Done", "Done", MB_OK);
|
|
|
|
BF_ASSERT(gDebugger == NULL);
|
|
|
|
//ShowMemoryUsage();
|
|
//BfFullReportMemory();
|
|
|
|
#ifdef CAPTURE_ALLOC_SOURCES
|
|
gInsideAlloc = true;
|
|
for (int i = 0; i < CAPTURE_ALLOC_POOL_SIZE; i++)
|
|
{
|
|
if (gHashCaptureAllocSize[i] != NULL)
|
|
{
|
|
free(gHashCaptureAllocSize[i]->mSymName);
|
|
delete gHashCaptureAllocSize[i];
|
|
gHashCaptureAllocSize[i] = NULL;
|
|
}
|
|
}
|
|
gBfCaptureSourceAllocMap.clear();
|
|
#endif
|
|
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
_CrtMemDumpAllObjectsSince(&gStartMemCheckpoint);
|
|
|
|
/*_CrtMemState curMemCheckpoint;
|
|
_CrtMemCheckpoint(&curMemCheckpoint);
|
|
|
|
_CrtMemState memDiff;
|
|
if (_CrtMemDifference(&memDiff, &gStartMemCheckpoint, &curMemCheckpoint))
|
|
_CrtMemDumpStatistics(&memDiff);*/
|
|
|
|
_CrtMemState curMemCheckpoint = { 0 };
|
|
_CrtMemCheckpoint(&curMemCheckpoint);
|
|
OutputDebugStrF("Heap memory usage: %dk\n", curMemCheckpoint.lTotalCount / 1024);
|
|
#endif //BF_PLATFORM_WINDOWS
|
|
|
|
BpShutdown();
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE Debugger_GetAddrSize()
|
|
{
|
|
if (gDebugger == NULL)
|
|
return 0;
|
|
return gDebugger->GetAddrSize();
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char* targetPath, const char* args, const char* workingDir, void* envBlockPtr, int envBlockSize)
|
|
{
|
|
BF_ASSERT(gDebugger == NULL);
|
|
|
|
if (!FileExists(launchPath))
|
|
{
|
|
gDebugManager->mOutMessages.push_back(StrFormat("error Unable to locate specified launch target '%s'", launchPath));
|
|
return false;
|
|
}
|
|
|
|
DebuggerResult debuggerResult = DebuggerResult_Ok;
|
|
if ((gDebugManager->mDebugger64 != NULL) && (gDebugManager->mDebugger64->CanOpen(launchPath, &debuggerResult)))
|
|
gDebugger = gDebugManager->mDebugger64;
|
|
else
|
|
gDebugger = gDebugManager->mDebugger32;
|
|
|
|
if (gDebugger == NULL)
|
|
{
|
|
if (debuggerResult == DebuggerResult_WrongBitSize)
|
|
gDebugManager->mOutMessages.push_back(StrFormat("error The file 32-bit file '%s' cannot be debugged because 32-bit debugger has been disabled", launchPath));
|
|
return false;
|
|
}
|
|
|
|
Array<uint8> envBlock;
|
|
if (envBlockPtr != NULL)
|
|
{
|
|
if (envBlockSize != 0)
|
|
envBlock.Insert(0, (uint8*)envBlockPtr, envBlockSize);
|
|
}
|
|
|
|
gDebugger->OpenFile(launchPath, targetPath, args, workingDir, envBlock);
|
|
return true;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_SetSymSrvOptions(const char* symCacheDir, const char* symSrvStr, int flags)
|
|
{
|
|
Array<String> symServers;
|
|
|
|
const char* startStr = symSrvStr;
|
|
for (const char* cPtr = symSrvStr; true; cPtr++)
|
|
{
|
|
if ((*cPtr == '\n') || (*cPtr == 0))
|
|
{
|
|
String symStr = String(startStr, cPtr - startStr);
|
|
symStr.Trim();
|
|
if (symStr.EndsWith('/'))
|
|
symStr.Remove((int)symStr.length() - 1, 1);
|
|
if (!symStr.IsEmpty())
|
|
symServers.Add(symStr);
|
|
startStr = cPtr;
|
|
}
|
|
|
|
if (*cPtr == 0)
|
|
break;
|
|
}
|
|
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
|
|
gDebugManager->mSymSrvOptions.mCacheDir = symCacheDir;
|
|
gDebugManager->mSymSrvOptions.mSymbolServers = symServers;
|
|
gDebugManager->mSymSrvOptions.mFlags = (BfSymSrvFlags)flags;
|
|
|
|
gDebugManager->mSymSrvOptions.mCacheDir.Trim();
|
|
if (gDebugManager->mSymSrvOptions.mCacheDir.IsEmpty())
|
|
gDebugManager->mSymSrvOptions.mFlags = BfSymSrvFlag_Disable;
|
|
|
|
if (flags & BfSymSrvFlag_TempCache)
|
|
{
|
|
if (!gDebugManager->mSymSrvOptions.mCacheDir.IsEmpty())
|
|
{
|
|
gDebugManager->mSymSrvOptions.mCacheDir.Append("\\temp");
|
|
RecursiveDeleteDirectory(gDebugManager->mSymSrvOptions.mCacheDir);
|
|
}
|
|
}
|
|
|
|
gDebugManager->SetSourceServerCacheDir();
|
|
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_OpenMiniDump(const char* fileName)
|
|
{
|
|
#ifdef BF_PLATFORM_WINDOWS
|
|
DbgMiniDump* dbgMiniDump = new DbgMiniDump();
|
|
bool result = dbgMiniDump->StartLoad(fileName);
|
|
if (!result)
|
|
{
|
|
delete dbgMiniDump;
|
|
return false;
|
|
}
|
|
|
|
|
|
if (dbgMiniDump->GetTargetBitCount() == 32)
|
|
gDebugger = CreateDebugger32(gDebugManager, dbgMiniDump);
|
|
else
|
|
gDebugger = CreateDebugger64(gDebugManager, dbgMiniDump);
|
|
|
|
return result;
|
|
#else //BF_PLATFORM_WINDOWS
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_Attach(int processId, BfDbgAttachFlags attachFlags)
|
|
{
|
|
BF_ASSERT(gDebugger == NULL);
|
|
|
|
if (gDebugManager->mDebugger64->Attach(processId, attachFlags))
|
|
{
|
|
gDebugger = gDebugManager->mDebugger64;
|
|
return true;
|
|
}
|
|
|
|
if (gDebugManager->mDebugger32->Attach(processId, attachFlags))
|
|
{
|
|
gDebugger = gDebugManager->mDebugger32;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_Run()
|
|
{
|
|
gDebugger->Run();
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_HotLoad(const char* fileNamesStr, int hotIdx)
|
|
{
|
|
//DbgModule* dwarf = new DbgModule(gDebugger);
|
|
//dwarf->ReadPE(fileName);
|
|
|
|
Array<String> fileNames;
|
|
const char* curPtr = fileNamesStr;
|
|
for (int i = 0; true; i++)
|
|
{
|
|
if ((fileNamesStr[i] == '\0') || (fileNamesStr[i] == '\n'))
|
|
{
|
|
String curFileName = String(curPtr, fileNamesStr + i);
|
|
|
|
if ((curFileName.IndexOf("/vdata.") != -1) || (curFileName.IndexOf("\\vdata.") != -1))
|
|
{
|
|
// Do vdata first - so new data and special functions don't have to be deferred resolved
|
|
fileNames.Insert(0, curFileName);
|
|
}
|
|
else
|
|
fileNames.Add(curFileName);
|
|
curPtr = fileNamesStr + i + 1;
|
|
}
|
|
|
|
if (fileNamesStr[i] == '\0')
|
|
break;
|
|
}
|
|
|
|
gDebugger->HotLoad(fileNames, hotIdx);
|
|
|
|
return true;
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_LoadDebugVisualizers(const char* fileName)
|
|
{
|
|
String fn = fileName;
|
|
bool worked = false;
|
|
worked = gDebugManager->mDebugVisualizers->Load(fileName);
|
|
if (!gDebugManager->mDebugVisualizers->mErrorString.empty())
|
|
{
|
|
gDebugManager->mOutMessages.push_back(StrFormat("msg ERROR: %s\n", gDebugManager->mDebugVisualizers->mErrorString.c_str()));
|
|
}
|
|
|
|
// {
|
|
// BF_FATAL(gDebugManager->mDebugVisualizers->mErrorString.c_str());
|
|
// }
|
|
return worked;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_StopDebugging()
|
|
{
|
|
gDebugger->StopDebugging();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_Terminate()
|
|
{
|
|
gDebugger->Terminate();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_Detach()
|
|
{
|
|
gDebugManager->mNetManager->CancelAll();
|
|
gDebugger->Detach();
|
|
if (gDebugger->IsOnDemandDebugger())
|
|
delete gDebugger;
|
|
gDebugger = NULL;
|
|
gDebugManager->mNetManager->Clear();
|
|
}
|
|
|
|
BF_EXPORT Breakpoint* BF_CALLTYPE Debugger_CreateBreakpoint(const char* fileName, int lineNum, int wantColumn, int instrOffset)
|
|
{
|
|
return gDebugger->CreateBreakpoint(fileName, lineNum, wantColumn, instrOffset);
|
|
}
|
|
|
|
BF_EXPORT Breakpoint* BF_CALLTYPE Debugger_CreateMemoryBreakpoint(intptr address, int byteCount)
|
|
{
|
|
return gDebugger->CreateMemoryBreakpoint(address, byteCount);
|
|
}
|
|
|
|
BF_EXPORT Breakpoint* BF_CALLTYPE Debugger_CreateSymbolBreakpoint(const char* symbolName)
|
|
{
|
|
return gDebugger->CreateSymbolBreakpoint(symbolName);
|
|
}
|
|
|
|
BF_EXPORT Breakpoint* BF_CALLTYPE Debugger_CreateAddressBreakpoint(intptr address)
|
|
{
|
|
return gDebugger->CreateAddressBreakpoint(address);
|
|
}
|
|
|
|
BF_EXPORT Breakpoint* BF_CALLTYPE Debugger_GetActiveBreakpoint()
|
|
{
|
|
return gDebugger->GetActiveBreakpoint();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_Delete(Breakpoint* wdBreakpoint)
|
|
{
|
|
gDebugger->DeleteBreakpoint(wdBreakpoint);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_Check(Breakpoint* breakpoint)
|
|
{
|
|
gDebugger->CheckBreakpoint(breakpoint);
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE Breakpoint_GetPendingHotBindIdx(Breakpoint* breakpoint)
|
|
{
|
|
return breakpoint->mPendingHotBindIdx;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_HotBindBreakpoint(Breakpoint* breakpoint, int lineNum, int hotIdx)
|
|
{
|
|
gDebugger->HotBindBreakpoint(breakpoint, lineNum, hotIdx);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_SetThreadId(Breakpoint* breakpoint, intptr threadId)
|
|
{
|
|
BfLogDbg("Breakpoint %p set ThreadId=%d\n", breakpoint, threadId);
|
|
breakpoint->mThreadId = threadId;
|
|
gDebugger->CheckBreakpoint(breakpoint);
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE Breakpoint_GetHitCount(Breakpoint* breapoint)
|
|
{
|
|
return breapoint->mHitCount;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_ClearHitCount(Breakpoint* breapoint)
|
|
{
|
|
breapoint->mHitCount = 0;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_SetHitCountTarget(Breakpoint* breakpoint, int targetHitCount, DbgHitCountBreakKind breakKind)
|
|
{
|
|
breakpoint->mTargetHitCount = targetHitCount;
|
|
breakpoint->mHitCountBreakKind = breakKind;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_SetCondition(Breakpoint* wdBreakpoint, const char* condition)
|
|
{
|
|
gDebugger->SetBreakpointCondition(wdBreakpoint, condition);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_SetLogging(Breakpoint* wdBreakpoint, const char* logging, bool breakAfterLogging)
|
|
{
|
|
gDebugger->SetBreakpointLogging(wdBreakpoint, logging, breakAfterLogging);
|
|
}
|
|
|
|
BF_EXPORT uintptr BF_CALLTYPE Breakpoint_GetAddress(Breakpoint* wdBreakpoint, Breakpoint** outLinkedSibling)
|
|
{
|
|
if (outLinkedSibling != NULL)
|
|
*outLinkedSibling = wdBreakpoint->mLinkedSibling;
|
|
return wdBreakpoint->GetAddr();
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Breakpoint_IsMemoryBreakpointBound(Breakpoint* wdBreakpoint)
|
|
{
|
|
return wdBreakpoint->IsMemoryBreakpointBound();
|
|
}
|
|
|
|
BF_EXPORT intptr BF_CALLTYPE Breakpoint_GetLineNum(Breakpoint* wdBreakpoint)
|
|
{
|
|
return wdBreakpoint->mLineNum;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_Move(Breakpoint* breakpoint, int lineNum, int wantColumn, bool rebindNow)
|
|
{
|
|
gDebugger->MoveBreakpoint(breakpoint, lineNum, wantColumn, rebindNow);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_MoveMemoryBreakpoint(Breakpoint* breakpoint, intptr addr, int byteCount)
|
|
{
|
|
gDebugger->MoveMemoryBreakpoint(breakpoint, addr, byteCount);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Breakpoint_Disable(Breakpoint* wdBreakpoint)
|
|
{
|
|
gDebugger->DisableBreakpoint(wdBreakpoint);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_CreateStepFilter(const char* filter, bool isGlobal, BfStepFilterKind filterKind)
|
|
{
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
StepFilter stepFilter;
|
|
stepFilter.mFilterKind = filterKind;
|
|
gDebugManager->mStepFilters[filter] = stepFilter;
|
|
gDebugManager->mStepFilterVersion++;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE StepFilter_Delete(const char* filter)
|
|
{
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
bool didRemove = gDebugManager->mStepFilters.Remove(filter);
|
|
BF_ASSERT(didRemove);
|
|
|
|
gDebugManager->mStepFilterVersion++;
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE Debugger_GetRunState()
|
|
{
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
if (gDebugger == NULL)
|
|
return RunState_NotStarted;
|
|
return gDebugger->mRunState;
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_HasPendingDebugLoads()
|
|
{
|
|
if (gDebugger == NULL)
|
|
return false;
|
|
return gDebugger->HasPendingDebugLoads();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_PopMessage()
|
|
{
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
if (gDebugManager->mOutMessages.size() == 0)
|
|
return NULL;
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugManager->mOutMessages.front();
|
|
gDebugManager->mOutMessages.pop_front();
|
|
//gDebugManager->mOutMessages.erase(gDebugManager->mOutMessages.begin());
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_HasMessages()
|
|
{
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
return gDebugManager->mOutMessages.size() != 0;
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetCurrentException()
|
|
{
|
|
/*outString = StrFormat("Exception at 0x%p, exception code 0x%08X",
|
|
gDebugger->mCurException.ExceptionAddress, gDebugger->mCurException.ExceptionCode);*/
|
|
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->GetCurrentException();
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_BreakAll()
|
|
{
|
|
if (gDebugger != NULL)
|
|
gDebugger->BreakAll();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_Continue()
|
|
{
|
|
BfLogDbg("Debugger_Continue\n");
|
|
gDebugger->ContinueDebugEvent();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_StepInto(bool inAssembly)
|
|
{
|
|
gDebugger->StepInto(inAssembly);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_StepIntoSpecific(intptr addr)
|
|
{
|
|
gDebugger->StepIntoSpecific(addr);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_StepOver(bool inAssembly)
|
|
{
|
|
gDebugger->StepOver(inAssembly);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_StepOut(bool inAssembly)
|
|
{
|
|
gDebugger->StepOut(inAssembly);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_SetNextStatement(bool inAssembly, const char* fileName, int64 wantLineNumOrAsmAddr, int wantColumn)
|
|
{
|
|
if (fileName == NULL)
|
|
fileName = "";
|
|
gDebugger->SetNextStatement(inAssembly, fileName, wantLineNumOrAsmAddr, wantColumn);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_Update()
|
|
{
|
|
if (gDebugger != NULL)
|
|
gDebugger->Update();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_SetDisplayTypes(const char* referenceId, int8 intDisplayType, int8 mmDisplayType)
|
|
{
|
|
DwDisplayInfo displayInfo;
|
|
displayInfo.mIntDisplayType = (DwIntDisplayType)intDisplayType;
|
|
displayInfo.mMmDisplayType = (DwMmDisplayType)mmDisplayType;
|
|
|
|
if (referenceId == NULL)
|
|
{
|
|
gDebugManager->mDefaultDisplayInfo = displayInfo;
|
|
}
|
|
else if ((displayInfo.mIntDisplayType == DwIntDisplayType_Default) &&
|
|
(displayInfo.mMmDisplayType == DwMmDisplayType_Default))
|
|
{
|
|
/*auto itr = gDebugManager->mDisplayInfos.find(referenceId);
|
|
if (itr != gDebugManager->mDisplayInfos.end())
|
|
gDebugManager->mDisplayInfos.erase(itr);*/
|
|
gDebugManager->mDisplayInfos.Remove(referenceId);
|
|
}
|
|
else
|
|
{
|
|
gDebugManager->mDisplayInfos[referenceId] = displayInfo;
|
|
}
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_GetDisplayTypes(const char* referenceId, int8* intDisplayType, int8* mmDisplayType)
|
|
{
|
|
bool foundSpecific = false;
|
|
DwDisplayInfo* displayInfo = &gDebugManager->mDefaultDisplayInfo;
|
|
if (referenceId != NULL)
|
|
{
|
|
/*auto itr = gDebugManager->mDisplayInfos.find(referenceId);
|
|
if (itr != gDebugManager->mDisplayInfos.end())
|
|
{
|
|
displayInfo = &itr->second;
|
|
foundSpecific = true;
|
|
}*/
|
|
|
|
if (gDebugManager->mDisplayInfos.TryGetValue(referenceId, &displayInfo))
|
|
{
|
|
foundSpecific = true;
|
|
}
|
|
}
|
|
|
|
*intDisplayType = (int)displayInfo->mIntDisplayType;
|
|
*mmDisplayType = (int)displayInfo->mMmDisplayType;
|
|
return foundSpecific;
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetDisplayTypeNames()
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString.clear();
|
|
for (auto& displayInfoEntry : gDebugManager->mDisplayInfos)
|
|
{
|
|
outString += displayInfoEntry.mKey + "\n";
|
|
}
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_EvaluateContinue()
|
|
{
|
|
auto debugger = gDebugger;
|
|
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = debugger->EvaluateContinue();
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_EvaluateContinueKeep()
|
|
{
|
|
auto debugger = gDebugger;
|
|
debugger->EvaluateContinueKeep();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_Evaluate(const char* expr, int callStackIdx, int cursorPos, int32 language, int8 expressionFlags)
|
|
{
|
|
auto debugger = gDebugger;
|
|
|
|
if (debugger == NULL)
|
|
debugger = gDebugManager->mDebugger64;
|
|
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString.clear();
|
|
outString = debugger->Evaluate(expr, callStackIdx, cursorPos, language, (DwEvalExpressionFlags)expressionFlags);
|
|
#ifdef BF_WANTS_LOG_DBG
|
|
{
|
|
int crPos = (int)outString.IndexOf('\n');
|
|
if (crPos != -1)
|
|
BfLogDbg("Debugger_Evaluate Result=%s\n", outString.Substring(0, crPos).c_str());
|
|
else
|
|
BfLogDbg("Debugger_Evaluate Result=%s\n", outString.c_str());
|
|
}
|
|
#endif
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_EvaluateToAddress(const char* expr, int callStackIdx, int cursorPos)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString.clear();
|
|
if (gDebugger != NULL)
|
|
outString = gDebugger->EvaluateToAddress(expr, callStackIdx, cursorPos);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_EvaluateAtAddress(const char* expr, intptr atAddr, int cursorPos)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString.clear();
|
|
if (gDebugger != NULL)
|
|
outString = gDebugger->EvaluateAtAddress(expr, atAddr, cursorPos);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetAutoExpressions(int callStackIdx, uint64 memoryRangeStart, uint64 memoryRangeLen)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->GetAutoExpressions(callStackIdx, memoryRangeStart, memoryRangeLen);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetAutoLocals(int callStackIdx, bool showRegs)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->GetAutoLocals(callStackIdx, showRegs);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_CompactChildExpression(const char* expr, const char* parentExpr, int callStackIdx)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->CompactChildExpression(expr, parentExpr, callStackIdx);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetCollectionContinuation(const char* continuationData, int callStackIdx, int count)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->GetCollectionContinuation(continuationData, callStackIdx, count);
|
|
return outString.c_str();
|
|
}
|
|
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_ForegroundTarget()
|
|
{
|
|
gDebugger->ForegroundTarget();
|
|
|
|
|
|
//BOOL worked = EnumThreadWindows(gDebugger->mProcessInfo.dwThreadId, WdEnumWindowsProc, 0);
|
|
//BF_ASSERT(worked);
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetThreadInfo()
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->GetThreadInfo();
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_SetActiveThread(int threadId)
|
|
{
|
|
gDebugger->SetActiveThread(threadId);
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE Debugger_GetActiveThread()
|
|
{
|
|
return gDebugger->GetActiveThread();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_FreezeThread(int threadId)
|
|
{
|
|
gDebugger->FreezeThread(threadId);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_ThawThread(int threadId)
|
|
{
|
|
gDebugger->ThawThread(threadId);
|
|
}
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Debugger_IsActiveThreadWaiting()
|
|
{
|
|
return gDebugger->IsActiveThreadWaiting();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE CallStack_Update()
|
|
{
|
|
gDebugger->UpdateCallStack();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE CallStack_Rehup()
|
|
{
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
gDebugger->ClearCallStack();
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE CallStack_GetCount()
|
|
{
|
|
return gDebugger->GetCallStackCount();
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE CallStack_GetRequestedStackFrameIdx()
|
|
{
|
|
return gDebugger->GetRequestedStackFrameIdx();
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE CallStack_GetBreakStackFrameIdx()
|
|
{
|
|
return gDebugger->GetBreakStackFrameIdx();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE CallStack_GetStackFrameInfo(int stackFrameIdx, intptr* addr, const char** outFile, int32* outHotIdx, int32* outDefLineStart, int32* outDefLineEnd,
|
|
int32* outLine, int32* outColumn, int32* outLanguage, int32* outStackSize, int8* outFlags)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
String& outString2 = *gTLStrReturn2.Get();
|
|
|
|
outString = gDebugger->GetStackFrameInfo(stackFrameIdx, addr, &outString2, outHotIdx, outDefLineStart, outDefLineEnd, outLine, outColumn, outLanguage, outStackSize, outFlags);
|
|
*outFile = outString2.c_str();
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Callstack_GetStackFrameOldFileInfo(int stackFrameIdx)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->Callstack_GetStackFrameOldFileInfo(stackFrameIdx);
|
|
return outString.c_str();
|
|
}
|
|
|
|
// -1 = no jump, 0 = won't jump, 1 = will jump
|
|
BF_EXPORT int BF_CALLTYPE CallStack_GetJmpState(int stackFrameIdx)
|
|
{
|
|
return gDebugger->GetJmpState(stackFrameIdx);
|
|
}
|
|
|
|
BF_EXPORT intptr BF_CALLTYPE Debugger_GetStackFrameCalleeAddr(int stackFrameIdx)
|
|
{
|
|
return gDebugger->GetStackFrameCalleeAddr(stackFrameIdx);
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetCodeAddrInfo(intptr addr, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString.clear();
|
|
gDebugger->GetCodeAddrInfo(addr, &outString, outHotIdx, outDefLineStart, outDefLineEnd, outLine, outColumn);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_GetStackAllocInfo(intptr addr, int* outThreadId, int* outStackIdx)
|
|
{
|
|
gDebugger->GetStackAllocInfo(addr, outThreadId, outStackIdx);
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE CallStack_GetStackMethodOwner(int stackFrameIdx, int& language)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->GetStackMethodOwner(stackFrameIdx, language);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_FindCodeAddresses(const char* fileName, int line, int column, bool allowAutoResolve)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->FindCodeAddresses(fileName, line, column, allowAutoResolve);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetAddressSourceLocation(intptr address)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
if (gDebugger != NULL)
|
|
outString = gDebugger->GetAddressSourceLocation(address);
|
|
else
|
|
outString = "";
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetAddressSymbolName(intptr address, bool demangle)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
if (gDebugger != NULL)
|
|
outString = gDebugger->GetAddressSymbolName(address, demangle);
|
|
else
|
|
outString = "";
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_FindLineCallAddresses(intptr address)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->FindLineCallAddresses(address);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_DisassembleAt(intptr address)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->DisassembleAt(address);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_ReadMemory(uintptr address, uintptr size, unsigned char* data)
|
|
{
|
|
if (gDebugger == NULL)
|
|
return;
|
|
|
|
//CDH TODO internally clamps to 32-bit here, need to make this more obvious in IDE memory panel etc.
|
|
gDebugger->ReadMemory(address, size, data);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_WriteMemory(uintptr address, uintptr size, unsigned char* data)
|
|
{
|
|
//CDH TODO internally clamps to 32-bit here, need to make this more obvious in IDE memory panel etc.
|
|
gDebugger->WriteMemory(address, data, size);
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetModulesInfo()
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = gDebugger->GetModulesInfo();
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_CancelSymSrv()
|
|
{
|
|
gDebugger->CancelSymSrv();
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE Debugger_LoadDebugInfoForModule(const char* moduleName) // 0 = No Change, 1 = Loaded, 2 = Loading in background
|
|
{
|
|
return gDebugger->LoadDebugInfoForModule(moduleName);
|
|
}
|
|
|
|
BF_EXPORT int BF_CALLTYPE Debugger_LoadDebugInfoForModuleWith(const char* moduleName, const char* debugFilePath) // 0 = No Change, 1 = Loaded, 2 = Loading in background
|
|
{
|
|
return gDebugger->LoadDebugInfoForModule(moduleName, debugFilePath);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_SetStepOverExternalFiles(bool stepOverExternalFiles)
|
|
{
|
|
gDebugManager->mStepOverExternalFiles = stepOverExternalFiles;
|
|
gDebugManager->mStepFilterVersion++;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE BfLog_Log(char* str)
|
|
{
|
|
BfLog(str);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE BfLog_LogDbg(char* str)
|
|
{
|
|
BfLogDbg(str);
|
|
}
|
|
|
|
BF_EXPORT Profiler* BF_CALLTYPE Debugger_StartProfiling(intptr threadId, char* desc, int sampleRate)
|
|
{
|
|
BF_ASSERT(sampleRate > 0);
|
|
Profiler* profiler = gDebugger->StartProfiling();
|
|
profiler->mTargetThreadId = threadId;
|
|
if (desc != NULL)
|
|
profiler->mDescription = desc;
|
|
profiler->mSamplesPerSecond = sampleRate;
|
|
profiler->Start();
|
|
return profiler;
|
|
}
|
|
|
|
BF_EXPORT Profiler* BF_CALLTYPE Debugger_PopProfiler()
|
|
{
|
|
Profiler* profiler = gDebugger->PopProfiler();
|
|
return profiler;
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Debugger_InitiateHotResolve(int flags)
|
|
{
|
|
if (gDebugger != NULL)
|
|
gDebugger->InitiateHotResolve((DbgHotResolveFlags)flags);
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetHotResolveData(uint8* outTypeData, int* outTypeDataSize)
|
|
{
|
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
|
|
|
if (gDebugger->mHotResolveData == NULL)
|
|
{
|
|
*outTypeDataSize = -1;
|
|
return NULL;
|
|
}
|
|
|
|
int dataSize = (int)gDebugger->mHotResolveData->mTypeData.size();
|
|
if (*outTypeDataSize < dataSize)
|
|
{
|
|
*outTypeDataSize = dataSize;
|
|
return NULL;
|
|
}
|
|
|
|
*outTypeDataSize = dataSize;
|
|
if (dataSize > 0)
|
|
memcpy(outTypeData, &gDebugger->mHotResolveData->mTypeData[0], dataSize);
|
|
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString.Clear();
|
|
|
|
for (auto& str : gDebugger->mHotResolveData->mBeefCallStackEntries)
|
|
{
|
|
if (!outString.IsEmpty())
|
|
outString += "\n";
|
|
outString += str;
|
|
}
|
|
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void Debugger_SetAliasPath(char* origPath, char* localPath)
|
|
{
|
|
gDebugger->SetAliasPath(origPath, localPath);
|
|
}
|
|
|
|
///
|
|
|
|
BF_EXPORT bool BF_CALLTYPE Profiler_IsRunning(Profiler* profiler)
|
|
{
|
|
return profiler->IsSampling();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Profiler_Stop(Profiler* profiler)
|
|
{
|
|
profiler->Stop();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Profiler_Clear(Profiler* profiler)
|
|
{
|
|
profiler->Clear();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Profiler_GetOverview(Profiler* profiler)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = profiler->GetOverview();
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Profiler_GetThreadList(Profiler* profiler)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = profiler->GetThreadList();
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT const char* BF_CALLTYPE Profiler_GetCallTree(Profiler* profiler, int threadId, bool reverse)
|
|
{
|
|
String& outString = *gTLStrReturn.Get();
|
|
outString = profiler->GetCallTree(threadId, reverse);
|
|
return outString.c_str();
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE Profiler_Delete(Profiler* profiler)
|
|
{
|
|
int z = 0;
|
|
delete profiler;
|
|
}
|
|
|
|
BF_TLS_DECLSPEC static int gTLSValue = 3;
|
|
|
|
BF_EXPORT void BF_CALLTYPE TimeTest(uint32 startTime)
|
|
{
|
|
gTLSValue++;
|
|
|
|
int elapsedTime = BFTickCount() - startTime;
|
|
OutputDebugStrF("Load Time: %d\n", elapsedTime);
|
|
}
|
|
|
|
BF_EXPORT void BF_CALLTYPE BFTest()
|
|
{
|
|
struct DeferredResolveEntry2
|
|
{
|
|
BfFieldDef* mFieldDef;
|
|
int mTypeArrayIdx;
|
|
};
|
|
|
|
DeferredResolveEntry2 entry = { NULL, 333 };
|
|
|
|
llvm::SmallVector<DeferredResolveEntry2, 8> vec;
|
|
vec.push_back(DeferredResolveEntry2 { NULL, 111 } );
|
|
vec.push_back(DeferredResolveEntry2 { NULL, 222 } );
|
|
}
|
|
|
|
///
|
|
|
|
// __attribute__((weak))
|
|
// Debugger* Beefy::CreateDebugger32(DebugManager* debugManager, DbgMiniDump* miniDump)
|
|
// {
|
|
// return NULL;
|
|
// }
|