Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: third_party/crazy_linker/crazy_linker/src/crazy_linker_wrappers.cpp

Issue 23717023: Android: Add chrome-specific dynamic linker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address later issues. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crazy_linker_wrappers.h"
6
7 #include <dlfcn.h>
8 #include <link.h>
9
10 #include "crazy_linker_debug.h"
11 #include "crazy_linker_globals.h"
12 #include "crazy_linker_library_list.h"
13 #include "crazy_linker_library_view.h"
14 #include "crazy_linker_shared_library.h"
15 #include "crazy_linker_thread.h"
16 #include "crazy_linker_util.h"
17
18 #ifdef __arm__
19 // On ARM, this function is exported by the dynamic linker but never
20 // declared in any official header. It is used at runtime to
21 // find the base address of the .ARM.exidx section for the
22 // shared library containing the instruction at |pc|, as well as
23 // the number of 8-byte entries in that section, written into |*pcount|
24 extern "C" _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr, int*);
25 #else
26 // On other architectures, this function is exported by the dynamic linker
27 // but never declared in any official header. It is used at runtime to
28 // iterate over all loaded libraries and call the |cb|. When the function
29 // returns non-0, the iteration returns and the function returns its
30 // value.
31 extern "C" int dl_iterate_phdr(
32 int (*cb)(dl_phdr_info *info, size_t size, void *data),
33 void *data);
34 #endif
35
36 namespace crazy {
37
38 namespace {
39
40 #ifdef __arm__
41 extern "C" int __cxa_atexit(void(*)(void*), void*, void*);
42
43 // On ARM, this function is defined as a weak symbol by libc.so.
44 // Unfortunately its address cannot be found through dlsym(), which will
45 // always return NULL. To work-around this, define a copy here that does
46 // exactly the same thing. The ARM EABI mandates the function's behaviour.
47 // __cxa_atexit() is implemented by the C library, but not declared by
48 // any official header. It's part of the low-level C++ support runtime.
49 int
50 __aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle)
51 {
52 return __cxa_atexit(destructor, object, dso_handle);
53 }
54 #endif
55
56 // Used to save the system dlerror() into our thread-specific data.
57 void SaveSystemError() {
58 ThreadData* data = GetThreadData();
59 data->SetError(::dlerror());
60 }
61
62 char* WrapDlerror() {
63 ThreadData* data = GetThreadData();
64 const char* error = data->GetError();
65 data->SwapErrorBuffers();
66 // dlerror() returns a 'char*', but no sane client code should ever
67 // try to write to this location.
68 return const_cast<char*>(error);
69 }
70
71 void* WrapDlopen(const char* path, int mode) {
72 ScopedGlobalLock lock;
73
74 // NOTE: If |path| is NULL, the wrapper should return a handle
75 // corresponding to the current executable. This can't be a crazy
76 // library, so don't try to handle it with the crazy linker.
77 if (path) {
78 LibraryList* lib_list = Globals::GetLibraries();
79 Error error;
80 LibraryView* wrap = lib_list->LoadLibrary(path,
81 mode,
82 0U /* load_address */,
83 0U /* file_offset */,
84 Globals::GetSearchPaths(),
85 &error);
86 if (wrap)
87 return wrap;
88 }
89
90 // Try to load the executable with the system dlopen() instead.
91 ::dlerror();
92 void* system_lib = ::dlopen(path, mode);
93 if (system_lib == NULL) {
94 SaveSystemError();
95 return NULL;
96 }
97
98 LibraryView* wrap_lib = new LibraryView();
99 wrap_lib->SetSystem(system_lib, path ? path : "<executable>");
100 Globals::GetLibraries()->AddLibrary(wrap_lib);
101 return wrap_lib;
102 }
103
104 void* WrapDlsym(void* lib_handle, const char* symbol_name) {
105 LibraryView* wrap_lib = reinterpret_cast<LibraryView*>(lib_handle);
106
107 if (!symbol_name) {
108 SetLinkerError("dlsym: NULL symbol name");
109 return NULL;
110 }
111
112 if (!lib_handle) {
113 SetLinkerError("dlsym: NULL library handle");
114 return NULL;
115 }
116
117 // TODO(digit): Handle RTLD_DEFAULT / RTLD_NEXT
118 if (lib_handle == RTLD_DEFAULT || lib_handle == RTLD_NEXT) {
119 SetLinkerError("dlsym: RTLD_DEFAULT/RTLD_NEXT are not implemented!");
120 return NULL;
121 }
122
123 // NOTE: The Android dlsym() only looks inside the target library,
124 // while the GNU one will perform a breadth-first search into its
125 // dependency tree.
126
127 // This implementation performs a correct breadth-first search
128 // when |lib_handle| corresponds to a crazy library, except that
129 // it stops at system libraries that it depends on.
130
131 void* result = NULL;
132
133 if (wrap_lib->IsSystem()) {
134 // Note: the system dlsym() only looks into the target library,
135 // while the GNU linker performs a breadth-first search.
136 result = ::dlsym(wrap_lib->GetSystem(), symbol_name);
137 if (!result) {
138 SaveSystemError();
139 LOG("dlsym:%s: could not find symbol '%s' from system library\n%s",
140 wrap_lib->GetName(), symbol_name,
141 GetThreadData()->GetError());
142 }
143 return result;
144 }
145
146 if (wrap_lib->IsCrazy()) {
147 ScopedGlobalLock lock;
148 LibraryList* lib_list = Globals::GetLibraries();
149 void* addr = lib_list->FindSymbolFrom(symbol_name, wrap_lib);
150 if (addr)
151 return addr;
152
153 SetLinkerError("dlsym: Could not find '%s' from library '%s'",
154 symbol_name, wrap_lib->GetName());
155 return NULL;
156
157 }
158
159 SetLinkerError("dlsym: Invalid library handle %p looking for '%s'",
160 lib_handle, symbol_name);
161 return NULL;
162 }
163
164 int WrapDladdr(void* address, Dl_info* info) {
165 // First, perform search in crazy libraries.
166 {
167 ScopedGlobalLock lock;
168 LibraryList* lib_list = Globals::GetLibraries();
169 LibraryView* wrap = lib_list->FindLibraryForAddress(address);
170 if (wrap && wrap->IsCrazy()) {
171 SharedLibrary* lib = wrap->GetCrazy();
172 ::memset(info, 0, sizeof(*info));
173 info->dli_fname = lib->base_name;
174 info->dli_fbase = reinterpret_cast<void*>(lib->base);
175
176 // Determine if any symbol in the library contains the specified address.
177 ELF::Sym* sym = lib->FindSymbolForAddress(address);
178 if (sym != NULL) {
179 info->dli_sname = lib->strtab + sym->st_name;
180 info->dli_saddr =
181 reinterpret_cast<void*>(lib->load_bias + sym->st_value);
182 }
183 return 0;
184 }
185 }
186 // Otherwise, use system version.
187 ::dlerror();
188 int ret = ::dladdr(address, info);
189 if (ret != 0)
190 SaveSystemError();
191 return ret;
192 }
193
194 int WrapDlclose(void* lib_handle) {
195 LibraryView* wrap_lib = reinterpret_cast<LibraryView*>(lib_handle);
196 if (!wrap_lib) {
197 SetLinkerError("NULL library handle");
198 return -1;
199 }
200
201 if (wrap_lib->IsSystem() || wrap_lib->IsCrazy()) {
202 ScopedGlobalLock lock;
203 LibraryList* lib_list = Globals::GetLibraries();
204 lib_list->UnloadLibrary(wrap_lib);
205 return 0;
206 }
207
208 // Invalid library handle!!
209 SetLinkerError("Invalid library handle %p", lib_handle);
210 return -1;
211 }
212
213 #ifdef __arm__
214 _Unwind_Ptr WrapDl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
215 {
216 // First lookup in crazy libraries.
217 {
218 ScopedGlobalLock lock;
219 LibraryList* list = Globals::GetLibraries();
220 _Unwind_Ptr result = list->FindArmExIdx(pc, pcount);
221 if (result)
222 return result;
223 }
224 // Lookup in system libraries.
225 return ::dl_unwind_find_exidx(pc, pcount);
226 }
227 #else // !__arm__
228 int WrapDl_iterate_phdr(int (*cb)(dl_phdr_info*, size_t, void*),
229 void* data) {
230 // First, iterate over crazy libraries.
231 {
232 ScopedGlobalLock lock;
233 LibraryList* list = Globals::GetLibraries();
234 int result = list->IteratePhdr(cb, data);
235 if (result)
236 return result;
237 }
238 // Then lookup through system ones.
239 return ::dl_iterate_phdr(cb, data);
240 }
241 #endif // !__arm__
242
243 } // namespace
244
245 void* WrapLinkerSymbol(const char* name) {
246 // Shortcut, since all names begin with 'dl'
247 // Take care of __aeabi_atexit on ARM though.
248 if (name[0] != 'd' || name[1] != 'l') {
249 #ifdef __arm__
250 if (name[0] == '_' && !strcmp("__aeabi_atexit", name))
251 return reinterpret_cast<void*>(&__aeabi_atexit);
252 #endif
253 return NULL;
254 }
255
256 static const struct {
257 const char* name;
258 void* address;
259 } kSymbols[] = {
260 { "dlopen", reinterpret_cast<void*>(&WrapDlopen) },
261 { "dlclose", reinterpret_cast<void*>(&WrapDlclose) },
262 { "dlerror", reinterpret_cast<void*>(&WrapDlerror) },
263 { "dlsym", reinterpret_cast<void*>(&WrapDlsym) },
264 { "dladdr", reinterpret_cast<void*>(&WrapDladdr) },
265 #ifdef __arm__
266 { "dl_unwind_find_exidx",
267 reinterpret_cast<void*>(&WrapDl_unwind_find_exidx) },
268 #else
269 { "dl_iterate_phdr", reinterpret_cast<void*>(&WrapDl_iterate_phdr) },
270 #endif
271 };
272 static const size_t kCount = sizeof(kSymbols)/sizeof(kSymbols[0]);
273 for (size_t n = 0; n < kCount; ++n) {
274 if (!strcmp(kSymbols[n].name, name))
275 return kSymbols[n].address;
276 }
277 return NULL;
278 }
279
280 } // namespace crazy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698