/* 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::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(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("< 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_sProgramDir + g_sFileNameSymbols[ iSymbolTable ]; nSymbols = ParseSymbolTable( sFileName, (SymbolTable_Index_e) iSymbolTable ); // Try optional alternate location if ((nSymbols == 0) && !g_sBuiltinSymbolsDir.empty()) { sFileName = g_sBuiltinSymbolsDir + 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; // 2.9.1.26: When adding symbols list the address first then the name for readability // Tell user symbol was added ConsolePrintFormat( /*CHC_DEFAULT*/ " Added: " CHC_ARG_SEP "$" CHC_ADDRESS "%04X" CHC_DEFAULT " " CHC_SYMBOL "%s" , nAddress , pSymbolName ); } } } // Syntax: // sym ! // sym ~ // sym = // sym @ = // 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; }