Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / android_crazy_linker / src / src / crazy_linker_api.cpp
1 // Copyright 2014 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 // Implements the crazy linker C-based API exposed by <crazy_linker.h>
6
7 #include <crazy_linker.h>
8
9 #include <string.h>
10
11 #include "crazy_linker_error.h"
12 #include "crazy_linker_ashmem.h"
13 #include "crazy_linker_globals.h"
14 #include "crazy_linker_proc_maps.h"
15 #include "crazy_linker_search_path_list.h"
16 #include "crazy_linker_shared_library.h"
17 #include "crazy_linker_thread.h"
18 #include "crazy_linker_util.h"
19 #include "crazy_linker_library_view.h"
20 #include "crazy_linker_system.h"
21
22 using crazy::Globals;
23 using crazy::Error;
24 using crazy::SearchPathList;
25 using crazy::ScopedGlobalLock;
26 using crazy::LibraryView;
27
28 //
29 // crazy_context_t
30 //
31
32 struct crazy_context_t {
33  public:
34   crazy_context_t()
35       : load_address(0),
36         file_offset(0),
37         error(),
38         search_paths(),
39         java_vm(NULL),
40         minimum_jni_version(0),
41         callback_poster(NULL),
42         callback_poster_opaque(NULL) {
43     ResetSearchPaths();
44   }
45
46   void ResetSearchPaths();
47
48   size_t load_address;
49   size_t file_offset;
50   Error error;
51   SearchPathList search_paths;
52   void* java_vm;
53   int minimum_jni_version;
54   crazy_callback_poster_t callback_poster;
55   void* callback_poster_opaque;
56 };
57
58 void crazy_context_t::ResetSearchPaths() {
59   search_paths.ResetFromEnv("LD_LIBRARY_PATH");
60 }
61
62 //
63 // API functions
64 //
65
66 extern "C" {
67
68 crazy_context_t* crazy_context_create(void) { return new crazy_context_t(); }
69
70 const char* crazy_context_get_error(crazy_context_t* context) {
71   const char* error = context->error.c_str();
72   return (error[0] != '\0') ? error : NULL;
73 }
74
75 // Clear error in a given context.
76 void crazy_context_clear_error(crazy_context_t* context) {
77   context->error = "";
78 }
79
80 void crazy_context_set_load_address(crazy_context_t* context,
81                                     size_t load_address) {
82   context->load_address = load_address;
83 }
84
85 size_t crazy_context_get_load_address(crazy_context_t* context) {
86   return context->load_address;
87 }
88
89 void crazy_context_set_file_offset(crazy_context_t* context,
90                                    size_t file_offset) {
91   context->file_offset = file_offset;
92 }
93
94 size_t crazy_context_get_file_offset(crazy_context_t* context) {
95   return context->file_offset;
96 }
97
98 crazy_status_t crazy_context_add_search_path(crazy_context_t* context,
99                                              const char* file_path) {
100   context->search_paths.AddPaths(file_path);
101   return CRAZY_STATUS_SUCCESS;
102 }
103
104 crazy_status_t crazy_context_add_search_path_for_address(
105     crazy_context_t* context,
106     void* address) {
107   uintptr_t load_address;
108   char path[512];
109   char* p;
110
111   if (crazy::FindElfBinaryForAddress(
112           address, &load_address, path, sizeof(path)) &&
113       (p = strrchr(path, '/')) != NULL && p[1]) {
114     *p = '\0';
115     return crazy_context_add_search_path(context, path);
116   }
117
118   context->error.Format("Could not find ELF binary at address @%p", address);
119   return CRAZY_STATUS_FAILURE;
120 }
121
122 void crazy_context_reset_search_paths(crazy_context_t* context) {
123   context->ResetSearchPaths();
124 }
125
126 void crazy_context_set_java_vm(crazy_context_t* context,
127                                void* java_vm,
128                                int minimum_jni_version) {
129   context->java_vm = java_vm;
130   context->minimum_jni_version = minimum_jni_version;
131 }
132
133 void crazy_context_get_java_vm(crazy_context_t* context,
134                                void** java_vm,
135                                int* minimum_jni_version) {
136   *java_vm = context->java_vm;
137   *minimum_jni_version = context->minimum_jni_version;
138 }
139
140 void crazy_context_set_callback_poster(crazy_context_t* context,
141                                        crazy_callback_poster_t poster,
142                                        void* poster_opaque) {
143   context->callback_poster = poster;
144   context->callback_poster_opaque = poster_opaque;
145 }
146
147 void crazy_context_get_callback_poster(crazy_context_t* context,
148                                        crazy_callback_poster_t* poster,
149                                        void** poster_opaque) {
150   *poster = context->callback_poster;
151   *poster_opaque = context->callback_poster_opaque;
152 }
153
154 void crazy_callback_run(crazy_callback_t* callback) {
155   (*callback->handler)(callback->opaque);
156 }
157
158 void crazy_context_destroy(crazy_context_t* context) { delete context; }
159
160 // Scoped delayed execution, removes RDebug callbacks on scope exit.  No-op
161 // if callback is NULL.
162 class ScopedDelayedCallbackPoster {
163  public:
164   ScopedDelayedCallbackPoster(crazy_context_t* context) {
165     if (context && context->callback_poster) {
166       crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(&PostFromContext,
167                                                             context);
168       set_delayed_callback_poster_ = true;
169     } else {
170       set_delayed_callback_poster_ = false;
171     }
172   }
173
174   ~ScopedDelayedCallbackPoster() {
175     if (set_delayed_callback_poster_)
176       crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(NULL, NULL);
177   }
178
179  private:
180   // Wrap callback hander and opaque into a call to a crazy_context_poster_t.
181   static bool PostFromContext(void* crazy_context,
182                               crazy_callback_handler_t handler,
183                               void* opaque) {
184     crazy_context_t* context = static_cast<crazy_context_t*>(crazy_context);
185     crazy_callback_t callback;
186     callback.handler = handler;
187     callback.opaque = opaque;
188     return context->callback_poster(&callback,
189                                     context->callback_poster_opaque);
190   }
191
192   // True if the context offered a callback_poster, otherwise false.
193   bool set_delayed_callback_poster_;
194 };
195
196 crazy_status_t crazy_library_open(crazy_library_t** library,
197                                   const char* lib_name,
198                                   crazy_context_t* context) {
199   ScopedDelayedCallbackPoster poster(context);
200   ScopedGlobalLock lock;
201
202   LibraryView* wrap =
203       crazy::Globals::GetLibraries()->LoadLibrary(lib_name,
204                                                   RTLD_NOW,
205                                                   context->load_address,
206                                                   context->file_offset,
207                                                   &context->search_paths,
208                                                   &context->error);
209
210   if (!wrap)
211     return CRAZY_STATUS_FAILURE;
212
213   if (context->java_vm != NULL && wrap->IsCrazy()) {
214     crazy::SharedLibrary* lib = wrap->GetCrazy();
215     if (!lib->SetJavaVM(
216              context->java_vm, context->minimum_jni_version, &context->error)) {
217       crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
218       return CRAZY_STATUS_FAILURE;
219     }
220   }
221
222   *library = reinterpret_cast<crazy_library_t*>(wrap);
223   return CRAZY_STATUS_SUCCESS;
224 }
225
226 crazy_status_t crazy_library_open_in_zip_file(crazy_library_t** library,
227                                               const char* zipfile_name,
228                                               const char* lib_name,
229                                               crazy_context_t* context) {
230   ScopedDelayedCallbackPoster poster(context);
231   ScopedGlobalLock lock;
232
233   LibraryView* wrap =
234       crazy::Globals::GetLibraries()->LoadLibraryInZipFile(
235           zipfile_name,
236           lib_name,
237           RTLD_NOW,
238           context->load_address,
239           &context->search_paths,
240           &context->error);
241
242   if (!wrap)
243     return CRAZY_STATUS_FAILURE;
244
245   if (context->java_vm != NULL && wrap->IsCrazy()) {
246     crazy::SharedLibrary* lib = wrap->GetCrazy();
247     if (!lib->SetJavaVM(
248              context->java_vm, context->minimum_jni_version, &context->error)) {
249       crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
250       return CRAZY_STATUS_FAILURE;
251     }
252   }
253
254   *library = reinterpret_cast<crazy_library_t*>(wrap);
255   return CRAZY_STATUS_SUCCESS;
256 }
257
258 crazy_status_t crazy_library_get_info(crazy_library_t* library,
259                                       crazy_context_t* context,
260                                       crazy_library_info_t* info) {
261   if (!library) {
262     context->error = "Invalid library file handle";
263     return CRAZY_STATUS_FAILURE;
264   }
265
266   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
267   if (!wrap->GetInfo(&info->load_address,
268                      &info->load_size,
269                      &info->relro_start,
270                      &info->relro_size,
271                      &context->error)) {
272     return CRAZY_STATUS_FAILURE;
273   }
274
275   return CRAZY_STATUS_SUCCESS;
276 }
277
278 crazy_status_t crazy_system_can_share_relro(void) {
279   crazy::AshmemRegion region;
280   if (!region.Allocate(PAGE_SIZE, NULL) ||
281       !region.SetProtectionFlags(PROT_READ) ||
282       !crazy::AshmemRegion::CheckFileDescriptorIsReadOnly(region.fd()))
283     return CRAZY_STATUS_FAILURE;
284
285   return CRAZY_STATUS_SUCCESS;
286 }
287
288 crazy_status_t crazy_library_create_shared_relro(crazy_library_t* library,
289                                                  crazy_context_t* context,
290                                                  size_t load_address,
291                                                  size_t* relro_start,
292                                                  size_t* relro_size,
293                                                  int* relro_fd) {
294   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
295
296   if (!library || !wrap->IsCrazy()) {
297     context->error = "Invalid library file handle";
298     return CRAZY_STATUS_FAILURE;
299   }
300
301   crazy::SharedLibrary* lib = wrap->GetCrazy();
302   if (!lib->CreateSharedRelro(
303            load_address, relro_start, relro_size, relro_fd, &context->error))
304     return CRAZY_STATUS_FAILURE;
305
306   return CRAZY_STATUS_SUCCESS;
307 }
308
309 crazy_status_t crazy_library_use_shared_relro(crazy_library_t* library,
310                                               crazy_context_t* context,
311                                               size_t relro_start,
312                                               size_t relro_size,
313                                               int relro_fd) {
314   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
315
316   if (!library || !wrap->IsCrazy()) {
317     context->error = "Invalid library file handle";
318     return CRAZY_STATUS_FAILURE;
319   }
320
321   crazy::SharedLibrary* lib = wrap->GetCrazy();
322   if (!lib->UseSharedRelro(relro_start, relro_size, relro_fd, &context->error))
323     return CRAZY_STATUS_FAILURE;
324
325   return CRAZY_STATUS_SUCCESS;
326 }
327
328 crazy_status_t crazy_library_find_by_name(const char* library_name,
329                                           crazy_library_t** library) {
330   {
331     ScopedGlobalLock lock;
332     LibraryView* wrap =
333         Globals::GetLibraries()->FindLibraryByName(library_name);
334     if (!wrap)
335       return CRAZY_STATUS_FAILURE;
336
337     wrap->AddRef();
338     *library = reinterpret_cast<crazy_library_t*>(wrap);
339   }
340   return CRAZY_STATUS_SUCCESS;
341 }
342
343 crazy_status_t crazy_library_find_symbol(crazy_library_t* library,
344                                          const char* symbol_name,
345                                          void** symbol_address) {
346   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
347
348   // TODO(digit): Handle NULL symbols properly.
349   *symbol_address = wrap->LookupSymbol(symbol_name);
350   return (*symbol_address == NULL) ? CRAZY_STATUS_FAILURE
351                                    : CRAZY_STATUS_SUCCESS;
352 }
353
354 crazy_status_t crazy_linker_find_symbol(const char* symbol_name,
355                                         void** symbol_address) {
356   // TODO(digit): Implement this.
357   return CRAZY_STATUS_FAILURE;
358 }
359
360 crazy_status_t crazy_library_find_from_address(void* address,
361                                                crazy_library_t** library) {
362   {
363     ScopedGlobalLock lock;
364     LibraryView* wrap = Globals::GetLibraries()->FindLibraryForAddress(address);
365     if (!wrap)
366       return CRAZY_STATUS_FAILURE;
367
368     wrap->AddRef();
369
370     *library = reinterpret_cast<crazy_library_t*>(wrap);
371     return CRAZY_STATUS_SUCCESS;
372   }
373 }
374
375 void crazy_library_close(crazy_library_t* library) {
376   crazy_library_close_with_context(library, NULL);
377 }
378
379 void crazy_library_close_with_context(crazy_library_t* library,
380                                       crazy_context_t* context) {
381   if (library) {
382     ScopedDelayedCallbackPoster poster(context);
383     ScopedGlobalLock lock;
384     LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
385
386     Globals::GetLibraries()->UnloadLibrary(wrap);
387   }
388 }
389
390 }  // extern "C"