~sergiusens/libhybris/autotests

« back to all changes in this revision

Viewing changes to hybris/common/gingerbread/dlfcn.c

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo
  • Date: 2013-06-04 07:33:11 UTC
  • Revision ID: package-import@ubuntu.com-20130604073311-20ldi2hm1axkvjl1
Tags: upstream-0.1.0+git20130601+dfb2e26
ImportĀ upstreamĀ versionĀ 0.1.0+git20130601+dfb2e26

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007 The Android Open Source Project
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 *
 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
#define _GNU_SOURCE
 
17
#include <dlfcn.h>
 
18
#include <pthread.h>
 
19
#include <time.h>
 
20
#include <stdio.h>
 
21
#include <string.h>
 
22
#include "linker.h"
 
23
#include "linker_format.h"
 
24
 
 
25
/* This file hijacks the symbols stubbed out in libdl.so. */
 
26
 
 
27
#define DL_SUCCESS                    0
 
28
#define DL_ERR_CANNOT_LOAD_LIBRARY    1
 
29
#define DL_ERR_INVALID_LIBRARY_HANDLE 2
 
30
#define DL_ERR_BAD_SYMBOL_NAME        3
 
31
#define DL_ERR_SYMBOL_NOT_FOUND       4
 
32
#define DL_ERR_SYMBOL_NOT_GLOBAL      5
 
33
 
 
34
static char dl_err_buf[1024];
 
35
static const char *dl_err_str;
 
36
 
 
37
static const char *dl_errors[] = {
 
38
    [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library",
 
39
    [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle",
 
40
    [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name",
 
41
    [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found",
 
42
    [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global",
 
43
};
 
44
 
 
45
#define likely(expr)   __builtin_expect (expr, 1)
 
46
#define unlikely(expr) __builtin_expect (expr, 0)
 
47
 
 
48
pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER;
 
49
 
 
50
static void set_dlerror(int err)
 
51
{
 
52
    format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err],
 
53
             linker_get_error());
 
54
    dl_err_str = (const char *)&dl_err_buf[0];
 
55
};
 
56
 
 
57
void *android_dlopen(const char *filename, int flag)
 
58
{
 
59
    soinfo *ret;
 
60
 
 
61
    pthread_mutex_lock(&dl_lock);
 
62
    ret = find_library(filename);
 
63
    if (unlikely(ret == NULL)) {
 
64
        set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
 
65
    } else {
 
66
        call_constructors_recursive(ret);
 
67
        ret->refcount++;
 
68
    }
 
69
    pthread_mutex_unlock(&dl_lock);
 
70
    return ret;
 
71
}
 
72
 
 
73
const char *android_dlerror(void)
 
74
{
 
75
    const char *tmp = dl_err_str;
 
76
    dl_err_str = NULL;
 
77
    return (const char *)tmp;
 
78
}
 
79
 
 
80
void *android_dlsym(void *handle, const char *symbol)
 
81
{
 
82
    soinfo *found;
 
83
    Elf32_Sym *sym;
 
84
    unsigned bind;
 
85
 
 
86
    pthread_mutex_lock(&dl_lock);
 
87
 
 
88
    if(unlikely(handle == 0)) { 
 
89
        set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE);
 
90
        goto err;
 
91
    }
 
92
    if(unlikely(symbol == 0)) {
 
93
        set_dlerror(DL_ERR_BAD_SYMBOL_NAME);
 
94
        goto err;
 
95
    }
 
96
 
 
97
    if(handle == RTLD_DEFAULT) {
 
98
        sym = lookup(symbol, &found, NULL);
 
99
    } else if(handle == RTLD_NEXT) {
 
100
        void *ret_addr = __builtin_return_address(0);
 
101
        soinfo *si = find_containing_library(ret_addr);
 
102
 
 
103
        sym = NULL;
 
104
        if(si && si->next) {
 
105
            sym = lookup(symbol, &found, si->next);
 
106
        }
 
107
    } else {
 
108
        found = (soinfo*)handle;
 
109
        sym = lookup_in_library(found, symbol);
 
110
    }
 
111
 
 
112
    if(likely(sym != 0)) {
 
113
        bind = ELF32_ST_BIND(sym->st_info);
 
114
 
 
115
        if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
 
116
            unsigned ret = sym->st_value + found->base;
 
117
            pthread_mutex_unlock(&dl_lock);
 
118
            return (void*)ret;
 
119
        }
 
120
 
 
121
        set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL);
 
122
    }
 
123
    else
 
124
        set_dlerror(DL_ERR_SYMBOL_NOT_FOUND);
 
125
 
 
126
err:
 
127
    pthread_mutex_unlock(&dl_lock);
 
128
    return 0;
 
129
}
 
130
 
 
131
int android_dladdr(const void *addr, Dl_info *info)
 
132
{
 
133
    int ret = 0;
 
134
 
 
135
    pthread_mutex_lock(&dl_lock);
 
136
 
 
137
    /* Determine if this address can be found in any library currently mapped */
 
138
    soinfo *si = find_containing_library(addr);
 
139
 
 
140
    if(si) {
 
141
        memset(info, 0, sizeof(Dl_info));
 
142
 
 
143
        info->dli_fname = si->name;
 
144
        info->dli_fbase = (void*)si->base;
 
145
 
 
146
        /* Determine if any symbol in the library contains the specified address */
 
147
        Elf32_Sym *sym = find_containing_symbol(addr, si);
 
148
 
 
149
        if(sym != NULL) {
 
150
            info->dli_sname = si->strtab + sym->st_name;
 
151
            info->dli_saddr = (void*)(si->base + sym->st_value);
 
152
        }
 
153
 
 
154
        ret = 1;
 
155
    }
 
156
 
 
157
    pthread_mutex_unlock(&dl_lock);
 
158
 
 
159
    return ret;
 
160
}
 
