|
Java Style Call Stack Printing In C++
Submitted by |
This small C++ library implements "Java-style" call stack printing using stack frames and map files. Makes
for example assertions more useful as you can see the context where the assertion failed. The library
is very easy to use (you need only one function, printStackTrace) and the library can be freely
used in any applications.
Regards,
Jani Kajala
Email: jani@sumea.com
Homepage: http://www.helsinki.fi/~kajala/
Editor's note: See /doc/printStackTrace.html within the zip file, for more information about the library.
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/Array.h] - (2,394 bytes)
#ifndef _DEV_ARRAY_H
#define _DEV_ARRAY_H
namespace dev
{
/** Very simple dynamic array. */
template <class T> class Array
{
public:
/** Creates an empty array. */
Array() :
m_data(0), m_len(0), m_cap(0)
{
}
/** Creates an array of specified size. */
explicit Array( int size ) :
m_data(0), m_len(0), m_cap(0)
{
setSize( size );
}
///
~Array()
{
delete[] m_data;
}
/** Appends an item at the end of the array. */
void add( const T& item )
{
if ( m_len+1 > m_cap )
setCapacity( m_len + 1 );
m_data[m_len++] = item;
}
/** Resizes the array. */
void setSize( int size )
{
if ( size > m_cap )
setCapacity( size );
m_len = size;
}
/** Returns ith item. */
T& operator[]( int i )
{
return m_data[i];
}
/** Returns pointer to the first element in the vector. */
T* begin()
{
return m_data;
}
/** Returns pointer to one beyond the last element in the vector. */
T* end()
{
return m_data + m_len;
}
/** Returns number of items in the array. */
int size() const
{
return m_len;
}
/** Returns ith item. */
const T& operator[]( int i ) const
{
return m_data[i];
}
/** Returns pointer to the first element in the vector. */
const T* begin() const
{
return m_data;
}
/** Returns pointer to one beyond the last element in the vector. */
const T* end() const
{
return m_data + m_len;
}
private:
T* m_data;
int m_len;
int m_cap;
void setCapacity( int cap )
{
++cap;
if ( cap < 8 )
cap = 8;
else if ( cap < m_cap*2 )
cap = m_cap*2;
m_cap = cap;
T* data = new T[cap];
for ( int i = 0 ; i < m_len ; ++i )
data[i] = m_data[i];
delete[] m_data;
m_data = data;
}
};
} // dev
#endif // _DEV_ARRAY_H
/*
* 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/MapFile.cpp] - (6,832 bytes)
#include "MapFile.h"
#include "MapFileEntry.h"
#include "TextFile.h"
#include "Array.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 = '.';
entries.add( MapFileEntry(seg,offs,0,entryname) );
// break at empty line
if ( nextLineEmpty() )
break;
}
}
};
//-----------------------------------------------------------------------------
MapFile::MapFile( const char* filename )
{
m_this = 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/MapFile.h] - (2,144 bytes)
#ifndef _DEV_MAPFILE_H
#define _DEV_MAPFILE_H
namespace dev
{
class MapFileEntry;
/**
* Linker generated module map file parser.
*/
class MapFile
{
public:
/** Error code. */
enum ErrorType
{
/** No error. */
ERROR_NONE,
/** File open failed. */
ERROR_OPEN,
/** File reading failed. */
ERROR_READ,
/** Syntax error. */
ERROR_PARSE
};
/** Reads a map file. */
explicit MapFile( const char* filename );
///
~MapFile();
/** Returns preferred load address. */
long loadAddress() const;
/** Returns ith entry from the map file. */
const MapFileEntry& getEntry( int i ) const;
/** Returns ith segment from the map file. */
const MapFileEntry& getSegment( int i ) const;
/** Returns number of segments in the map file. */
int segments() const;
/** Returns number of entries in the map file. */
int entries() const;
/** Returns error code or 0 (ERROR_NONE) if no error. */
ErrorType error() const;
/** Returns line number of last successful read character. */
int line() const;
/**
* Finds entry which contains specified address.
* @return Entry index or -1 if not found.
*/
int findEntry( long addr ) const;
/**
* Returns current module name, with map extension.
* The output buffer is always 0-terminated.
*/
static void getModuleMapFilename( char* buffer, int bufferSize );
private:
class MapFileImpl;
MapFileImpl* m_this;
MapFile( const MapFile& );
MapFile& operator=( const MapFile& );
};
} // dev
#endif // _DEV_MAPFILE_H
/*
* 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/MapFileEntry.cpp] - (1,451 bytes)
#include "MapFileEntry.h"
#include <string.h>
//-----------------------------------------------------------------------------
namespace dev
{
MapFileEntry::MapFileEntry()
{
m_sec = 0;
m_addr = 0;
m_len = 0;
m_name[0] = 0;
}
MapFileEntry::MapFileEntry( long section, long offset, long length, const char* name )
{
m_sec = section;
m_addr = offset;
m_len = length;
strncpy( m_name, name, MAX_NAME );
m_name[MAX_NAME] = 0;
}
long MapFileEntry::section() const
{
return m_sec;
}
long MapFileEntry::offset() const
{
return m_addr;
}
long MapFileEntry::length() const
{
return m_len;
}
const char* MapFileEntry::name() const
{
return m_name;
}
bool MapFileEntry::operator<( const MapFileEntry& other ) const
{
if ( m_sec < other.m_sec )
return true;
if ( m_sec > other.m_sec )
return false;
return m_addr < other.m_addr;
}
} // 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/MapFileEntry.h] - (1,548 bytes)
#ifndef _DEV_MAPFILEENTRY_H
#define _DEV_MAPFILEENTRY_H
namespace dev
{
/** An entry in the map file. */
class MapFileEntry
{
public:
/** Class constants. */
enum Constants
{
/** Maximum number of characters in map file entry name. */
MAX_NAME = 256
};
///
MapFileEntry();
/** Creates an entry with specified section, offset, length and name. */
MapFileEntry( long section, long offset, long length, const char* name );
/** Returns section of the entry. */
long section() const;
/** Returns offset of the entry. */
long offset() const;
/** Returns length of the entry (only defined for segments). */
long length() const;
/** Returns name of the entry. */
const char* name() const;
/** Returns true if the offset of this entry is before the other one. */
bool operator<( const MapFileEntry& other ) const;
private:
long m_sec;
long m_addr;
long m_len;
char m_name[MAX_NAME+1];
};
} // dev
#endif // _DEV_MAPFILEENTRY_H
/*
* 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/StackTrace.cpp] - (2,945 bytes)
#include "StackTrace.h"
#include "MapFile.h"
#include "MapFileEntry.h"
#include <string.h>
#include <stdio.h>
//-----------------------------------------------------------------------------
#define MAX_DEPTH 32
//-----------------------------------------------------------------------------
namespace dev
{
static long getCaller( int index )
{
#if defined(_DEBUG) && defined(_MSC_VER) && defined(_M_IX86)
long caller = 0;
__asm
{
mov ebx, ebp
mov ecx, index
inc ecx
xor eax, eax
StackTrace_getCaller_next:
mov eax, [ebx+4]
mov ebx, [ebx]
dec ecx
jnz StackTrace_getCaller_next
mov caller, eax
}
return caller;
#else
return 0;
#endif
}
int StackTrace::printStackTrace( MapFile** map, int maps,
int initLevel, int maxDepth,
char* buffer, int bufferSize )
{
if ( maxDepth > MAX_DEPTH )
maxDepth = MAX_DEPTH;
// list callers
long callersAddr[MAX_DEPTH];
int callers = 0;
int i;
for ( i = initLevel ; i < maxDepth ; ++i )
{
long addr = getCaller( i );
callersAddr[callers++] = addr;
// end tracing here if the entry is not in a map file
int entry = -1;
for ( int j = 0 ; j < maps ; ++j )
{
entry = map[j]->findEntry( addr );
if ( -1 != entry )
break;
}
if ( -1 == entry )
break;
}
// output call stack
if ( bufferSize > 0 )
*buffer = 0;
int needed = 0;
for ( i = initLevel ; i < callers ; ++i )
{
long addr = callersAddr[callers-i-1];
// find entry info
int entry = -1;
const MapFile* entryMap = 0;
for ( int j = 0 ; j < maps ; ++j )
{
entry = map[j]->findEntry( addr );
if ( -1 != entry )
{
entryMap = map[j];
break;
}
}
// format entry to tempory buf
char buf[MapFileEntry::MAX_NAME+MAX_DEPTH+20]; // name + margin + hex number
buf[0] = 0;
for ( int k = initLevel-1 ; k < i ; ++k )
strcat( buf, " " );
if ( !entryMap )
sprintf( buf+strlen(buf), "0x%x\n", addr );
else
sprintf( buf+strlen(buf), "%s (%x)\n", entryMap->getEntry(entry).name(), addr );
// append temporary buf to output buffer if space left
needed += strlen( buf );
if ( needed < bufferSize )
strcat( buffer, buf );
}
// terminate output buffer
if ( needed < bufferSize )
buffer[needed] = 0;
else if ( bufferSize > 0 )
buffer[bufferSize-1] = 0;
return needed;
}
} // 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/StackTrace.h] - (1,373 bytes)
#ifndef _DEV_STACKTRACE_H
#define _DEV_STACKTRACE_H
namespace dev
{
class MapFile;
/** Stack tracing utility. */
class StackTrace
{
public:
/**
* Prints formatted call stack to the user buffer.
* Always terminates the user buffer with 0.
*
* @param map Array of pointers to map files.
* @param maps Number of map files.
* @param initLevel Number of functions to skip before starting the tracing.
* @param maxDepth Maximum number of levels in the stack trace.
* @param buffer [out] Output buffer for the formatted stack trace.
* @param bufferSize Size of the output buffer.
* @return Needed buffer size.
*/
static int printStackTrace( MapFile** map, int maps,
int initLevel, int maxDepth,
char* buffer, int bufferSize );
};
} // dev
#endif // _DEV_STACKTRACE_H
/*
* 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/TextFile.cpp] - (4,554 bytes)
#include "TextFile.h"
#include <stdio.h>
#include <ctype.h>
//-----------------------------------------------------------------------------
namespace dev
{
class TextFile::TextFileImpl
{
public:
TextFile::ErrorType err;
int line;
explicit TextFileImpl( const char* filename )
{
err = TextFile::ERROR_NONE;
line = 1;
m_peeked = false;
m_peekedChar = 0;
m_file = fopen( filename, "rt" );
if ( !m_file )
err = TextFile::ERROR_OPEN;
}
~TextFileImpl()
{
if ( m_file )
{
fclose( m_file );
m_file = 0;
}
}
bool eof() const
{
if ( err )
return true;
return 0 != feof(m_file);
}
bool peekChar( char* ch )
{
if ( err )
return false;
if ( !m_peeked )
{
int c = getc( m_file );
if ( EOF != c )
{
m_peeked = true;
m_peekedChar = (char)c;
}
else
{
if ( ferror(m_file) )
err = TextFile::ERROR_READ;
}
}
if ( m_peeked )
*ch = m_peekedChar;
return m_peeked;
}
bool readChar( char* ch )
{
if ( err )
return false;
bool more = peekChar( ch );
m_peeked = false;
if ( more && *ch == '\n' )
++line;
return more;
}
bool skipWhitespace()
{
if ( err )
return false;
char ch;
while ( peekChar(&ch) )
{
if ( !isspace(ch) )
break;
readChar( &ch );
}
return !eof();
}
bool readString( char* buf, int size )
{
if ( err )
return false;
skipWhitespace();
int count = 0;
char ch;
while ( peekChar(&ch) )
{
if ( isspace(ch) )
break;
if ( count+1 < size )
buf[count++] = ch;
readChar( &ch );
}
if ( size > 0 )
buf[count] = 0;
return count > 0;
}
void skipLine()
{
if ( err )
return;
char ch;
while ( readChar(&ch) )
{
if ( ch == '\n' )
break;
}
}
long readHex()
{
if ( err )
return 0;
skipWhitespace();
// hex must start with alphanumeric character
char ch;
if ( !peekChar(&ch) || !isalnum(ch) )
{
err = TextFile::ERROR_PARSE;
return 0;
}
long x = 0;
while ( peekChar(&ch) )
{
switch ( ch )
{
case '0': x <<= 4; x += 0; break;
case '1': x <<= 4; x += 1; break;
case '2': x <<= 4; x += 2; break;
case '3': x <<= 4; x += 3; break;
case '4': x <<= 4; x += 4; break;
case '5': x <<= 4; x += 5; break;
case '6': x <<= 4; x += 6; break;
case '7': x <<= 4; x += 7; break;
case '8': x <<= 4; x += 8; break;
case '9': x <<= 4; x += 9; break;
case 'a':
case 'A': x <<= 4; x += 0xA; break;
case 'b':
case 'B': x <<= 4; x += 0xB; break;
case 'c':
case 'C': x <<= 4; x += 0xC; break;
case 'd':
case 'D': x <<= 4; x += 0xD; break;
case 'e':
case 'E': x <<= 4; x += 0xE; break;
case 'f':
case 'F': x <<= 4; x += 0xF; break;
default: return x;
}
readChar( &ch );
}
return x;
}
private:
bool m_peeked;
char m_peekedChar;
FILE* m_file;
TextFileImpl( const TextFileImpl& );
TextFileImpl& operator=( const TextFileImpl& );
};
//-----------------------------------------------------------------------------
TextFile::TextFile( const char* filename )
{
m_this = new TextFileImpl( filename );
}
TextFile::~TextFile()
{
delete m_this;
}
bool TextFile::readString( char* buf, int size )
{
return m_this->readString( buf, size );
}
void TextFile::skipLine()
{
m_this->skipLine();
}
long TextFile::readHex()
{
return m_this->readHex();
}
bool TextFile::skipWhitespace()
{
return m_this->skipWhitespace();
}
TextFile::ErrorType TextFile::error() const
{
return m_this->err;
}
bool TextFile::readChar( char* ch )
{
return m_this->readChar( ch );
}
bool TextFile::peekChar( char* ch )
{
return m_this->peekChar( ch );
}
bool TextFile::eof() const
{
return m_this->eof();
}
int TextFile::line() const
{
return m_this->line;
}
} // 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [internal/TextFile.h] - (2,316 bytes)
#ifndef _DEV_TEXTFILE_H
#define _DEV_TEXTFILE_H
namespace dev
{
/**
* ASCII-7 text file parser. Doesnt throw exceptions.
*/
class TextFile
{
public:
/** Error code. */
enum ErrorType
{
/** No error. */
ERROR_NONE,
/** File open failed. */
ERROR_OPEN,
/** File reading failed. */
ERROR_READ,
/** Syntax error. */
ERROR_PARSE
};
/** Opens a file. */
explicit TextFile( const char* filename );
///
~TextFile();
/**
* Reads a single character.
* @return true if read ok.
*/
bool readChar( char* ch );
/**
* Peeks a single character.
* @return true if peek ok.
*/
bool peekChar( char* ch );
/**
* Reads whitespace delimited string.
* If the string doesnt fit to the buffer then
* the rest of the string is skipped. Buffer
* is always 0-terminated.
* @param buf [out] Pointer to string buffer.
* @param size String buffer size. Must be larger than 0.
* @return false if end-of-file reached before any characters was read.
*/
bool readString( char* buf, int size );
/** Skips the rest of the line. */
void skipLine();
/** Reads hex integer. Skips preceding whitespace. */
long readHex();
/**
* Skips whitespace characters.
* @return false if end-of-file reached.
*/
bool skipWhitespace();
/** Returns true if end-of-file have been reached. */
bool eof() const;
/** Returns error code or 0 (ERROR_NONE) if no error. */
ErrorType error() const;
/** Returns line number of last successful read character. */
int line() const;
private:
class TextFileImpl;
TextFileImpl* m_this;
TextFile( const TextFile& );
TextFile& operator=( const TextFile& );
};
} // dev
#endif // _DEV_TEXTFILE_H
/*
* 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [test/main.cpp] - (937 bytes)
#include "../printStackTrace.h"
#include <stdio.h>
//-----------------------------------------------------------------------------
#define testAssert( EXPR ) if (EXPR) {} else {testAssertFailed(__FILE__,__LINE__,#EXPR);}
//-----------------------------------------------------------------------------
void testAssertFailed( const char* fname, int line, const char* expr )
{
char buf[1000];
printStackTrace( buf, sizeof(buf) );
printf( "Test assertion: %s(%i)\n", fname, line );
printf( "Expression: %s\n", expr );
printf( "Stack trace:\n" );
puts( buf );
}
//-----------------------------------------------------------------------------
void testfunc3( int x )
{
testAssert( x == 3 );
}
void testfunc2( int arg1 )
{
testfunc3( arg1 );
}
void testfunc1( int arg1 )
{
testfunc2( arg1 );
}
int main()
{
testfunc1( 4 );
puts( "Press enter to exit" );
getchar();
return 0;
}
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [printStackTrace.cpp] - (1,835 bytes)
#include "printStackTrace.h"
#include "StackTrace.h"
#include "MapFile.h"
#include <stdio.h>
#include <string.h>
//-----------------------------------------------------------------------------
using namespace dev;
//-----------------------------------------------------------------------------
/**
* Prints stack trace to user defined buffer.
* Always terminates the buffer with 0.
*/
void printStackTrace( char* buffer, int bufferSize )
{
// find out map file name
char modname[500];
MapFile::getModuleMapFilename( modname, sizeof(modname) );
// parse map file
char buf[600];
MapFile map( modname );
switch ( map.error() )
{
case MapFile::ERROR_OPEN: sprintf( buf, "Failed to open map file %s\n", modname ); break;
case MapFile::ERROR_READ: sprintf( buf, "Error while reading map file %s(%i)\n", modname, map.line() ); break;
case MapFile::ERROR_PARSE: sprintf( buf, "Parse error in map file %s(%i)\n", modname, map.line() ); break;
default: break;
}
// print stack trace to buffer
if ( !map.error() )
{
MapFile* maps[] = {&map};
StackTrace::printStackTrace( maps, 1, 1, 16, buf, sizeof(buf) );
}
// copy to user buffer
if ( bufferSize > 0 )
{
strncpy( buffer, buf, bufferSize );
buffer[bufferSize-1] = 0;
}
}
/*
* 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.
*/
|
|
Currently browsing [stacktrace.zip] (38,843 bytes) - [printStackTrace.h] - (907 bytes)
#ifndef _PRINTSTACKTRACE_H
#define _PRINTSTACKTRACE_H
/**
* Prints formatted call stack to the user defined buffer,
* always terminating the buffer with 0.
* Uses stack frame to find out the caller function address and
* the map file to find out the function name.
*/
void printStackTrace( char* buffer, int bufferSize );
#endif // _PRINTSTACKTRACE_H
/*
* 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.
*/
|
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|