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.
5 // Implements the crazy linker C-based API exposed by <crazy_linker.h>
7 #include <crazy_linker.h>
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"
24 using crazy::SearchPathList;
25 using crazy::ScopedGlobalLock;
26 using crazy::LibraryView;
32 struct crazy_context_t {
40 minimum_jni_version(0),
41 callback_poster(NULL),
42 callback_poster_opaque(NULL),
43 no_map_exec_support_fallback_enabled(false) {
47 void ResetSearchPaths();
52 SearchPathList search_paths;
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;
60 void crazy_context_t::ResetSearchPaths() {
61 search_paths.ResetFromEnv("LD_LIBRARY_PATH");
70 crazy_context_t* crazy_context_create(void) { return new crazy_context_t(); }
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;
77 // Clear error in a given context.
78 void crazy_context_clear_error(crazy_context_t* context) {
82 void crazy_context_set_load_address(crazy_context_t* context,
83 size_t load_address) {
84 context->load_address = load_address;
87 size_t crazy_context_get_load_address(crazy_context_t* context) {
88 return context->load_address;
91 void crazy_context_set_file_offset(crazy_context_t* context,
93 context->file_offset = file_offset;
96 size_t crazy_context_get_file_offset(crazy_context_t* context) {
97 return context->file_offset;
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;
106 crazy_status_t crazy_context_add_search_path_for_address(
107 crazy_context_t* context,
109 uintptr_t load_address;
113 if (crazy::FindElfBinaryForAddress(
114 address, &load_address, path, sizeof(path)) &&
115 (p = strrchr(path, '/')) != NULL && p[1]) {
117 return crazy_context_add_search_path(context, path);
120 context->error.Format("Could not find ELF binary at address @%p", address);
121 return CRAZY_STATUS_FAILURE;
124 void crazy_context_reset_search_paths(crazy_context_t* context) {
125 context->ResetSearchPaths();
128 void crazy_context_set_java_vm(crazy_context_t* context,
130 int minimum_jni_version) {
131 context->java_vm = java_vm;
132 context->minimum_jni_version = minimum_jni_version;
135 void crazy_context_get_java_vm(crazy_context_t* context,
137 int* minimum_jni_version) {
138 *java_vm = context->java_vm;
139 *minimum_jni_version = context->minimum_jni_version;
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;
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;
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;
162 void crazy_callback_run(crazy_callback_t* callback) {
163 (*callback->handler)(callback->opaque);
166 void crazy_context_destroy(crazy_context_t* context) { delete context; }
168 // Scoped delayed execution, removes RDebug callbacks on scope exit. No-op
169 // if callback is NULL.
170 class ScopedDelayedCallbackPoster {
172 ScopedDelayedCallbackPoster(crazy_context_t* context) {
173 if (context && context->callback_poster) {
174 crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(&PostFromContext,
176 set_delayed_callback_poster_ = true;
178 set_delayed_callback_poster_ = false;
182 ~ScopedDelayedCallbackPoster() {
183 if (set_delayed_callback_poster_)
184 crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(NULL, NULL);
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,
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);
200 // True if the context offered a callback_poster, otherwise false.
201 bool set_delayed_callback_poster_;
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;
211 crazy::Globals::GetLibraries()->LoadLibrary(lib_name,
213 context->load_address,
214 context->file_offset,
215 &context->search_paths,
220 return CRAZY_STATUS_FAILURE;
222 if (context->java_vm != NULL && wrap->IsCrazy()) {
223 crazy::SharedLibrary* lib = wrap->GetCrazy();
225 context->java_vm, context->minimum_jni_version, &context->error)) {
226 crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
227 return CRAZY_STATUS_FAILURE;
231 *library = reinterpret_cast<crazy_library_t*>(wrap);
232 return CRAZY_STATUS_SUCCESS;
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;
243 crazy::Globals::GetLibraries()->LoadLibraryInZipFile(
247 context->load_address,
248 &context->search_paths,
249 context->no_map_exec_support_fallback_enabled,
253 return CRAZY_STATUS_FAILURE;
255 if (context->java_vm != NULL && wrap->IsCrazy()) {
256 crazy::SharedLibrary* lib = wrap->GetCrazy();
258 context->java_vm, context->minimum_jni_version, &context->error)) {
259 crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
260 return CRAZY_STATUS_FAILURE;
264 *library = reinterpret_cast<crazy_library_t*>(wrap);
265 return CRAZY_STATUS_SUCCESS;
268 crazy_status_t crazy_library_get_info(crazy_library_t* library,
269 crazy_context_t* context,
270 crazy_library_info_t* info) {
272 context->error = "Invalid library file handle";
273 return CRAZY_STATUS_FAILURE;
276 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
277 if (!wrap->GetInfo(&info->load_address,
282 return CRAZY_STATUS_FAILURE;
285 return CRAZY_STATUS_SUCCESS;
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;
295 return CRAZY_STATUS_SUCCESS;
298 crazy_status_t crazy_library_create_shared_relro(crazy_library_t* library,
299 crazy_context_t* context,
304 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
306 if (!library || !wrap->IsCrazy()) {
307 context->error = "Invalid library file handle";
308 return CRAZY_STATUS_FAILURE;
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;
316 return CRAZY_STATUS_SUCCESS;
319 crazy_status_t crazy_library_use_shared_relro(crazy_library_t* library,
320 crazy_context_t* context,
324 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
326 if (!library || !wrap->IsCrazy()) {
327 context->error = "Invalid library file handle";
328 return CRAZY_STATUS_FAILURE;
331 crazy::SharedLibrary* lib = wrap->GetCrazy();
332 if (!lib->UseSharedRelro(relro_start, relro_size, relro_fd, &context->error))
333 return CRAZY_STATUS_FAILURE;
335 return CRAZY_STATUS_SUCCESS;
338 crazy_status_t crazy_library_find_by_name(const char* library_name,
339 crazy_library_t** library) {
341 ScopedGlobalLock lock;
343 Globals::GetLibraries()->FindLibraryByName(library_name);
345 return CRAZY_STATUS_FAILURE;
348 *library = reinterpret_cast<crazy_library_t*>(wrap);
350 return CRAZY_STATUS_SUCCESS;
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);
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;
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;
370 crazy_status_t crazy_library_find_from_address(void* address,
371 crazy_library_t** library) {
373 ScopedGlobalLock lock;
374 LibraryView* wrap = Globals::GetLibraries()->FindLibraryForAddress(address);
376 return CRAZY_STATUS_FAILURE;
380 *library = reinterpret_cast<crazy_library_t*>(wrap);
381 return CRAZY_STATUS_SUCCESS;
385 crazy_status_t crazy_library_file_path_in_zip_file(const char* lib_name,
387 size_t buffer_size) {
388 crazy::String path = crazy::LibraryList::GetLibraryFilePathInZipFile(
390 if (path.size() >= buffer_size) {
391 return CRAZY_STATUS_FAILURE;
394 memcpy(buffer, path.c_str(), path.size());
395 buffer[path.size()] = '\0';
396 return CRAZY_STATUS_SUCCESS;
399 crazy_status_t crazy_linker_check_library_is_mappable_in_zip_file(
400 const char* zipfile_name,
401 const char* lib_name) {
403 if (crazy::LibraryList::FindMappableLibraryInZipFile(
404 zipfile_name, lib_name, &error) == CRAZY_OFFSET_FAILED)
405 return CRAZY_STATUS_FAILURE;
407 return CRAZY_STATUS_SUCCESS;
410 void crazy_library_close(crazy_library_t* library) {
411 crazy_library_close_with_context(library, NULL);
414 void crazy_library_close_with_context(crazy_library_t* library,
415 crazy_context_t* context) {
417 ScopedDelayedCallbackPoster poster(context);
418 ScopedGlobalLock lock;
419 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
421 Globals::GetLibraries()->UnloadLibrary(wrap);