Danny Backx wrote:
> On Sat, 2007-06-02 at 20:59 +0100, Pedro Alves wrote:
>> Pedro Alves wrote:
>>> Kevin O'Connor wrote:
>>> I recently ported the haret application
>>> (http://www.handhelds.org/moin/moin.cgi/HaRET) to mingwce32.  In the
>>> process, I used the c++ compiler, mainly because there were a few
>>> places in the existing msvc code that would catch bad pointer accesses
>>> and handle them gracefully.
> 
>>>   try
>>>   {
>>>     while (wcount--)
>>>       *vaddr++ = value;
>>>   }
>>>   catch (...)
>>>   {
>>>     Output(C_ERROR "EXCEPTION while writing %08x to address %p",
>>>       value, vaddr);
>>>   }
>>>
>>> However, it doesn't work.  (A bad memory access causes the program to
>>> terminate.)  What can be done to get this working?
> [...]
>> Now, on ARM, SEH is table based, like DWARF2 exceptions are too.  This
>> means, the compiler must put unwind information in tables that the OS
>> will read.  Only the compiler and linker have enough information to
>> build those tables.  There is a very rudimentary SEH handler
>> implemented in src/newlib/libc/wince/crt0.S, and
>> src/newlib/libc/wince/startup.c, that install a catch all top level
>> handler.  You could install a top level handler like crt0.S does in
>> your app, having but more handlers is something I don't think is
>> practical to do manually.
> 
> I'm not sure we're talking about the same things here.
> 

Yes, we are.  Kevin wants __try/__except, which is syntax sugar on
top of SEH.  Start here for info on SEH on ARM WinCE:

http://msdn2.microsoft.com/en-us/library/ms925781.aspx

The best reference on SEH on x86 is this, well worth a read:

http://www.microsoft.com/msj/0197/exception/exception.aspx

Basically, whenever an OS exception happens, Windows will look for
a handler that can "catch" the exception.  On x68, it will look in
a linked list of structures built on the stack, where each handler
will have a pointer into the next handler deeper in the stack.  The last
entry on the list is a handler always installed by the OS that displays
that "exception happenned" message box on desktop Windows.  If no handler
handles the exception, that handler will.  The downside of this scheme
is that the compiler must always insert code to built and manage that
linked list on the stack.  The upside is that it is very fast in finding
a handler when an exception happens.  Since that is an exceptional case,
MS took the opportunity of changing the scheme for other archs where
backward compatibility isn't a problem, so, ...

... on ARM, (and SH, and MIPS, and x64), the scheme is different.
The compiler emits tables with information like:

Function f1 starts at address x1, and its prologue ends at y1.  The
handler in case an exception happens is at z1.
Function f2 starts at address x2, and its prologue ends at y2.  The
handler in case an exception happens is at z2.
etc, etc.

(of the top of my head, real data stored will be certainly a bit
different, but you get the picture).

So, when an exception happens, the OS will look for a handler by
looking at those tables, and use the start/end prologue coluns, to
virtually unwind the stack.  Compared to the x86 scheme, this scheme
is slower in finding the right handler, but, will be faster on
the normal non-exceptional code, since there won't be a linked list
to build at run-time.  Since exception are, well, exceptional, this
is certainly an improvement.

Now, on cegcc's crt0.S there is code that builds an entry of the table
I was talking about.  That entry registers a handler that is found
on startup.c, and lies to CE, by saying that the function it handles
is huge:

         .section .pdata
         .word __EH_CODE_START__
@ max 22 bits for number of instructions
         .word 0xc0000002 | (0xFFFFF << 8)

This is the entry for __EH_CODE_START__, which is defined as:

__EH_CODE_START__:
WinMainCRTStartup:
_mainCRTStartup:
         stmdb sp!, {r11, lr}
         ldr r11, _P__set_runtime_thread_mode
(...)

Meaning: __EH_CODE_START__ is an alias for WinMainCRTStartup.
Directly above you will find:

@ for kernel exception handler, must be directly before ___EH_CODE_START__
         FUNC_START __EH_HANDLER__
         .word _eh_handler @handler
         .word 0           @handler data

The SEH ABI states that the there will be an 8 byte entry directly before
the function start, which contains the pointer into the handler
(in this case _eh_handler, which is found in startup.c), and 4 bytes of
arbitrary to be passed to the handler.

> Pedro was mentioning src/newlib/* while Kevin asks for mingw32ce. Two
> different worlds.
> 

Both worlds exist on the CE galaxy.

> I have been looking into getting a generic exception handler to work for
> mingw32ce, but haven't had any success yet. This is a requirement for
> having any kind of exception handling - I am not very knowledgable about
> the differences between g++ and SEH. But right now, I think neither can
> work.
> 

What do you mean by neither?

The exception c++ model that both mingw32ce and cegcc use is the sjlj model.
It is similar with the SEH model on x86.  It certainly works.

SEH is an OS thing, so it always works, but it happens that registering
handlers manually is much harder on ARM than it is on x86/9x/NT.

You could try changing your main function to something like:

lib code:

static void (*seh_user_top_level_handler) (void);

void __seh_handler ()
{
        if (seh_top_level_handler)
                seh_top_level_handler();
        else
                (...);
}

int main()
{
        return __main_seh_wrapper (real_main);
}

void SetUnhandledExceptionFilter (void (*handler) (void))
{
        seh_user_top_level_handler = handler;
}


user code:

void my_handler ()
{
        MessageBox ("bad things happened");
        exit (1);
}

int real_main ()
{
        SetUnhandledExceptionFilter (my_handler);

        /* your app code here */
}

main_seh_wrapper would be implemented in asm, and would use
a similar technique as cegcc's crt0.S.  It would call
__seh_handler when an exception occurs, and __seh_handler would
call the user's registered handler.

The SetUnhandledExceptionFilter function name isn't arbitrary.
It is a real function on 9x/NT.

SEH is used internally by the OS dlls.  For example, the IsBadWritePtr function
I was suggesting to Kevin, internally does something like:

BOOL IsBadWritePtr(LPVOID lp, UINT_PTR ucb)
{
        __try
        {
                try to write to the the [lp ... lp + ucb[ range.
                return TRUE;
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
                return FALSE;
        }
}

(MSFT's compiler will trunslate the __try/__except s into those
tables.  Gcc doesn't.  This year, there is a google summer of code
project to implement it for x86.  Maybe someone will then port it
to x64, and then porting it to ARM will be "easy".  At least I
hope it will ;) )


IsBadWritePtr docs:
http://msdn2.microsoft.com/en-us/library/aa366716.aspx

So Kevin's code could be rewritten as something like:

while (wcount--)
{
        if (IsBadWritePtr (vaddr, sizeof (*vaddr)))
        {
            Complain (C_ERROR ("EXCEPTION while writing %08x to"
                        "address %08x"),
                      value, vaddr);
        }
        else
        {
              *vaddr = value;
        }
        ++vaddr;
}

I'm certainly not the best technical writer around, but I hope it
is clearer now.

Cheers,
Pedro Alves


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Cegcc-devel mailing list
Cegcc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/cegcc-devel

Reply via email to