mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-23 00:30:17 +00:00
1045 lines
28 KiB
C++
1045 lines
28 KiB
C++
/*
|
|
AppleWin : An Apple //e emulator for Windows
|
|
|
|
Copyright (C) 1994-1996, Michael O'Brien
|
|
Copyright (C) 1999-2001, Oliver Schmidt
|
|
Copyright (C) 2002-2005, Tom Charlesworth
|
|
Copyright (C) 2006-2014, Tom Charlesworth, Michael Pohoreski
|
|
|
|
AppleWin is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
AppleWin is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with AppleWin; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/* Description: Debugger Symbol Tables
|
|
*
|
|
* Author: Copyright (C) 2006-2010 Michael Pohoreski
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "Debug.h"
|
|
|
|
#include "../Windows/AppleWin.h"
|
|
#include "../Core.h"
|
|
|
|
// 2.6.2.13 Added: Can now enable/disable selected symbol table(s) !
|
|
// Allow the user to disable/enable symbol tables
|
|
// xxx1xxx symbol table is active (are displayed in disassembly window, etc.)
|
|
// xxx1xxx symbol table is disabled (not displayed in disassembly window, etc.)
|
|
// See: CmdSymbolsListTable(), g_bDisplaySymbolTables
|
|
int g_bDisplaySymbolTables = ((1 << NUM_SYMBOL_TABLES) - 1) & (~(int)SYMBOL_TABLE_PRODOS);// default to all symbol tables displayed/active
|
|
|
|
// Symbols ________________________________________________________________________________________
|
|
|
|
const char* g_sFileNameSymbols[ NUM_SYMBOL_TABLES ] = {
|
|
"APPLE2E.SYM"
|
|
,"A2_BASIC.SYM"
|
|
,"A2_ASM.SYM"
|
|
,"A2_USER1.SYM" // "A2_USER.SYM",
|
|
,"A2_USER2.SYM"
|
|
,"A2_SRC1.SYM" // "A2_SRC.SYM",
|
|
,"A2_SRC2.SYM"
|
|
,"A2_DOS33.SYM"
|
|
,"A2_PRODOS.SYM"
|
|
};
|
|
std::string g_sFileNameSymbolsUser;
|
|
|
|
const char * g_aSymbolTableNames[ NUM_SYMBOL_TABLES ] =
|
|
{
|
|
"Main"
|
|
,"Basic"
|
|
,"Asm" // "Assembly",
|
|
,"User1" // User
|
|
,"User2"
|
|
,"Src1"
|
|
,"Src2"
|
|
,"DOS33"
|
|
,"ProDOS"
|
|
};
|
|
|
|
bool g_bSymbolsDisplayMissingFile = true;
|
|
|
|
SymbolTable_t g_aSymbols[ NUM_SYMBOL_TABLES ];
|
|
int g_nSymbolsLoaded = 0; // on Last Load
|
|
|
|
// Utils _ ________________________________________________________________________________________
|
|
|
|
std::string _CmdSymbolsInfoHeader( int iTable, int nDisplaySize = 0 );
|
|
void _PrintCurrentPath();
|
|
Update_t _PrintSymbolInvalidTable();
|
|
|
|
|
|
// Private ________________________________________________________________________________________
|
|
|
|
//===========================================================================
|
|
void _PrintCurrentPath()
|
|
{
|
|
ConsoleDisplayError( g_sProgramDir.c_str() );
|
|
}
|
|
|
|
Update_t _PrintSymbolInvalidTable()
|
|
{
|
|
// TODO: display the user specified file name
|
|
ConsoleBufferPush( "Invalid symbol table." );
|
|
|
|
ConsolePrintFormat( "Only " CHC_NUM_DEC "%d" CHC_DEFAULT " symbol tables are supported:"
|
|
, NUM_SYMBOL_TABLES
|
|
);
|
|
|
|
std::string sText;
|
|
|
|
// Similar to _CmdSymbolsInfoHeader()
|
|
for ( int iTable = 0; iTable < NUM_SYMBOL_TABLES; iTable++ )
|
|
{
|
|
sText += StrFormat( CHC_USAGE "%s" CHC_ARG_SEP "%c "
|
|
, g_aSymbolTableNames[ iTable ]
|
|
, (iTable != (NUM_SYMBOL_TABLES-1))
|
|
? ','
|
|
: '.'
|
|
);
|
|
}
|
|
|
|
// return ConsoleDisplayError( sText.c_str() );
|
|
ConsolePrint( sText.c_str() );
|
|
return ConsoleUpdate();
|
|
}
|
|
|
|
|
|
// Public _________________________________________________________________________________________
|
|
|
|
|
|
//===========================================================================
|
|
std::string const& GetSymbol (WORD nAddress, int nBytes, std::string& sAddressBuf)
|
|
{
|
|
std::string const* pSymbol = FindSymbolFromAddress( nAddress );
|
|
if (pSymbol)
|
|
return *pSymbol;
|
|
|
|
return sAddressBuf = FormatAddress( nAddress, nBytes );
|
|
}
|
|
|
|
//===========================================================================
|
|
int GetSymbolTableFromCommand()
|
|
{
|
|
return (g_iCommand - CMD_SYMBOLS_ROM);
|
|
}
|
|
|
|
// @param iTable_ Which symbol table the symbol is in if any. If none will be NUM_SYMBOL_TABLES
|
|
//===========================================================================
|
|
std::string const* FindSymbolFromAddress (WORD nAddress, int * iTable_ )
|
|
{
|
|
// Bugfix/User feature: User symbols should be searched first
|
|
int iTable = NUM_SYMBOL_TABLES;
|
|
if (iTable_)
|
|
{
|
|
*iTable_ = iTable;
|
|
}
|
|
|
|
while (iTable-- > 0)
|
|
{
|
|
if (! g_aSymbols[iTable].size())
|
|
continue;
|
|
|
|
if (! (g_bDisplaySymbolTables & (1 << iTable)))
|
|
continue;
|
|
|
|
std::map<WORD, std::string>::iterator iSymbols = g_aSymbols[iTable].find(nAddress);
|
|
if (g_aSymbols[iTable].find(nAddress) != g_aSymbols[iTable].end())
|
|
{
|
|
if (iTable_)
|
|
{
|
|
*iTable_ = iTable;
|
|
}
|
|
return &iSymbols->second;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//===========================================================================
|
|
bool FindAddressFromSymbol ( const char* pSymbol, WORD * pAddress_, int * iTable_ )
|
|
{
|
|
// Bugfix/User feature: User symbols should be searched first
|
|
for (int iTable = NUM_SYMBOL_TABLES; iTable-- > 0; )
|
|
{
|
|
if (! g_aSymbols[iTable].size())
|
|
continue;
|
|
|
|
if (! (g_bDisplaySymbolTables & (1 << iTable)))
|
|
continue;
|
|
|
|
SymbolTable_t :: iterator iSymbol = g_aSymbols[iTable].begin();
|
|
while (iSymbol != g_aSymbols[iTable].end())
|
|
{
|
|
if (!_tcsicmp( iSymbol->second.c_str(), pSymbol))
|
|
{
|
|
if (pAddress_)
|
|
{
|
|
*pAddress_ = iSymbol->first;
|
|
}
|
|
if (iTable_)
|
|
{
|
|
*iTable_ = iTable;
|
|
}
|
|
return true;
|
|
}
|
|
iSymbol++;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
// Symbols ________________________________________________________________________________________
|
|
|
|
//===========================================================================
|
|
WORD GetAddressFromSymbol (const char* pSymbol)
|
|
{
|
|
WORD nAddress;
|
|
bool bFoundSymbol = FindAddressFromSymbol( pSymbol, & nAddress );
|
|
if (! bFoundSymbol)
|
|
{
|
|
nAddress = 0;
|
|
}
|
|
return nAddress;
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
bool String2Address( LPCTSTR pText, WORD & nAddress_ )
|
|
{
|
|
TCHAR sHexApple[ CONSOLE_WIDTH ];
|
|
|
|
if (pText[0] == '$')
|
|
{
|
|
if (!TextIsHexString( pText+1))
|
|
return false;
|
|
|
|
_tcscpy( sHexApple, "0x" );
|
|
_tcsncpy( sHexApple+2, pText+1, MAX_SYMBOLS_LEN - 3 );
|
|
sHexApple[2 + (MAX_SYMBOLS_LEN - 3) - 1] = 0;
|
|
pText = sHexApple;
|
|
}
|
|
|
|
if (pText[0] == TEXT('0'))
|
|
{
|
|
if ((pText[1] == TEXT('X')) || pText[1] == TEXT('x'))
|
|
{
|
|
if (!TextIsHexString( pText+2))
|
|
return false;
|
|
|
|
TCHAR *pEnd;
|
|
nAddress_ = (WORD) _tcstol( pText, &pEnd, 16 );
|
|
return true;
|
|
}
|
|
if (TextIsHexString( pText ))
|
|
{
|
|
TCHAR *pEnd;
|
|
nAddress_ = (WORD) _tcstol( pText, &pEnd, 16 );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
Update_t CmdSymbols (int nArgs)
|
|
{
|
|
if (! nArgs)
|
|
return CmdSymbolsInfo( 0 );
|
|
|
|
Update_t iUpdate = _CmdSymbolsUpdate( nArgs, SYMBOL_TABLE_USER_1 );
|
|
if (iUpdate != UPDATE_NOTHING)
|
|
return iUpdate;
|
|
|
|
int bSymbolTables = (1 << NUM_SYMBOL_TABLES) - 1;
|
|
return _CmdSymbolsListTables( nArgs, bSymbolTables );
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdSymbolsClear (int nArgs)
|
|
{
|
|
SymbolTable_Index_e eSymbolTable = SYMBOLS_USER_1;
|
|
_CmdSymbolsClear( eSymbolTable );
|
|
return (UPDATE_DISASM | UPDATE_SYMBOLS);
|
|
}
|
|
|
|
// Format the summary of the specified symbol table
|
|
//===========================================================================
|
|
std::string _CmdSymbolsInfoHeader( int iTable, int nDisplaySize /* = 0 */ )
|
|
{
|
|
// Common case is to use/calc the table size
|
|
bool bActive = (g_bDisplaySymbolTables & (1 << iTable)) ? true : false;
|
|
int nSymbols = nDisplaySize ? nDisplaySize : g_aSymbols[ iTable ].size();
|
|
|
|
// Short Desc: `MAIN`: `1000`
|
|
// // 2.6.2.19 Color for name of symbol table: _CmdPrintSymbol() "SYM HOME" _CmdSymbolsInfoHeader "SYM"
|
|
// CHC_STRING and CHC_NUM_DEC are both cyan, using CHC_USAGE instead of CHC_STRING
|
|
return StrFormat(CHC_USAGE "%s" CHC_ARG_SEP ":%s%d " // CHC_DEFAULT
|
|
, g_aSymbolTableNames[ iTable ]
|
|
, bActive ? CHC_NUM_DEC : CHC_WARNING, nSymbols
|
|
);
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdSymbolsInfo (int nArgs)
|
|
{
|
|
int bDisplaySymbolTables = 0;
|
|
|
|
if (! nArgs)
|
|
{
|
|
// default to all tables
|
|
bDisplaySymbolTables = (1 << NUM_SYMBOL_TABLES) - 1;
|
|
}
|
|
else
|
|
{ // Convert Command Index to parameter
|
|
int iWhichTable = GetSymbolTableFromCommand();
|
|
if ((iWhichTable < 0) || (iWhichTable >= NUM_SYMBOL_TABLES))
|
|
{
|
|
return _PrintSymbolInvalidTable();
|
|
}
|
|
|
|
bDisplaySymbolTables = (1 << iWhichTable);
|
|
}
|
|
|
|
//sprintf( sText, " Symbols Main: %s%d%s User: %s%d%s Source: %s%d%s"
|
|
// "Main:# Basic:# Asm:# User1:# User2:# Src1:# Src2:# Dos:# Prodos:#
|
|
|
|
std::string const sIndent = " ";
|
|
std::string sText = sIndent; // Indent new line
|
|
|
|
for ( int iTable = 0, bTable = 1; bTable <= bDisplaySymbolTables; iTable++, bTable <<= 1 )
|
|
{
|
|
if ( !!(bDisplaySymbolTables & bTable) )
|
|
{
|
|
std::string hdr = _CmdSymbolsInfoHeader( iTable ); // 15 chars per table
|
|
|
|
// 2.8.0.4 BUGFIX: Check for buffer overflow and wrap text
|
|
int nLen = ConsoleColor_StringLength( hdr.c_str() );
|
|
int nDst = ConsoleColor_StringLength( sText.c_str() );
|
|
if ( (nDst + nLen) > CONSOLE_WIDTH )
|
|
{
|
|
ConsolePrint( sText.c_str() );
|
|
sText = sIndent; // Indent new line
|
|
}
|
|
sText += hdr;
|
|
}
|
|
}
|
|
ConsolePrint( sText.c_str() );
|
|
|
|
return ConsoleUpdate();
|
|
}
|
|
|
|
//===========================================================================
|
|
void _CmdPrintSymbol( LPCTSTR pSymbol, WORD nAddress, int iTable )
|
|
{
|
|
// 2.6.2.19 Color for name of symbol table: _CmdPrintSymbol() "SYM HOME" _CmdSymbolsInfoHeader "SYM"
|
|
// CHC_STRING and CHC_NUM_DEC are both cyan, using CHC_USAGE instead of CHC_STRING
|
|
|
|
// 2.6.2.20 Changed: Output of found symbol more table friendly. Symbol table name displayed first.
|
|
ConsolePrintFormat( " %s%s%s: $%s%04X %s%s"
|
|
, CHC_USAGE, g_aSymbolTableNames[ iTable ]
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS, nAddress
|
|
, CHC_SYMBOL, pSymbol );
|
|
|
|
// ConsoleBufferPush( sText );
|
|
}
|
|
|
|
|
|
// Test if bit-mask to index (equal to number of bit-shifs required to reach table)
|
|
//=========================================================================== */
|
|
bool _FindSymbolTable( int bSymbolTables, int iTable )
|
|
{
|
|
// iTable is enumeration
|
|
// bSymbolTables is bit-flags of enabled tables to search
|
|
|
|
if ( bSymbolTables & (1 << iTable) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Convert bit-mask to index
|
|
//=========================================================================== */
|
|
int _GetSymbolTableFromFlag( int bSymbolTables )
|
|
{
|
|
int iTable = 0;
|
|
int bTable = 1;
|
|
|
|
for ( ; bTable <= bSymbolTables; iTable++, bTable <<= 1 )
|
|
{
|
|
if ( bTable & bSymbolTables )
|
|
break;
|
|
}
|
|
|
|
return iTable;
|
|
}
|
|
|
|
|
|
/**
|
|
@param bSymbolTables Bit Flags of which symbol tables to search
|
|
//=========================================================================== */
|
|
bool _CmdSymbolList_Address2Symbol( int nAddress, int bSymbolTables )
|
|
{
|
|
int iTable = 0;
|
|
std::string const* pSymbol = FindSymbolFromAddress( nAddress, &iTable );
|
|
|
|
if (pSymbol)
|
|
{
|
|
if (_FindSymbolTable( bSymbolTables, iTable ))
|
|
{
|
|
_CmdPrintSymbol( pSymbol->c_str(), nAddress, iTable);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//===========================================================================
|
|
bool _CmdSymbolList_Symbol2Address( LPCTSTR pSymbol, int bSymbolTables )
|
|
{
|
|
int iTable;
|
|
WORD nAddress;
|
|
|
|
|
|
bool bFoundSymbol = FindAddressFromSymbol( pSymbol, &nAddress, &iTable );
|
|
if (bFoundSymbol)
|
|
{
|
|
if (_FindSymbolTable( bSymbolTables, iTable ))
|
|
{
|
|
_CmdPrintSymbol( pSymbol, nAddress, iTable );
|
|
}
|
|
}
|
|
return bFoundSymbol;
|
|
}
|
|
|
|
// LIST is normally an implicit "LIST *", but due to the numbers of symbols
|
|
// only look up symbols the user specifies
|
|
//===========================================================================
|
|
Update_t CmdSymbolsList (int nArgs )
|
|
{
|
|
int bSymbolTables = (1 << NUM_SYMBOL_TABLES) - 1; // default to all
|
|
return _CmdSymbolsListTables( nArgs, bSymbolTables );
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
Update_t _CmdSymbolsListTables (int nArgs, int bSymbolTables )
|
|
{
|
|
if (! nArgs)
|
|
{
|
|
return Help_Arg_1( CMD_SYMBOLS_LIST );
|
|
}
|
|
|
|
/*
|
|
Test Cases
|
|
|
|
SYM 0 RESET FA6F $FA59
|
|
$0000 LOC0
|
|
$FA6F RESET
|
|
$FA6F INITAN
|
|
$FA59 OLDBRK
|
|
SYM B
|
|
|
|
SYMBOL B = $2000
|
|
SYM B
|
|
*/
|
|
|
|
for ( int iArgs = 1; iArgs <= nArgs; iArgs++ )
|
|
{
|
|
WORD nAddress = g_aArgs[iArgs].nValue;
|
|
LPCTSTR pSymbol = g_aArgs[iArgs].sArg;
|
|
|
|
// Dump all symbols for this table
|
|
if ( g_aArgRaw[iArgs].eToken == TOKEN_STAR)
|
|
{
|
|
// int iWhichTable = (g_iCommand - CMD_SYMBOLS_MAIN);
|
|
// bDisplaySymbolTables = (1 << iWhichTable);
|
|
|
|
int iTable = 0;
|
|
int bTable = 1;
|
|
for ( ; bTable <= bSymbolTables; iTable++, bTable <<= 1 )
|
|
{
|
|
if ( bTable & bSymbolTables )
|
|
{
|
|
int nSymbols = g_aSymbols[iTable].size();
|
|
if (nSymbols)
|
|
{
|
|
SymbolTable_t :: iterator iSymbol = g_aSymbols[iTable].begin();
|
|
while (iSymbol != g_aSymbols[iTable].end())
|
|
{
|
|
const char *pSymbol = iSymbol->second.c_str();
|
|
unsigned short nAddress = iSymbol->first;
|
|
_CmdPrintSymbol( pSymbol, nAddress, iTable );
|
|
++iSymbol;
|
|
}
|
|
}
|
|
ConsolePrint(_CmdSymbolsInfoHeader(iTable).c_str() );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (nAddress)
|
|
{ // Have address, do symbol lookup first
|
|
if (! _CmdSymbolList_Symbol2Address( pSymbol, bSymbolTables ))
|
|
{
|
|
// nope, ok, try as address
|
|
if (! _CmdSymbolList_Address2Symbol( nAddress, bSymbolTables))
|
|
{
|
|
ConsolePrintFormat( " Address not found: %s$%s%04X%s"
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS, nAddress, CHC_DEFAULT );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // Have symbol, do address lookup
|
|
if (! _CmdSymbolList_Symbol2Address( pSymbol, bSymbolTables ))
|
|
{ // nope, ok, try as address
|
|
if (String2Address( pSymbol, nAddress ))
|
|
{
|
|
if (! _CmdSymbolList_Address2Symbol( nAddress, bSymbolTables ))
|
|
{
|
|
ConsolePrintFormat( " %sSymbol not found: %s%s%s"
|
|
, CHC_ERROR, CHC_SYMBOL, pSymbol, CHC_DEFAULT
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ConsolePrintFormat( " %sSymbol not found: %s%s%s"
|
|
, CHC_ERROR, CHC_SYMBOL, pSymbol, CHC_DEFAULT
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ConsoleUpdate();
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
int ParseSymbolTable(const std::string & pPathFileName, SymbolTable_Index_e eSymbolTableWrite, int nSymbolOffset )
|
|
{
|
|
bool bFileDisplayed = false;
|
|
|
|
const int nMaxLen = std::min<int>(DISASM_DISPLAY_MAX_TARGET_LEN, MAX_SYMBOLS_LEN);
|
|
|
|
int nSymbolsLoaded = 0;
|
|
|
|
if (pPathFileName.empty())
|
|
return nSymbolsLoaded;
|
|
|
|
std::string sFormat1 = StrFormat( "%%x %%%ds", MAX_SYMBOLS_LEN ); // i.e. "%x %13s"
|
|
std::string sFormat2 = StrFormat( "%%%ds %%x", MAX_SYMBOLS_LEN ); // i.e. "%13s %x"
|
|
|
|
FILE *hFile = fopen( pPathFileName.c_str(), "rt" );
|
|
|
|
if ( !hFile && g_bSymbolsDisplayMissingFile )
|
|
{
|
|
// TODO: print filename! Bug #242 Help file (.chm) description for "Symbols" #242
|
|
ConsoleDisplayError( "Symbol File not found:" );
|
|
_PrintCurrentPath();
|
|
nSymbolsLoaded = -1; // HACK: ERROR: FILE NOT EXIST
|
|
}
|
|
|
|
bool bDupSymbolHeader = false;
|
|
if ( hFile )
|
|
{
|
|
while ( !feof(hFile) )
|
|
{
|
|
// Support 2 types of symbols files:
|
|
// 1) AppleWin:
|
|
// . 0000 SYMBOL
|
|
// . FFFF SYMBOL
|
|
// 2) ACME:
|
|
// . SYMBOL =$0000; Comment
|
|
// . SYMBOL =$FFFF; Comment
|
|
//
|
|
DWORD nAddress = _6502_MEM_END + 1; // default to invalid address
|
|
char sName[ MAX_SYMBOLS_LEN+1 ] = "";
|
|
|
|
const int MAX_LINE = 256;
|
|
char szLine[ MAX_LINE ] = "";
|
|
|
|
if ( !fgets(szLine, MAX_LINE-1, hFile) ) // Get next line
|
|
{
|
|
//ConsolePrint("<<EOF");
|
|
break;
|
|
}
|
|
|
|
if (strstr(szLine, "$") == NULL)
|
|
{
|
|
sscanf(szLine, sFormat1.c_str(), &nAddress, sName);
|
|
}
|
|
else
|
|
{
|
|
char* p = strstr(szLine, "="); // Optional
|
|
if (p) *p = ' ';
|
|
p = strstr(szLine, "$");
|
|
if (p) *p = ' ';
|
|
p = strstr(szLine, ";"); // Optional
|
|
if (p) *p = 0;
|
|
p = strstr(szLine, " "); // 1st space between name & value
|
|
if (p)
|
|
{
|
|
int nLen = p - szLine;
|
|
if (nLen > MAX_SYMBOLS_LEN)
|
|
{
|
|
memset(&szLine[MAX_SYMBOLS_LEN], ' ', nLen - MAX_SYMBOLS_LEN); // sscanf fails for nAddress if string too long
|
|
}
|
|
}
|
|
sscanf(szLine, sFormat2.c_str(), sName, &nAddress);
|
|
}
|
|
|
|
// SymbolOffset
|
|
nAddress += nSymbolOffset;
|
|
|
|
if ( (nAddress > _6502_MEM_END) || (sName[0] == 0) )
|
|
continue;
|
|
|
|
// 2.9.0.11 Bug #479
|
|
int nLen = strlen( sName );
|
|
if (nLen > nMaxLen)
|
|
{
|
|
ConsolePrintFormat( " %sWarn.: %s%s %s(%s%d %s> %s%d%s)"
|
|
, CHC_WARNING
|
|
, CHC_SYMBOL
|
|
, sName
|
|
, CHC_ARG_SEP
|
|
, CHC_NUM_DEC
|
|
, nLen
|
|
, CHC_ARG_SEP
|
|
, CHC_NUM_DEC
|
|
, nMaxLen
|
|
, CHC_ARG_SEP
|
|
);
|
|
ConsoleUpdate(); // Flush buffered output so we don't ask the user to pause
|
|
}
|
|
|
|
int iTable = 0;
|
|
|
|
// 2.8.0.5 Bug #244 (Debugger) Duplicate symbols for identical memory addresses in APPLE2E.SYM
|
|
std::string const* pSymbolPrev = FindSymbolFromAddress( (WORD)nAddress, &iTable ); // don't care which table it is in
|
|
if ( pSymbolPrev )
|
|
{
|
|
if ( !bFileDisplayed )
|
|
{
|
|
bFileDisplayed = true;
|
|
|
|
// TODO: Must check for buffer overflow !
|
|
ConsolePrintFormat( "%s%s"
|
|
, CHC_PATH
|
|
, pPathFileName.c_str()
|
|
);
|
|
}
|
|
|
|
ConsolePrintFormat( " %sInfo.: %s%-16s %saliases %s$%s%04X %s%-12s%s (%s%s%s)" // MAGIC NUMBER: -MAX_SYMBOLS_LEN
|
|
, CHC_INFO // 2.9.0.10 was CHC_WARNING, see #479
|
|
, CHC_SYMBOL
|
|
, sName
|
|
, CHC_INFO
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS
|
|
, nAddress
|
|
, CHC_SYMBOL
|
|
, pSymbolPrev->c_str()
|
|
, CHC_DEFAULT
|
|
, CHC_STRING
|
|
, g_aSymbolTableNames[ iTable ]
|
|
, CHC_DEFAULT
|
|
);
|
|
|
|
ConsoleUpdate(); // Flush buffered output so we don't ask the user to pause
|
|
/*
|
|
ConsolePrintFormat( " %sWarning: %sAddress already has symbol Name%s (%s%s%s): %s%s"
|
|
, CHC_WARNING
|
|
, CHC_INFO
|
|
, CHC_ARG_SEP
|
|
, CHC_STRING
|
|
, g_aSymbolTableNames[ iTable ]
|
|
, CHC_DEFAULT
|
|
, CHC_SYMBOL
|
|
, pSymbolPrev
|
|
);
|
|
|
|
ConsolePrintFormat( " %s$%s%04X %s%-31s%s"
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS
|
|
, nAddress
|
|
, CHC_SYMBOL
|
|
, sName
|
|
, CHC_DEFAULT
|
|
);
|
|
*/
|
|
}
|
|
|
|
// If updating symbol, print duplicate symbols
|
|
WORD nAddressPrev = 0;
|
|
|
|
bool bExists = FindAddressFromSymbol( sName, &nAddressPrev, &iTable );
|
|
if ( bExists )
|
|
{
|
|
if ( !bDupSymbolHeader )
|
|
{
|
|
bDupSymbolHeader = true;
|
|
ConsolePrintFormat( " %sDup Symbol Name%s (%s%s%s) %s"
|
|
, CHC_ERROR
|
|
, CHC_DEFAULT
|
|
, CHC_STRING
|
|
, g_aSymbolTableNames[ iTable ]
|
|
, CHC_DEFAULT
|
|
, pPathFileName.c_str()
|
|
);
|
|
}
|
|
|
|
ConsolePrintFormat( " %s$%s%04X %s%-31s%s"
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS
|
|
, nAddress
|
|
, CHC_SYMBOL
|
|
, sName
|
|
, CHC_DEFAULT
|
|
);
|
|
}
|
|
|
|
// else // It is not a bug to have duplicate addresses by different names
|
|
|
|
g_aSymbols[ eSymbolTableWrite ] [ (WORD) nAddress ] = sName;
|
|
nSymbolsLoaded++; // TODO: FIXME: BUG: This is the total symbols read, not added
|
|
}
|
|
fclose(hFile);
|
|
}
|
|
|
|
return nSymbolsLoaded;
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdSymbolsLoad (int nArgs)
|
|
{
|
|
std::string sFileName = g_sProgramDir;
|
|
|
|
int iSymbolTable = GetSymbolTableFromCommand();
|
|
if ((iSymbolTable < 0) || (iSymbolTable >= NUM_SYMBOL_TABLES))
|
|
{
|
|
return _PrintSymbolInvalidTable();
|
|
}
|
|
|
|
int nSymbols = 0;
|
|
|
|
// Debugger will call us with 0 args on startup as a way to pre-load symbol tables
|
|
if (! nArgs)
|
|
{
|
|
sFileName += g_sFileNameSymbols[ iSymbolTable ];
|
|
nSymbols = ParseSymbolTable( sFileName, (SymbolTable_Index_e) iSymbolTable );
|
|
}
|
|
|
|
int iArg = 1;
|
|
if (iArg <= nArgs)
|
|
{
|
|
std::string pFileName;
|
|
|
|
if ( g_aArgs[ iArg ].bType & TYPE_QUOTED_2 )
|
|
{
|
|
pFileName = g_aArgs[ iArg ].sArg;
|
|
|
|
sFileName = g_sProgramDir + pFileName;
|
|
|
|
// Remember File Name of last symbols loaded
|
|
g_sFileNameSymbolsUser = pFileName;
|
|
}
|
|
|
|
// SymbolOffset
|
|
// sym load "filename" [,symbol_offset]
|
|
unsigned int nOffsetAddr = 0;
|
|
|
|
iArg++;
|
|
if ( iArg <= nArgs)
|
|
{
|
|
if (g_aArgs[ iArg ].eToken == TOKEN_COMMA)
|
|
{
|
|
iArg++;
|
|
if ( iArg <= nArgs )
|
|
{
|
|
nOffsetAddr = g_aArgs[ iArg ].nValue;
|
|
if ( (nOffsetAddr < _6502_MEM_BEGIN) || (nOffsetAddr > _6502_MEM_END) )
|
|
{
|
|
nOffsetAddr = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !pFileName.empty() )
|
|
{
|
|
nSymbols = ParseSymbolTable( sFileName, (SymbolTable_Index_e) iSymbolTable, nOffsetAddr );
|
|
}
|
|
}
|
|
|
|
if ( nSymbols > 0 )
|
|
{
|
|
g_nSymbolsLoaded = nSymbols;
|
|
}
|
|
|
|
Update_t bUpdateDisplay = UPDATE_DISASM;
|
|
bUpdateDisplay |= (nSymbols > 0) ? UPDATE_SYMBOLS : 0;
|
|
|
|
return bUpdateDisplay;
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t _CmdSymbolsClear( SymbolTable_Index_e eSymbolTable )
|
|
{
|
|
g_aSymbols[ eSymbolTable ].clear();
|
|
|
|
return UPDATE_SYMBOLS;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
void SymbolUpdate( SymbolTable_Index_e eSymbolTable, const char *pSymbolName, WORD nAddress, bool bRemoveSymbol, bool bUpdateSymbol )
|
|
{
|
|
if (bRemoveSymbol)
|
|
pSymbolName = g_aArgs[2].sArg;
|
|
|
|
if (_tcslen( pSymbolName ) < MAX_SYMBOLS_LEN)
|
|
{
|
|
WORD nAddressPrev;
|
|
int iTable;
|
|
bool bExists = FindAddressFromSymbol( pSymbolName, &nAddressPrev, &iTable );
|
|
|
|
if (bExists)
|
|
{
|
|
if (iTable == eSymbolTable)
|
|
{
|
|
if (bRemoveSymbol)
|
|
{
|
|
ConsoleBufferPush( TEXT(" Removing symbol." ) );
|
|
}
|
|
|
|
g_aSymbols[ eSymbolTable ].erase( nAddressPrev );
|
|
|
|
if (bUpdateSymbol)
|
|
{
|
|
ConsolePrintFormat( " Updating %s%s%s from %s$%s%04X%s to %s$%s%04X%s"
|
|
, CHC_SYMBOL, pSymbolName, CHC_DEFAULT
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS, nAddressPrev, CHC_DEFAULT
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS, nAddress, CHC_DEFAULT
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bRemoveSymbol)
|
|
{
|
|
ConsoleBufferPush( TEXT(" Symbol not in table." ) );
|
|
}
|
|
}
|
|
|
|
if (bUpdateSymbol)
|
|
{
|
|
#if _DEBUG
|
|
std::string const* pSymbol = FindSymbolFromAddress( nAddress, &iTable );
|
|
{
|
|
// Found another symbol for this address. Harmless.
|
|
// TODO: Probably should check if same name?
|
|
}
|
|
#endif
|
|
g_aSymbols[ eSymbolTable ][ nAddress ] = pSymbolName;
|
|
|
|
// Tell user symbol was added
|
|
ConsolePrintFormat( " Added symbol: %s%s%s %s$%s%04X%s"
|
|
, CHC_SYMBOL, pSymbolName, CHC_DEFAULT
|
|
, CHC_ARG_SEP
|
|
, CHC_ADDRESS, nAddress, CHC_DEFAULT
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Syntax:
|
|
// sym ! <symbol>
|
|
// sym ~ <symbol>
|
|
// sym <symbol> =
|
|
// sym @ = <addr>
|
|
// NOTE: Listing of the symbols is handled via returning UPDATE_NOTHING which is triggered by:
|
|
// sym *
|
|
//===========================================================================
|
|
Update_t _CmdSymbolsUpdate( int nArgs, int bSymbolTables )
|
|
{
|
|
bool bRemoveSymbol = false;
|
|
bool bUpdateSymbol = false;
|
|
|
|
TCHAR *pSymbolName = g_aArgs[1].sArg;
|
|
WORD nAddress = g_aArgs[3].nValue;
|
|
|
|
if ((nArgs == 2)
|
|
&& ((g_aArgs[ 1 ].eToken == TOKEN_EXCLAMATION) || (g_aArgs[1].eToken == TOKEN_TILDE)) )
|
|
bRemoveSymbol = true;
|
|
|
|
if ((nArgs == 3) && (g_aArgs[ 2 ].eToken == TOKEN_EQUAL ))
|
|
bUpdateSymbol = true;
|
|
|
|
// 2.9.1.7 Added: QoL for automatic symbol names
|
|
if ((nArgs == 2)
|
|
&& (g_aArgRaw[ 1 ].eToken == TOKEN_AT ) // NOTE: @ is parsed and evaluated and NOT in the cooked args
|
|
&& (g_aArgs [ 1 ].eToken == TOKEN_EQUAL))
|
|
{
|
|
if (bSymbolTables == SYMBOL_TABLE_USER_1)
|
|
bSymbolTables = SYMBOL_TABLE_USER_2; // Autogenerated symbol names go in table 2 for organization when reverse engineering. Table 1 = known, Table 2 = unknown.
|
|
|
|
nAddress = g_aArgs[2].nValue;
|
|
strncpy_s( g_aArgs[1].sArg, StrFormat("_%04X", nAddress).c_str(), _TRUNCATE ); // Autogenerated symbol name
|
|
|
|
bUpdateSymbol = true;
|
|
}
|
|
|
|
if (bRemoveSymbol || bUpdateSymbol)
|
|
{
|
|
int iTable = _GetSymbolTableFromFlag( bSymbolTables );
|
|
SymbolUpdate( (SymbolTable_Index_e) iTable, pSymbolName, nAddress, bRemoveSymbol, bUpdateSymbol );
|
|
return ConsoleUpdate();
|
|
}
|
|
|
|
return UPDATE_NOTHING;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
Update_t _CmdSymbolsCommon ( int nArgs, int bSymbolTables )
|
|
{
|
|
if (! nArgs)
|
|
{
|
|
return Help_Arg_1( g_iCommand );
|
|
}
|
|
|
|
Update_t iUpdate = _CmdSymbolsUpdate( nArgs, bSymbolTables );
|
|
if (iUpdate != UPDATE_NOTHING)
|
|
return iUpdate;
|
|
|
|
int iArg = 0;
|
|
while (iArg++ <= nArgs)
|
|
{
|
|
int iParam;
|
|
int nParams = FindParam( g_aArgs[iArg].sArg, MATCH_EXACT, iParam ); // MATCH_FUZZY
|
|
if (nParams)
|
|
{
|
|
if (iParam == PARAM_CLEAR)
|
|
{
|
|
int iTable = _GetSymbolTableFromFlag( bSymbolTables );
|
|
if (iTable != NUM_SYMBOL_TABLES)
|
|
{
|
|
Update_t iUpdate = _CmdSymbolsClear( (SymbolTable_Index_e) iTable );
|
|
ConsolePrintFormat( " Cleared symbol table: %s%s"
|
|
, CHC_STRING, g_aSymbolTableNames[ iTable ]
|
|
);
|
|
iUpdate |= ConsoleUpdate();
|
|
return iUpdate;
|
|
}
|
|
else
|
|
{
|
|
// Shouldn't have multiple symbol tables selected
|
|
// nArgs = _Arg_1( eSymbolsTable );
|
|
ConsoleBufferPush( TEXT(" Error: Unknown Symbol Table Type") );
|
|
return ConsoleUpdate();
|
|
}
|
|
}
|
|
else
|
|
if (iParam == PARAM_LOAD)
|
|
{
|
|
nArgs = _Arg_Shift( iArg, nArgs);
|
|
Update_t bUpdate = CmdSymbolsLoad( nArgs );
|
|
|
|
int iTable = _GetSymbolTableFromFlag( bSymbolTables );
|
|
if (iTable != NUM_SYMBOL_TABLES)
|
|
{
|
|
if ( bUpdate & UPDATE_SYMBOLS )
|
|
{
|
|
ConsolePrint( _CmdSymbolsInfoHeader( iTable, g_nSymbolsLoaded ).c_str() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ConsoleBufferPush( TEXT(" Error: Unknown Symbol Table Type") );
|
|
}
|
|
return ConsoleUpdate();
|
|
}
|
|
else
|
|
if (iParam == PARAM_SAVE)
|
|
{
|
|
nArgs = _Arg_Shift( iArg, nArgs);
|
|
return CmdSymbolsSave( nArgs );
|
|
}
|
|
else
|
|
if (iParam == PARAM_ON)
|
|
{
|
|
g_bDisplaySymbolTables |= bSymbolTables;
|
|
int iTable = _GetSymbolTableFromFlag( bSymbolTables );
|
|
if (iTable != NUM_SYMBOL_TABLES)
|
|
{
|
|
ConsolePrint( _CmdSymbolsInfoHeader( iTable ).c_str() );
|
|
}
|
|
return ConsoleUpdate() | UPDATE_DISASM;
|
|
}
|
|
else
|
|
if (iParam == PARAM_OFF)
|
|
{
|
|
g_bDisplaySymbolTables &= ~bSymbolTables;
|
|
int iTable = _GetSymbolTableFromFlag( bSymbolTables );
|
|
if (iTable != NUM_SYMBOL_TABLES)
|
|
{
|
|
ConsolePrint( _CmdSymbolsInfoHeader( iTable ).c_str() );
|
|
}
|
|
return ConsoleUpdate() | UPDATE_DISASM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return _CmdSymbolsListTables( nArgs, bSymbolTables );
|
|
}
|
|
|
|
}
|
|
|
|
return ConsoleUpdate();
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdSymbolsCommand (int nArgs)
|
|
{
|
|
if (! nArgs)
|
|
{
|
|
return CmdSymbolsInfo( 1 );
|
|
}
|
|
|
|
int bSymbolTable = SYMBOL_TABLE_MAIN << GetSymbolTableFromCommand();
|
|
return _CmdSymbolsCommon( nArgs, bSymbolTable ); // BUGFIX 2.6.2.12 Hard-coded to SYMMAIN
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdSymbolsSave (int nArgs)
|
|
{
|
|
return UPDATE_CONSOLE_DISPLAY;
|
|
}
|