You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
8.1 KiB
362 lines
8.1 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program 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 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program 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 this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
#include "HeadSpin.h" |
|
#include "pfMapFile.h" |
|
#include "pfMapFileEntry.h" |
|
#include "pfTextFile.h" |
|
#include "pfArray.h" |
|
#include <algorithm> |
|
#include <string.h> |
|
#include <ctype.h> |
|
#ifdef WIN32 |
|
#include <windows.h> |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
namespace dev |
|
{ |
|
|
|
|
|
class MapFile::MapFileImpl |
|
{ |
|
public: |
|
long loadAddr; |
|
char name[256]; |
|
Array<MapFileEntry> segments; |
|
Array<MapFileEntry> entries; |
|
|
|
MapFileImpl( const char* filename ) : |
|
loadAddr(0), m_file( filename ), m_err( MapFile::ERROR_NONE ) |
|
{ |
|
m_file.readString( name, sizeof(name) ); |
|
|
|
char buf[1024]; |
|
while ( m_file.readString(buf,sizeof(buf)) ) |
|
{ |
|
if ( !strcmp("Preferred",buf) ) |
|
parseLoadAddress(); |
|
else if ( !strcmp("Start",buf) ) |
|
parseSegments(); |
|
else if ( !strcmp("Address",buf) ) |
|
parseEntries(); |
|
else |
|
m_file.skipLine(); |
|
} |
|
|
|
std::sort( segments.begin(), segments.end() ); |
|
std::sort( entries.begin(), entries.end() ); |
|
} |
|
|
|
~MapFileImpl() |
|
{ |
|
} |
|
|
|
ErrorType error() const |
|
{ |
|
if ( m_err != MapFile::ERROR_NONE ) |
|
return m_err; |
|
|
|
switch ( m_file.error() ) |
|
{ |
|
case TextFile::ERROR_OPEN: return MapFile::ERROR_OPEN; |
|
case TextFile::ERROR_READ: return MapFile::ERROR_READ; |
|
case TextFile::ERROR_PARSE: return MapFile::ERROR_PARSE; |
|
default: return MapFile::ERROR_NONE; |
|
} |
|
} |
|
|
|
int line() const |
|
{ |
|
if ( m_err != MapFile::ERROR_NONE ) |
|
return m_errLine; |
|
|
|
return m_file.line(); |
|
} |
|
|
|
private: |
|
TextFile m_file; |
|
MapFile::ErrorType m_err; |
|
int m_errLine; |
|
|
|
/** |
|
* Returns true if the next line is empty. |
|
*/ |
|
bool nextLineEmpty() |
|
{ |
|
m_file.skipLine(); |
|
char ch; |
|
while ( m_file.peekChar(&ch) && isspace(ch) && ch != '\n' ) |
|
m_file.readChar( &ch ); |
|
if ( m_file.peekChar(&ch) && ch == '\n' ) |
|
return true; |
|
return false; |
|
} |
|
|
|
/** |
|
* Parses specified string. |
|
* Sets error if parsed string doesnt match. |
|
*/ |
|
void parse( const char* str ) |
|
{ |
|
char buf[256]; |
|
m_file.readString( buf, sizeof(buf) ); |
|
if ( strcmp(str,buf) ) |
|
{ |
|
m_err = MapFile::ERROR_PARSE; |
|
m_errLine = m_file.line(); |
|
} |
|
} |
|
|
|
/** |
|
* Parses specified character. |
|
* Sets error if parsed character doesnt match. |
|
*/ |
|
void parse( char ch ) |
|
{ |
|
char ch2; |
|
if ( !m_file.readChar(&ch2) || ch2 != ch ) |
|
{ |
|
m_err = MapFile::ERROR_PARSE; |
|
m_errLine = m_file.line(); |
|
} |
|
} |
|
|
|
/** |
|
* Example: |
|
* (Preferred) load address is 00400000 |
|
*/ |
|
void parseLoadAddress() |
|
{ |
|
parse( "load" ); parse( "address" ); parse( "is" ); |
|
loadAddr = m_file.readHex(); |
|
} |
|
|
|
/** |
|
* Example: |
|
* (Start) Length Name Class |
|
* 0001:00000000 00002c05H .text CODE |
|
*/ |
|
void parseSegments() |
|
{ |
|
parse( "Length" ); |
|
parse( "Name" ); |
|
parse( "Class" ); |
|
m_file.skipWhitespace(); |
|
|
|
while ( !error() ) |
|
{ |
|
int seg = m_file.readHex(); |
|
parse( ':' ); |
|
int offs = m_file.readHex(); |
|
int len = m_file.readHex(); |
|
parse( 'H' ); |
|
char buf[256]; |
|
m_file.readString( buf, sizeof(buf) ); |
|
segments.add( MapFileEntry(seg,offs,len,buf) ); |
|
|
|
// break at empty line |
|
if ( nextLineEmpty() ) |
|
break; |
|
} |
|
} |
|
|
|
/** |
|
* Example: |
|
* (Address) Publics by Value Rva+Base Lib:Object |
|
* 0001:000001a0 ?stackTrace@@YAXXZ 004011a0 f main.obj |
|
*/ |
|
void parseEntries() |
|
{ |
|
parse( "Publics" ); parse( "by" ); parse( "Value" ); |
|
parse( "Rva+Base" ); |
|
parse( "Lib:Object" ); |
|
m_file.skipWhitespace(); |
|
|
|
while ( !error() ) |
|
{ |
|
int seg = m_file.readHex(); |
|
parse( ':' ); |
|
int offs = m_file.readHex(); |
|
char buf[256]; |
|
m_file.readString( buf, sizeof(buf) ); |
|
char* entryname = buf; |
|
|
|
// chop entry name at @@ |
|
char* end = strstr( entryname, "@@" ); |
|
if ( end ) |
|
*end = 0; |
|
// skip preceding ?01.. |
|
while ( isdigit(*entryname) || *entryname == '?' || *entryname == '$' ) |
|
++entryname; |
|
// conv @ -> . |
|
for ( char* str = entryname ; *str ; ++str ) |
|
if ( *str == '@' ) |
|
*str = '.'; |
|
|
|
// Added 9.5.02 mcn - Reverse the order of the symbols to be more natural |
|
if( strlen( entryname ) < 512 ) |
|
{ |
|
static char newName[ 512 ]; |
|
char *search; |
|
newName[ 0 ] = 0; |
|
while( ( search = strrchr( entryname, '.' ) ) != 0 ) |
|
{ |
|
*search = 0; |
|
if( newName[ 0 ] != 0 ) |
|
strcat( newName, "::" ); |
|
strcat( newName, search + 1 ); |
|
} |
|
if( newName[ 0 ] != 0 ) |
|
strcat( newName, "::" ); |
|
strcat( newName, entryname ); |
|
|
|
entryname = newName; |
|
} |
|
|
|
|
|
entries.add( MapFileEntry(seg,offs,0,entryname) ); |
|
|
|
// break at empty line |
|
if ( nextLineEmpty() ) |
|
break; |
|
} |
|
} |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
MapFile::MapFile( const char* filename ) |
|
{ |
|
m_this = TRACKED_NEW MapFileImpl( filename ); |
|
} |
|
|
|
MapFile::~MapFile() |
|
{ |
|
delete m_this; |
|
} |
|
|
|
long MapFile::loadAddress() const |
|
{ |
|
return m_this->loadAddr; |
|
} |
|
|
|
const MapFileEntry& MapFile::getSegment( int i ) const |
|
{ |
|
return m_this->segments[i]; |
|
} |
|
|
|
const MapFileEntry& MapFile::getEntry( int i ) const |
|
{ |
|
return m_this->entries[i]; |
|
} |
|
|
|
int MapFile::segments() const |
|
{ |
|
return m_this->segments.size(); |
|
} |
|
|
|
int MapFile::entries() const |
|
{ |
|
return m_this->entries.size(); |
|
} |
|
|
|
MapFile::ErrorType MapFile::error() const |
|
{ |
|
return m_this->error(); |
|
} |
|
|
|
int MapFile::line() const |
|
{ |
|
return m_this->line(); |
|
} |
|
|
|
int MapFile::findEntry( long addr ) const |
|
{ |
|
for ( int j = 0 ; j < segments() ; ++j ) |
|
{ |
|
const MapFileEntry& segment = getSegment( j ); |
|
long section = segment.section(); |
|
long segmentBegin = loadAddress() + (segment.section() << 12) + segment.offset(); |
|
long segmentEnd = segmentBegin + segment.length(); |
|
|
|
if ( addr >= segmentBegin && addr < segmentEnd ) |
|
{ |
|
for ( int i = entries()-1 ; i >= 0 ; --i ) |
|
{ |
|
const MapFileEntry entry = getEntry( i ); |
|
if ( entry.section() == section ) |
|
{ |
|
long entryAddr = loadAddress() + (entry.section() << 12) + entry.offset(); |
|
if ( entryAddr <= addr ) |
|
return i; |
|
} |
|
} |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
void MapFile::getModuleMapFilename( char* buffer, int bufferSize ) |
|
{ |
|
int len = 0; |
|
buffer[len] = 0; |
|
|
|
#ifdef WIN32 |
|
// get name of the exe/dll |
|
len = GetModuleFileName( GetModuleHandle(0), buffer, bufferSize-1 ); |
|
buffer[len] = 0; |
|
#endif |
|
|
|
// remove .exe or .dll extension |
|
if ( len > 3 && |
|
(!strcmp(buffer+len-4,".exe") || !strcmp(buffer+len-4,".EXE") || |
|
!strcmp(buffer+len-4,".DLL") || !strcmp(buffer+len-4,".dll")) ) |
|
{ |
|
buffer[len-4] = 0; |
|
} |
|
|
|
// append .map extension |
|
if ( (int)strlen(buffer)+4 < bufferSize ) |
|
{ |
|
strcat( buffer, ".map" ); |
|
} |
|
} |
|
|
|
|
|
} // dev |
|
/* |
|
* Copyright (c) 2001 Jani Kajala |
|
* |
|
* Permission to use, copy, modify, distribute and sell this |
|
* software and its documentation for any purpose is hereby |
|
* granted without fee, provided that the above copyright notice |
|
* appear in all copies and that both that copyright notice and |
|
* this permission notice appear in supporting documentation. |
|
* Jani Kajala makes no representations about the suitability |
|
* of this software for any purpose. It is provided "as is" |
|
* without express or implied warranty. |
|
*/
|
|
|