source: libcfa/src/interpose.cfa@ 20be782

ADT ast-experimental pthread-emulation
Last change on this file since 20be782 was 20be782, checked in by z277zhu <z277zhu@…>, 3 years ago

add pthread

  • Property mode set to 100644
File size: 14.3 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// interpose.c --
8//
9// Author : Thierry Delisle
10// Created On : Wed Mar 29 16:10:31 2017
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Mar 13 17:35:37 2020
13// Update Count : 178
14//
15
16#include <stdarg.h> // va_start, va_end
17#include <stdio.h>
18#include <string.h> // strlen
19#include <unistd.h> // _exit, getpid
20#define __USE_GNU
21#include <signal.h>
22#undef __USE_GNU
23extern "C" {
24#include <dlfcn.h> // dlopen, dlsym
25#include <execinfo.h> // backtrace, messages
26}
27
28#include "bits/debug.hfa"
29#include "bits/defs.hfa"
30#include "bits/signal.hfa" // sigHandler_?
31#include "startup.hfa" // STARTUP_PRIORITY_CORE
32#include <assert.h>
33
34//=============================================================================================
35// Interposing helpers
36//=============================================================================================
37
38static void preload_libgcc(void) {
39 dlopen( "libgcc_s.so.1", RTLD_NOW );
40 if ( const char * error = dlerror() ) abort( "interpose_symbol : internal error pre-loading libgcc, %s\n", error );
41}
42
43typedef void (* generic_fptr_t)(void);
44static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
45 const char * error;
46
47 static void * library;
48 static void * pthread_library;
49 if ( ! library ) {
50 #if defined( RTLD_NEXT )
51 library = RTLD_NEXT;
52 #else
53 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
54 library = dlopen( "libc.so.6", RTLD_LAZY );
55 error = dlerror();
56 if ( error ) {
57 abort( "interpose_symbol : failed to open libc, %s\n", error );
58 }
59 #endif
60 } // if
61 if ( ! pthread_library ) {
62 #if defined( RTLD_NEXT )
63 pthread_library = RTLD_NEXT;
64 #else
65 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
66 pthread_library = dlopen( "libpthread.so", RTLD_LAZY );
67 error = dlerror();
68 if ( error ) {
69 abort( "interpose_symbol : failed to open libpthread, %s\n", error );
70 }
71 #endif
72 } // if
73
74 union { generic_fptr_t fptr; void * ptr; } originalFunc;
75
76 #if defined( _GNU_SOURCE )
77 if ( version ) {
78 originalFunc.ptr = dlvsym( library, symbol, version );
79 } else {
80 originalFunc.ptr = dlsym( library, symbol );
81 }
82 #else
83 originalFunc.ptr = dlsym( library, symbol );
84 #endif // _GNU_SOURCE
85
86 error = dlerror();
87 if ( error ) {
88 originalFunc.ptr = dlsym( pthread_library, symbol );
89 error = dlerror();
90 if (error){
91 abort( "interpose_symbol : internal error, %s\n", error );
92 } // if
93 } // if
94
95 return originalFunc.fptr;
96}
97
98#define INTERPOSE_LIBC( x, ver ) __cabi_libc.x = (typeof(__cabi_libc.x))interpose_symbol( #x, ver )
99
100//=============================================================================================
101// Interposition Startup logic
102//=============================================================================================
103
104static void sigHandler_segv( __CFA_SIGPARMS__ );
105static void sigHandler_ill ( __CFA_SIGPARMS__ );
106static void sigHandler_fpe ( __CFA_SIGPARMS__ );
107static void sigHandler_abrt( __CFA_SIGPARMS__ );
108static void sigHandler_term( __CFA_SIGPARMS__ );
109
110static struct {
111 void (* exit)( int ) __attribute__(( __noreturn__ ));
112 void (* abort)( void ) __attribute__(( __noreturn__ ));
113 typeof(pthread_create) pthread_create;
114 typeof(pthread_join) pthread_join;
115 typeof(pthread_self) pthread_self;
116 typeof(pthread_attr_init) pthread_attr_init;
117 typeof(pthread_attr_setstack ) pthread_attr_setstack;
118 typeof(pthread_attr_destroy) pthread_attr_destroy;
119 typeof(pthread_attr_getstacksize) pthread_attr_getstacksize;
120 //typeof(pthread_sigmask) pthread_sigmask;
121 //typeof(pthread_sigqueue) pthread_sigqueue;
122} __cabi_libc;
123
124libcfa_public int cfa_main_returned;
125
126extern "C" {
127 void __cfaabi_interpose_startup( void ) {
128 const char *version = 0p;
129 cfa_main_returned = 0;
130
131 preload_libgcc();
132
133#pragma GCC diagnostic push
134#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
135 INTERPOSE_LIBC( abort, version );
136 INTERPOSE_LIBC( exit , version );
137 INTERPOSE_LIBC( pthread_create , version );
138 INTERPOSE_LIBC( pthread_join , version );
139 INTERPOSE_LIBC( pthread_self , version );
140 INTERPOSE_LIBC( pthread_attr_init , version );
141 INTERPOSE_LIBC( pthread_attr_destroy , version );
142 INTERPOSE_LIBC( pthread_attr_setstack , version );
143 INTERPOSE_LIBC( pthread_attr_getstacksize , version );
144 //INTERPOSE_LIBC( pthread_sigmask , version );
145 //INTERPOSE_LIBC( pthread_sigqueue , version );
146#pragma GCC diagnostic pop
147
148 // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
149 // task stacks might be very small (4K) and the signal delivery corrupts memory to the point that a clean
150 // shutdown is impossible. Also, when a stack overflow encounters the non-accessible sentinel page (debug only)
151 // and generates a segment fault, the signal cannot be delivered on the sentinel page. Finally, calls to abort
152 // print a stack trace that uses substantial stack space.
153
154 #define MINSTKSZ SIGSTKSZ * 8
155 static char stack[MINSTKSZ] __attribute__(( aligned (16) ));
156 static stack_t ss;
157
158 ss.ss_sp = stack;
159 ss.ss_size = MINSTKSZ;
160 ss.ss_flags = 0;
161 if ( sigaltstack( &ss, 0p ) == -1 ) {
162 abort( "__cfaabi_interpose_startup : internal error, sigaltstack error(%d) %s.", errno, strerror( errno ) );
163 } // if
164
165 // Failure handler
166 // internal errors
167 __cfaabi_sigaction( SIGSEGV, sigHandler_segv, SA_SIGINFO | SA_ONSTACK ); // Invalid memory reference (default: Core)
168 __cfaabi_sigaction( SIGBUS , sigHandler_segv, SA_SIGINFO | SA_ONSTACK ); // Bus error, bad memory access (default: Core)
169 __cfaabi_sigaction( SIGILL , sigHandler_ill , SA_SIGINFO | SA_ONSTACK ); // Illegal Instruction (default: Core)
170 __cfaabi_sigaction( SIGFPE , sigHandler_fpe , SA_SIGINFO | SA_ONSTACK ); // Floating-point exception (default: Core)
171
172 // handlers to outside errors
173 // reset in-case they insist and send it over and over
174 __cfaabi_sigaction( SIGTERM, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Termination signal (default: Term)
175 __cfaabi_sigaction( SIGINT , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Interrupt from keyboard (default: Term)
176 __cfaabi_sigaction( SIGHUP , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Hangup detected on controlling terminal or death of controlling process (default: Term)
177 __cfaabi_sigaction( SIGQUIT, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Quit from keyboard (default: Core)
178 __cfaabi_sigaction( SIGABRT, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Abort signal from abort(3) (default: Core)
179 }
180}
181
182//=============================================================================================
183// Terminating Signals logic
184//=============================================================================================
185
186// Forward declare abort after the __typeof__ call to avoid ambiguities
187libcfa_public void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
188libcfa_public void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
189libcfa_public void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
190libcfa_public void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
191
192extern "C" {
193 libcfa_public void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
194 abort( false, "%s", "" );
195 }
196
197 libcfa_public void __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {
198 va_list argp;
199 va_start( argp, fmt );
200 __abort( false, fmt, argp );
201 va_end( argp );
202 }
203
204 libcfa_public void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
205 __cabi_libc.exit( status );
206 }
207
208 libcfa_public int real_pthread_create(pthread_t *_thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg){
209 return __cabi_libc.pthread_create(_thread, attr, start_routine, arg);
210 }
211
212 libcfa_public int real_pthread_join(pthread_t _thread, void **retval){
213 return __cabi_libc.pthread_join(_thread, retval);
214 }
215
216 libcfa_public pthread_t real_pthread_self(void){
217 return __cabi_libc.pthread_self();
218 }
219 libcfa_public int real_pthread_attr_init(pthread_attr_t *attr){
220 return __cabi_libc.pthread_attr_init(attr);
221 }
222 libcfa_public int real_pthread_attr_destroy(pthread_attr_t *attr){
223 return __cabi_libc.pthread_attr_destroy(attr);
224 }
225 libcfa_public int real_pthread_attr_setstack( pthread_attr_t *attr, void *stackaddr, size_t stacksize ){
226 return __cabi_libc.pthread_attr_setstack(attr, stackaddr, stacksize);
227 }
228 libcfa_public int read_pthread_attr_getstacksize( const pthread_attr_t *attr, size_t *stacksize ){
229 return __cabi_libc.pthread_attr_getstacksize(attr, stacksize);
230 }
231 // libcfa_public int real_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset){
232 // return __cabi_libc.pthread_sigmask(how, set, oldset);
233 // }
234 // libcfa_public int real_pthread_sigqueue(pthread_t _thread, int sig, const union sigval value){
235 // return __cabi_libc.real_pthread_sigqueue(_thread, sig, value);
236 // }
237}
238
239// See concurrency/kernel.cfa and concurrency/preemption.cfa for strong definition used in multi-processor mode.
240void __kernel_abort_lock( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
241void __kernel_abort_msg( char buffer[], int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
242int __kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
243
244enum { abort_text_size = 1024 };
245static char abort_text[ abort_text_size ];
246
247static void __cfaabi_backtrace( int start ) {
248 enum { Frames = 50, }; // maximum number of stack frames
249 int last = __kernel_abort_lastframe(); // skip last N stack frames
250
251 void * array[Frames];
252 size_t size = backtrace( array, Frames );
253 char ** messages = backtrace_symbols( array, size ); // does not demangle names
254
255 *index( messages[0], '(' ) = '\0'; // find executable name
256 __cfaabi_bits_print_nolock( STDERR_FILENO, "Stack back trace for: %s\n", messages[0]);
257
258 for ( unsigned int i = start; i < size - last && messages != 0p; i += 1 ) {
259 char * name = 0p, * offset_begin = 0p, * offset_end = 0p;
260
261 for ( char * p = messages[i]; *p; p += 1 ) { // find parantheses and +offset
262 //__cfaabi_bits_print_nolock( "X %s\n", p);
263 if ( *p == '(' ) {
264 name = p;
265 } else if ( *p == '+' ) {
266 offset_begin = p;
267 } else if ( *p == ')' ) {
268 offset_end = p;
269 break;
270 }
271 }
272
273 // if line contains symbol, print it
274 int frameNo = i - start;
275 if ( name && offset_begin && offset_end && name < offset_begin ) {
276 *name++ = '\0'; // delimit strings
277 *offset_begin++ = '\0';
278 *offset_end++ = '\0';
279
280 __cfaabi_bits_print_nolock( STDERR_FILENO, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
281 } else { // otherwise, print the whole line
282 __cfaabi_bits_print_nolock( STDERR_FILENO, "(%i) %s\n", frameNo, messages[i] );
283 }
284 }
285 free( messages );
286}
287
288void exit( int status, const char fmt[], ... ) {
289 va_list args;
290 va_start( args, fmt );
291 vfprintf( stderr, fmt, args );
292 va_end( args );
293 __cabi_libc.exit( status );
294}
295
296static volatile bool __abort_first = 0;
297
298// Cannot forward va_list.
299void __abort( bool signalAbort, const char fmt[], va_list args ) {
300 // Multiple threads can come here from multiple paths
301 // To make sure this is safe any concurrent/subsequent call to abort is redirected to libc-abort
302 bool first = ! __atomic_test_and_set( &__abort_first, __ATOMIC_SEQ_CST);
303
304 // Prevent preemption from kicking-in and messing with the abort
305 __kernel_abort_lock();
306
307 // first to abort ?
308 if ( !first ) {
309 // We aren't the first to abort just let C handle it
310 signal( SIGABRT, SIG_DFL ); // restore default in case we came here through the function.
311 __cabi_libc.abort();
312 }
313
314 int len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
315 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
316
317 // print the cause of the error
318 assert( fmt );
319 len = vsnprintf( abort_text, abort_text_size, fmt, args );
320 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
321
322 // add optional newline if missing at the end of the format text
323 if ( fmt[strlen( fmt ) - 1] != '\n' ) {
324 __cfaabi_bits_write( STDERR_FILENO, "\n", 1 );
325 } // if
326
327 // Give the kernel the chance to add some data in here
328 __kernel_abort_msg( abort_text, abort_text_size );
329
330 // print stack trace in handler
331 __cfaabi_backtrace( signalAbort ? 4 : 2 );
332
333 // Finally call abort
334 __cabi_libc.abort();
335
336}
337
338void abort( const char fmt[], ... ) {
339 va_list args;
340 va_start( args, fmt );
341 __abort( false, fmt, args );
342 // CONTROL NEVER REACHES HERE!
343 va_end( args );
344}
345
346void abort( bool signalAbort, const char fmt[], ... ) {
347 va_list args;
348 va_start( args, fmt );
349 __abort( signalAbort, fmt, args );
350 // CONTROL NEVER REACHES HERE!
351 va_end( args );
352}
353
354void sigHandler_segv( __CFA_SIGPARMS__ ) {
355 if ( sfp->si_addr == 0p ) {
356 abort( true, "Null pointer (0p) dereference.\n" );
357 } else {
358 abort( true, "%s at memory location %p.\n"
359 "Possible cause is reading outside the address space or writing to a protected area within the address space with an invalid pointer or subscript.\n",
360 (sig == SIGSEGV ? "Segment fault" : "Bus error"), sfp->si_addr );
361 }
362}
363
364void sigHandler_ill( __CFA_SIGPARMS__ ) {
365 abort( true, "Executing illegal instruction at location %p.\n"
366 "Possible cause is stack corruption.\n",
367 sfp->si_addr );
368}
369
370void sigHandler_fpe( __CFA_SIGPARMS__ ) {
371 const char * msg;
372
373 choose( sfp->si_code ) {
374 case FPE_INTDIV, FPE_FLTDIV: msg = "divide by zero";
375 case FPE_FLTOVF: msg = "overflow";
376 case FPE_FLTUND: msg = "underflow";
377 case FPE_FLTRES: msg = "inexact result";
378 case FPE_FLTINV: msg = "invalid operation";
379 default: msg = "unknown";
380 } // choose
381 abort( true, "Computation error %s at location %p.\n", msg, sfp->si_addr );
382}
383
384void sigHandler_term( __CFA_SIGPARMS__ ) {
385 abort( true, "Application interrupted by signal: %s.\n", strsignal( sig ) );
386}
387
388// Local Variables: //
389// mode: c //
390// tab-width: 4 //
391// End: //
Note: See TracBrowser for help on using the repository browser.