148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Copyright (c) 2013 The Chromium Authors. All rights reserved.
248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Use of this source code is governed by a BSD-style license that can be
348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// found in the LICENSE file.
448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Implements the crazy linker C-based API exposed by <crazy_linker.h>
648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include <crazy_linker.h>
848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include <string.h>
1048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
1148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_error.h"
1248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_ashmem.h"
1348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_globals.h"
1448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_proc_maps.h"
1548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_search_path_list.h"
1648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_shared_library.h"
1748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_thread.h"
1848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_util.h"
1948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_library_view.h"
2048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_system.h"
2148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
2248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerusing crazy::Globals;
2348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerusing crazy::Error;
2448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerusing crazy::SearchPathList;
2548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerusing crazy::ScopedGlobalLock;
2648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerusing crazy::LibraryView;
2748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
2848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner//
2948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// crazy_context_t
3048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner//
3148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
3248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerstruct crazy_context_t {
3348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner public:
3448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  crazy_context_t()
3548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      : load_address(0),
3648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        file_offset(0),
3748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        error(),
3848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        search_paths(),
3948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        java_vm(NULL),
406788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin        minimum_jni_version(0),
416788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin        callback_poster(NULL),
426788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin        callback_poster_opaque(NULL) {
4348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ResetSearchPaths();
4448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
4548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
4648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  void ResetSearchPaths();
4748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
4848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  size_t load_address;
4948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  size_t file_offset;
5048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  Error error;
5148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  SearchPathList search_paths;
5248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  void* java_vm;
5348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  int minimum_jni_version;
546788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  crazy_callback_poster_t callback_poster;
556788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  void* callback_poster_opaque;
5648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner};
5748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
5848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_t::ResetSearchPaths() {
5948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  search_paths.ResetFromEnv("LD_LIBRARY_PATH");
6048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
6148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
6248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner//
6348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// API functions
6448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner//
6548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
6648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerextern "C" {
6748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
6848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_context_t* crazy_context_create(void) { return new crazy_context_t(); }
6948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
7048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerconst char* crazy_context_get_error(crazy_context_t* context) {
7148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  const char* error = context->error.c_str();
7248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return (error[0] != '\0') ? error : NULL;
7348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
7448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
7548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Clear error in a given context.
7648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_clear_error(crazy_context_t* context) {
7748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->error = "";
7848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
7948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
8048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_set_load_address(crazy_context_t* context,
8148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                    size_t load_address) {
8248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->load_address = load_address;
8348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
8448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
8548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnersize_t crazy_context_get_load_address(crazy_context_t* context) {
8648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return context->load_address;
8748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
8848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
8948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_set_file_offset(crazy_context_t* context,
9048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                   size_t file_offset) {
9148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->file_offset = file_offset;
9248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
9348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
9448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnersize_t crazy_context_get_file_offset(crazy_context_t* context) {
9548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return context->file_offset;
9648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
9748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
9848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_context_add_search_path(crazy_context_t* context,
9948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                             const char* file_path) {
10048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->search_paths.AddPaths(file_path);
10148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_SUCCESS;
10248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
10348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
10448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_context_add_search_path_for_address(
10548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    crazy_context_t* context,
10648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    void* address) {
10748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  uintptr_t load_address;
10848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  char path[512];
10948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  char* p;
11048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
11148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (crazy::FindElfBinaryForAddress(
11248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner          address, &load_address, path, sizeof(path)) &&
11348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      (p = strrchr(path, '/')) != NULL && p[1]) {
11448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    *p = '\0';
11548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return crazy_context_add_search_path(context, path);
11648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
11748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
11848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->error.Format("Could not find ELF binary at address @%p", address);
11948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_FAILURE;
12048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
12148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
12248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_reset_search_paths(crazy_context_t* context) {
12348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->ResetSearchPaths();
12448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
12548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
12648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_set_java_vm(crazy_context_t* context,
12748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                               void* java_vm,
12848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                               int minimum_jni_version) {
12948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->java_vm = java_vm;
13048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  context->minimum_jni_version = minimum_jni_version;
13148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
13248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
13348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_get_java_vm(crazy_context_t* context,
13448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                               void** java_vm,
13548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                               int* minimum_jni_version) {
13648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  *java_vm = context->java_vm;
13748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  *minimum_jni_version = context->minimum_jni_version;
13848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
13948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
1406788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinvoid crazy_context_set_callback_poster(crazy_context_t* context,
1416788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                                       crazy_callback_poster_t poster,
1426788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                                       void* poster_opaque) {
1436788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  context->callback_poster = poster;
1446788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  context->callback_poster_opaque = poster_opaque;
1456788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin}
1466788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
1476788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinvoid crazy_context_get_callback_poster(crazy_context_t* context,
1486788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                                       crazy_callback_poster_t* poster,
1496788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                                       void** poster_opaque) {
1506788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  *poster = context->callback_poster;
1516788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  *poster_opaque = context->callback_poster_opaque;
1526788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin}
1536788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
1546788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinvoid crazy_callback_run(crazy_callback_t* callback) {
1556788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  (*callback->handler)(callback->opaque);
1566788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin}
1576788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
15848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_context_destroy(crazy_context_t* context) { delete context; }
15948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
1606788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// Scoped delayed execution, removes RDebug callbacks on scope exit.  No-op
1616788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// if callback is NULL.
1626788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinclass ScopedDelayedCallbackPoster {
1636788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin public:
1646788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  ScopedDelayedCallbackPoster(crazy_context_t* context) {
1656788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    if (context && context->callback_poster) {
1666788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin      crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(&PostFromContext,
1676788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                                                            context);
1686788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin      set_delayed_callback_poster_ = true;
1696788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    } else {
1706788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin      set_delayed_callback_poster_ = false;
1716788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    }
1726788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  }
1736788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
1746788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  ~ScopedDelayedCallbackPoster() {
1756788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    if (set_delayed_callback_poster_)
1766788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin      crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(NULL, NULL);
1776788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  }
1786788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
1796788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin private:
1806788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  // Wrap callback hander and opaque into a call to a crazy_context_poster_t.
1816788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  static bool PostFromContext(void* crazy_context,
1826788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                              crazy_callback_handler_t handler,
1836788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                              void* opaque) {
1846788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    crazy_context_t* context = static_cast<crazy_context_t*>(crazy_context);
1856788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    crazy_callback_t callback;
1866788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    callback.handler = handler;
1876788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    callback.opaque = opaque;
1886788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    return context->callback_poster(&callback,
1896788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                                    context->callback_poster_opaque);
1906788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  }
1916788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
1926788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  // True if the context offered a callback_poster, otherwise false.
1936788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  bool set_delayed_callback_poster_;
1946788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin};
1956788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
19648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_library_open(crazy_library_t** library,
19748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                  const char* lib_name,
19848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                  crazy_context_t* context) {
1996788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  ScopedDelayedCallbackPoster poster(context);
20048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ScopedGlobalLock lock;
2016788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
20248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LibraryView* wrap =
20348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      crazy::Globals::GetLibraries()->LoadLibrary(lib_name,
20448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                                  RTLD_NOW,
20548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                                  context->load_address,
20648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                                  context->file_offset,
20748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                                  &context->search_paths,
20848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                                  &context->error);
2096788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
21048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!wrap)
21148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
21248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
21348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (context->java_vm != NULL && wrap->IsCrazy()) {
21448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    crazy::SharedLibrary* lib = wrap->GetCrazy();
21548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (!lib->SetJavaVM(
21648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner             context->java_vm, context->minimum_jni_version, &context->error)) {
21748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
21848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      return CRAZY_STATUS_FAILURE;
21948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    }
22048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
22148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
22248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  *library = reinterpret_cast<crazy_library_t*>(wrap);
22348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_SUCCESS;
22448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
22548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
22648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_library_get_info(crazy_library_t* library,
22748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                      crazy_context_t* context,
22848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                      crazy_library_info_t* info) {
22948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!library) {
23048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    context->error = "Invalid library file handle";
23148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
23248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
23348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
23448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
23548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!wrap->GetInfo(&info->load_address,
23648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                     &info->load_size,
23748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                     &info->relro_start,
23848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                     &info->relro_size,
23948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                     &context->error)) {
24048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
24148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
24248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
24348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_SUCCESS;
24448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
24548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
24648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_system_can_share_relro(void) {
24748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  crazy::AshmemRegion region;
24848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!region.Allocate(PAGE_SIZE, NULL) ||
24948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      !region.SetProtectionFlags(PROT_READ) ||
250cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner      !crazy::AshmemRegion::CheckFileDescriptorIsReadOnly(region.fd()))
25148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
25248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
25348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_SUCCESS;
25448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
25548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
256cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turnercrazy_status_t crazy_library_create_shared_relro(crazy_library_t* library,
257cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                                 crazy_context_t* context,
258cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                                 size_t load_address,
259cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                                 size_t* relro_start,
260cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                                 size_t* relro_size,
261cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                                 int* relro_fd) {
26248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
26348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
264cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner  if (!library || !wrap->IsCrazy()) {
26548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    context->error = "Invalid library file handle";
26648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
26748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
26848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
269cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner  crazy::SharedLibrary* lib = wrap->GetCrazy();
270cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner  if (!lib->CreateSharedRelro(
271cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner           load_address, relro_start, relro_size, relro_fd, &context->error))
27248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
27348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
27448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_SUCCESS;
27548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
27648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
277cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turnercrazy_status_t crazy_library_use_shared_relro(crazy_library_t* library,
278cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                              crazy_context_t* context,
279cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                              size_t relro_start,
280cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                              size_t relro_size,
281cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner                                              int relro_fd) {
28248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
28348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
284cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner  if (!library || !wrap->IsCrazy()) {
28548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    context->error = "Invalid library file handle";
28648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
28748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
28848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
289cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner  crazy::SharedLibrary* lib = wrap->GetCrazy();
290cc87d1d56b0e1cef0131d9193c702d528417b61aDavid 'Digit' Turner  if (!lib->UseSharedRelro(relro_start, relro_size, relro_fd, &context->error))
29148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_FAILURE;
29248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
29348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_SUCCESS;
29448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
29548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
29648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_library_find_by_name(const char* library_name,
29748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                          crazy_library_t** library) {
29848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  {
29948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ScopedGlobalLock lock;
30048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LibraryView* wrap =
30148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        Globals::GetLibraries()->FindLibraryByName(library_name);
30248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (!wrap)
30348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      return CRAZY_STATUS_FAILURE;
30448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
30548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    wrap->AddRef();
30648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    *library = reinterpret_cast<crazy_library_t*>(wrap);
30748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
30848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_SUCCESS;
30948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
31048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
31148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_library_find_symbol(crazy_library_t* library,
31248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                         const char* symbol_name,
31348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                         void** symbol_address) {
31448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
31548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
31648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // TODO(digit): Handle NULL symbols properly.
31748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  *symbol_address = wrap->LookupSymbol(symbol_name);
31848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return (*symbol_address == NULL) ? CRAZY_STATUS_FAILURE
31948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                   : CRAZY_STATUS_SUCCESS;
32048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
32148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
32248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_linker_find_symbol(const char* symbol_name,
32348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                        void** symbol_address) {
32448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // TODO(digit): Implement this.
32548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return CRAZY_STATUS_FAILURE;
32648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
32748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
32848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnercrazy_status_t crazy_library_find_from_address(void* address,
32948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                                               crazy_library_t** library) {
33048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  {
33148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ScopedGlobalLock lock;
33248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LibraryView* wrap = Globals::GetLibraries()->FindLibraryForAddress(address);
33348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (!wrap)
33448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      return CRAZY_STATUS_FAILURE;
33548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
33648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    wrap->AddRef();
33748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
33848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    *library = reinterpret_cast<crazy_library_t*>(wrap);
33948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return CRAZY_STATUS_SUCCESS;
34048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
34148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
34248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
34348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid crazy_library_close(crazy_library_t* library) {
3446788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  crazy_library_close_with_context(library, NULL);
3456788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin}
3466788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
3476788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinvoid crazy_library_close_with_context(crazy_library_t* library,
3486788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                                      crazy_context_t* context) {
34948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (library) {
3506788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    ScopedDelayedCallbackPoster poster(context);
35148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ScopedGlobalLock lock;
35248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
35348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
35448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    Globals::GetLibraries()->UnloadLibrary(wrap);
35548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
35648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
35748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
35848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}  // extern "C"
359