C++ exceptions in freebsd-arm doesn't seem to work

Olavi Kumpulainen olavi.m.kumpulainen at gmail.com
Sat Jun 7 12:12:49 UTC 2014


Hi there,

If this question has been discussed before, sorry. I couldn’t find anything when scanning through the archives though.

So, I’m running FreeBSD-10/stable on a RPI version B as you can see here;


Copyright (c) 1992-2014 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
        The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 10.0-STABLE #0 r266807: Thu May 29 07:07:08 UTC 2014
    root at grind.freebsd.org:/usr/obj/arm.armv6/usr/src/sys/RPI-B arm
FreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512


I have this little program;

$ cat t.cc

#include <stdexcept>
#include <iostream>

void func() 
{
	throw std::exception();
}


int main()
{
	std::cout << "Starting throw-test" << std::endl;

	try
	{
		func();
	}
	catch(std::exception){
		std::cout << “In my exception handler" << std::endl;
	}
        catch(...) {
                std::cout << "In catch-all handler" << std::endl;
        }

	return 0;
}

With this Makefile;

$ cat Makefile

all : t

t : t.cc
	c++ -o t -fexceptions t.cc


Running the above produces the following result;

$ ./t
Starting throw-test
Fatal error during phase 1 unwinding
Abort (core dumped)

Which indeed is not what I expected.

I’ve tried debugging this for a couple of days and have concluded that my throw clause ends up in contrib/gcc/config/arm/unwind-arm.c. The associated code in unwind-arm.c is;

static _Unwind_Reason_Code
get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address)
{
  const __EIT_entry * eitp;
  int nrec;
  
  /* The return address is the address of the instruction following the
     call instruction (plus one in thumb mode).  If this was the last
     instruction in the function the address will lie in the following
     function.  Subtract 2 from the address so that it points within the call
     instruction itself.  */
  return_address -= 2;

  if (__gnu_Unwind_Find_exidx)
    {
      eitp = (const __EIT_entry *) __gnu_Unwind_Find_exidx (return_address,
							    &nrec);
      if (!eitp)
	{
	  UCB_PR_ADDR (ucbp) = 0;
	  return _URC_FAILURE;
	}
    }
  else
    {
      eitp = &__exidx_start;
      nrec = &__exidx_end - &__exidx_start;
    }


Since __gnu_Unwind_Find_exidx == NULL, the EIT is located in an array located between __exidx_start and __exidx_end.

However, __exidx_end == __exidx_start! So the EIT has a length of zero, nrec will be 0. libgcc will fail the lookup and return _URC_FAILURE to libcxxrt.cc, which in turn will produce the fprintf(stderr, "Fatal error during phase 1 unwinding\n");

# readelf -s t | grep exidx
    36: 0000a267     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_start
    47: 0000a267     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_end
   115: 0000a267     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_end
   150: 0000a267     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_start

So exception throwing in clang++ doesn’t seem to work.

Can any of you guys shed some light on this?

Cheers,

/Olavi




More information about the freebsd-arm mailing list