c++exceptiong++adagnat

how to get Ada exception message when catching from C++ handler?


Using GNAT Ada and Gnu C++, I'm interfacing an Ada piece of code with a c++ wrapper and I'd like to catch Ada exceptions properly when running this (stupid) code:

with ada.text_io;

package body ada_throw is

   procedure ada_throw is
   begin
      ada.text_io.put_line ("hello");
      raise program_error;
   end ada_throw;       

end ada_throw;

relevant spec code is:

package ada_throw is

   procedure ada_throw;
   pragma export (convention => C, entity => ada_throw, external_name => "ada_throw");

end ada_throw;

Whe doing this on the C++ side:

#include <iostream>

extern "C"
{
  void ada_throw();
  void adainit();
}

int main()
{
  adainit();
  ada_throw();
  std::cout << "end of program" << std::endl;
  return 0;
}

I'm getting this:

hello

raised PROGRAM_ERROR : ada_throw.adb:8 explicit raise

So the exception mechanism works, I don't get the last print of my C++ program and the return code is non-zero.

Now I want to catch the exception. If I use catch(...) it works, but I can't get the explicit error message anymore, so I tried this:

#include <iostream>
#include <cxxabi.h>
extern "C"
{
  void ada_throw();
  void adainit();
}

int main()
{
  adainit();

  try
  {
    ada_throw();
  }
  catch (abi::__foreign_exception const &e)
  {
    std::cout << "exception" << std::endl;        
  }

  std::cout << "end of program" << std::endl;
  return 0;
}

it works properly, I get:

hello
exception
end of program

The only catch is that abi::__foreign_exception doesn't have a what() method, so I cannot get hold of the meaningful error message.

And debugging the program to try to hack into e is also a dead end since it's just a null pointer with the proper type:

(gdb) p &e
$2 = (const __cxxabiv1::__foreign_exception *) 0x0

Is there a way to get it from the C++ ?


Solution

  • In Ada you can get information about an exception occurrence using the functions Ada.Exceptions.Exception_Name and Ada.Exceptions.Exception_Message, which are a part of the standard library. One option is to provide a thin binding to these two functions, and call them, when you need information about the exception. (Exactly how to map abi::__foreign_exception to Ada.Exceptions.Exception_ID is left as an exercise for the reader.)

    Another option is to make it explicit to the Ada compiler that you are writing C++ on the other side, and use CPP instead of C as your export convention. That may make the compiler provide exceptions, which C++ understands.

    This is only a partial answer, as I'm very much out of practice with C++, but I hope it can help you in the right direction.