Browse Source

Fix garbled stack traces.

Newer versions of VS and Windows use ASLR for security purposes, meaning
that the module may be relocated from what is expected by the linker map
file. While we could kludge around that by disabling ASLR, it would be
better to just map the actual stack addresses to the expected addresses.
This also simplifies all of the weird segment math to simply use the
rvabase value in the map file.
working_subtitles
Adam Johnson 3 years ago committed by rarified
parent
commit
c9fddca6d5
  1. 39
      Sources/Plasma/FeatureLib/pfStackTrace/pfMapFile.cpp
  2. 9
      Sources/Plasma/FeatureLib/pfStackTrace/pfMapFileEntry.cpp
  3. 6
      Sources/Plasma/FeatureLib/pfStackTrace/pfMapFileEntry.h
  4. 11
      Sources/Plasma/FeatureLib/pfStackTrace/pfStackTrace.cpp

39
Sources/Plasma/FeatureLib/pfStackTrace/pfMapFile.cpp

@ -6,8 +6,11 @@
#include <algorithm> #include <algorithm>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
extern "C" IMAGE_DOS_HEADER __ImageBase;
#endif #endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -151,7 +154,7 @@ private:
parse( 'H' ); parse( 'H' );
char buf[256]; char buf[256];
m_file.readString( buf, sizeof(buf) ); m_file.readString( buf, sizeof(buf) );
segments.add( MapFileEntry(seg,offs,len,buf) ); segments.add( MapFileEntry(seg,offs,len,buf,0) );
// break at empty line // break at empty line
if ( nextLineEmpty() ) if ( nextLineEmpty() )
@ -212,8 +215,9 @@ private:
entryname = newName; entryname = newName;
} }
long rvabase = m_file.readHex();
entries.add( MapFileEntry(seg,offs,0,entryname) ); entries.add( MapFileEntry(seg,offs,0,entryname,rvabase) );
// break at empty line // break at empty line
if ( nextLineEmpty() ) if ( nextLineEmpty() )
@ -271,27 +275,22 @@ int MapFile::line() const
int MapFile::findEntry( long addr ) const int MapFile::findEntry( long addr ) const
{ {
for ( int j = 0 ; j < segments() ; ++j ) #ifdef WIN32
{ // Cope with Windows ASLR. Note that these operations are not commutative.
const MapFileEntry& segment = getSegment( j ); addr -= (long)&__ImageBase;
long section = segment.section(); addr += loadAddress();
long segmentBegin = loadAddress() + (segment.section() << 12) + segment.offset(); #endif
long segmentEnd = segmentBegin + segment.length();
if ( addr >= segmentBegin && addr < segmentEnd ) // The code before ASLR-proofing tried to compute things by segment.
{ // It didn't work for whatever reason, so here's something simpler
for ( int i = entries()-1 ; i >= 0 ; --i ) // by address. Just be sure to toss anything larger than the
{ // highest address we know about.
const MapFileEntry entry = getEntry( i ); if (addr == 0 || addr > getEntry(entries() - 1).rvabase())
if ( entry.section() == section ) return -1;
{ for (int i = entries() - 1; i >= 0; --i) {
long entryAddr = loadAddress() + (entry.section() << 12) + entry.offset(); if (getEntry(i).rvabase() <= addr)
if ( entryAddr <= addr )
return i; return i;
} }
}
}
}
return -1; return -1;
} }

9
Sources/Plasma/FeatureLib/pfStackTrace/pfMapFileEntry.cpp

@ -12,14 +12,16 @@ MapFileEntry::MapFileEntry()
m_sec = 0; m_sec = 0;
m_addr = 0; m_addr = 0;
m_len = 0; m_len = 0;
m_rvabase = 0;
m_name[0] = 0; m_name[0] = 0;
} }
MapFileEntry::MapFileEntry( long section, long offset, long length, const char* name ) MapFileEntry::MapFileEntry( long section, long offset, long length, const char* name, long rvabase )
{ {
m_sec = section; m_sec = section;
m_addr = offset; m_addr = offset;
m_len = length; m_len = length;
m_rvabase = rvabase;
strncpy( m_name, name, MAX_NAME ); strncpy( m_name, name, MAX_NAME );
m_name[MAX_NAME] = 0; m_name[MAX_NAME] = 0;
@ -45,6 +47,11 @@ const char* MapFileEntry::name() const
return m_name; return m_name;
} }
long MapFileEntry::rvabase() const
{
return m_rvabase;
}
bool MapFileEntry::operator<( const MapFileEntry& other ) const bool MapFileEntry::operator<( const MapFileEntry& other ) const
{ {
if ( m_sec < other.m_sec ) if ( m_sec < other.m_sec )

6
Sources/Plasma/FeatureLib/pfStackTrace/pfMapFileEntry.h

@ -21,7 +21,7 @@ public:
MapFileEntry(); MapFileEntry();
/** Creates an entry with specified section, offset, length and name. */ /** Creates an entry with specified section, offset, length and name. */
MapFileEntry( long section, long offset, long length, const char* name ); MapFileEntry( long section, long offset, long length, const char* name, long rvabase );
/** Returns section of the entry. */ /** Returns section of the entry. */
long section() const; long section() const;
@ -35,6 +35,9 @@ public:
/** Returns name of the entry. */ /** Returns name of the entry. */
const char* name() const; const char* name() const;
/** Returns the location of the entry. */
long rvabase() const;
/** Returns true if the offset of this entry is before the other one. */ /** Returns true if the offset of this entry is before the other one. */
bool operator<( const MapFileEntry& other ) const; bool operator<( const MapFileEntry& other ) const;
@ -43,6 +46,7 @@ private:
long m_addr; long m_addr;
long m_len; long m_len;
char m_name[MAX_NAME+1]; char m_name[MAX_NAME+1];
long m_rvabase;
}; };

11
Sources/Plasma/FeatureLib/pfStackTrace/pfStackTrace.cpp

@ -6,6 +6,8 @@
#pragma optimize( "y", off ) #pragma optimize( "y", off )
extern "C" struct IMAGE_DOS_HEADER __ImageBase;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define MAX_DEPTH 32 #define MAX_DEPTH 32
@ -155,9 +157,14 @@ int StackTrace::printStackTrace( MapFile** map, int maps,
else else
{ {
const MapFileEntry &en = entryMap->getEntry( entry ); const MapFileEntry &en = entryMap->getEntry( entry );
long entryAddr = entryMap->loadAddress() + (en.section() << 12) + en.offset(); long entryAddr = en.rvabase();
long stackAddr = addr;
#ifdef WIN32
stackAddr -= (long)&__ImageBase;
stackAddr += entryMap->loadAddress();
#endif
sprintf( buf+strlen(buf), "%s (0x%08X + 0x%08X)\r\n", en.name(), entryAddr, addr - entryAddr ); sprintf( buf+strlen(buf), "%s (0x%08X + 0x%08X)\r\n", en.name(), entryAddr, stackAddr - entryAddr );
} }
// append temporary buf to output buffer if space left // append temporary buf to output buffer if space left

Loading…
Cancel
Save