1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #define TRACK_REFERENCES 0
28
29 #include "va_copy.h"
30 #include "sysdir-priv.h"
31
32 #include <kfs/extern.h>
33 #include <kfs/dyload.h>
34 #include <kfs/directory.h>
35 #include <klib/refcount.h>
36 #include <klib/vector.h>
37 #include <klib/text.h>
38 #include <klib/printf.h>
39 #include <klib/out.h>
40 #include <klib/log.h>
41 #include <klib/status.h>
42 #include <klib/debug.h>
43 #include <klib/rc.h>
44 #include <sysalloc.h>
45
46 #include "os-native.h"
47
48 #ifdef __GNUC__
49 #pragma GCC diagnostic ignored "-Wpedantic"
50 #endif
51
52 /* old Sun includes won't define PATH_MAX */
53
54 #ifndef __XOPEN_OR_POSIX
55 #define __XOPEN_OR_POSIX 1
56 #endif
57
58 #include <limits.h>
59
60 #undef __XOPEN_OR_POSIX
61
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <string.h>
65 #include <errno.h>
66 #include <assert.h>
67
68 #include <dlfcn.h>
69
70
71 #if _DEBUGGING
72 #define DLOPEN_MODE RTLD_NOW
73 #else
74 #define DLOPEN_MODE RTLD_LAZY
75 #endif
76
77 #define ALWAYS_ADD_EXE 1
78 #define USE_DYLOAD 1
79
80 /* PATH_MAX is not really universal even on Linux/Unix */
81 #ifndef PATH_MAX
82 #define PATH_MAX 4096
83 #endif
84
85 /*--------------------------------------------------------------------------
86 * KDirectory
87 */
88 static
KDirRefRelease(void * item,void * ignore)89 void KDirRefRelease ( void *item, void *ignore )
90 {
91 KDirectoryRelease ( ( const void* ) item );
92 }
93
94 /*--------------------------------------------------------------------------
95 * KDyld
96 * dynamic library loader
97 *
98 * maintains cache of libraries it has opened while they remain open
99 * such that subsequent requests for an open library will return a
100 * new reference to the existing library.
101 */
102 struct KDyld
103 {
104 Vector search;
105 KRefcount refcount;
106 };
107
108
109 /* Whack
110 */
111 static
KDyldWhack(KDyld * self)112 rc_t KDyldWhack ( KDyld *self )
113 {
114 KRefcountWhack ( & self -> refcount, "KDyld" );
115
116 VectorWhack ( & self -> search, KDirRefRelease, NULL );
117 free ( self );
118
119 return 0;
120 }
121
122
123 /* Make
124 * create a dynamic loader object
125 *
126 * "dl" [ OUT ] - return parameter for loader
127 */
KDyldMake(KDyld ** dlp)128 LIB_EXPORT rc_t CC KDyldMake ( KDyld **dlp )
129 {
130 rc_t rc;
131
132 if ( dlp == NULL )
133 rc = RC ( rcFS, rcDylib, rcConstructing, rcParam, rcNull );
134 else
135 {
136 KDyld *dl = malloc ( sizeof * dl );
137 if ( dl == NULL )
138 rc = RC ( rcFS, rcDylib, rcConstructing, rcMemory, rcExhausted );
139 else
140 {
141 VectorInit ( & dl -> search, 1, 8 );
142 KRefcountInit ( & dl -> refcount, 1, "KDyld", "make", "dl" );
143
144 * dlp = dl;
145 return 0;
146 }
147
148 * dlp = NULL;
149 }
150
151 return rc;
152 }
153
154
155 /* AddRef
156 * Release
157 */
KDyldAddRef(const KDyld * self)158 LIB_EXPORT rc_t CC KDyldAddRef ( const KDyld *self )
159 {
160 if ( self != NULL )
161 {
162 switch ( KRefcountAdd ( & self -> refcount, "KDyld" ) )
163 {
164 case krefLimit:
165 return RC ( rcFS, rcDylib, rcAttaching, rcRange, rcExcessive );
166 }
167 }
168 return 0;
169 }
170
KDyldRelease(const KDyld * self)171 LIB_EXPORT rc_t CC KDyldRelease ( const KDyld *self )
172 {
173 if ( self != NULL )
174 {
175 switch ( KRefcountDrop ( & self -> refcount, "KDyld" ) )
176 {
177 case krefWhack:
178 return KDyldWhack ( ( KDyld* ) self );
179 case krefNegative:
180 return RC ( rcFS, rcDylib, rcReleasing, rcRange, rcExcessive );
181 }
182 }
183 return 0;
184 }
185
186
187 /* Attach
188 * Sever
189 */
190 static
KDyldAttach(const KDyld * self)191 KDyld *KDyldAttach ( const KDyld *self )
192 {
193 if ( self != NULL )
194 {
195 switch ( KRefcountAddDep ( & self -> refcount, "KDyld" ) )
196 {
197 case krefLimit:
198 return NULL;
199 }
200 }
201 return ( KDyld* ) self;
202 }
203
204 static
KDyldSever(const KDyld * self)205 rc_t KDyldSever ( const KDyld *self )
206 {
207 if ( self != NULL )
208 {
209 switch ( KRefcountDropDep ( & self -> refcount, "KDyld" ) )
210 {
211 case krefWhack:
212 return KDyldWhack ( ( KDyld* ) self );
213 case krefNegative:
214 return RC ( rcFS, rcDylib, rcReleasing, rcRange, rcExcessive );
215 }
216 }
217 return 0;
218 }
219
220
221 /* AddSearchPath
222 * add a search path to loader for locating library files
223 */
KDyldVAddSearchPath(KDyld * self,const char * path,va_list args)224 LIB_EXPORT rc_t CC KDyldVAddSearchPath ( KDyld *self, const char *path, va_list args )
225 {
226 rc_t rc;
227 if ( self == NULL )
228 rc = RC ( rcFS, rcDylib, rcUpdating, rcSelf, rcNull );
229 else
230 {
231 KDirectory *wd;
232 rc = KDirectoryNativeDir ( & wd );
233 if ( rc == 0 )
234 {
235 const KDirectory *dir;
236 rc = KDirectoryVOpenDirRead ( wd, & dir, false, path, args );
237 if ( rc == 0 )
238 {
239 rc = VectorAppend ( & self -> search, NULL, dir );
240 if ( rc != 0 )
241 KDirectoryRelease ( dir );
242 }
243
244 KDirectoryRelease ( wd );
245 }
246 }
247 return rc;
248 }
249
KDyldAddSearchPath(KDyld * self,const char * path,...)250 LIB_EXPORT rc_t CC KDyldAddSearchPath ( KDyld *self, const char *path, ... )
251 {
252 rc_t rc;
253 va_list args;
254
255 va_start ( args, path );
256 rc = KDyldVAddSearchPath ( self, path, args );
257 va_end ( args );
258
259 return rc;
260 }
261
262 static
KDyldForEach(const KDyld * self,void (* f)(const KDirectory * dir,void * data),void * data)263 void KDyldForEach ( const KDyld *self,
264 void ( * f ) ( const KDirectory *dir, void *data ), void *data )
265 {
266 VectorForEach ( & self -> search, false,
267 ( void ( * ) ( void*, void* ) ) f, data );
268 }
269
270
271 /* HomeDirectory
272 * returns a KDirectory where the binary for a given function is located
273 *
274 * "dir" [ OUT ] - return parameter for home directory ( read-only ), if found
275 *
276 * "func" [ IN ] - function pointer within binary to be located
277 */
KDyldHomeDirectory(const KDyld * self,const KDirectory ** dir,fptr_t func)278 LIB_EXPORT rc_t CC KDyldHomeDirectory ( const KDyld *self, const KDirectory **dir, fptr_t func )
279 {
280 rc_t rc;
281
282 if ( dir == NULL )
283 rc = RC ( rcFS, rcDylib, rcSearching, rcParam, rcNull );
284 else
285 {
286 * dir = NULL;
287
288 if ( self == NULL )
289 rc = RC ( rcFS, rcDylib, rcSearching, rcSelf, rcNull );
290 else if ( func == NULL )
291 rc = RC ( rcFS, rcDylib, rcSearching, rcFunction, rcNull );
292 else
293 {
294 Dl_info info;
295 memset ( & info, 0, sizeof info );
296 if ( dladdr ( ( void* ) func, & info ) == 0 )
297 rc = RC ( rcFS, rcDylib, rcSearching, rcFunction, rcNotFound );
298 else
299 {
300 KDirectory *wd;
301 rc = KDirectoryNativeDir ( & wd );
302 if ( rc == 0 )
303 {
304 /* turn this into a real path */
305 const KSysDir *sdir = KDirectoryGetSysDir ( wd );
306 if ( sdir == NULL )
307 rc = RC ( rcFS, rcDylib, rcSearching, rcDirectory, rcIncorrect );
308 else
309 {
310 /* "dladdr" will return a simple name rather than a path
311 when the address is within the application itself and
312 the application was found using PATH. this is brilliant
313 design at its best. */
314 char thanks_for_brilliant_APIs [ PATH_MAX ];
315 const char *dli_fname = info . dli_fname;
316
317 /* check for a path rather than a name */
318 const char *last_slash = strrchr ( info . dli_fname, '/' );
319 if ( last_slash == NULL )
320 {
321 /* simple name - get PATH */
322 const char *PATH = getenv ( "PATH" );
323 rc = RC ( rcFS, rcDylib, rcSearching, rcPath, rcNotFound );
324 if ( PATH != NULL )
325 {
326 /* loop over PATH */
327 const char *path_start, *path_end;
328 for ( path_start = PATH;; path_start = path_end + 1 )
329 {
330 /* look for non-empty directory */
331 path_end = strchr ( path_start, ':' );
332 if ( path_start != path_end && path_start [ 0 ] != 0 )
333 {
334 rc_t rc2;
335 uint32_t path_type;
336
337 /* handle last element in list */
338 if ( path_end == NULL )
339 last_slash = path_start + strlen ( path_start );
340 else for ( last_slash = path_end; last_slash > path_start; -- last_slash )
341 {
342 if ( last_slash [ -1 ] != '/' )
343 break;
344 }
345
346 /* create possible path, using up to ':' */
347 rc2 = string_printf ( thanks_for_brilliant_APIs, sizeof thanks_for_brilliant_APIs, NULL,
348 "%.*s/%s", ( int ) ( last_slash - path_start ), path_start, dli_fname );
349
350 /* if failed to create path string */
351 if ( rc2 != 0 )
352 break;
353
354 /* check path against working directory */
355 path_type = KDirectoryPathType ( wd, "%s", thanks_for_brilliant_APIs );
356 if ( ( path_type & ~ kptAlias ) == kptFile )
357 {
358 uint32_t access = 0;
359 rc = KDirectoryAccess ( wd, & access, "%s", thanks_for_brilliant_APIs );
360 if ( rc != 0 )
361 break;
362
363 /* try to do a quick check that the file can be executed.
364 but it could fail to do the right guess. */
365 if ( access & 0100 || access & 0010 || access & 0001 ) {
366 /* this is a file, which can be assumed to be an executable */
367 dli_fname = thanks_for_brilliant_APIs;
368 last_slash
369 = & thanks_for_brilliant_APIs [ last_slash - path_start ];
370 rc = 0;
371 break;
372 }
373 }
374 }
375
376 /* exit if no more paths */
377 if ( path_end == NULL )
378 break;
379 }
380 }
381 }
382
383 if ( rc == 0 )
384 {
385 char real [ PATH_MAX ];
386 rc = KSysDirRealPath ( sdir, real, sizeof real, "%.*s"
387 , ( int ) ( last_slash - dli_fname ), dli_fname );
388
389 if ( rc == 0 )
390 rc = KDirectoryOpenDirRead ( wd, dir, false, "%s", real );
391
392 DBGMSG(DBG_KFS, DBG_FLAG(DBG_KFS_DIR), ("%s: %R path is '%s'\n", __func__, rc, real));
393 }
394 }
395
396 KDirectoryRelease ( wd );
397 }
398 }
399 }
400 }
401
402 return rc;
403 }
404
405
406 /*--------------------------------------------------------------------------
407 * KDylib
408 * Unix dynamic library
409 */
410 struct KDylib
411 {
412 void *handle;
413 String path;
414 KRefcount refcount;
415 };
416
417
418 /* Whack
419 */
420 static
KDylibWhack(KDylib * self)421 rc_t KDylibWhack ( KDylib *self )
422 {
423 KRefcountWhack ( & self -> refcount, "KDylib" );
424
425
426 /* Darwin, especially before 10.5 doesn't/didn't do this well */
427 #if ! MAC
428 /* try to close library */
429 if ( self -> handle && dlclose ( self -> handle ) )
430 {
431 /* report error */
432 const char *msg = dlerror ();
433 rc_t rc = RC ( rcFS, rcDylib, rcClosing, rcNoObj, rcUnknown );
434 LOGERR ( klogInt, rc, msg );
435 ( void ) msg;
436
437 return rc;
438 }
439 #endif
440 free ( self );
441 return 0;
442 }
443
444
445 /* Make
446 */
447 static
KDylibMake(KDylib ** libp,const String * path)448 rc_t KDylibMake ( KDylib **libp, const String *path )
449 {
450 KDylib *lib = malloc ( sizeof * lib + path -> size + 1 );
451 if ( lib == NULL )
452 return RC ( rcFS, rcDylib, rcConstructing, rcMemory, rcExhausted );
453
454 lib -> handle = NULL;
455 string_copy ( ( char* ) ( lib + 1 ), path -> size + 1, path -> addr, path -> size );
456 StringInit ( & lib -> path, ( char* ) ( lib + 1 ), path -> size, path -> len );
457 KRefcountInit ( & lib -> refcount, 1, "KDylib", "make", lib -> path . addr );
458
459 * libp = lib;
460 return 0;
461 }
462
463
464 /* SetLogging
465 */
466 static
KDylibSetLogging(const KDylib * self)467 rc_t KDylibSetLogging ( const KDylib *self )
468 {
469 rc_t ( CC * set_formatter ) ( KFmtWriter writer, KLogFmtFlags flags, void *data );
470 rc_t ( CC * set_writer ) ( KWrtWriter writer, void *data );
471 rc_t ( CC * set_level ) ( KLogLevel lvl );
472
473 if ( ! self -> handle )
474 {
475 return 0;
476 }
477
478 /* set the current logging level */
479 set_level = ( rc_t ( * ) ( KLogLevel ) ) dlsym ( self -> handle, "KLogLevelSet" );
480 if ( set_level != NULL )
481 {
482 KLogLevel lvl = KLogLevelGet ();
483 ( * set_level ) ( lvl );
484 }
485
486 /* determine current library logging */
487 set_writer = ( rc_t ( * ) ( KWrtWriter, void* ) ) dlsym ( self -> handle, "KOutHandlerSet" );
488 if ( set_writer != NULL ) {
489 const KWrtHandler* handler = KOutHandlerGet ();
490 ( * set_writer ) ( handler -> writer, handler -> data );
491 }
492
493 set_formatter = ( rc_t ( * ) ( KFmtWriter, KLogFmtFlags, void* ) ) dlsym ( self -> handle, "KLogLibFmtHandlerSet" );
494 if ( set_formatter != NULL ) {
495 KLogFmtFlags flags = KLogLibFmtFlagsGet ();
496 const KFmtHandler* fmt_handler = KLogFmtHandlerGet ();
497 ( * set_formatter ) ( fmt_handler -> formatter, flags, fmt_handler -> data );
498 }
499 set_writer = ( rc_t ( * ) ( KWrtWriter, void* ) ) dlsym ( self -> handle, "KLogLibHandlerSet" );
500 if ( set_writer != NULL ) {
501 const KWrtHandler* handler = KLogLibHandlerGet ();
502 ( * set_writer ) ( handler -> writer, handler -> data );
503 }
504
505 set_formatter = ( rc_t ( * ) ( KFmtWriter, KLogFmtFlags, void* ) ) dlsym ( self -> handle, "KStsLibFmtHandlerSet" );
506 if ( set_formatter != NULL ) {
507 KStsFmtFlags flags = KStsLibFmtFlagsGet ();
508 const KFmtHandler* fmt_handler = KStsFmtHandlerGet ();
509 ( * set_formatter ) ( fmt_handler -> formatter, flags, fmt_handler -> data );
510 }
511 set_writer = ( rc_t ( * ) ( KWrtWriter, void* ) ) dlsym ( self -> handle, "KStsLibHandlerSet" );
512 if ( set_writer != NULL ) {
513 const KWrtHandler* handler = KStsLibHandlerGet ();
514 ( * set_writer ) ( handler -> writer, handler -> data );
515 }
516 #if _DEBUGGING
517 set_writer = ( rc_t ( * ) ( KWrtWriter, void* ) ) dlsym ( self -> handle, "KDbgHandlerSet" );
518 if ( set_writer != NULL ) {
519 const KWrtHandler* handler = KDbgHandlerGet ();
520 ( * set_writer ) ( handler -> writer, handler -> data );
521 }
522 #endif
523 return 0;
524 }
525
526 /* LoadLib
527 * load a dynamic library
528 *
529 * "lib" [ OUT ] - return parameter for loaded library
530 *
531 * "path" [ IN ] - NUL terminated string in directory-native
532 * character set denoting target library
533 */
534 static
KDyldLoad(KDyld * self,KDylib * lib,const char * path)535 rc_t KDyldLoad ( KDyld *self, KDylib *lib, const char *path )
536 {
537 /* (VDB-1391) remove dynamic linker interfaces from system */
538 #if USE_DYLOAD
539 rc_t rc;
540 const char *msg;
541 size_t msg_len;
542
543 lib -> handle = dlopen ( path, path == NULL ? RTLD_LAZY : DLOPEN_MODE );
544 if ( lib -> handle != NULL )
545 return KDylibSetLogging ( lib );
546
547 msg = dlerror ();
548 rc = RC ( rcFS, rcDylib, rcLoading, rcNoObj, rcUnknown );
549
550 msg_len = strlen(msg);
551 if ( msg_len > lib -> path . size + 2 )
552 {
553 const char *cmp = & msg [ lib -> path . size + 2 ];
554 if ( strcmp ( cmp, "cannot open shared object file: No such file or directory" ) == 0 )
555 rc = RC ( rcFS, rcDylib, rcLoading, rcPath, rcNotFound );
556 else if ( strncmp ( cmp, "undefined symbol: ", sizeof "undefined symbol: " - 1 ) == 0 )
557 rc = RC ( rcFS, rcDylib, rcLoading, rcDylib, rcIncomplete );
558 }
559 if (GetRCState(rc) == rcUnknown) {
560 static const char imageNotFound[] = " image not found";
561 const char *cmp1 = strstr(msg, imageNotFound);
562 const char *cmp2 = msg + msg_len - (sizeof(imageNotFound) - 1);
563 if (cmp1 == cmp2)
564 rc = RC ( rcFS, rcDylib, rcLoading, rcPath, rcNotFound );
565 }
566
567 DBGMSG (DBG_KFS, DBG_FLAG(DBG_KFS_DLL), ("%s: %R %s\n", __func__, rc, msg));
568 if (GetRCState(rc) == rcUnknown) {
569 (void)LOGMSG(klogWarn, (msg));
570 }
571
572 return rc;
573 #else
574 lib -> handle = NULL;
575 return 0;
576 #endif
577 }
578
579 static
KDyldVTryLoadLib(KDyld * self,KDylib ** lib,const KDirectory * dir,const char * path,va_list args)580 rc_t KDyldVTryLoadLib ( KDyld *self, KDylib **lib,
581 const KDirectory *dir, const char *path, va_list args )
582 {
583 rc_t rc;
584
585 const KSysDir *sdir = KDirectoryGetSysDir ( dir );
586 if ( sdir == NULL )
587 rc = RC ( rcFS, rcDylib, rcLoading, rcDirectory, rcIncorrect );
588 else
589 {
590 char real [ PATH_MAX ];
591 rc = KSysDirVRealPath ( sdir, real, sizeof real, path, args );
592 if ( rc == 0 )
593 {
594 String pstr;
595 StringInitCString ( & pstr, real );
596
597 rc = KDylibMake ( lib, & pstr );
598 if ( rc == 0 )
599 {
600 rc = KDyldLoad ( self, * lib, real );
601 if ( rc == 0 )
602 return 0;
603
604 free ( * lib );
605 }
606 }
607 }
608
609 * lib = NULL;
610
611 return rc;
612 }
613
614 static
KDyldTryLoadLib(KDyld * self,KDylib ** lib,const KDirectory * dir,const char * path,...)615 rc_t KDyldTryLoadLib ( KDyld *self, KDylib **lib,
616 const KDirectory *dir, const char *path, ... )
617 {
618 rc_t rc;
619 va_list args;
620 va_start ( args, path );
621 rc = KDyldVTryLoadLib ( self, lib, dir, path, args );
622 va_end ( args );
623 return rc;
624 }
625
KDyldVLoadLib(KDyld * self,KDylib ** lib,const char * path,va_list args)626 LIB_EXPORT rc_t CC KDyldVLoadLib ( KDyld *self,
627 KDylib **lib, const char *path, va_list args )
628 {
629 rc_t rc;
630
631 if ( lib == NULL )
632 rc = RC ( rcFS, rcDylib, rcLoading, rcParam, rcNull );
633 else
634 {
635 if ( self == NULL )
636 rc = RC ( rcFS, rcDylib, rcLoading, rcSelf, rcNull );
637 else if ( path == NULL || path [ 0 ] == 0 )
638 {
639 String pstr;
640 CONST_STRING ( & pstr, "" );
641
642 rc = KDylibMake ( lib, & pstr );
643 if ( rc == 0 )
644 {
645 rc = KDyldLoad ( self, * lib, NULL );
646 if ( rc == 0 )
647 return 0;
648
649 free ( * lib );
650 }
651 }
652 else
653 {
654 uint32_t i = VectorStart ( & self -> search );
655 uint32_t end = i + VectorLength ( & self -> search );
656
657 if ( i == end )
658 {
659 char name [ 4096 ];
660 /* VDB-4386: cannot treat va_list as a pointer!*/
661 int len = 0;
662 if ( path != NULL ) /*( args == NULL ) ? snprintf ( name, sizeof name, "%s", path ) :*/
663 len = vsnprintf ( name, sizeof name, path, args );
664 if ( len < 0 || len >= sizeof name )
665 rc = RC ( rcFS, rcDylib, rcLoading, rcPath, rcExcessive );
666 else
667 {
668 String pstr;
669 StringInit ( & pstr, name, len, string_len ( name, len ) );
670
671 rc = KDylibMake ( lib, & pstr );
672 if ( rc == 0 )
673 {
674 rc = KDyldLoad ( self, * lib, name );
675 if ( rc == 0 )
676 return 0;
677
678 free ( * lib );
679 }
680 }
681 }
682 else
683 {
684 for ( * lib = NULL; i < end; ++ i )
685 {
686 const KDirectory *dir;
687
688 va_list cpy;
689 va_copy ( cpy, args );
690
691 dir = ( const void* ) VectorGet ( & self -> search, i );
692 rc = KDyldVTryLoadLib ( self, lib, dir, path, cpy );
693
694 va_end ( cpy );
695
696 if ( rc == 0 || GetRCState ( rc ) != rcNotFound )
697 return rc;
698 }
699
700 rc = RC ( rcFS, rcDylib, rcLoading, rcPath, rcNotFound );
701 }
702 }
703
704 * lib = NULL;
705 }
706
707 return rc;
708 }
709
KDyldLoadLib(KDyld * self,KDylib ** lib,const char * path,...)710 LIB_EXPORT rc_t CC KDyldLoadLib ( KDyld *self,
711 KDylib **lib, const char *path, ... )
712 {
713 rc_t rc;
714 va_list args;
715
716 va_start ( args, path );
717 rc = KDyldVLoadLib ( self, lib, path, args );
718 va_end ( args );
719
720 return rc;
721 }
722
723
724 /* AddRef
725 * Release
726 */
KDylibAddRef(const KDylib * self)727 LIB_EXPORT rc_t CC KDylibAddRef ( const KDylib *self )
728 {
729 if ( self != NULL )
730 {
731 switch ( KRefcountAdd ( & self -> refcount, "KDylib" ) )
732 {
733 case krefLimit:
734 return RC ( rcFS, rcDylib, rcAttaching, rcRange, rcExcessive );
735 }
736 }
737 return 0;
738 }
739
KDylibRelease(const KDylib * self)740 LIB_EXPORT rc_t CC KDylibRelease ( const KDylib *self )
741 {
742 if ( self != NULL )
743 {
744 switch ( KRefcountDrop ( & self -> refcount, "KDylib" ) )
745 {
746 case krefWhack:
747 return KDylibWhack ( ( KDylib* ) self );
748 case krefNegative:
749 return RC ( rcFS, rcDylib, rcReleasing, rcRange, rcExcessive );
750 }
751 }
752 return 0;
753 }
754
755 static
KDylibVectRelease(void * item,void * ignore)756 void KDylibVectRelease ( void *item, void *ignore )
757 {
758 KDylib *self = item;
759 KDylibRelease ( self );
760 }
761
762
763 /* Attach
764 * Sever
765 */
766 static
KDylibAttach(const KDylib * self)767 KDylib *KDylibAttach ( const KDylib *self )
768 {
769 if ( self != NULL )
770 {
771 switch ( KRefcountAddDep ( & self -> refcount, "KDylib" ) )
772 {
773 case krefLimit:
774 return NULL;
775 }
776 }
777 return ( KDylib* ) self;
778 }
779
780 static
KDylibSever(const KDylib * self)781 rc_t KDylibSever ( const KDylib *self )
782 {
783 if ( self != NULL )
784 {
785 switch ( KRefcountDropDep ( & self -> refcount, "KDylib" ) )
786 {
787 case krefWhack:
788 return KDylibWhack ( ( KDylib* ) self );
789 case krefNegative:
790 return RC ( rcFS, rcDylib, rcReleasing, rcRange, rcExcessive );
791 }
792 }
793 return 0;
794 }
795
796 /* Sort
797 */
798 static
KDylibSort(const void * item,const void * n)799 int64_t KDylibSort ( const void *item, const void *n )
800 {
801 const KDylib *a = item;
802 const KDylib *b = n;
803 return StringOrderNoNullCheck ( & a -> path, & b -> path );
804 }
805
806
807 /* FullPath
808 * return full path to library
809 */
KDylibFullPath(const KDylib * self,char * path,size_t psize)810 LIB_EXPORT rc_t CC KDylibFullPath ( const KDylib *self, char *path, size_t psize )
811 {
812 rc_t rc;
813
814 if ( psize == 0 )
815 rc = RC ( rcFS, rcDylib, rcAccessing, rcBuffer, rcInsufficient );
816 else if ( path == NULL )
817 rc = RC ( rcFS, rcDylib, rcAccessing, rcBuffer, rcNull );
818 else
819 {
820 if ( self == NULL )
821 rc = RC ( rcFS, rcDylib, rcAccessing, rcSelf, rcNull );
822 else
823 {
824 size_t bytes = string_copy ( path, psize,
825 self -> path . addr, self -> path . size );
826 if ( bytes < psize )
827 return 0;
828
829 rc = RC ( rcFS, rcDylib, rcAccessing, rcBuffer, rcInsufficient );
830 }
831
832 path [ 0 ] = 0;
833 }
834
835 return rc;
836 }
837
838
839 /*--------------------------------------------------------------------------
840 * KDlset
841 * ordered set of dynamic libraries
842 * contained libraries remain resident until set is released
843 */
844 struct KDlset
845 {
846 KDyld *dl;
847 Vector name, ord;
848 KRefcount refcount;
849 };
850
851
852 /* Whack
853 */
854 static
KDlsetWhack(KDlset * self)855 rc_t KDlsetWhack ( KDlset *self )
856 {
857 KRefcountWhack ( & self -> refcount, "KDlset" );
858
859 VectorWhack ( & self -> name, NULL, NULL );
860 VectorWhack ( & self -> ord, KDylibVectRelease, NULL );
861 KDyldSever ( self -> dl );
862 free ( self );
863
864 return 0;
865 }
866
867 #define STRINGIZE(s) #s
868 #define LIBNAME(pref, name, suff) STRINGIZE(pref) name STRINGIZE(suff)
869 /* MakeSet
870 * load a dynamic library
871 *
872 * "set" [ OUT ] - return parameter for lib set
873 */
KDyldMakeSet(const KDyld * self,KDlset ** setp)874 LIB_EXPORT rc_t CC KDyldMakeSet ( const KDyld *self, KDlset **setp )
875 {
876 rc_t rc = 0;
877
878 if ( setp == NULL )
879 rc = RC ( rcFS, rcDylib, rcConstructing, rcParam, rcNull );
880 else
881 {
882 if ( self == NULL )
883 rc = RC ( rcFS, rcDylib, rcConstructing, rcSelf, rcNull );
884 else
885 {
886 KDlset *set = malloc ( sizeof * set );
887 if ( set == NULL )
888 rc = RC ( rcFS, rcDylib, rcConstructing, rcMemory, rcExhausted );
889 else
890 {
891 set -> dl = KDyldAttach ( self );
892 VectorInit ( & set -> name, 0, 16 );
893 VectorInit ( & set -> ord, 0, 16 );
894 KRefcountInit ( & set -> refcount, 1, "KDlset", "make", "dlset" );
895 #if ! ALWAYS_ADD_EXE
896 {
897 KDylib *jni;
898 const char* libname = LIBNAME(LIBPREFIX, "vdb_jni.", SHLIBEXT);
899 if ( KDyldLoadLib ( ( KDyld* ) self, & jni, libname ) == 0 )
900 {
901 rc = KDlsetAddLib ( set, jni );
902 KDylibRelease ( jni );
903 }
904 if (rc == 0)
905 {
906 * setp = set;
907 return 0;
908 }
909 }
910 #else
911 {
912 KDylib *exe;
913 rc = KDyldLoadLib ( ( KDyld* ) self, & exe, NULL );
914 if ( rc == 0 )
915 {
916 rc = KDlsetAddLib ( set, exe );
917 KDylibRelease ( exe );
918 if ( rc == 0 )
919 {
920 * setp = set;
921 return 0;
922 }
923 }
924 }
925 #endif
926 KDlsetRelease ( set );
927 }
928 }
929
930 * setp = NULL;
931 }
932
933 return rc;
934 }
935
936
937 /* AddRef
938 * Release
939 */
KDlsetAddRef(const KDlset * self)940 LIB_EXPORT rc_t CC KDlsetAddRef ( const KDlset *self )
941 {
942 if ( self != NULL )
943 {
944 switch ( KRefcountAdd ( & self -> refcount, "KDlset" ) )
945 {
946 case krefLimit:
947 return RC ( rcFS, rcDylib, rcAttaching, rcRange, rcExcessive );
948 }
949 }
950 return 0;
951 }
952
KDlsetRelease(const KDlset * self)953 LIB_EXPORT rc_t CC KDlsetRelease ( const KDlset *self )
954 {
955 if ( self != NULL )
956 {
957 switch ( KRefcountDrop ( & self -> refcount, "KDlset" ) )
958 {
959 case krefWhack:
960 return KDlsetWhack ( ( KDlset* ) self );
961 case krefNegative:
962 return RC ( rcFS, rcDylib, rcReleasing, rcRange, rcExcessive );
963 }
964 }
965 return 0;
966 }
967
968
969 /* AddLib
970 * adds a dynamic library to end of ordered set
971 *
972 * "lib" [ IN ] - library returned from KDyldLoadLib
973 */
974 static
KDlsetAddLibInt(KDlset * self,KDylib * lib)975 rc_t KDlsetAddLibInt ( KDlset *self, KDylib *lib )
976 {
977 uint32_t idx;
978 rc_t rc = VectorAppend ( & self -> ord, & idx, lib );
979 if ( rc == 0 )
980 {
981 void *ignore;
982
983 rc = VectorInsertUnique ( & self -> name,
984 lib, NULL, KDylibSort );
985 if ( rc == 0 )
986 return 0;
987
988 VectorSwap ( & self -> ord, idx, NULL, & ignore );
989 }
990
991 return rc;
992 }
993
KDlsetAddLib(KDlset * self,KDylib * lib)994 LIB_EXPORT rc_t CC KDlsetAddLib ( KDlset *self, KDylib *lib )
995 {
996 rc_t rc;
997
998 if ( self == NULL )
999 rc = RC ( rcFS, rcDylib, rcInserting, rcSelf, rcNull );
1000 else if ( lib == NULL )
1001 rc = RC ( rcFS, rcDylib, rcInserting, rcDylib, rcNull );
1002 else
1003 {
1004 rc = KDylibAddRef ( lib );
1005 if ( rc == 0 )
1006 {
1007 rc = KDlsetAddLibInt ( self, lib );
1008 if ( rc == 0 )
1009 return 0;
1010
1011 KDylibRelease ( lib );
1012 }
1013 }
1014
1015 return rc;
1016 }
1017
1018
1019 /* AddAll
1020 * adds all dynamic libraries found in dl search path
1021 */
1022 static
KDlsetTryLib(const KDirectory * dir,uint32_t type,const char * name,void * data)1023 rc_t KDlsetTryLib ( const KDirectory *dir,
1024 uint32_t type, const char *name, void *data )
1025 {
1026 KDlset *self = data;
1027
1028 if ( ( type & ~ kptAlias ) == kptFile )
1029 {
1030 rc_t rc;
1031 KDylib *lib;
1032 #ifdef SHLX
1033 /* force simple shared library extension */
1034 if ( sizeof SHLX >= 2 )
1035 {
1036 /* SHLX has at least 1 character plus NUL byte */
1037 uint32_t len = strlen ( name );
1038 /* name must be at least 1 character larger */
1039 if ( len <= ( sizeof SHLX - 1 ) )
1040 return 0;
1041 /* name must end with shared library extension */
1042 if ( memcmp ( & name [ len - ( sizeof SHLX - 1 ) ], SHLX, sizeof SHLX - 1 ) != 0 )
1043 return 0;
1044 }
1045 #endif
1046 rc = KDyldTryLoadLib ( self -> dl, & lib, dir, name );
1047 if ( rc == 0 )
1048 {
1049 rc = KDlsetAddLibInt ( self, lib );
1050 if ( rc == 0 )
1051 return 0;
1052
1053 KDylibRelease ( lib );
1054 }
1055 }
1056
1057 return 0;
1058 }
1059
1060 static
KDlsetVisitDir(const KDirectory * dir,void * data)1061 void KDlsetVisitDir ( const KDirectory *dir, void *data )
1062 {
1063 KDirectoryVisit ( dir, false, KDlsetTryLib, data, "." );
1064 }
1065
KDlsetAddAll(KDlset * self)1066 LIB_EXPORT rc_t CC KDlsetAddAll ( KDlset *self )
1067 {
1068 if ( self == NULL )
1069 return RC ( rcFS, rcDylib, rcInserting, rcSelf, rcNull );
1070 KDyldForEach ( self -> dl, KDlsetVisitDir, self );
1071 return 0;
1072 }
1073
1074
1075 /*--------------------------------------------------------------------------
1076 * KSymAddr
1077 * symbol address within a dynamic library
1078 */
1079 struct KSymAddr
1080 {
1081 KDylib *lib;
1082 void *addr;
1083 KRefcount refcount;
1084 };
1085
1086
1087 /* Whack
1088 */
1089 static
KSymAddrWhack(KSymAddr * self)1090 rc_t KSymAddrWhack ( KSymAddr *self )
1091 {
1092 KRefcountWhack ( & self -> refcount, "KSymAddr" );
1093
1094 KDylibSever ( self -> lib );
1095 free ( self );
1096
1097 return 0;
1098 }
1099
1100
1101 /* AddRef
1102 * Release
1103 */
KSymAddrAddRef(const KSymAddr * self)1104 LIB_EXPORT rc_t CC KSymAddrAddRef ( const KSymAddr *self )
1105 {
1106 if ( self != NULL )
1107 {
1108 switch ( KRefcountAdd ( & self -> refcount, "KSymAddr" ) )
1109 {
1110 case krefLimit:
1111 return RC ( rcFS, rcDylib, rcAttaching, rcRange, rcExcessive );
1112 }
1113 }
1114 return 0;
1115 }
1116
KSymAddrRelease(const KSymAddr * self)1117 LIB_EXPORT rc_t CC KSymAddrRelease ( const KSymAddr *self )
1118 {
1119 if ( self != NULL )
1120 {
1121 switch ( KRefcountDrop ( & self -> refcount, "KSymAddr" ) )
1122 {
1123 case krefWhack:
1124 return KSymAddrWhack ( ( KSymAddr* ) self );
1125 case krefNegative:
1126 return RC ( rcFS, rcDylib, rcReleasing, rcRange, rcExcessive );
1127 }
1128 }
1129 return 0;
1130 }
1131
1132
1133 /* Make
1134 */
1135 static
KSymAddrMake(KSymAddr ** symp,const KDylib * lib,const char * name)1136 rc_t KSymAddrMake ( KSymAddr **symp,
1137 const KDylib *lib, const char *name )
1138 {
1139 if ( lib -> handle )
1140 {
1141 void *addr = dlsym ( lib -> handle, name );
1142 const char *estr = dlerror();
1143
1144 if ( addr != NULL || estr == NULL )
1145 {
1146 KSymAddr *sym = malloc ( sizeof * sym );
1147 if ( sym == NULL )
1148 return RC ( rcFS, rcDylib, rcConstructing, rcMemory, rcExhausted );
1149
1150 sym -> lib = KDylibAttach ( lib );
1151 sym -> addr = addr;
1152 KRefcountInit ( & sym -> refcount, 1, "KSymAddr", "make", name );
1153 * symp = sym;
1154 return 0;
1155 }
1156 }
1157 * symp = NULL;
1158 return RC ( rcFS, rcDylib, rcSelecting, rcName, rcNotFound );
1159 }
1160
1161
1162 /* Symbol
1163 * find a symbol within dynamic library
1164 *
1165 * "sym" [ OUT ] - return parameter for exported symbol address
1166 *
1167 * "name" [ IN ] - NUL terminated symbol name in
1168 * library-native character set
1169 */
KDylibSymbol(const KDylib * self,KSymAddr ** sym,const char * name)1170 LIB_EXPORT rc_t CC KDylibSymbol ( const KDylib *self, KSymAddr **sym, const char *name )
1171 {
1172 rc_t rc;
1173
1174 if ( sym == NULL )
1175 rc = RC ( rcFS, rcDylib, rcSelecting, rcParam, rcNull );
1176 else
1177 {
1178 if ( self == NULL )
1179 rc = RC ( rcFS, rcDylib, rcSelecting, rcSelf, rcNull );
1180 else if ( name == NULL )
1181 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcNull );
1182 else if ( name [ 0 ] == 0 )
1183 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcEmpty );
1184 else
1185 {
1186 return KSymAddrMake ( sym, self, name );
1187 }
1188
1189 * sym = NULL;
1190 }
1191
1192 return rc;
1193 }
1194
1195 typedef struct KDlsetTrySymData KDlsetTrySymData;
1196 struct KDlsetTrySymData
1197 {
1198 const KDlset *self;
1199 const char *name;
1200
1201 bool ( CC * test ) ( const KSymAddr *sym, void *data );
1202 void *data;
1203
1204 KSymAddr *sym;
1205 rc_t rc;
1206 bool first;
1207 };
1208
1209 static
KDlsetTrySymbol(void * item,void * data)1210 bool KDlsetTrySymbol ( void *item, void *data )
1211 {
1212 KSymAddr *sym;
1213 KDlsetTrySymData *pb = data;
1214 pb -> rc = KDylibSymbol ( item, & sym, pb -> name );
1215 if ( pb -> rc == 0 )
1216 {
1217 /* simple case */
1218 if ( pb -> test == NULL )
1219 {
1220 pb -> sym = sym;
1221 return true;
1222 }
1223
1224 /* apply filter function */
1225 if ( ( * pb -> test ) ( sym, pb -> data ) )
1226 {
1227 KSymAddrRelease ( pb -> sym );
1228 pb -> sym = sym;
1229 return pb -> first;
1230 }
1231
1232 KSymAddrRelease ( sym );
1233 }
1234 return false;
1235 }
1236
KDlsetSymbol(const KDlset * self,KSymAddr ** sym,const char * name)1237 LIB_EXPORT rc_t CC KDlsetSymbol ( const KDlset *self, KSymAddr **sym, const char *name )
1238 {
1239 rc_t rc;
1240
1241 if ( sym == NULL )
1242 rc = RC ( rcFS, rcDylib, rcSelecting, rcParam, rcNull );
1243 else
1244 {
1245 if ( self == NULL )
1246 rc = RC ( rcFS, rcDylib, rcSelecting, rcSelf, rcNull );
1247 else if ( name == NULL )
1248 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcNull );
1249 else if ( name [ 0 ] == 0 )
1250 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcEmpty );
1251 else
1252 {
1253 KDlsetTrySymData pb;
1254 memset ( & pb, 0, sizeof pb );
1255 pb . self = self;
1256 pb . name = name;
1257 pb . rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcNotFound );
1258
1259 if ( VectorDoUntil ( & self -> ord, false, KDlsetTrySymbol, & pb ) )
1260 {
1261 * sym = pb . sym;
1262 return 0;
1263 }
1264
1265 rc = pb . rc;
1266 }
1267
1268 * sym = NULL;
1269 }
1270
1271 return rc;
1272 }
1273
1274
1275 /* FirstSymbol
1276 * LastSymbol
1277 * find a symbol within dynamic library set matching criteria
1278 *
1279 * "sym" [ OUT ] - return parameter for exported symbol address
1280 *
1281 * "name" [ IN ] - NUL terminated symbol name in
1282 * library-native character set
1283 *
1284 * "test" [ IN ] and "data" [ IN, OPAQUE ] - callback filter function
1285 * return true if symbol matches criteria
1286 */
KDlsetFirstSymbol(const KDlset * self,KSymAddr ** sym,const char * name,bool (CC * test)(const KSymAddr * sym,void * data),void * data)1287 LIB_EXPORT rc_t CC KDlsetFirstSymbol ( const KDlset *self, KSymAddr **sym, const char *name,
1288 bool ( CC * test ) ( const KSymAddr *sym, void *data ), void *data )
1289 {
1290 rc_t rc;
1291
1292 if ( sym == NULL )
1293 rc = RC ( rcFS, rcDylib, rcSelecting, rcParam, rcNull );
1294 else
1295 {
1296 if ( self == NULL )
1297 rc = RC ( rcFS, rcDylib, rcSelecting, rcSelf, rcNull );
1298 else if ( name == NULL )
1299 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcNull );
1300 else if ( name [ 0 ] == 0 )
1301 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcEmpty );
1302 else if ( test == NULL )
1303 rc = RC ( rcFS, rcDylib, rcSelecting, rcFunction, rcNull );
1304 else
1305 {
1306 KDlsetTrySymData pb;
1307 memset ( & pb, 0, sizeof pb );
1308 pb . self = self;
1309 pb . name = name;
1310 pb . test = test;
1311 pb . data = data;
1312 pb . rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcNotFound );
1313 pb . first = true;
1314
1315 if ( VectorDoUntil ( & self -> ord, false, KDlsetTrySymbol, & pb ) )
1316 {
1317 * sym = pb . sym;
1318 return 0;
1319 }
1320
1321 rc = pb . rc;
1322 }
1323
1324 * sym = NULL;
1325 }
1326
1327 return rc;
1328 }
1329
KDlsetLastSymbol(const KDlset * self,KSymAddr ** sym,const char * name,bool (CC * test)(const KSymAddr * sym,void * data),void * data)1330 LIB_EXPORT rc_t CC KDlsetLastSymbol ( const KDlset *self, KSymAddr **sym, const char *name,
1331 bool ( CC * test ) ( const KSymAddr *sym, void *data ), void *data )
1332 {
1333 rc_t rc;
1334
1335 if ( sym == NULL )
1336 rc = RC ( rcFS, rcDylib, rcSelecting, rcParam, rcNull );
1337 else
1338 {
1339 if ( self == NULL )
1340 rc = RC ( rcFS, rcDylib, rcSelecting, rcSelf, rcNull );
1341 else if ( name == NULL )
1342 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcNull );
1343 else if ( name [ 0 ] == 0 )
1344 rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcEmpty );
1345 else if ( test == NULL )
1346 rc = RC ( rcFS, rcDylib, rcSelecting, rcFunction, rcNull );
1347 else
1348 {
1349 KDlsetTrySymData pb;
1350 memset ( & pb, 0, sizeof pb );
1351 pb . self = self;
1352 pb . name = name;
1353 pb . test = test;
1354 pb . data = data;
1355 pb . rc = RC ( rcFS, rcDylib, rcSelecting, rcName, rcNotFound );
1356
1357 VectorDoUntil ( & self -> ord, false, KDlsetTrySymbol, & pb );
1358 if ( pb . sym != NULL )
1359 {
1360 * sym = pb . sym;
1361 return 0;
1362 }
1363
1364 rc = pb . rc;
1365 }
1366
1367 * sym = NULL;
1368 }
1369
1370 return rc;
1371 }
1372
1373
1374 /* List - PRIVATE
1375 * list the paths to the libraries in the set
1376 */
1377 typedef struct list_dylib_param list_dylib_param;
1378 struct list_dylib_param
1379 {
1380 VNamelist *list;
1381 rc_t rc;
1382 };
1383
1384 static
list_dylib(void * item,void * data)1385 bool CC list_dylib ( void *item, void *data )
1386 {
1387 list_dylib_param *pb = data;
1388 const KDylib *lib = ( const void* ) item;
1389
1390 /* "lib" was created with KDylibMake
1391 which creates a NUL terminated path.
1392 of course, this could seg-fault if bad... */
1393 assert ( lib -> path . addr [ lib -> path . size ] == 0 );
1394
1395 pb -> rc = VNamelistAppend ( pb -> list, lib -> path . addr );
1396 return pb -> rc != 0;
1397 }
1398
KDlsetList(const KDlset * self,KNamelist ** listp)1399 LIB_EXPORT rc_t CC KDlsetList ( const KDlset *self, KNamelist **listp )
1400 {
1401 list_dylib_param pb;
1402
1403 assert ( listp != NULL );
1404
1405 if ( self == NULL )
1406 pb . rc = RC ( rcFS, rcDylib, rcListing, rcSelf, rcNull );
1407 else
1408 {
1409 pb . rc = VNamelistMake ( & pb . list, VectorLength ( & self -> name ) );
1410 if ( pb . rc == 0 )
1411 {
1412 bool fail = VectorDoUntil ( & self -> name, false, list_dylib, & pb );
1413 if ( ! fail )
1414 pb . rc = VNamelistToNamelist ( pb . list, listp );
1415
1416 VNamelistRelease ( pb . list );
1417 }
1418 }
1419
1420 return pb . rc;
1421 }
1422
1423
1424 /* AsObj
1425 * AsFunc
1426 * retrieve symbol address as pointer to object
1427 */
KSymAddrAsObj(const KSymAddr * self)1428 LIB_EXPORT void * CC KSymAddrAsObj ( const KSymAddr *self )
1429 {
1430 if ( self != NULL )
1431 return self -> addr;
1432 return NULL;
1433 }
1434
KSymAddrAsFunc(const KSymAddr * self,fptr_t * fp)1435 LIB_EXPORT void CC KSymAddrAsFunc ( const KSymAddr *self, fptr_t *fp )
1436 {
1437 if ( self != NULL && fp != NULL )
1438 * fp = ( fptr_t ) self -> addr;
1439 }
1440
1441
1442