1*0b57cec5SDimitry Andric//===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- C++ -*-===//
2*0b57cec5SDimitry Andric//
3*0b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric//
7*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric//
9*0b57cec5SDimitry Andric// This file provides the UNIX specific implementation of DynamicLibrary.
10*0b57cec5SDimitry Andric//
11*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric
13*0b57cec5SDimitry Andric#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)
14*0b57cec5SDimitry Andric#include <dlfcn.h>
15*0b57cec5SDimitry Andric
16*0b57cec5SDimitry AndricDynamicLibrary::HandleSet::~HandleSet() {
17*0b57cec5SDimitry Andric  // Close the libraries in reverse order.
18*0b57cec5SDimitry Andric  for (void *Handle : llvm::reverse(Handles))
19*0b57cec5SDimitry Andric    ::dlclose(Handle);
20*0b57cec5SDimitry Andric  if (Process)
21*0b57cec5SDimitry Andric    ::dlclose(Process);
22*0b57cec5SDimitry Andric
23*0b57cec5SDimitry Andric  // llvm_shutdown called, Return to default
24*0b57cec5SDimitry Andric  DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
25*0b57cec5SDimitry Andric}
26*0b57cec5SDimitry Andric
27*0b57cec5SDimitry Andricvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
28*0b57cec5SDimitry Andric  void *Handle = ::dlopen(File, RTLD_LAZY|RTLD_GLOBAL);
29*0b57cec5SDimitry Andric  if (!Handle) {
30*0b57cec5SDimitry Andric    if (Err) *Err = ::dlerror();
31*0b57cec5SDimitry Andric    return &DynamicLibrary::Invalid;
32*0b57cec5SDimitry Andric  }
33*0b57cec5SDimitry Andric
34*0b57cec5SDimitry Andric#ifdef __CYGWIN__
35*0b57cec5SDimitry Andric  // Cygwin searches symbols only in the main
36*0b57cec5SDimitry Andric  // with the handle of dlopen(NULL, RTLD_GLOBAL).
37*0b57cec5SDimitry Andric  if (!File)
38*0b57cec5SDimitry Andric    Handle = RTLD_DEFAULT;
39*0b57cec5SDimitry Andric#endif
40*0b57cec5SDimitry Andric
41*0b57cec5SDimitry Andric  return Handle;
42*0b57cec5SDimitry Andric}
43*0b57cec5SDimitry Andric
44*0b57cec5SDimitry Andricvoid DynamicLibrary::HandleSet::DLClose(void *Handle) {
45*0b57cec5SDimitry Andric  ::dlclose(Handle);
46*0b57cec5SDimitry Andric}
47*0b57cec5SDimitry Andric
48*0b57cec5SDimitry Andricvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
49*0b57cec5SDimitry Andric  return ::dlsym(Handle, Symbol);
50*0b57cec5SDimitry Andric}
51*0b57cec5SDimitry Andric
52*0b57cec5SDimitry Andric#else // !HAVE_DLOPEN
53*0b57cec5SDimitry Andric
54*0b57cec5SDimitry AndricDynamicLibrary::HandleSet::~HandleSet() {}
55*0b57cec5SDimitry Andric
56*0b57cec5SDimitry Andricvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
57*0b57cec5SDimitry Andric  if (Err) *Err = "dlopen() not supported on this platform";
58*0b57cec5SDimitry Andric  return &Invalid;
59*0b57cec5SDimitry Andric}
60*0b57cec5SDimitry Andric
61*0b57cec5SDimitry Andricvoid DynamicLibrary::HandleSet::DLClose(void *Handle) {
62*0b57cec5SDimitry Andric}
63*0b57cec5SDimitry Andric
64*0b57cec5SDimitry Andricvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
65*0b57cec5SDimitry Andric  return nullptr;
66*0b57cec5SDimitry Andric}
67*0b57cec5SDimitry Andric
68*0b57cec5SDimitry Andric#endif
69*0b57cec5SDimitry Andric
70*0b57cec5SDimitry Andric// Must declare the symbols in the global namespace.
71*0b57cec5SDimitry Andricstatic void *DoSearch(const char* SymbolName) {
72*0b57cec5SDimitry Andric#define EXPLICIT_SYMBOL(SYM) \
73*0b57cec5SDimitry Andric   extern void *SYM; if (!strcmp(SymbolName, #SYM)) return (void*)&SYM
74*0b57cec5SDimitry Andric
75*0b57cec5SDimitry Andric  // If this is darwin, it has some funky issues, try to solve them here.  Some
76*0b57cec5SDimitry Andric  // important symbols are marked 'private external' which doesn't allow
77*0b57cec5SDimitry Andric  // SearchForAddressOfSymbol to find them.  As such, we special case them here,
78*0b57cec5SDimitry Andric  // there is only a small handful of them.
79*0b57cec5SDimitry Andric
80*0b57cec5SDimitry Andric#ifdef __APPLE__
81*0b57cec5SDimitry Andric  {
82*0b57cec5SDimitry Andric    // __eprintf is sometimes used for assert() handling on x86.
83*0b57cec5SDimitry Andric    //
84*0b57cec5SDimitry Andric    // FIXME: Currently disabled when using Clang, as we don't always have our
85*0b57cec5SDimitry Andric    // runtime support libraries available.
86*0b57cec5SDimitry Andric#ifndef __clang__
87*0b57cec5SDimitry Andric#ifdef __i386__
88*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(__eprintf);
89*0b57cec5SDimitry Andric#endif
90*0b57cec5SDimitry Andric#endif
91*0b57cec5SDimitry Andric  }
92*0b57cec5SDimitry Andric#endif
93*0b57cec5SDimitry Andric
94*0b57cec5SDimitry Andric#ifdef __CYGWIN__
95*0b57cec5SDimitry Andric  {
96*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(_alloca);
97*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(__main);
98*0b57cec5SDimitry Andric  }
99*0b57cec5SDimitry Andric#endif
100*0b57cec5SDimitry Andric
101*0b57cec5SDimitry Andric#undef EXPLICIT_SYMBOL
102*0b57cec5SDimitry Andric
103*0b57cec5SDimitry Andric// This macro returns the address of a well-known, explicit symbol
104*0b57cec5SDimitry Andric#define EXPLICIT_SYMBOL(SYM) \
105*0b57cec5SDimitry Andric   if (!strcmp(SymbolName, #SYM)) return &SYM
106*0b57cec5SDimitry Andric
107*0b57cec5SDimitry Andric// Under glibc we have a weird situation. The stderr/out/in symbols are both
108*0b57cec5SDimitry Andric// macros and global variables because of standards requirements. So, we
109*0b57cec5SDimitry Andric// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
110*0b57cec5SDimitry Andric#if defined(__GLIBC__)
111*0b57cec5SDimitry Andric  {
112*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(stderr);
113*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(stdout);
114*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(stdin);
115*0b57cec5SDimitry Andric  }
116*0b57cec5SDimitry Andric#else
117*0b57cec5SDimitry Andric  // For everything else, we want to check to make sure the symbol isn't defined
118*0b57cec5SDimitry Andric  // as a macro before using EXPLICIT_SYMBOL.
119*0b57cec5SDimitry Andric  {
120*0b57cec5SDimitry Andric#ifndef stdin
121*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(stdin);
122*0b57cec5SDimitry Andric#endif
123*0b57cec5SDimitry Andric#ifndef stdout
124*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(stdout);
125*0b57cec5SDimitry Andric#endif
126*0b57cec5SDimitry Andric#ifndef stderr
127*0b57cec5SDimitry Andric    EXPLICIT_SYMBOL(stderr);
128*0b57cec5SDimitry Andric#endif
129*0b57cec5SDimitry Andric  }
130*0b57cec5SDimitry Andric#endif
131*0b57cec5SDimitry Andric#undef EXPLICIT_SYMBOL
132*0b57cec5SDimitry Andric
133*0b57cec5SDimitry Andric  return nullptr;
134*0b57cec5SDimitry Andric}
135