project64/Source/Project64/UserInterface/Debugger/Symbols.cpp

470 lines
9.0 KiB
C++

#include "stdafx.h"
#include "Symbols.h"
bool CSymbols::m_bInitialized = false;
vector<CSymbolEntry*> CSymbols::m_Symbols;
int CSymbols::m_NextSymbolId;
CFile CSymbols::m_SymFileHandle;
char* CSymbols::m_SymFileBuffer;
size_t CSymbols::m_SymFileSize;
char CSymbols::m_ParserDelimeter;
char* CSymbols::m_ParserToken;
size_t CSymbols::m_ParserTokenLength;
bool CSymbols::m_bHaveFirstToken;
char* CSymbols::m_SymFileParseBuffer;
CRITICAL_SECTION CSymbols::m_CriticalSection = {0};
int CSymbols::GetTypeNumber(char* typeName)
{
const char* name;
for (int i = 0; (name = SymbolTypes[i]) != NULL; i++)
{
if (strcmp(typeName, name) == 0)
{
return i;
}
}
return -1;
}
const char* CSymbols::GetTypeName(int typeNumber)
{
if (typeNumber > 11)
{
return NULL;
}
return SymbolTypes[typeNumber];
}
// Open symbols file for game and parse into list
CPath CSymbols::GetSymFilePath()
{
stdstr symFileName;
symFileName.Format("%s.sym", g_Settings->LoadStringVal(Game_GameName).c_str());
CPath symFilePath(g_Settings->LoadStringVal(Directory_NativeSave).c_str(), symFileName.c_str());
if (g_Settings->LoadBool(Setting_UniqueSaveDir))
{
symFilePath.AppendDirectory(g_Settings->LoadStringVal(Game_UniqueSaveDir).c_str());
}
symFilePath.NormalizePath(CPath(CPath::MODULE_DIRECTORY));
if (!symFilePath.DirectoryExists())
{
symFilePath.DirectoryCreate();
}
return symFilePath;
}
void CSymbols::ParserInit()
{
m_SymFileParseBuffer = (char*)malloc(m_SymFileSize + 1);
strcpy(m_SymFileParseBuffer, m_SymFileBuffer);
m_bHaveFirstToken = false;
}
void CSymbols::ParserDone()
{
free(m_SymFileParseBuffer);
}
void CSymbols::ParserFetchToken(const char* delim)
{
if (!m_bHaveFirstToken)
{
m_ParserToken = strtok(m_SymFileParseBuffer, delim);
m_bHaveFirstToken = true;
}
else
{
m_ParserToken = strtok(NULL, delim);
}
if (m_ParserToken != NULL)
{
m_ParserTokenLength = strlen(m_ParserToken);
m_ParserDelimeter = m_SymFileBuffer[m_ParserToken - m_SymFileParseBuffer + m_ParserTokenLength];
}
else
{
m_ParserTokenLength = 0;
m_ParserDelimeter = '\0';
}
}
void CSymbols::Load()
{
m_NextSymbolId = 0;
Reset();
if (g_Settings->LoadStringVal(Game_GameName).length() == 0)
{
MessageBox(NULL, "Game must be loaded", "Symbols", MB_ICONWARNING | MB_OK);
return;
}
CPath symFilePath = GetSymFilePath();
bool bOpened = m_SymFileHandle.Open(symFilePath, CFileBase::modeRead);
if (!bOpened)
{
return;
}
m_SymFileSize = m_SymFileHandle.GetLength();
m_SymFileBuffer = (char*)malloc(m_SymFileSize + 1);
m_SymFileHandle.Read(m_SymFileBuffer, m_SymFileSize);
m_SymFileHandle.Close();
m_SymFileBuffer[m_SymFileSize] = '\0';
ParseError errorCode = ERR_SUCCESS;
int lineNumber = 1;
ParserInit();
while (true)
{
uint32_t address = 0;
int type = 0;
char* name = NULL;
char* description = NULL;
// Address
ParserFetchToken(",\n\0");
if (m_ParserToken == NULL || m_ParserTokenLength == 0)
{
// Empty line @EOF
errorCode = ERR_SUCCESS;
break;
}
char* endptr;
address = (uint32_t)strtoull(m_ParserToken, &endptr, 16);
if (endptr == m_ParserToken)
{
errorCode = ERR_INVALID_ADDR;
break;
}
// Type
if (m_ParserDelimeter != ',')
{
errorCode = ERR_MISSING_FIELDS;
break;
}
ParserFetchToken(",\n\0");
type = GetTypeNumber(m_ParserToken);
if (type == -1)
{
errorCode = ERR_INVALID_TYPE;
break;
}
// Name
if (m_ParserDelimeter != ',')
{
errorCode = ERR_MISSING_FIELDS;
break;
}
ParserFetchToken(",\n\0");
name = m_ParserToken;
// Optional description
if (m_ParserDelimeter == ',')
{
ParserFetchToken("\n\0");
description = m_ParserToken;
}
// Add symbol object to the vector
Add(type, address, name, description);
if (m_ParserDelimeter == '\0')
{
errorCode = ERR_SUCCESS;
break;
}
lineNumber++;
}
ParserDone();
free(m_SymFileBuffer);
switch (errorCode)
{
case ERR_SUCCESS:
break;
case ERR_INVALID_ADDR:
ParseErrorAlert("Invalid address", lineNumber);
break;
case ERR_INVALID_TYPE:
ParseErrorAlert("Invalid type", lineNumber);
break;
case ERR_INVALID_NAME:
ParseErrorAlert("Invalid name", lineNumber);
break;
case ERR_MISSING_FIELDS:
ParseErrorAlert("Missing required field(s)", lineNumber);
break;
}
}
void CSymbols::Save()
{
int nSymbols = m_Symbols.size();
char* symfile;
int symfile_size = 0;
int symfile_idx = 0;
// Determine file size
for (int i = 0; i < nSymbols; i++)
{
CSymbolEntry* symbol = m_Symbols[i];
symfile_size += 11; // address 8, required commas 2, newline 1
symfile_size += strlen(symbol->m_Name);
symfile_size += strlen(symbol->TypeName());
if (symbol->m_Description != NULL && strlen(symbol->m_Description) != 0)
{
symfile_size += 1; // comma
symfile_size += strlen(symbol->m_Description);
}
}
if (symfile_size == 0)
{
return;
}
symfile = (char*) malloc(symfile_size + 1);
symfile[symfile_size] = '\0';
// Write out
for (int i = 0; i < nSymbols; i++)
{
CSymbolEntry* symbol = m_Symbols[i];
symfile_idx += sprintf(&symfile[symfile_idx], "%08X,%s,%s", symbol->m_Address, symbol->TypeName(), symbol->m_Name);
if (symbol->m_Description != NULL)
{
symfile_idx += sprintf(&symfile[symfile_idx], ",%s", symbol->m_Description);
}
symfile_idx += sprintf(&symfile[symfile_idx], "\n");
}
m_SymFileHandle.Open(GetSymFilePath(), CFileBase::modeCreate | CFileBase::modeReadWrite);
m_SymFileHandle.SeekToBegin();
m_SymFileHandle.Write(symfile, symfile_size);
m_SymFileHandle.SetEndOfFile();
m_SymFileHandle.Close();
free(symfile);
}
void CSymbols::GetValueString(char* dest, CSymbolEntry* lpSymbol)
{
uint8_t v8;
uint16_t v16;
uint32_t v32;
uint64_t v64;
float vf;
double vd;
uint32_t address = lpSymbol->m_Address;
switch (lpSymbol->m_Type)
{
case TYPE_CODE:
case TYPE_DATA:
sprintf(dest, "");
break;
case TYPE_U8:
g_MMU->LB_VAddr(address, v8);
sprintf(dest, "%u", v8);
break;
case TYPE_U16:
g_MMU->LH_VAddr(address, v16);
sprintf(dest, "%u", v16);
break;
case TYPE_U32:
g_MMU->LW_VAddr(address, v32);
sprintf(dest, "%u", v32);
break;
case TYPE_U64:
g_MMU->LD_VAddr(address, v64);
sprintf(dest, "%I64u", v64);
break;
case TYPE_S8:
g_MMU->LB_VAddr(address, v8);
sprintf(dest, "%ihh", v8);
break;
case TYPE_S16:
g_MMU->LH_VAddr(address, v16);
sprintf(dest, "%i", v16);
break;
case TYPE_S32:
g_MMU->LW_VAddr(address, v32);
sprintf(dest, "%i", v32);
break;
case TYPE_S64:
g_MMU->LD_VAddr(address, v64);
sprintf(dest, "%I64i", v64);
break;
case TYPE_FLOAT:
g_MMU->LW_VAddr(address, *(uint32_t*)&vf);
sprintf(dest, "%f", vf);
break;
case TYPE_DOUBLE:
g_MMU->LD_VAddr(address, *(uint64_t*)&vd);
sprintf(dest, "%f", vd);
break;
default:
MessageBox(NULL, "unkown type", "", MB_OK);
break;
}
}
void CSymbols::ParseErrorAlert(char* message, int lineNumber)
{
stdstr messageFormatted = stdstr_f("%s\nLine %d", message, lineNumber);
MessageBox(NULL, messageFormatted.c_str(), "Parse error", MB_OK | MB_ICONWARNING);
}
void CSymbols::Reset()
{
for (int i = 0; i < GetCount(); i++)
{
delete m_Symbols[i];
}
m_Symbols.clear();
}
const char* CSymbols::GetNameByAddress(uint32_t address)
{
uint32_t len = GetCount();
for (uint32_t i = 0; i < len; i++)
{
if (m_Symbols[i]->m_Address == address)
{
return m_Symbols[i]->m_Name;
}
}
return NULL;
}
bool CSymbols::SortFunction(CSymbolEntry* a, CSymbolEntry* b)
{
return (a->m_Address < b->m_Address);
}
void CSymbols::Add(int type, uint32_t address, char* name, char* description)
{
if (name == NULL || strlen(name) == 0)
{
return;
}
if (description == NULL || strlen(description) == 0)
{
description = NULL;
}
int id = m_NextSymbolId++;
CSymbolEntry* symbol = new CSymbolEntry(id, type, address, name, description);
m_Symbols.push_back(symbol);
sort(m_Symbols.begin(), m_Symbols.end(), SortFunction);
}
int CSymbols::GetCount()
{
return m_Symbols.size();
}
CSymbolEntry* CSymbols::GetEntryByIndex(int index)
{
if (index < 0 || index >= GetCount())
{
return NULL;
}
return m_Symbols[index];
}
CSymbolEntry* CSymbols::GetEntryByAddress(uint32_t address)
{
for (int i = 0; i < GetCount(); i++)
{
if (m_Symbols[i]->m_Address == address)
{
return m_Symbols[i];
}
}
return NULL;
}
CSymbolEntry* CSymbols::GetEntryById(int id)
{
for (int i = 0; i < GetCount(); i++)
{
if (m_Symbols[i]->m_Id == id)
{
return m_Symbols[i];
}
}
return NULL;
}
void CSymbols::RemoveEntryById(int id)
{
for (int i = 0; i < GetCount(); i++)
{
if (m_Symbols[i]->m_Id == id)
{
delete m_Symbols[i];
m_Symbols.erase(m_Symbols.begin() + i);
break;
}
}
}
void CSymbols::EnterCriticalSection()
{
::EnterCriticalSection(&m_CriticalSection);
}
void CSymbols::LeaveCriticalSection()
{
::LeaveCriticalSection(&m_CriticalSection);
}
void CSymbols::InitializeCriticalSection()
{
if (!m_bInitialized)
{
m_bInitialized = true;
::InitializeCriticalSection(&m_CriticalSection);
}
}
void CSymbols::DeleteCriticalSection()
{
if (m_bInitialized)
{
m_bInitialized = false;
::DeleteCriticalSection(&m_CriticalSection);
}
}