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