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++ ?
function Get_Exception_Machine_Occurrence (X : Exception_Occurrence) return System.Address; pragma Export (Ada, Get_Exception_Machine_Occurrence,"__gnat_get_exception_machine_occurrence"); -- Get the machine occurrence corresponding to an exception occurrence. It is Null_Address if there is no machine occurrence (in runtimes tha doesn't use GCC mechanism) or if it has been lost (Save_Occurrence doesn't save the machine occurrence).- LoneWandererGNAT.Last_Exception(don't remember exactly) to get the last thrown exception. Not perfect in multithreaded environment, but would work most of the time (unfortunately the feature is broken, and being fixed at the current time, only for beta releases of the GNATPro edition, so not available to the public / GPL until 2019) - Jean-François Fabre