1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-07 19:18:19 +02:00
Beef/IDEHelper/DebugManager.cpp
2024-07-24 09:41:08 +02:00

1834 lines
No EOL
47 KiB
C++

#include "DebugManager.h"
#include "BeefySysLib/util/CritSect.h"
#include "Compiler/BfSystem.h"
#include "Compiler/BfParser.h"
#include "Compiler/MemReporter.h"
#include "Compiler/BfIRCodeGen.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"
#include "Compiler/CeDebugger.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"
#pragma warning(disable:4190)
#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();
mOutputFilterFlags = BfOutputFilterFlags_None;
}
DebugManager::~DebugManager()
{
if ((gDebugger != NULL) && (gDebugger->IsOnDemandDebugger()))
{
delete gDebugger;
gDebugger = NULL;
}
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
}
void DebugManager::SetOutputFilterFlags(BfOutputFilterFlags outputFilterFlags)
{
mOutputFilterFlags = outputFilterFlags;
}
BfOutputFilterFlags DebugManager::GetOutputFilterFlags()
{
return mOutputFilterFlags;
}
//#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 char* reason, bool gen_crash_diag)
{
BF_FATAL(reason);
OutputDebugStrF("LLVM ERROR: %s\n", reason);
}
#ifdef BF_PLATFORM_WINDOWS
BOOL WINAPI DllMain(
HANDLE hDllHandle,
DWORD dwReason,
LPVOID lpreserved)
{
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();
namespace BeefyDbg64
{
class WinDebugger;
void TestPDB(const StringImpl& fileName, WinDebugger* debugger);
}
#ifdef BF_PLATFORM_WINDOWS
static _CrtMemState gStartMemCheckpoint;
#endif
BF_EXPORT void BF_CALLTYPE Debugger_Create()
{
//TODO: Very slow, remove
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF);
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_EVERY_16_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
//BeefyDbg64::TestPDB("C:/Beef/IDE/dist/IDEHelper64_d.pdb", (BeefyDbg64::WinDebugger*)gDebugManager->mDebugger64);
}
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 IDEHelper_ProgramStart()
{
BfIRCodeGen::StaticInit();
}
BF_EXPORT void BF_CALLTYPE IDEHelper_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, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags)
{
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, hotSwapEnabled, openFileFlags);
return true;
}
BF_EXPORT bool BF_CALLTYPE Debugger_ComptimeAttach(void* bfCompiler)
{
gDebugger = new CeDebugger(gDebugManager, (BfCompiler*)bfCompiler);
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 void BF_CALLTYPE Debugger_SetSourcePathRemap(const char* remapStr)
{
AutoCrit autoCrit(gDebugManager->mCritSect);
gDebugManager->mSourcePathRemap.Clear();
const char* startStr = remapStr;
for (const char* cPtr = remapStr; true; cPtr++)
{
if ((*cPtr == '\n') || (*cPtr == 0))
{
String remapStr = String(startStr, cPtr - startStr);
remapStr.Trim();
int eqPos = (int)remapStr.IndexOf('=');
if (eqPos != -1)
{
auto keyStr = remapStr.Substring(0, eqPos);
keyStr.Trim();
auto valueStr = remapStr.Substring(eqPos + 1);
valueStr.Trim();
gDebugManager->mSourcePathRemap[keyStr] = valueStr;
}
startStr = cPtr;
}
if (*cPtr == 0)
break;
}
}
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 Debugger_GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
{
if (gDebugger != NULL)
gDebugger->GetStdHandles(outStdIn, outStdOut, outStdErr);
}
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 gDebugger->GetBreakpointAddr(wdBreakpoint);
}
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 Debugger_HasLoadedTargetBinary()
{
AutoCrit autoCrit(gDebugManager->mCritSect);
if (gDebugger == NULL)
return false;
return gDebugger->HasLoadedTargetBinary();
}
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, const char* formatStr, int8 intDisplayType, int8 mmDisplayType, int8 floatDisplayType)
{
AutoCrit autoCrit(gDebugManager->mCritSect);
DwDisplayInfo* displayInfo = NULL;
if (referenceId == NULL)
displayInfo = &gDebugManager->mDefaultDisplayInfo;
else
gDebugManager->mDisplayInfos.TryAdd(referenceId, NULL, &displayInfo);
if (formatStr != NULL)
displayInfo->mFormatStr = formatStr;
displayInfo->mIntDisplayType = (DwIntDisplayType)intDisplayType;
displayInfo->mMmDisplayType = (DwMmDisplayType)mmDisplayType;
displayInfo->mFloatDisplayType = (DwFloatDisplayType)floatDisplayType;
if ((referenceId != NULL) &&
(displayInfo->mFormatStr.IsEmpty()) &&
(displayInfo->mIntDisplayType == DwIntDisplayType_Default) &&
(displayInfo->mMmDisplayType == DwMmDisplayType_Default) &&
(displayInfo->mFloatDisplayType == DwFloatDisplayType_Default))
{
gDebugManager->mDisplayInfos.Remove(referenceId);
}
}
BF_EXPORT const char* BF_CALLTYPE Debugger_GetDisplayTypes(const char* referenceId, int8* intDisplayType, int8* mmDisplayType, int8* floatDisplayType, bool* foundSpecific)
{
AutoCrit autoCrit(gDebugManager->mCritSect);
*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 = (int8)displayInfo->mIntDisplayType;
*mmDisplayType = (int8)displayInfo->mMmDisplayType;
*floatDisplayType = (int8)displayInfo->mFloatDisplayType;
return displayInfo->mFormatStr.c_str();
}
BF_EXPORT const char* BF_CALLTYPE Debugger_GetDisplayTypeNames()
{
AutoCrit autoCrit(gDebugManager->mCritSect);
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 StringView BF_CALLTYPE Debugger_Evaluate(const char* expr, int callStackIdx, int cursorPos, int32 language, uint16 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;
}
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(int altProcessId)
{
gDebugger->ForegroundTarget(altProcessId);
//BOOL worked = EnumThreadWindows(gDebugger->mProcessInfo.dwThreadId, WdEnumWindowsProc, 0);
//BF_ASSERT(worked);
}
BF_EXPORT const char* BF_CALLTYPE Debugger_GetProcessInfo()
{
String& outString = *gTLStrReturn.Get();
outString = gDebugger->GetProcessInfo();
return outString.c_str();
}
BF_EXPORT int BF_CALLTYPE Debugger_GetProcessId()
{
return gDebugger->GetProcessId();
}
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_GetStackFrameId(int stackFrameIdx)
{
String& outString = *gTLStrReturn.Get();
outString = gDebugger->GetStackFrameId(stackFrameIdx);
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, intptr inlineCallAddr, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn)
{
String& outString = *gTLStrReturn.Get();
outString.clear();
gDebugger->GetCodeAddrInfo(addr, inlineCallAddr, &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;
gDebugger->ReadMemory(address, size, data);
}
BF_EXPORT void BF_CALLTYPE Debugger_WriteMemory(uintptr address, uintptr size, unsigned char* data)
{
if (gDebugger == NULL)
return;
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 const char* BF_CALLTYPE Debugger_GetModuleInfo(const char* moduleName)
{
String& outString = *gTLStrReturn.Get();
outString = gDebugger->GetModuleInfo(moduleName);
return outString.c_str();
}
BF_EXPORT void BF_CALLTYPE Debugger_CancelSymSrv()
{
gDebugger->CancelSymSrv();
}
BF_EXPORT int BF_CALLTYPE Debugger_LoadImageForModuleWith(const char* moduleName, const char* debugFilePath) // 0 = No Change, 1 = Loaded, 2 = Loading in background
{
return gDebugger->LoadImageForModule(moduleName, debugFilePath);
}
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 intptr BF_CALLTYPE Debugger_GetDbgAllocHeapSize()
{
AutoCrit autoCrit(gDebugManager->mCritSect);
return gDebugger->GetDbgAllocHeapSize();
}
BF_EXPORT const char* BF_CALLTYPE Debugger_GetDbgAllocInfo()
{
AutoCrit autoCrit(gDebugManager->mCritSect);
String& outString = *gTLStrReturn.Get();
outString = gDebugger->GetDbgAllocInfo();
return outString.c_str();
}
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)
{
for (int i = 0; i < dataSize; i++)
outTypeData[i] = (gDebugger->mHotResolveData->mTypeData[i].mCount > 0) ? 1 : 0;
}
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 const char* BF_CALLTYPE Debugger_GetEmitSource(char* inFilePath)
{
AutoCrit autoCrit(gDebugManager->mCritSect);
String& outString = *gTLStrReturn.Get();
outString.Clear();
if (!gDebugger->GetEmitSource(inFilePath, outString))
return NULL;
return outString.c_str();
}
BF_EXPORT void BF_CALLTYPE Debugger_SetOutputFilterFlags(int flags)
{
if (gDebugManager != NULL)
{
gDebugManager->SetOutputFilterFlags((BfOutputFilterFlags)flags);
}
}
BF_EXPORT int BF_CALLTYPE Debugger_GetOutputFilterFlags()
{
if (gDebugManager != NULL)
{
return (int)gDebugManager->GetOutputFilterFlags();
}
return 0;
}
BF_EXPORT NetResult* HTTP_GetFile(char* url, char* destPath)
{
AutoCrit autoCrit(gDebugManager->mNetManager->mThreadPool.mCritSect);
auto netResult = gDebugManager->mNetManager->QueueGet(url, destPath, false);
netResult->mDoneEvent = new SyncEvent();
return netResult;
}
BF_EXPORT int HTTP_GetResult(NetResult* netResult, int waitMS)
{
if (netResult->mDoneEvent->WaitFor(waitMS))
{
return netResult->mFailed ? 0 : 1;
}
else
{
return -1;
}
}
BF_EXPORT void HTTP_GetLastError(NetResult* netResult, const char** error, int* errorLength)
{
*error = netResult->mError.GetPtr();
*errorLength = netResult->mError.GetLength();
}
BF_EXPORT void HTTP_Delete(NetResult* netResult)
{
if (!netResult->mDoneEvent->WaitFor(0))
{
///
{
AutoCrit autoCrit(gDebugManager->mNetManager->mThreadPool.mCritSect);
if (netResult->mCurRequest != NULL)
netResult->mCurRequest->Cancel();
}
netResult->mDoneEvent->WaitFor(-1);
}
delete netResult;
}
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;
// }