MapFile.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. * Copyright (c) 2006 Michael Eddington
  3. * Copyright (c) 2001 Jani Kajala
  4. *
  5. * Permission to use, copy, modify, distribute and sell this
  6. * software and its documentation for any purpose is hereby
  7. * granted without fee, provided that the above copyright notice
  8. * appear in all copies and that both that copyright notice and
  9. * this permission notice appear in supporting documentation.
  10. * Jani Kajala makes no representations about the suitability
  11. * of this software for any purpose. It is provided "as is"
  12. * without express or implied warranty.
  13. */
  14. /* $Id$ */
  15. #include "MapFile.h"
  16. #include "MapFileEntry.h"
  17. #include "TextFile.h"
  18. #include "Array.h"
  19. #include <algorithm>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #ifdef WIN32
  23. #include <windows.h>
  24. #endif
  25. /*---------------------------------------------------------------------------*/
  26. namespace dev
  27. {
  28. /* Lots of changes from origional to fix bugs */
  29. /* improve spead, and clean things up. */
  30. /* We are only parsing function entries now, but */
  31. /* should add support for line numbers. */
  32. class MapFile::MapFileImpl
  33. {
  34. public:
  35. long loadAddr;
  36. char name[256];
  37. Array<MapFileEntry*> entries;
  38. MapFileImpl( const char* filename ) :
  39. loadAddr(0), m_file( filename ), m_err( MapFile::ERROR_NONE )
  40. {
  41. m_file.readString( name, sizeof(name) );
  42. char buf[1024];
  43. while ( m_file.readString(buf,sizeof(buf)) )
  44. {
  45. if ( !strcmp("Address",buf) )
  46. parseEntries();
  47. else
  48. m_file.skipLine();
  49. }
  50. std::sort( entries.begin(), entries.end() );
  51. }
  52. ~MapFileImpl()
  53. {
  54. for(int i = entries.size(); i; i--)
  55. delete entries[i];
  56. }
  57. ErrorType error() const
  58. {
  59. if ( m_err != MapFile::ERROR_NONE )
  60. return m_err;
  61. switch ( m_file.error() )
  62. {
  63. case TextFile::ERROR_OPEN: return MapFile::ERROR_OPEN;
  64. case TextFile::ERROR_READ: return MapFile::ERROR_READ;
  65. case TextFile::ERROR_PARSE: return MapFile::ERROR_PARSE;
  66. default: return MapFile::ERROR_NONE;
  67. }
  68. }
  69. int line() const
  70. {
  71. if ( m_err != MapFile::ERROR_NONE )
  72. return m_errLine;
  73. return m_file.line();
  74. }
  75. private:
  76. TextFile m_file;
  77. MapFile::ErrorType m_err;
  78. int m_errLine;
  79. /**
  80. * Returns true if the next line is empty.
  81. */
  82. bool nextLineEmpty()
  83. {
  84. m_file.skipLine();
  85. char ch;
  86. while ( m_file.peekChar(&ch) && isspace(ch) && ch != '\n' )
  87. m_file.readChar( &ch );
  88. if ( m_file.peekChar(&ch) && ch == '\n' )
  89. return true;
  90. return false;
  91. }
  92. /**
  93. * Parses specified string.
  94. * Sets error if parsed string doesnt match.
  95. */
  96. void parse( const char* str )
  97. {
  98. char buf[256];
  99. m_file.readString( buf, sizeof(buf) );
  100. if ( strcmp(str,buf) )
  101. {
  102. m_err = MapFile::ERROR_PARSE;
  103. m_errLine = m_file.line();
  104. }
  105. }
  106. /**
  107. * Parses specified character.
  108. * Sets error if parsed character doesnt match.
  109. */
  110. void parse( char ch )
  111. {
  112. char ch2;
  113. if ( !m_file.readChar(&ch2) || ch2 != ch )
  114. {
  115. m_err = MapFile::ERROR_PARSE;
  116. m_errLine = m_file.line();
  117. }
  118. }
  119. /**
  120. * Example:
  121. * (Preferred) load address is 00400000
  122. */
  123. void parseLoadAddress()
  124. {
  125. parse( "load" ); parse( "address" ); parse( "is" );
  126. loadAddr = m_file.readHex();
  127. }
  128. /**
  129. * Example:
  130. * (Address) Publics by Value Rva+Base Lib:Object
  131. * 0001:000001a0 ?stackTrace@@YAXXZ 004011a0 f main.obj
  132. */
  133. void parseEntries()
  134. {
  135. unsigned int seg;
  136. unsigned int offs;
  137. unsigned int rvabase;
  138. char buf[256];
  139. char* entryname;
  140. char lib[256];
  141. char* str;
  142. parse( "Publics" ); parse( "by" ); parse( "Value" );
  143. parse( "Rva+Base" );
  144. parse( "Lib:Object" );
  145. m_file.skipWhitespace();
  146. while ( !error() )
  147. {
  148. seg = m_file.readHex();
  149. parse( ':' );
  150. offs = m_file.readHex();
  151. m_file.readString( buf, sizeof(buf) );
  152. entryname = buf;
  153. rvabase = m_file.readHex();
  154. m_file.readString( lib, sizeof(lib) );
  155. if(!strcmp(lib, "f"))
  156. m_file.readString( lib, sizeof(lib) );
  157. /* chop entry name at @@ */
  158. str = strstr( entryname, "@@" );
  159. if ( str )
  160. *str = 0;
  161. /* skip preceding ?01.. */
  162. while ( isdigit(*entryname) || *entryname == '?' || *entryname == '$' )
  163. ++entryname;
  164. /* conv @ -> . */
  165. for ( str = entryname ; *str ; ++str )
  166. if ( *str == '@' )
  167. *str = '.';
  168. entries.add( new MapFileEntry(seg,offs,0,entryname, rvabase, lib) );
  169. // break at empty line
  170. if ( nextLineEmpty() )
  171. break;
  172. }
  173. }
  174. };
  175. //-----------------------------------------------------------------------------
  176. MapFile::MapFile( const char* filename )
  177. {
  178. m_this = new MapFileImpl( filename );
  179. }
  180. MapFile::~MapFile()
  181. {
  182. delete m_this;
  183. }
  184. long MapFile::loadAddress() const
  185. {
  186. return m_this->loadAddr;
  187. }
  188. MapFileEntry* MapFile::getEntry( int i ) const
  189. {
  190. return m_this->entries[i];
  191. }
  192. int MapFile::entries() const
  193. {
  194. return m_this->entries.size();
  195. }
  196. MapFile::ErrorType MapFile::error() const
  197. {
  198. return m_this->error();
  199. }
  200. int MapFile::line() const
  201. {
  202. return m_this->line();
  203. }
  204. int MapFile::findEntry( long addr ) const
  205. {
  206. // Changed this to use the rvabase instead
  207. // of calculating things based on segment.
  208. // Addresses of zero are bogus
  209. if(addr == 0)
  210. return -1;
  211. // Check and see if our addr is way larger then
  212. // the highest rva+base address we have.
  213. if(addr > (getEntry(entries()-1)->rvabase() + 10000))
  214. return -1;
  215. // Entries are sorted, so searching from last
  216. // to first will work well
  217. for ( int i = entries()-1 ; i >= 0 ; --i )
  218. {
  219. if(getEntry( i )->rvabase() <= addr)
  220. return i;
  221. }
  222. return -1;
  223. }
  224. void MapFile::getModuleMapFilename( char* buffer, int bufferSize )
  225. {
  226. int len = 0;
  227. buffer[len] = 0;
  228. #ifdef WIN32
  229. // get name of the exe/dll
  230. len = GetModuleFileName( GetModuleHandle(0), buffer, bufferSize-1 );
  231. buffer[len] = 0;
  232. #endif
  233. // remove .exe or .dll extension
  234. if ( len > 3 &&
  235. (!strcmp(buffer+len-4,".exe") || !strcmp(buffer+len-4,".EXE") ||
  236. !strcmp(buffer+len-4,".DLL") || !strcmp(buffer+len-4,".dll")) )
  237. {
  238. buffer[len-4] = 0;
  239. }
  240. // append .map extension
  241. if ( (int)strlen(buffer)+4 < bufferSize )
  242. {
  243. strcat( buffer, ".map" );
  244. }
  245. }
  246. } // dev