Commit d80a8cc9 authored by twanvl's avatar twanvl

try to get stack traces for InternalErrors, it doesn't work yet for errors...

try to get stack traces for InternalErrors, it doesn't work yet for errors caught with OnExceptionInMainLoop, because they are rethrown.
parent 56abe556
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/error.hpp> #include <util/error.hpp>
#include <cli/text_io_handler.hpp> #include <cli/text_io_handler.hpp>
#include <cli/text_io_handler.hpp>
#if wxUSE_STACKWALKER
#include <wx/stackwalk.h>
#endif
DECLARE_TYPEOF_COLLECTION(ScriptParseError); DECLARE_TYPEOF_COLLECTION(ScriptParseError);
...@@ -43,6 +47,85 @@ String Error::what() const { ...@@ -43,6 +47,85 @@ String Error::what() const {
return message; return message;
} }
// Stolen from wx/appbase.cpp
// we can't just call it, because of static linkage
#if wxUSE_STACKWALKER
String get_stack_trace() {
wxString stackTrace;
class StackDumper : public wxStackWalker {
public:
StackDumper() {}
const wxString& GetStackTrace() const { return m_stackTrace; }
protected:
virtual void OnStackFrame(const wxStackFrame& frame) {
m_stackTrace << wxString::Format(_("[%02d] "), frame.GetLevel());
wxString name = frame.GetName();
if ( !name.empty() ) {
m_stackTrace << wxString::Format(_("%-40s"), name.c_str());
} else {
m_stackTrace << wxString::Format(
_("%p"),
(void*)frame.GetAddress()
);
}
if ( frame.HasSourceLocation() ) {
m_stackTrace << _('\t')
<< frame.GetFileName()
<< _(':')
<< (unsigned int)frame.GetLine();
}
m_stackTrace << _('\n');
}
private:
wxString m_stackTrace;
};
StackDumper dump;
dump.Walk(2); // don't show InternalError() call itself
stackTrace = dump.GetStackTrace();
// don't show more than maxLines or we could get a dialog too tall to be
// shown on screen: 20 should be ok everywhere as even with 15 pixel high
// characters it is still only 300 pixels...
static const int maxLines = 20;
const int count = stackTrace.Freq(wxT('\n'));
for ( int i = 0; i < count - maxLines; i++ )
stackTrace = stackTrace.BeforeLast(wxT('\n'));
return stackTrace;
}
#else
String get_stack_trace() {
return _(""); // not supported
}
#endif // wxUSE_STACKWALKER
InternalError::InternalError(const String& str)
: Error(
_("An internal error occured:\n\n") +
str + _("\n")
_("Please save your work (use 'save as' to so you don't overwrite things)\n")
_("and restart Magic Set Editor.\n\n")
_("You should leave a bug report on http://magicseteditor.sourceforge.net/\n")
_("Press Ctrl+C to copy this message to the clipboard.")
)
{
// add a stacktrace
const String stack_trace = get_stack_trace();
if (!stack_trace.empty()) {
message << _("\n\nCall stack:\n") << stack_trace;
}
}
// ----------------------------------------------------------------------------- : Parse errors // ----------------------------------------------------------------------------- : Parse errors
ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename, const String& error) ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename, const String& error)
......
...@@ -27,7 +27,7 @@ class Error { ...@@ -27,7 +27,7 @@ class Error {
/// Return the error message /// Return the error message
virtual String what() const; virtual String what() const;
private: protected:
String message; ///< The error message String message; ///< The error message
}; };
...@@ -35,9 +35,7 @@ class Error { ...@@ -35,9 +35,7 @@ class Error {
/// Internal errors /// Internal errors
class InternalError : public Error { class InternalError : public Error {
public: public:
inline InternalError(const String& str) InternalError(const String& str);
: Error(_ERROR_1_("internal error", str.c_str()))
{}
}; };
// ----------------------------------------------------------------------------- : File errors // ----------------------------------------------------------------------------- : File errors
...@@ -148,6 +146,9 @@ void handle_warning(const String& w, bool now = true); ...@@ -148,6 +146,9 @@ void handle_warning(const String& w, bool now = true);
/** Should be called repeatedly (e.g. in an onIdle event handler) */ /** Should be called repeatedly (e.g. in an onIdle event handler) */
void handle_pending_errors(); void handle_pending_errors();
/// Make a stack trace for use in InternalErrors
String get_stack_trace();
/// Catch all types of errors, and pass then to handle_error /// Catch all types of errors, and pass then to handle_error
#define CATCH_ALL_ERRORS(handle_now) \ #define CATCH_ALL_ERRORS(handle_now) \
catch (const Error& e) { \ catch (const Error& e) { \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment