Porting MS Structured Exception Handling to Linux.

Tervel Atanassov
Wed, 11 Jul 2001 18:38:57 -0000

Hello all,

I am trying to port some more code from windows 2000 to linux.  The
specific functionality I would like to port is called "Structured
Exception Handling" and it works like so:

1. Define a function which based upons a signal throws an exceptoion.
For example:
 void translateException(unsigned int u, EXCEPTION_POINTERS* pExp)
 {
  switch (u)
  {
  case (unsigned int)0xc0000005:
   throw AccessViolationException("SE_Exception::translateException() - u
=0xc0000005", pExp, u);
  break;
  default:
   throw SE_Exception("SE_Exception::translateException() - default:",
pExp,
u );
  }
 }
 The idea here is that the function translates the windows "signal" to
a
user defined exception object.

2. call the Windows API function _set_se_translator(translateException).
3. when a OS trap -- like an access violation -- occurs the specified
function will be called.
4. From within the body of that function a user defined exception object
(MyAccessViolationException) can be thrown  which can be caught anywhere in
the offending stack frame. e.g.
 try
 {
  int* pNull = 0;
  *pNull = 12;
 }
 catch (MyAccessViolationException& e)
 {
  printf ("success.\n");
 }

Having researched the web, I have taken the followign approach:  When I
receive a SIGSEGV signal, I need to insert the "exception throwing"
function
into the stack frame which caused the exceptoion, return to it, and throw
out the exception from within it.  In effect I need to insert a new function
to be exectued after the signal has been handled.  This stack tampering
needs to be done because when I handle the signal I have no guarantee, and
in fact am not in the same stack frame I was in when the synchronous
exception arose.  I know that messing with the stack is about as
non-portable as you can be, but oh well I'd rather have my code work on one
other platform besides Windows then none at all.

So in my quest to figure out how to do all this I stumbled upond a gnu
article on how to translate signals into Java exceptions.  Based on that I
came up with the following code:

int i = 0;
//Signal handler function.  The remmed out args reflect my attempt to make
this work with both POSIX.1 and POSIX.4

void on_accvio(int signo/*, siginfo_t *info, void *ignored*/)
{
 printf ("[%d] - on_accvio() : entered %d\n", pthread_self(), i++);
 void **_p = (void **)&signo;
 throw true;

 struct sigcontext_struct *_regs = (struct sigcontext_struct *)++_p;
 register unsigned long _ebp = _regs->ebp;
 register unsigned long _eip = _regs->eip;
 asm volatile ("mov %0, (%%ebp); mov %1, 4(%%ebp)" : :
"r"(_ebp),
"r"(_eip));
 //These are remmed out because I was testing stuff.
// register unsigned long _esp = _regs->esp;
// asm volatile ("mov %0, (%%ebp); mov %1, 4(%%ebp); mov %1, 4(%%esp)"
: :
"r"(_ebp), "r"(_eip), "r"(_esp));
 //I am throwing out the boolean just for now.  Later it will be a real
exception object.
 throw true;
}

struct sigaction sa;
void init_signal_machinery()
{
 sigemptyset(&sa.sa_mask);
 sa.sa_handler = on_accvio;
 sa.sa_flags = 0;
 if (sigaction(SIGSEGV, &sa, NULL))
 {
  printf("initlog() : sigaction() failed.\n");
  exit(1);
 } return;
}

Anyways, this approach is close, but not exactly there.  It modifies the
stack frame alright, and the thrown boolean is caught fine.  However when I
return to the offending stack code, my stack is pretty much messed up; no
passed in arguments, including the implicit this pointer are correct.
However if I return out of that particular function everything is fine.
Anyways I need to know how to modify my stack memory pointer before
returning to the offending code.

Any help would be greatly appreciated, as assembly and I are on VERY formal
terms.

Thanks,

Tervel Atanassov