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" 391