1317683Sdim//===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- C++ -*-===//
2317683Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6317683Sdim//
7317683Sdim//===----------------------------------------------------------------------===//
8317683Sdim//
9317683Sdim// This file provides the UNIX specific implementation of DynamicLibrary.
10317683Sdim//
11317683Sdim//===----------------------------------------------------------------------===//
12317683Sdim
13317683Sdim#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)
14317683Sdim#include <dlfcn.h>
15317683Sdim
16317683SdimDynamicLibrary::HandleSet::~HandleSet() {
17319799Sdim  // Close the libraries in reverse order.
18319799Sdim  for (void *Handle : llvm::reverse(Handles))
19317683Sdim    ::dlclose(Handle);
20317683Sdim  if (Process)
21317683Sdim    ::dlclose(Process);
22320970Sdim
23320970Sdim  // llvm_shutdown called, Return to default
24320970Sdim  DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
25317683Sdim}
26317683Sdim
27317683Sdimvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
28317683Sdim  void *Handle = ::dlopen(File, RTLD_LAZY|RTLD_GLOBAL);
29317683Sdim  if (!Handle) {
30317683Sdim    if (Err) *Err = ::dlerror();
31317683Sdim    return &DynamicLibrary::Invalid;
32317683Sdim  }
33317683Sdim
34317683Sdim#ifdef __CYGWIN__
35317683Sdim  // Cygwin searches symbols only in the main
36317683Sdim  // with the handle of dlopen(NULL, RTLD_GLOBAL).
37317969Sdim  if (!File)
38317683Sdim    Handle = RTLD_DEFAULT;
39317683Sdim#endif
40317683Sdim
41317683Sdim  return Handle;
42317683Sdim}
43317683Sdim
44317683Sdimvoid DynamicLibrary::HandleSet::DLClose(void *Handle) {
45317683Sdim  ::dlclose(Handle);
46317683Sdim}
47317683Sdim
48317683Sdimvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
49317683Sdim  return ::dlsym(Handle, Symbol);
50317683Sdim}
51317683Sdim
52317683Sdim#else // !HAVE_DLOPEN
53317683Sdim
54317683SdimDynamicLibrary::HandleSet::~HandleSet() {}
55317683Sdim
56317683Sdimvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
57317683Sdim  if (Err) *Err = "dlopen() not supported on this platform";
58317683Sdim  return &Invalid;
59317683Sdim}
60317683Sdim
61317683Sdimvoid DynamicLibrary::HandleSet::DLClose(void *Handle) {
62317683Sdim}
63317683Sdim
64317683Sdimvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
65317683Sdim  return nullptr;
66317683Sdim}
67317683Sdim
68317683Sdim#endif
69317683Sdim
70317683Sdim// Must declare the symbols in the global namespace.
71317683Sdimstatic void *DoSearch(const char* SymbolName) {
72317683Sdim#define EXPLICIT_SYMBOL(SYM) \
73327952Sdim   extern void *SYM; if (!strcmp(SymbolName, #SYM)) return (void*)&SYM
74317683Sdim
75317683Sdim  // If this is darwin, it has some funky issues, try to solve them here.  Some
76317683Sdim  // important symbols are marked 'private external' which doesn't allow
77317683Sdim  // SearchForAddressOfSymbol to find them.  As such, we special case them here,
78317683Sdim  // there is only a small handful of them.
79317683Sdim
80317683Sdim#ifdef __APPLE__
81317683Sdim  {
82317683Sdim    // __eprintf is sometimes used for assert() handling on x86.
83317683Sdim    //
84317683Sdim    // FIXME: Currently disabled when using Clang, as we don't always have our
85317683Sdim    // runtime support libraries available.
86317683Sdim#ifndef __clang__
87317683Sdim#ifdef __i386__
88317683Sdim    EXPLICIT_SYMBOL(__eprintf);
89317683Sdim#endif
90317683Sdim#endif
91317683Sdim  }
92317683Sdim#endif
93317683Sdim
94317683Sdim#ifdef __CYGWIN__
95317683Sdim  {
96317683Sdim    EXPLICIT_SYMBOL(_alloca);
97317683Sdim    EXPLICIT_SYMBOL(__main);
98317683Sdim  }
99317683Sdim#endif
100317683Sdim
101317683Sdim#undef EXPLICIT_SYMBOL
102317683Sdim
103317683Sdim// This macro returns the address of a well-known, explicit symbol
104317683Sdim#define EXPLICIT_SYMBOL(SYM) \
105317683Sdim   if (!strcmp(SymbolName, #SYM)) return &SYM
106317683Sdim
107319799Sdim// Under glibc we have a weird situation. The stderr/out/in symbols are both
108317683Sdim// macros and global variables because of standards requirements. So, we
109317683Sdim// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
110319799Sdim#if defined(__GLIBC__)
111317683Sdim  {
112317683Sdim    EXPLICIT_SYMBOL(stderr);
113317683Sdim    EXPLICIT_SYMBOL(stdout);
114317683Sdim    EXPLICIT_SYMBOL(stdin);
115317683Sdim  }
116317683Sdim#else
117317683Sdim  // For everything else, we want to check to make sure the symbol isn't defined
118317683Sdim  // as a macro before using EXPLICIT_SYMBOL.
119317683Sdim  {
120317683Sdim#ifndef stdin
121317683Sdim    EXPLICIT_SYMBOL(stdin);
122317683Sdim#endif
123317683Sdim#ifndef stdout
124317683Sdim    EXPLICIT_SYMBOL(stdout);
125317683Sdim#endif
126317683Sdim#ifndef stderr
127317683Sdim    EXPLICIT_SYMBOL(stderr);
128317683Sdim#endif
129317683Sdim  }
130317683Sdim#endif
131317683Sdim#undef EXPLICIT_SYMBOL
132317683Sdim
133317683Sdim  return nullptr;
134317683Sdim}
135