// ld65dbg.cpp #include #include #include #include #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( ::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 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; } //--------------------------------------------------------------------------------------------------- }