fceux/src/ld65dbg.cpp

421 lines
9.1 KiB
C++

// ld65dbg.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "types.h"
#include "ld65dbg.h"
#include "utils/StringUtils.h"
namespace ld65
{
//---------------------------------------------------------------------------------------------------
segment::segment( int id, const char *name, int startAddr, int size, int ofs, unsigned char type )
: _name(name ? name : ""), _id(id), _startAddr(startAddr), _size(size), _ofs(ofs), _type(type)
{
}
//---------------------------------------------------------------------------------------------------
scope::scope(int id, const char *name, int size, int parentID)
: _name(name ? name : ""), _id(id), _parentID(parentID), _size(size), _parent(nullptr)
{
}
//---------------------------------------------------------------------------------------------------
void scope::getFullName(std::string &out)
{
if ( _parent )
{
_parent->getFullName(out);
}
if (!_name.empty())
{
out.append(_name);
out.append("::");
}
}
//---------------------------------------------------------------------------------------------------
sym::sym(int id, const char *name, int size, int value, int type)
: _name(name ? name : ""), _id(id), _size(size), _value(value), _type(type), _scope(nullptr), _segment(nullptr)
{
}
//---------------------------------------------------------------------------------------------------
database::database(void)
{
}
//---------------------------------------------------------------------------------------------------
database::~database(void)
{
for (auto itSym = symMap.begin(); itSym != symMap.end(); itSym++)
{
delete itSym->second;
}
for (auto itScope = scopeMap.begin(); itScope != scopeMap.end(); itScope++)
{
delete itScope->second;
}
for (auto itSeg = segmentMap.begin(); itSeg != segmentMap.end(); itSeg++)
{
delete itSeg->second;
}
}
//---------------------------------------------------------------------------------------------------
database::dbgLine::dbgLine(size_t bufferSize)
{
buf = NULL;
bufSize = 0;
readPtr = 0;
allocBuffer( bufferSize );
}
//---------------------------------------------------------------------------------------------------
database::dbgLine::~dbgLine(void)
{
if (buf)
{
::free(buf); buf = NULL;
}
bufSize = 0;
readPtr = 0;
}
//---------------------------------------------------------------------------------------------------
void database::dbgLine::allocBuffer(size_t bufferSize)
{
if (buf)
{
::free(buf); buf = NULL;
}
bufSize = 0;
readPtr = 0;
buf = static_cast<char*>( ::malloc( bufferSize ) );
if (buf == NULL)
{
bufSize = 0;
}
else
{
buf[0] = 0;
bufSize = bufferSize;
}
readPtr = 0;
}
//---------------------------------------------------------------------------------------------------
const char *database::dbgLine::readFromFile( FILE *fp )
{
readPtr = 0;
return fgets(buf, bufSize, fp);
}
//---------------------------------------------------------------------------------------------------
int database::dbgLine::readToken( char *tk, size_t tkSize )
{
int charsRead = 0;
size_t i,j;
i=readPtr; j=0;
if ( buf[i] != 0 )
{
while (isspace(buf[i])) i++;
if ( isalpha(buf[i]) || (buf[i] == '_') )
{
while ( isalnum(buf[i]) || (buf[i] == '_') )
{
if (j < tkSize)
{
tk[j] = buf[i]; j++;
}
i++;
}
}
else if (buf[i] != 0)
{
if (j < tkSize)
{
tk[j] = buf[i]; j++;
}
i++;
}
}
charsRead = j;
readPtr = i;
if (j < tkSize)
{
tk[j] = 0;
}
else
{
tk[tkSize-1] = 0;
}
return charsRead;
}
//---------------------------------------------------------------------------------------------------
int database::dbgLine::readKeyValuePair( char *keyValueBuffer, size_t keyValueBufferSize )
{
int charsRead = 0;
size_t i,j;
bool isStringLiteral = false;
i=readPtr; j=0;
if ( buf[i] != 0 )
{
while (isspace(buf[i])) i++;
if ( isalpha(buf[i]) || (buf[i] == '_') )
{
while ( isalnum(buf[i]) || (buf[i] == '_') )
{
if (j < keyValueBufferSize)
{
keyValueBuffer[j] = buf[i]; j++;
}
i++;
}
}
else if (buf[i] != 0)
{
if (j < keyValueBufferSize)
{
keyValueBuffer[j] = buf[i]; j++;
}
i++;
}
while (isspace(buf[i])) i++;
}
if ( buf[i] == '=' )
{
if (j < keyValueBufferSize)
{
keyValueBuffer[j] = buf[i]; j++;
}
i++;
while (isspace(buf[i])) i++;
while ( buf[i] != 0 )
{
if ( !isStringLiteral && buf[i] == ',' )
{
break;
}
else if ( buf[i] == '\"' )
{
isStringLiteral = !isStringLiteral;
}
else
{
if (j < keyValueBufferSize)
{
if (!isspace(buf[i]))
{
keyValueBuffer[j] = buf[i]; j++;
}
}
}
i++;
}
if (buf[i] == ',')
{
i++;
}
}
charsRead = j;
readPtr = i;
if (j < keyValueBufferSize)
{
keyValueBuffer[j] = 0;
}
else
{
keyValueBuffer[keyValueBufferSize-1] = 0;
}
return charsRead;
}
//---------------------------------------------------------------------------------------------------
int database::dbgLine::splitKeyValuePair( char *keyValueBuffer, char **keyPtr, char **valuePtr )
{
size_t i=0;
if (keyPtr != nullptr)
{
*keyPtr = keyValueBuffer;
}
while (keyValueBuffer[i] != 0)
{
if (keyValueBuffer[i] == '=')
{
keyValueBuffer[i] = 0; i++; break;
}
i++;
}
if (valuePtr != nullptr)
{
*valuePtr = &keyValueBuffer[i];
}
return 0;
}
//---------------------------------------------------------------------------------------------------
int database::dbgFileLoad( const char *dbgFilePath )
{
static constexpr size_t lineSize = 4096;
FILE *fp;
dbgLine line( lineSize );
char lineType[64];
fceuScopedPtr <char> keyValueBuffer( new char[ lineSize ], FCEU_ALLOC_TYPE_NEW_ARRAY );
fp = ::fopen( dbgFilePath, "r");
if (fp == NULL)
{
return -1;
}
while ( line.readFromFile(fp) != NULL )
{
//printf("%s", line.getLine());
if ( line.readToken( lineType, sizeof(lineType) ) )
{
int id = -1, size = 0, startAddr = 0, ofs = -1, parentID = -1, scopeID = -1, segmentID = -1;
int value = 0;
unsigned char segType = segment::READ;
char name[256];
char type[32];
name[0] = 0;
type[0] = 0;
while ( line.readKeyValuePair( keyValueBuffer.get(), lineSize) )
{
char *key, *val;
line.splitKeyValuePair( keyValueBuffer.get(), &key, &val );
//printf(" Key '%s' -> Value '%s' \n", key, val );
if ( strcmp( key, "id") == 0 )
{
id = strtol( val, nullptr, 0 );
}
else if ( strcmp( key, "name") == 0 )
{
Strlcpy( name, val, sizeof(name));
}
else if ( strcmp( key, "size") == 0 )
{
size = strtol( val, nullptr, 0 );
}
else if ( strcmp( key, "val") == 0 )
{
value = strtol( val, nullptr, 0 );
}
else if ( strcmp( key, "scope") == 0 )
{
scopeID = strtol( val, nullptr, 0 );
}
else if ( strcmp( key, "parent") == 0 )
{
parentID = strtol( val, nullptr, 0 );
}
else if ( strcmp( key, "seg") == 0 )
{
segmentID = strtol( val, nullptr, 0 );
}
else if ( strcmp( key, "ooffs") == 0 )
{
ofs = strtol( val, nullptr, 0 );
}
else if ( strcmp( key, "type") == 0 )
{
Strlcpy( type, val, sizeof(type));
}
}
if ( strcmp( lineType, "seg" ) == 0 )
{
if ( id >= 0 )
{
segment *s = new segment( id, name, startAddr, size, ofs, segType );
segmentMap[id] = s;
}
}
else if ( strcmp( lineType, "scope" ) == 0 )
{
if ( id >= 0 )
{
scope *s = new scope( id, name, size, parentID );
scopeMap[id] = s;
auto it = scopeMap.find( parentID );
if ( it != scopeMap.end() )
{
//printf("Found Parent:%i for %i\n", parentID, id );
s->_parent = it->second;
}
}
}
else if ( strcmp( lineType, "sym") == 0 )
{
if ( id >= 0 )
{
int symType = sym::IMPORT;
if ( strcmp( type, "lab") == 0)
{
symType = sym::LABEL;
}
else if ( strcmp( type, "equ") == 0)
{
symType = sym::EQU;
}
sym *s = new sym( id, name, size, value, symType );
auto it = scopeMap.find( scopeID );
if ( it != scopeMap.end() )
{
//printf("Found Scope:%i for %s\n", scopeID, name );
s->_scope = it->second;
}
auto itSeg = segmentMap.find( segmentID );
if ( itSeg != segmentMap.end() )
{
//printf("Found Segment:%i for %s\n", segmentID, name );
s->_segment = itSeg->second;
}
symMap[id] = s;
}
}
}
}
::fclose(fp);
return 0;
}
//---------------------------------------------------------------------------------------------------
int database::iterateSymbols( void *userData, void (*cb)( void *userData, sym *s ) )
{
int numSyms = 0;
for (auto it = symMap.begin(); it != symMap.end(); it++)
{
cb( userData, it->second );
numSyms++;
}
return numSyms;
}
//---------------------------------------------------------------------------------------------------
}