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