161
 
 
162
int android_dlclose(void *handle)
 
163
{
 
164
    pthread_mutex_lock(&dl_lock);
 
165
    (void)unload_library((soinfo*)handle);
 
166
    pthread_mutex_unlock(&dl_lock);
 
167
    return 0;
 
168
}
 
169
 
 
170
 
 
171
#if defined(ANDROID_ARM_LINKER)
 
172
//                     0000000 00011111 111112 22222222 2333333 333344444444445555555
 
173
//                     0123456 78901234 567890 12345678 9012345 678901234567890123456
 
174
#define ANDROID_LIBDL_STRTAB \
 
175
                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0"
 
176
 
 
177
_Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
 
178
 
 
179
#elif defined(ANDROID_X86_LINKER)
 
180
//                     0000000 00011111 111112 22222222 2333333 3333444444444455
 
181
//                     0123456 78901234 567890 12345678 9012345 6789012345678901
 
182
#define ANDROID_LIBDL_STRTAB \
 
183
                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
 
184
int
 
185
android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),
 
186
                void *data);
 
187
 
 
188
#else
 
189
#error Unsupported architecture. Only ARM and x86 are presently supported.
 
190
#endif
 
191
 
 
192
 
 
193
static Elf32_Sym libdl_symtab[] = {
 
194
      // total length of libdl_info.strtab, including trailing 0
 
195
      // This is actually the the STH_UNDEF entry. Technically, it's
 
196
      // supposed to have st_name == 0, but instead, it points to an index
 
197
      // in the strtab with a \0 to make iterating through the symtab easier.
 
198
    { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
 
199
    },
 
200
    { st_name: 0,   // starting index of the name in libdl_info.strtab
 
201
      st_value: (Elf32_Addr) &android_dlopen,
 
202
      st_info: STB_GLOBAL << 4,
 
203
      st_shndx: 1,
 
204
    },
 
205
    { st_name: 7,
 
206
      st_value: (Elf32_Addr) &android_dlclose,
 
207
      st_info: STB_GLOBAL << 4,
 
208
      st_shndx: 1,
 
209
    },
 
210
    { st_name: 15,
 
211
      st_value: (Elf32_Addr) &android_dlsym,
 
212
      st_info: STB_GLOBAL << 4,
 
213
      st_shndx: 1,
 
214
    },
 
215
    { st_name: 21,
 
216
      st_value: (Elf32_Addr) &android_dlerror,
 
217
      st_info: STB_GLOBAL << 4,
 
218
      st_shndx: 1,
 
219
    },
 
220
    { st_name: 29,
 
221
      st_value: (Elf32_Addr) &android_dladdr,
 
222
      st_info: STB_GLOBAL << 4,
 
223
      st_shndx: 1,
 
224
    },
 
225
#ifdef ANDROID_ARM_LINKER
 
226
    { st_name: 36,
 
227
      st_value: (Elf32_Addr) &android_dl_unwind_find_exidx,
 
228
      st_info: STB_GLOBAL << 4,
 
229
      st_shndx: 1,
 
230
    },
 
231
#elif defined(ANDROID_X86_LINKER)
 
232
    { st_name: 36,
 
233
      st_value: (Elf32_Addr) &android_dl_iterate_phdr,
 
234
      st_info: STB_GLOBAL << 4,
 
235
      st_shndx: 1,
 
236
    },
 
237
#endif
 
238
};
 
239
 
 
240
/* Fake out a hash table with a single bucket.
 
241
 * A search of the hash table will look through
 
242
 * libdl_symtab starting with index [1], then
 
243
 * use libdl_chains to find the next index to
 
244
 * look at.  libdl_chains should be set up to
 
245
 * walk through every element in libdl_symtab,
 
246
 * and then end with 0 (sentinel value).
 
247
 *
 
248
 * I.e., libdl_chains should look like
 
249
 * { 0, 2, 3, ... N, 0 } where N is the number
 
250
 * of actual symbols, or nelems(libdl_symtab)-1
 
251
 * (since the first element of libdl_symtab is not
 
252
 * a real symbol).
 
253
 *
 
254
 * (see _elf_lookup())
 
255
 *
 
256
 * Note that adding any new symbols here requires
 
257
 * stubbing them out in libdl.
 
258
 */
 
259
static unsigned libdl_buckets[1] = { 1 };
 
260
static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 };
 
261
 
 
262
soinfo libdl_info = {
 
263
    name: "libdl.so",
 
264
    flags: FLAG_LINKED,
 
265
 
 
266
    strtab: ANDROID_LIBDL_STRTAB,
 
267
    symtab: libdl_symtab,
 
268
 
 
269
    nbucket: 1,
 
270
    nchain: 7,
 
271
    bucket: libdl_buckets,
 
272
    chain: libdl_chains,
 
273
};
 
274