1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifndef CRAZY_LINKER_RDEBUG_H
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define CRAZY_LINKER_RDEBUG_H
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <stdint.h>
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// The system linker maintains two lists of libraries at runtime:
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// - A list that is used by GDB and other tools to search for the
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   binaries that are loaded in the process.
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   This list is accessible by looking at the DT_DEBUG field of the
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   dynamic section of any ELF binary loaded by the linker (including
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   itself). The field contains the address of a global '_r_debug'
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   variable. More on this later.
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// - A list that is used internally to implement library and symbol
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   lookup. The list head and tail are called 'solist' and 'sonext'
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   in the linker sources, and their address is unknown (and randomized
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   by ASLR), and there is no point trying to change it.
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// This means that you cannot call the linker's dlsym() function to
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// lookup symbols in libraries that are not loaded through it, i.e.
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// any custom dynamic linker needs its own dlopen() / dlsym() and other
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// related functions, and ensure the loaded code only uses its own version.
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// (See support code in crazy_linker_wrappers.cpp)
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// The global '_r_debug' variable is a r_debug structure, whose layout
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// must be known by GDB, with the following fields:
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     r_version   -> version of the structure (must be 1)
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     r_map       -> head of a linked list of 'link_map_t' entries,
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//                    one per ELF 'binary' in the process address space.
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     r_brk       -> pointer to a specific debugging function (see below).
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     r_state     -> state variable to be read in r_brk().
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     r_ldbase    -> unused by the system linker, should be 0. (?)
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// The 'r_brk' field points to an empty function in the system linker
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// that is used to notify GDB of changes in the list of shared libraries,
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// this works as follows:
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   - When the linker wants to add a new shared library to the list,
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     it first writes RT_ADD to 'r_state', then calls 'r_brk()'.
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     It modifies the list, then writes RT_CONSISTENT to 'r_state' and
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     calls 'r_brk()' again.
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   - When unloading a library, RT_DELETE + RT_CONSISTENT are used
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     instead.
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// GDB will always place a breakpoint on the function pointed to by
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// 'r_brk', and will be able to synchronize with the linker's
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// modifications.
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// The 'r_map' field is a list of nodes with the following structure
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// describing each loaded shared library for GDB:
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   l_addr  -> Load address of the first PT_LOAD segment in a
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//              shared library. Note that this is 0 for the linker itself
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//              and the load-bias for an executable.
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   l_name  -> Name of the executable. This is _always_ a basename!!
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   l_ld    -> Address of the dynamic table for this binary.
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   l_next  -> Pointer to next item in 'r_map' list or NULL.
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   l_prev  -> Pointer to previous item in 'r_map' list.
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Note that the system linker ensures that there are always at least
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// two items in this list:
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// - The first item always describes the linker itself, the fields
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   actually point to a specially crafted fake entry for it called
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   'libdl_info' in the linker sources.
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// - The second item describes the executable that was started by
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   the kernel. For Android applications, it will always be 'app_process'
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   and completely uninteresting.
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// - Eventually, another entry for VDSOs on platforms that support them.
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// When implementing a custom linker, being able to debug the process
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// unfortunately requires modifying the 'r_map' list to also account
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// for libraries loading through it.
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// One issue with this is that the linker also uses another internal
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// variable, called '_r_debut_tail' that points to the last item in
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// the list. And there is no way to access it directly. This can lead
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// to problems when calling APIs that actually end up using the system's
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// own dlopen(). Consider this example:
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//  1/ Program loads crazy_linker
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//  2/ Program uses crazy_linker to load libfoo.so, this adds
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     a new entry at the end of the '_r_debug.r_map' list, but
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     '_r_debug.tail' is unmodified.
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//  3/ libfoo.so or the Java portion of the program calls a system API
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     that ends up loading another library (e.g. libGLESv2_vendor.so),
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     this calls the system dlopen().
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//  4/ The system dlopen() adds a new entry to the "_r_debug.r_map"
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     list by updating the l_next / l_prev fields of the entry pointed
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     to by '_r_debug_tail', and this removes 'libfoo.so' from the list!
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// There is a simple work-around for this issue: Always insert our
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// libraries at the _start_ of the 'r_map' list, instead of appending
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// them to the end. The system linker doesn't know about custom-loaded
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// libraries and thus will never try to unload them.
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Note that the linker never uses the 'r_map' list (except or updating
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// it for GDB), it only uses 'solist / sonext' to actually perform its
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// operations. That's ok if our custom linker completely wraps and
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// re-implements these.
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// The system linker expects to be the only item modifying the 'r_map'
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// list, and as such it may set the pages that contain the list readonly
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// outside of its own modifications. In threaded environments where the
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// system linker and the crazy linker are operating simultaneously on
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// different threads this may be a problem; we need these pages to be
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// writable when we have to update the list. We cannot track the system
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// linker's actions, so to avoid clashing with it we may need to try and
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// move 'r_map' updates to a different thread, to serialize them with
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// other system linker activity.
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace crazy {
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)struct link_map_t {
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uintptr_t l_addr;
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  char* l_name;
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uintptr_t l_ld;
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  link_map_t* l_next;
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  link_map_t* l_prev;
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Values for r_debug->r_state
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)enum {
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RT_CONSISTENT,
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RT_ADD,
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RT_DELETE
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)struct r_debug {
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int32_t r_version;
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  link_map_t* r_map;
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void (*r_brk)(void);
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int32_t r_state;
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uintptr_t r_ldbase;
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// A callback poster is a function that can be called to request a later
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// callback. Poster arguments are: an opaque pointer to the caller's
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// context, a pointer to a function with a single void* argument that will
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// handle the callback, and the opaque void* argument value to send with
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// the callback.
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)typedef void (*crazy_callback_handler_t)(void* opaque);
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)typedef bool (*rdebug_callback_poster_t)(void* context,
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                         crazy_callback_handler_t,
158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                         void* opaque);
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// A callback handler is a static function, either AddEntryInternal() or
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// DelEntryInternal(). It calls the appropriate r_map update member
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// function, AddEntryImpl() or DelEntryImpl().
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class RDebug;
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)typedef void (*rdebug_callback_handler_t)(RDebug*, link_map_t*);
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class RDebug {
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RDebug() : r_debug_(NULL), init_(false),
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             readonly_entries_(false), post_for_later_execution_(NULL),
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             post_for_later_execution_context_(NULL) {}
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ~RDebug() {}
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Add entries to and remove entries from the list. If post for later
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // execution is enabled, schedule callbacks and return. Otherwise
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // action immediately.
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void AddEntry(link_map_t* entry) { RunOrDelay(&AddEntryInternal, entry); }
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void DelEntry(link_map_t* entry) { RunOrDelay(&DelEntryInternal, entry); }
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Assign the function used to request a callback from another thread.
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The context here is opaque, but is the API's crazy_context.
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void SetDelayedCallbackPoster(rdebug_callback_poster_t poster,
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                void* context) {
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    post_for_later_execution_ = poster;
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    post_for_later_execution_context_ = context;
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  r_debug* GetAddress() { return r_debug_; }
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Try to find the address of the global _r_debug variable, even
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // though there is no symbol for it. Returns true on success.
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool Init();
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Support for scheduling list manipulation through callbacks.
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // AddEntry() and DelEntry() pass the addresses of static functions to
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // to RunOrDelay(). This requests a callback if later execution
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // is enabled, otherwise it runs immediately on the current thread.
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // AddEntryImpl() and DelEntryImpl() are the member functions called
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // by the static ones to do the actual work.
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void AddEntryImpl(link_map_t* entry);
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void DelEntryImpl(link_map_t* entry);
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static void AddEntryInternal(RDebug* rdebug, link_map_t* entry) {
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    rdebug->AddEntryImpl(entry);
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static void DelEntryInternal(RDebug* rdebug, link_map_t* entry) {
206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    rdebug->DelEntryImpl(entry);
207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Post handler for delayed execution. Return true if delayed execution
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // is enabled and posting succeeded.
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool PostCallback(rdebug_callback_handler_t handler, link_map_t* entry);
212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Run handler as a callback if enabled, otherwise immediately.
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void RunOrDelay(rdebug_callback_handler_t handler, link_map_t* entry) {
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!PostCallback(handler, entry))
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      (*handler)(this, entry);
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RDebug(const RDebug&);
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RDebug& operator=(const RDebug&);
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  r_debug* r_debug_;
223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool init_;
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool readonly_entries_;
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  rdebug_callback_poster_t post_for_later_execution_;
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void* post_for_later_execution_context_;
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace crazy
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // CRAZY_LINKER_REDUG_H
232