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) {
46 void ResetSearchPaths();
51 SearchPathList search_paths;
53 int minimum_jni_version;
54 crazy_callback_poster_t callback_poster;
55 void* callback_poster_opaque;
58 void crazy_context_t::ResetSearchPaths() {
59 search_paths.ResetFromEnv("LD_LIBRARY_PATH");
68 crazy_context_t* crazy_context_create(void) { return new crazy_context_t(); }
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;
75 // Clear error in a given context.
76 void crazy_context_clear_error(crazy_context_t* context) {
80 void crazy_context_set_load_address(crazy_context_t* context,
81 size_t load_address) {
82 context->load_address = load_address;
85 size_t crazy_context_get_load_address(crazy_context_t* context) {
86 return context->load_address;
89 void crazy_context_set_file_offset(crazy_context_t* context,
91 context->file_offset = file_offset;
94 size_t crazy_context_get_file_offset(crazy_context_t* context) {
95 return context->file_offset;
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;
104 crazy_status_t crazy_context_add_search_path_for_address(
105 crazy_context_t* context,
107 uintptr_t load_address;
111 if (crazy::FindElfBinaryForAddress(
112 address, &load_address, path, sizeof(path)) &&
113 (p = strrchr(path, '/')) != NULL && p[1]) {
115 return crazy_context_add_search_path(context, path);
118 context->error.Format("Could not find ELF binary at address @%p", address);
119 return CRAZY_STATUS_FAILURE;
122 void crazy_context_reset_search_paths(crazy_context_t* context) {
123 context->ResetSearchPaths();
126 void crazy_context_set_java_vm(crazy_context_t* context,
128 int minimum_jni_version) {
129 context->java_vm = java_vm;
130 context->minimum_jni_version = minimum_jni_version;
133 void crazy_context_get_java_vm(crazy_context_t* context,
135 int* minimum_jni_version) {
136 *java_vm = context->java_vm;
137 *minimum_jni_version = context->minimum_jni_version;
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;
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;
154 void crazy_callback_run(crazy_callback_t* callback) {
155 (*callback->handler)(callback->opaque);
158 void crazy_context_destroy(crazy_context_t* context) { delete context; }
160 // Scoped delayed execution, removes RDebug callbacks on scope exit. No-op
161 // if callback is NULL.
162 class ScopedDelayedCallbackPoster {
164 ScopedDelayedCallbackPoster(crazy_context_t* context) {
165 if (context && context->callback_poster) {
166 crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(&PostFromContext,
168 set_delayed_callback_poster_ = true;
170 set_delayed_callback_poster_ = false;
174 ~ScopedDelayedCallbackPoster() {
175 if (set_delayed_callback_poster_)
176 crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(NULL, NULL);
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,
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);
192 // True if the context offered a callback_poster, otherwise false.
193 bool set_delayed_callback_poster_;
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;
203 crazy::Globals::GetLibraries()->LoadLibrary(lib_name,
205 context->load_address,
206 context->file_offset,
207 &context->search_paths,
211 return CRAZY_STATUS_FAILURE;
213 if (context->java_vm != NULL && wrap->IsCrazy()) {
214 crazy::SharedLibrary* lib = wrap->GetCrazy();
216 context->java_vm, context->minimum_jni_version, &context->error)) {
217 crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
218 return CRAZY_STATUS_FAILURE;
222 *library = reinterpret_cast<crazy_library_t*>(wrap);
223 return CRAZY_STATUS_SUCCESS;
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;
234 crazy::Globals::GetLibraries()->LoadLibraryInZipFile(
238 context->load_address,
239 &context->search_paths,
243 return CRAZY_STATUS_FAILURE;
245 if (context->java_vm != NULL && wrap->IsCrazy()) {
246 crazy::SharedLibrary* lib = wrap->GetCrazy();
248 context->java_vm, context->minimum_jni_version, &context->error)) {
249 crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
250 return CRAZY_STATUS_FAILURE;
254 *library = reinterpret_cast<crazy_library_t*>(wrap);
255 return CRAZY_STATUS_SUCCESS;
258 crazy_status_t crazy_library_get_info(crazy_library_t* library,
259 crazy_context_t* context,
260 crazy_library_info_t* info) {
262 context->error = "Invalid library file handle";
263 return CRAZY_STATUS_FAILURE;
266 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
267 if (!wrap->GetInfo(&info->load_address,
272 return CRAZY_STATUS_FAILURE;
275 return CRAZY_STATUS_SUCCESS;
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;
285 return CRAZY_STATUS_SUCCESS;
288 crazy_status_t crazy_library_create_shared_relro(crazy_library_t* library,
289 crazy_context_t* context,
294 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
296 if (!library || !wrap->IsCrazy()) {
297 context->error = "Invalid library file handle";
298 return CRAZY_STATUS_FAILURE;
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;
306 return CRAZY_STATUS_SUCCESS;
309 crazy_status_t crazy_library_use_shared_relro(crazy_library_t* library,
310 crazy_context_t* context,
314 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
316 if (!library || !wrap->IsCrazy()) {
317 context->error = "Invalid library file handle";
318 return CRAZY_STATUS_FAILURE;
321 crazy::SharedLibrary* lib = wrap->GetCrazy();
322 if (!lib->UseSharedRelro(relro_start, relro_size, relro_fd, &context->error))
323 return CRAZY_STATUS_FAILURE;
325 return CRAZY_STATUS_SUCCESS;
328 crazy_status_t crazy_library_find_by_name(const char* library_name,
329 crazy_library_t** library) {
331 ScopedGlobalLock lock;
333 Globals::GetLibraries()->FindLibraryByName(library_name);
335 return CRAZY_STATUS_FAILURE;
338 *library = reinterpret_cast<crazy_library_t*>(wrap);
340 return CRAZY_STATUS_SUCCESS;
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);
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;
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;
360 crazy_status_t crazy_library_find_from_address(void* address,
361 crazy_library_t** library) {
363 ScopedGlobalLock lock;
364 LibraryView* wrap = Globals::GetLibraries()->FindLibraryForAddress(address);
366 return CRAZY_STATUS_FAILURE;
370 *library = reinterpret_cast<crazy_library_t*>(wrap);
371 return CRAZY_STATUS_SUCCESS;
375 void crazy_library_close(crazy_library_t* library) {
376 crazy_library_close_with_context(library, NULL);
379 void crazy_library_close_with_context(crazy_library_t* library,
380 crazy_context_t* context) {
382 ScopedDelayedCallbackPoster poster(context);
383 ScopedGlobalLock lock;
384 LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
386 Globals::GetLibraries()->UnloadLibrary(wrap);