I am working migrating an old c++ application from OpenVMS to linux. The application heavily uses the os functionalities and we are struggling to find similar ones in linux. One is global exception handle by the os system library function that is callable from c++ code. This function catches the exception and uses sys$unwind function (another OpenVMS system function) to unwind the stack and jumps back to previous point/ function before exception. One of the reasons it is done to prevent system to crash when it tries to access another application or resources that might be unavailable. So rather than failing or crashing the application it goes back to the previous point and tries again. I know its very risky and not ideal but I am looking for a similar library or function in c++/ linux.
I came across libunwind lib for linux but couldn't figure out how to use it to handle global exception and jump to a previous function. Any help will be greatly appreciated.
Too long for a comment, so ...
C++ has try-throw-catch. You need to understand for what and why the VMS exception handling was used. There is/was a reason. VMS applications usually do not use exception handling to fix a divide by zero exception or segmentation fault (aka ACCESS violation) and to continue from the exception. They usually return an error status to an parent function/routine. That means that checking and returning a status does not have to be coded in each intermediate function.
That is, one or more functions enable a (their own) handler. The application (or the OS) signals an (OS or application defined) error code. All of the handlers in the call chain are called and decide if they can/want to handle the error condition. One of the handlers decides to unwind the stack, usually to return an error code from the function in which it (the handler) was enabled. There is always a handler. There is at least one handler in the RTL or in the OS - the last chance handler that usually prints traceback information. While unwinding, all the handlers are called again so that they can do any necessary cleanup.
With the libunwind library you should be able to implement VMS's exception handling. I would not even think of trying to do this. I would rather use the C++ language constructs and adjust or rewrite the code with this. But again, you need to understand for what and why the VMS exception handling was used.
I don't want to start a another answer, so I add something here. A quick and dirty example:
/*
* cc -m64 -o ./unwind -L libunwind/src/.libs -lunwind -I libunwind/include/ unwind.c
*/
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define UNW_LOCAL_ONLY
#include <libunwind.h>
static void unwind (void) {
unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip;
char proc_name[128];
unw_word_t off;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
do {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_proc_name(&cursor, proc_name, sizeof proc_name, &off);
printf ("%s, %s, %lx\n", __func__, proc_name, (long) ip);
if (0==strcmp("foo",proc_name))
break;
} while (unw_step(&cursor) > 0);
unw_resume(&cursor);
printf ("%s, oh no, it didn't work\n", __func__);
}
static void foobarhandler (int sig) {
printf ("%s, sig %08x\n", __func__,sig);
unwind();
return;
}
static int foobar (void) {
signal(SIGTERM,foobarhandler);
printf ("%s\n", __func__);
printf ("%s, raise SIGTERM\n", __func__);
int s = raise(SIGTERM);
printf ("back in %s, s: %08x\n", __func__, s);
return 1;
}
static void bar (void) {
printf ("%s\n", __func__);
int s = foobar();
printf ("back in %s, s: %08x\n", __func__, s);
}
static int foo () {
printf ("%s\n", __func__);
bar();
printf ("back in %s\n", __func__);
return 4711;
}
int main (void) {
printf ("%s\n", __func__);
int status = foo();;
printf ("back in %s\n", __func__);
printf ("%s, foo: %08x\n", __func__, status);
return EXIT_SUCCESS;
}
Expected output is:
main
foo
bar
foobar
foobar, raise SIGTERM
foobarhandler, sig 0000000f
unwind, unwind, 4008dc
unwind, foobarhandler, 4009e1
unwind, killpg, 7f01e062b400
unwind, gsignal, 7f01e062b387
unwind, foobar, 400a23
unwind, bar, 400a5d
unwind, foo, 400a8f
back in foo
back in main
main, foo: 00001267
The printed IPs should match the code addresses in the function, but I didn't double check.
I didn't try C++, which will have mangled names and finding the target call frame is not as easy as in plain C.
To find and call handlers in the call chain you need personality routines (.cfi_personality), which you do not get in C and what C++ adds is probably a common handler in the RTL and not a user defined one as on VMS.