Bug 588607 - 0. Add bionic linker files, r=lvilla a=blocking-fennec

--HG--
extra : rebase_source : 8ea4efe4309b8fac52ba62cd22a2c69039061755
This commit is contained in:
Michael Wu 2010-10-15 11:27:48 -07:00
parent a3298dd3ca
commit f71e519090
12 changed files with 4196 additions and 0 deletions

156
other-licenses/android/ba.c Normal file
View File

@ -0,0 +1,156 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "linker.h"
#include "linker_debug.h"
#include "ba.h"
#undef min
#define min(a,b) ((a)<(b)?(a):(b))
#define BA_IS_FREE(index) (!(ba->bitmap[index].allocated))
#define BA_ORDER(index) ba->bitmap[index].order
#define BA_BUDDY_INDEX(index) ((index) ^ (1 << BA_ORDER(index)))
#define BA_NEXT_INDEX(index) ((index) + (1 << BA_ORDER(index)))
#define BA_OFFSET(index) ((index) * ba->min_alloc)
#define BA_START_ADDR(index) (BA_OFFSET(index) + ba->base)
#define BA_LEN(index) ((1 << BA_ORDER(index)) * ba->min_alloc)
static unsigned long ba_order(struct ba *ba, unsigned long len);
void ba_init(struct ba *ba)
{
int i, index = 0;
unsigned long max_order = ba_order(ba, ba->size);
if (ba->max_order == 0 || ba->max_order > max_order)
ba->max_order = max_order;
for (i = sizeof(ba->num_entries) * 8 - 1; i >= 0; i--) {
if (ba->num_entries & 1<<i) {
BA_ORDER(index) = i;
index = BA_NEXT_INDEX(index);
}
}
}
int ba_free(struct ba *ba, int index)
{
int buddy, curr = index;
/* clean up the bitmap, merging any buddies */
ba->bitmap[curr].allocated = 0;
/* find a slots buddy Buddy# = Slot# ^ (1 << order)
* if the buddy is also free merge them
* repeat until the buddy is not free or end of the bitmap is reached
*/
do {
buddy = BA_BUDDY_INDEX(curr);
if (BA_IS_FREE(buddy) &&
BA_ORDER(buddy) == BA_ORDER(curr)) {
BA_ORDER(buddy)++;
BA_ORDER(curr)++;
curr = min(buddy, curr);
} else {
break;
}
} while (curr < ba->num_entries);
return 0;
}
static unsigned long ba_order(struct ba *ba, unsigned long len)
{
unsigned long i;
len = (len + ba->min_alloc - 1) / ba->min_alloc;
len--;
for (i = 0; i < sizeof(len)*8; i++)
if (len >> i == 0)
break;
return i;
}
int ba_allocate(struct ba *ba, unsigned long len)
{
int curr = 0;
int end = ba->num_entries;
int best_fit = -1;
unsigned long order = ba_order(ba, len);
if (order > ba->max_order)
return -1;
/* look through the bitmap:
* if you find a free slot of the correct order use it
* otherwise, use the best fit (smallest with size > order) slot
*/
while (curr < end) {
if (BA_IS_FREE(curr)) {
if (BA_ORDER(curr) == (unsigned char)order) {
/* set the not free bit and clear others */
best_fit = curr;
break;
}
if (BA_ORDER(curr) > (unsigned char)order &&
(best_fit < 0 ||
BA_ORDER(curr) < BA_ORDER(best_fit)))
best_fit = curr;
}
curr = BA_NEXT_INDEX(curr);
}
/* if best_fit < 0, there are no suitable slots,
* return an error
*/
if (best_fit < 0)
return -1;
/* now partition the best fit:
* split the slot into 2 buddies of order - 1
* repeat until the slot is of the correct order
*/
while (BA_ORDER(best_fit) > (unsigned char)order) {
int buddy;
BA_ORDER(best_fit) -= 1;
buddy = BA_BUDDY_INDEX(best_fit);
BA_ORDER(buddy) = BA_ORDER(best_fit);
}
ba->bitmap[best_fit].allocated = 1;
return best_fit;
}
unsigned long ba_start_addr(struct ba *ba, int index)
{
return BA_START_ADDR(index);
}
unsigned long ba_len(struct ba *ba, int index)
{
return BA_LEN(index);
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __LINKER_BA_H
#define __LINKER_BA_H
struct ba_bits {
unsigned allocated:1; /* 1 if allocated, 0 if free */
unsigned order:7; /* size of the region in ba space */
};
struct ba {
/* start address of the ba space */
unsigned long base;
/* total size of the ba space */
unsigned long size;
/* the smaller allocation that can be made */
unsigned long min_alloc;
/* the order of the largest allocation that can be made */
unsigned long max_order;
/* number of entries in the ba space */
int num_entries;
/* the bitmap for the region indicating which entries are allocated
* and which are free */
struct ba_bits *bitmap;
};
extern void ba_init(struct ba *ba);
extern int ba_allocate(struct ba *ba, unsigned long len);
extern int ba_free(struct ba *ba, int index);
extern unsigned long ba_start_addr(struct ba *ba, int index);
extern unsigned long ba_len(struct ba *ba, int index);
#endif

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SYS_TLS_H
#define _SYS_TLS_H
#include <sys/cdefs.h>
__BEGIN_DECLS
/** WARNING WARNING WARNING
**
** This header file is *NOT* part of the public Bionic ABI/API
** and should not be used/included by user-serviceable parts of
** the system (e.g. applications).
**
** It is only provided here for the benefit of the system dynamic
** linker and the OpenGL sub-system (which needs to access the
** pre-allocated slot directly for performance reason).
**/
/* maximum number of elements in the TLS array */
#define BIONIC_TLS_SLOTS 64
/* note that slot 0, called TLS_SLOT_SELF must point to itself.
* this is required to implement thread-local storage with the x86
* Linux kernel, that reads the TLS from fs:[0], where 'fs' is a
* thread-specific segment descriptor...
*/
/* Well known TLS slots */
#define TLS_SLOT_SELF 0
#define TLS_SLOT_THREAD_ID 1
#define TLS_SLOT_ERRNO 2
#define TLS_SLOT_OPENGL_API 3
#define TLS_SLOT_OPENGL 4
/* this slot is only used to pass information from the dynamic linker to
* libc.so when the C library is loaded in to memory. The C runtime init
* function will then clear it. Since its use is extremely temporary,
* we reuse an existing location.
*/
#define TLS_SLOT_BIONIC_PREINIT (TLS_SLOT_ERRNO+1)
/* small technical note: it is not possible to call pthread_setspecific
* on keys that are <= TLS_SLOT_MAX_WELL_KNOWN, which is why it is set to
* TLS_SLOT_ERRNO.
*
* later slots like TLS_SLOT_OPENGL are pre-allocated through the use of
* TLS_DEFAULT_ALLOC_MAP. this means that there is no need to use
* pthread_key_create() to initialize them. on the other hand, there is
* no destructor associated to them (we might need to implement this later)
*/
#define TLS_SLOT_MAX_WELL_KNOWN TLS_SLOT_ERRNO
#define TLS_DEFAULT_ALLOC_MAP 0x0000001F
/* set the Thread Local Storage, must contain at least BIONIC_TLS_SLOTS pointers */
extern void __init_tls(void** tls, void* thread_info);
/* syscall only, do not call directly */
extern int __set_tls(void *ptr);
/* get the TLS */
#ifdef __arm__
/* Linux kernel helpers for its TLS implementation */
/* For performance reasons, avoid calling the kernel helper
* Note that HAVE_ARM_TLS_REGISTER is build-specific
* (it must match your kernel configuration)
*/
# ifdef HAVE_ARM_TLS_REGISTER
# define __get_tls() \
({ register unsigned int __val asm("r0"); \
asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \
(volatile void*)__val; })
# else /* !HAVE_ARM_TLS_REGISTER */
# define __get_tls() ( *((volatile void **) 0xffff0ff0) )
# endif
#else
extern void* __get_tls( void );
#endif
/* return the stack base and size, used by our malloc debugger */
extern void* __get_stack_base(int *p_stack_size);
__END_DECLS
#endif /* _SYS_TLS_H */

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <signal.h>
#include <sys/mman.h>
#include <errno.h>
#include "linker.h"
#include <sys/socket.h>
#include <cutils/sockets.h>
void notify_gdb_of_libraries();
#define RETRY_ON_EINTR(ret,cond) \
do { \
ret = (cond); \
} while (ret < 0 && errno == EINTR)
void debugger_signal_handler(int n)
{
unsigned tid;
int s;
/* avoid picking up GC interrupts */
signal(SIGUSR1, SIG_IGN);
tid = gettid();
s = socket_local_client("android:debuggerd",
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if(s >= 0) {
/* debugger knows our pid from the credentials on the
* local socket but we need to tell it our tid. It
* is paranoid and will verify that we are giving a tid
* that's actually in our process
*/
int ret;
RETRY_ON_EINTR(ret, write(s, &tid, sizeof(unsigned)));
if (ret == sizeof(unsigned)) {
/* if the write failed, there is no point to read on
* the file descriptor. */
RETRY_ON_EINTR(ret, read(s, &tid, 1));
notify_gdb_of_libraries();
}
close(s);
}
/* remove our net so we fault for real when we return */
signal(n, SIG_IGN);
}
void debugger_init()
{
signal(SIGILL, debugger_signal_handler);
signal(SIGABRT, debugger_signal_handler);
signal(SIGBUS, debugger_signal_handler);
signal(SIGFPE, debugger_signal_handler);
signal(SIGSEGV, debugger_signal_handler);
signal(SIGSTKFLT, debugger_signal_handler);
signal(SIGPIPE, debugger_signal_handler);
}

View File

@ -0,0 +1,276 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include "linker.h"
#include "linker_format.h"
/* This file hijacks the symbols stubbed out in libdl.so. */
#define DL_SUCCESS 0
#define DL_ERR_CANNOT_LOAD_LIBRARY 1
#define DL_ERR_INVALID_LIBRARY_HANDLE 2
#define DL_ERR_BAD_SYMBOL_NAME 3
#define DL_ERR_SYMBOL_NOT_FOUND 4
#define DL_ERR_SYMBOL_NOT_GLOBAL 5
static char dl_err_buf[1024];
static const char *dl_err_str;
static const char *dl_errors[] = {
[DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library",
[DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle",
[DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name",
[DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found",
[DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global",
};
#define likely(expr) __builtin_expect (expr, 1)
#define unlikely(expr) __builtin_expect (expr, 0)
static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER;
static void set_dlerror(int err)
{
format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err],
linker_get_error());
dl_err_str = (const char *)&dl_err_buf[0];
};
void *dlopen(const char *filename, int flag)
{
soinfo *ret;
pthread_mutex_lock(&dl_lock);
ret = find_library(filename);
if (unlikely(ret == NULL)) {
set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
} else {
ret->refcount++;
}
pthread_mutex_unlock(&dl_lock);
return ret;
}
const char *dlerror(void)
{
const char *tmp = dl_err_str;
dl_err_str = NULL;
return (const char *)tmp;
}
void *dlsym(void *handle, const char *symbol)
{
soinfo *found;
Elf32_Sym *sym;
unsigned bind;
pthread_mutex_lock(&dl_lock);
if(unlikely(handle == 0)) {
set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE);
goto err;
}
if(unlikely(symbol == 0)) {
set_dlerror(DL_ERR_BAD_SYMBOL_NAME);
goto err;
}
if(handle == RTLD_DEFAULT) {
sym = lookup(symbol, &found, NULL);
} else if(handle == RTLD_NEXT) {
void *ret_addr = __builtin_return_address(0);
soinfo *si = find_containing_library(ret_addr);
sym = NULL;
if(si && si->next) {
sym = lookup(symbol, &found, si->next);
}
} else {
found = (soinfo*)handle;
sym = lookup_in_library(found, symbol);
}
if(likely(sym != 0)) {
bind = ELF32_ST_BIND(sym->st_info);
if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
unsigned ret = sym->st_value + found->base;
pthread_mutex_unlock(&dl_lock);
return (void*)ret;
}
set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL);
}
else
set_dlerror(DL_ERR_SYMBOL_NOT_FOUND);
err:
pthread_mutex_unlock(&dl_lock);
return 0;
}
int dladdr(void *addr, Dl_info *info)
{
int ret = 0;
pthread_mutex_lock(&dl_lock);
/* Determine if this address can be found in any library currently mapped */
soinfo *si = find_containing_library(addr);
if(si) {
memset(info, 0, sizeof(Dl_info));
info->dli_fname = si->name;
info->dli_fbase = (void*)si->base;
/* Determine if any symbol in the library contains the specified address */
Elf32_Sym *sym = find_containing_symbol(addr, si);
if(sym != NULL) {
info->dli_sname = si->strtab + sym->st_name;
info->dli_saddr = (void*)(si->base + sym->st_value);
}
ret = 1;
}
pthread_mutex_unlock(&dl_lock);
return ret;
}
int dlclose(void *handle)
{
pthread_mutex_lock(&dl_lock);
(void)unload_library((soinfo*)handle);
pthread_mutex_unlock(&dl_lock);
return 0;
}
#if defined(ANDROID_ARM_LINKER)
// 0000000 00011111 111112 22222222 2333333 333344444444445555555
// 0123456 78901234 567890 12345678 9012345 678901234567890123456
#define ANDROID_LIBDL_STRTAB \
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0"
#elif defined(ANDROID_X86_LINKER)
// 0000000 00011111 111112 22222222 2333333 3333444444444455
// 0123456 78901234 567890 12345678 9012345 6789012345678901
#define ANDROID_LIBDL_STRTAB \
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
#elif defined(ANDROID_SH_LINKER)
// 0000000 00011111 111112 22222222 2333333 3333444444444455
// 0123456 78901234 567890 12345678 9012345 6789012345678901
#define ANDROID_LIBDL_STRTAB \
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
#else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */
#error Unsupported architecture. Only ARM and x86 are presently supported.
#endif
static Elf32_Sym libdl_symtab[] = {
// total length of libdl_info.strtab, including trailing 0
// This is actually the the STH_UNDEF entry. Technically, it's
// supposed to have st_name == 0, but instead, it points to an index
// in the strtab with a \0 to make iterating through the symtab easier.
{ st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
},
{ st_name: 0, // starting index of the name in libdl_info.strtab
st_value: (Elf32_Addr) &dlopen,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
{ st_name: 7,
st_value: (Elf32_Addr) &dlclose,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
{ st_name: 15,
st_value: (Elf32_Addr) &dlsym,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
{ st_name: 21,
st_value: (Elf32_Addr) &dlerror,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
{ st_name: 29,
st_value: (Elf32_Addr) &dladdr,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
#ifdef ANDROID_ARM_LINKER
{ st_name: 36,
st_value: (Elf32_Addr) &dl_unwind_find_exidx,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
#elif defined(ANDROID_X86_LINKER)
{ st_name: 36,
st_value: (Elf32_Addr) &dl_iterate_phdr,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
#elif defined(ANDROID_SH_LINKER)
{ st_name: 36,
st_value: (Elf32_Addr) &dl_iterate_phdr,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
#endif
};
/* Fake out a hash table with a single bucket.
* A search of the hash table will look through
* libdl_symtab starting with index [1], then
* use libdl_chains to find the next index to
* look at. libdl_chains should be set up to
* walk through every element in libdl_symtab,
* and then end with 0 (sentinel value).
*
* I.e., libdl_chains should look like
* { 0, 2, 3, ... N, 0 } where N is the number
* of actual symbols, or nelems(libdl_symtab)-1
* (since the first element of libdl_symtab is not
* a real symbol).
*
* (see _elf_lookup())
*
* Note that adding any new symbols here requires
* stubbing them out in libdl.
*/
static unsigned libdl_buckets[1] = { 1 };
static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 };
soinfo libdl_info = {
name: "libdl.so",
flags: FLAG_LINKED,
strtab: ANDROID_LIBDL_STRTAB,
symtab: libdl_symtab,
nbucket: 1,
nchain: 7,
bucket: libdl_buckets,
chain: libdl_chains,
};

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __DLFCN_H__
#define __DLFCN_H__
#include <sys/cdefs.h>
__BEGIN_DECLS
typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Address at which shared object
is loaded */
const char *dli_sname; /* Name of nearest symbol with address
lower than addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;
extern void* dlopen(const char* filename, int flag);
extern int dlclose(void* handle);
extern const char* dlerror(void);
extern void* dlsym(void* handle, const char* symbol);
extern int dladdr(void* addr, Dl_info *info);
enum {
RTLD_NOW = 0,
RTLD_LAZY = 1,
RTLD_LOCAL = 0,
RTLD_GLOBAL = 2,
};
#define RTLD_DEFAULT ((void*) 0xffffffff)
#define RTLD_NEXT ((void*) 0xfffffffe)
__END_DECLS
#endif /* __DLFCN_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,239 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LINKER_H_
#define _LINKER_H_
#include <unistd.h>
#include <sys/types.h>
#include <linux/elf.h>
#undef PAGE_MASK
#undef PAGE_SIZE
#define PAGE_SIZE 4096
#define PAGE_MASK 4095
void debugger_init();
const char *addr_to_name(unsigned addr);
/* magic shared structures that GDB knows about */
struct link_map
{
uintptr_t l_addr;
char * l_name;
uintptr_t l_ld;
struct link_map * l_next;
struct link_map * l_prev;
};
/* needed for dl_iterate_phdr to be passed to the callbacks provided */
struct dl_phdr_info
{
Elf32_Addr dlpi_addr;
const char *dlpi_name;
const Elf32_Phdr *dlpi_phdr;
Elf32_Half dlpi_phnum;
};
// Values for r_debug->state
enum {
RT_CONSISTENT,
RT_ADD,
RT_DELETE
};
struct r_debug
{
int32_t r_version;
struct link_map * r_map;
void (*r_brk)(void);
int32_t r_state;
uintptr_t r_ldbase;
};
typedef struct soinfo soinfo;
#define FLAG_LINKED 0x00000001
#define FLAG_ERROR 0x00000002
#define FLAG_EXE 0x00000004 // The main executable
#define FLAG_PRELINKED 0x00000008 // This is a pre-linked lib
#define SOINFO_NAME_LEN 128
struct soinfo
{
const char name[SOINFO_NAME_LEN];
Elf32_Phdr *phdr;
int phnum;
unsigned entry;
unsigned base;
unsigned size;
// buddy-allocator index, negative for prelinked libraries
int ba_index;
unsigned *dynamic;
unsigned wrprotect_start;
unsigned wrprotect_end;
soinfo *next;
unsigned flags;
const char *strtab;
Elf32_Sym *symtab;
unsigned nbucket;
unsigned nchain;
unsigned *bucket;
unsigned *chain;
unsigned *plt_got;
Elf32_Rel *plt_rel;
unsigned plt_rel_count;
Elf32_Rel *rel;
unsigned rel_count;
#ifdef ANDROID_SH_LINKER
Elf32_Rela *plt_rela;
unsigned plt_rela_count;
Elf32_Rela *rela;
unsigned rela_count;
#endif /* ANDROID_SH_LINKER */
unsigned *preinit_array;
unsigned preinit_array_count;
unsigned *init_array;
unsigned init_array_count;
unsigned *fini_array;
unsigned fini_array_count;
void (*init_func)(void);
void (*fini_func)(void);
#ifdef ANDROID_ARM_LINKER
/* ARM EABI section used for stack unwinding. */
unsigned *ARM_exidx;
unsigned ARM_exidx_count;
#endif
unsigned refcount;
struct link_map linkmap;
};
extern soinfo libdl_info;
/* these must all be powers of two */
#ifdef ARCH_SH
#define LIBBASE 0x60000000
#define LIBLAST 0x70000000
#define LIBINC 0x00100000
#else
#define LIBBASE 0x80000000
#define LIBLAST 0x90000000
#define LIBINC 0x00100000
#endif
#ifdef ANDROID_ARM_LINKER
#define R_ARM_COPY 20
#define R_ARM_GLOB_DAT 21
#define R_ARM_JUMP_SLOT 22
#define R_ARM_RELATIVE 23
/* According to the AAPCS specification, we only
* need the above relocations. However, in practice,
* the following ones turn up from time to time.
*/
#define R_ARM_ABS32 2
#define R_ARM_REL32 3
#elif defined(ANDROID_X86_LINKER)
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GLOB_DAT 6
#define R_386_JUMP_SLOT 7
#define R_386_RELATIVE 8
#elif defined(ANDROID_SH_LINKER)
#define R_SH_DIR32 1
#define R_SH_GLOB_DAT 163
#define R_SH_JUMP_SLOT 164
#define R_SH_RELATIVE 165
#endif /* ANDROID_*_LINKER */
#ifndef DT_INIT_ARRAY
#define DT_INIT_ARRAY 25
#endif
#ifndef DT_FINI_ARRAY
#define DT_FINI_ARRAY 26
#endif
#ifndef DT_INIT_ARRAYSZ
#define DT_INIT_ARRAYSZ 27
#endif
#ifndef DT_FINI_ARRAYSZ
#define DT_FINI_ARRAYSZ 28
#endif
#ifndef DT_PREINIT_ARRAY
#define DT_PREINIT_ARRAY 32
#endif
#ifndef DT_PREINIT_ARRAYSZ
#define DT_PREINIT_ARRAYSZ 33
#endif
soinfo *find_library(const char *name);
unsigned unload_library(soinfo *si);
Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start);
soinfo *find_containing_library(void *addr);
Elf32_Sym *find_containing_symbol(void *addr, soinfo *si);
const char *linker_get_error(void);
#ifdef ANDROID_ARM_LINKER
typedef long unsigned int *_Unwind_Ptr;
_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_SH_LINKER)
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
#endif
#endif

View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2008-2010 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LINKER_DEBUG_H_
#define _LINKER_DEBUG_H_
#include <stdio.h>
#ifndef LINKER_DEBUG
#error LINKER_DEBUG should be defined to either 1 or 0 in Android.mk
#endif
/* set LINKER_DEBUG_TO_LOG to 1 to send the logs to logcat,
* or 0 to use stdout instead.
*/
#define LINKER_DEBUG_TO_LOG 1
#define TRACE_DEBUG 1
#define DO_TRACE_LOOKUP 1
#define DO_TRACE_RELO 1
#define TIMING 0
#define STATS 0
#define COUNT_PAGES 0
/*********************************************************************
* You shouldn't need to modify anything below unless you are adding
* more debugging information.
*
* To enable/disable specific debug options, change the defines above
*********************************************************************/
/*********************************************************************/
#undef TRUE
#undef FALSE
#define TRUE 1
#define FALSE 0
/* Only use printf() during debugging. We have seen occasional memory
* corruption when the linker uses printf().
*/
#if LINKER_DEBUG
#include "linker_format.h"
extern int debug_verbosity;
#if LINKER_DEBUG_TO_LOG
extern int format_log(int, const char *, const char *, ...);
#define _PRINTVF(v,f,x...) \
do { \
if (debug_verbosity > (v)) format_log(5-(v),"linker",x); \
} while (0)
#else /* !LINKER_DEBUG_TO_LOG */
extern int format_fd(int, const char *, ...);
#define _PRINTVF(v,f,x...) \
do { \
if (debug_verbosity > (v)) format_fd(1, x); \
} while (0)
#endif /* !LINKER_DEBUG_TO_LOG */
#else /* !LINKER_DEBUG */
#define _PRINTVF(v,f,x...) do {} while(0)
#endif /* LINKER_DEBUG */
#define PRINT(x...) _PRINTVF(-1, FALSE, x)
#define INFO(x...) _PRINTVF(0, TRUE, x)
#define TRACE(x...) _PRINTVF(1, TRUE, x)
#define WARN(fmt,args...) \
_PRINTVF(-1, TRUE, "%s:%d| WARNING: " fmt, __FILE__, __LINE__, ## args)
#define ERROR(fmt,args...) \
_PRINTVF(-1, TRUE, "%s:%d| ERROR: " fmt, __FILE__, __LINE__, ## args)
#if TRACE_DEBUG
#define DEBUG(x...) _PRINTVF(2, TRUE, "DEBUG: " x)
#else /* !TRACE_DEBUG */
#define DEBUG(x...) do {} while (0)
#endif /* TRACE_DEBUG */
#if LINKER_DEBUG
#define TRACE_TYPE(t,x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0)
#else /* !LINKER_DEBUG */
#define TRACE_TYPE(t,x...) do {} while (0)
#endif /* LINKER_DEBUG */
#if STATS
#define RELOC_ABSOLUTE 0
#define RELOC_RELATIVE 1
#define RELOC_COPY 2
#define RELOC_SYMBOL 3
#define NUM_RELOC_STATS 4
struct _link_stats {
int reloc[NUM_RELOC_STATS];
};
extern struct _link_stats linker_stats;
#define COUNT_RELOC(type) \
do { if (type >= 0 && type < NUM_RELOC_STATS) { \
linker_stats.reloc[type] += 1; \
} else { \
PRINT("Unknown reloc stat requested\n"); \
} \
} while(0)
#else /* !STATS */
#define COUNT_RELOC(type) do {} while(0)
#endif /* STATS */
#if TIMING
#undef WARN
#define WARN(x...) do {} while (0)
#endif /* TIMING */
#if COUNT_PAGES
extern unsigned bitmask[];
#define MARK(offset) do { \
bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
} while(0)
#else
#define MARK(x) do {} while (0)
#endif
#define DEBUG_DUMP_PHDR(phdr, name, pid) do { \
DEBUG("%5d %s (phdr = 0x%08x)\n", (pid), (name), (unsigned)(phdr)); \
DEBUG("\t\tphdr->offset = 0x%08x\n", (unsigned)((phdr)->p_offset)); \
DEBUG("\t\tphdr->p_vaddr = 0x%08x\n", (unsigned)((phdr)->p_vaddr)); \
DEBUG("\t\tphdr->p_paddr = 0x%08x\n", (unsigned)((phdr)->p_paddr)); \
DEBUG("\t\tphdr->p_filesz = 0x%08x\n", (unsigned)((phdr)->p_filesz)); \
DEBUG("\t\tphdr->p_memsz = 0x%08x\n", (unsigned)((phdr)->p_memsz)); \
DEBUG("\t\tphdr->p_flags = 0x%08x\n", (unsigned)((phdr)->p_flags)); \
DEBUG("\t\tphdr->p_align = 0x%08x\n", (unsigned)((phdr)->p_align)); \
} while (0)
#endif /* _LINKER_DEBUG_H_ */

View File

@ -0,0 +1,703 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <stddef.h>
#include "linker_format.h"
#include "linker_debug.h"
/* define UNIT_TESTS to build this file as a single executable that runs
* the formatter's unit tests
*/
#define xxUNIT_TESTS
/*** Generic output sink
***/
typedef struct {
void *opaque;
void (*send)(void *opaque, const char *data, int len);
} Out;
static void
out_send(Out *o, const void *data, size_t len)
{
o->send(o->opaque, data, (int)len);
}
static void
out_send_repeat(Out *o, char ch, int count)
{
char pad[8];
const int padSize = (int)sizeof(pad);
memset(pad, ch, sizeof(pad));
while (count > 0) {
int avail = count;
if (avail > padSize) {
avail = padSize;
}
o->send(o->opaque, pad, avail);
count -= avail;
}
}
/* forward declaration */
static void
out_vformat(Out *o, const char *format, va_list args);
/*** Bounded buffer output
***/
typedef struct {
Out out[1];
char *buffer;
char *pos;
char *end;
int total;
} BufOut;
static void
buf_out_send(void *opaque, const char *data, int len)
{
BufOut *bo = opaque;
if (len < 0)
len = strlen(data);
bo->total += len;
while (len > 0) {
int avail = bo->end - bo->pos;
if (avail == 0)
break;
if (avail > len)
avail = len;
memcpy(bo->pos, data, avail);
bo->pos += avail;
bo->pos[0] = '\0';
len -= avail;
}
}
static Out*
buf_out_init(BufOut *bo, char *buffer, size_t size)
{
if (size == 0)
return NULL;
bo->out->opaque = bo;
bo->out->send = buf_out_send;
bo->buffer = buffer;
bo->end = buffer + size - 1;
bo->pos = bo->buffer;
bo->pos[0] = '\0';
bo->total = 0;
return bo->out;
}
static int
buf_out_length(BufOut *bo)
{
return bo->total;
}
static int
vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
{
BufOut bo;
Out *out;
out = buf_out_init(&bo, buff, buffsize);
if (out == NULL)
return 0;
out_vformat(out, format, args);
return buf_out_length(&bo);
}
int
format_buffer(char *buff, size_t buffsize, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vformat_buffer(buff, buffsize, format, args);
va_end(args);
return ret;
}
/* The __stack_chk_fail() function calls __libc_android_log_print()
* which calls vsnprintf().
*
* We define our version of the function here to avoid dragging
* about 25 KB of C library routines related to formatting.
*/
int
vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
{
return format_buffer(buff, bufsize, format, args);
}
#if LINKER_DEBUG
#if !LINKER_DEBUG_TO_LOG
/*** File descriptor output
***/
typedef struct {
Out out[1];
int fd;
int total;
} FdOut;
static void
fd_out_send(void *opaque, const char *data, int len)
{
FdOut *fdo = opaque;
if (len < 0)
len = strlen(data);
while (len > 0) {
int ret = write(fdo->fd, data, len);
if (ret < 0) {
if (errno == EINTR)
continue;
break;
}
data += ret;
len -= ret;
fdo->total += ret;
}
}
static Out*
fd_out_init(FdOut *fdo, int fd)
{
fdo->out->opaque = fdo;
fdo->out->send = fd_out_send;
fdo->fd = fd;
fdo->total = 0;
return fdo->out;
}
static int
fd_out_length(FdOut *fdo)
{
return fdo->total;
}
int
format_fd(int fd, const char *format, ...)
{
FdOut fdo;
Out* out;
va_list args;
out = fd_out_init(&fdo, fd);
if (out == NULL)
return 0;
va_start(args, format);
out_vformat(out, format, args);
va_end(args);
return fd_out_length(&fdo);
}
#else /* LINKER_DEBUG_TO_LOG */
/*** Log output
***/
/* We need our own version of __libc_android_log_vprint, otherwise
* the log output is completely broken. Probably due to the fact
* that the C library is not initialized yet.
*
* You can test that by setting CUSTOM_LOG_VPRINT to 0
*/
#define CUSTOM_LOG_VPRINT 1
#if CUSTOM_LOG_VPRINT
#include <unistd.h>
#include <fcntl.h>
#include <sys/uio.h>
static int log_vprint(int prio, const char *tag, const char *fmt, va_list args)
{
char buf[1024];
int result;
static int log_fd = -1;
result = vformat_buffer(buf, sizeof buf, fmt, args);
if (log_fd < 0) {
log_fd = open("/dev/log/main", O_WRONLY);
if (log_fd < 0)
return result;
}
{
ssize_t ret;
struct iovec vec[3];
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
vec[1].iov_len = strlen(tag) + 1;
vec[2].iov_base = (void *) buf;
vec[2].iov_len = strlen(buf) + 1;
do {
ret = writev(log_fd, vec, 3);
} while ((ret < 0) && (errno == EINTR));
}
return result;
}
#define __libc_android_log_vprint log_vprint
#else /* !CUSTOM_LOG_VPRINT */
extern int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap);
#endif /* !CUSTOM_LOG_VPRINT */
int
format_log(int prio, const char *tag, const char *format, ...)
{
int ret;
va_list args;
va_start(args, format);
ret = __libc_android_log_vprint(prio, tag, format, args);
va_end(args);
return ret;
}
#endif /* LINKER_DEBUG_TO_LOG */
#endif /* LINKER_DEBUG */
/*** formatted output implementation
***/
/* Parse a decimal string from 'format + *ppos',
* return the value, and writes the new position past
* the decimal string in '*ppos' on exit.
*
* NOTE: Does *not* handle a sign prefix.
*/
static unsigned
parse_decimal(const char *format, int *ppos)
{
const char* p = format + *ppos;
unsigned result = 0;
for (;;) {
int ch = *p;
unsigned d = (unsigned)(ch - '0');
if (d >= 10U)
break;
result = result*10 + d;
p++;
}
*ppos = p - format;
return result;
}
/* write an octal/decimal/number into a bounded buffer.
* assumes that bufsize > 0, and 'digits' is a string of
* digits of at least 'base' values.
*/
static void
format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
{
char *pos = buffer;
char *end = buffer + bufsize - 1;
/* generate digit string in reverse order */
while (value) {
unsigned d = value % base;
value /= base;
if (pos < end) {
*pos++ = digits[d];
}
}
/* special case for 0 */
if (pos == buffer) {
if (pos < end) {
*pos++ = '0';
}
}
pos[0] = '\0';
/* now reverse digit string in-place */
end = pos - 1;
pos = buffer;
while (pos < end) {
int ch = pos[0];
pos[0] = end[0];
end[0] = (char) ch;
pos++;
end--;
}
}
/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
static void
format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
{
if (isSigned && (int64_t)value < 0) {
buffer[0] = '-';
buffer += 1;
buffsize -= 1;
value = (uint64_t)(-(int64_t)value);
}
format_number(buffer, buffsize, value, base, "0123456789");
}
/* Write an octal into a buffer, assumes buffsize > 2 */
static void
format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
{
format_integer(buffer, buffsize, value, 8, isSigned);
}
/* Write a decimal into a buffer, assumes buffsize > 2 */
static void
format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
{
format_integer(buffer, buffsize, value, 10, isSigned);
}
/* Write an hexadecimal into a buffer, isCap is true for capital alphas.
* Assumes bufsize > 2 */
static void
format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
{
const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
format_number(buffer, buffsize, value, 16, digits);
}
/* Perform formatted output to an output target 'o' */
static void
out_vformat(Out *o, const char *format, va_list args)
{
int nn = 0, mm;
int padZero = 0;
int padLeft = 0;
char sign = '\0';
int width = -1;
int prec = -1;
size_t bytelen = sizeof(int);
const char* str;
int slen;
char buffer[32]; /* temporary buffer used to format numbers */
for (;;) {
char c;
/* first, find all characters that are not 0 or '%' */
/* then send them to the output directly */
mm = nn;
do {
c = format[mm];
if (c == '\0' || c == '%')
break;
mm++;
} while (1);
if (mm > nn) {
out_send(o, format+nn, mm-nn);
nn = mm;
}
/* is this it ? then exit */
if (c == '\0')
break;
/* nope, we are at a '%' modifier */
nn++; // skip it
/* parse flags */
for (;;) {
c = format[nn++];
if (c == '\0') { /* single trailing '%' ? */
c = '%';
out_send(o, &c, 1);
return;
}
else if (c == '0') {
padZero = 1;
continue;
}
else if (c == '-') {
padLeft = 1;
continue;
}
else if (c == ' ' || c == '+') {
sign = c;
continue;
}
break;
}
/* parse field width */
if ((c >= '0' && c <= '9')) {
nn --;
width = (int)parse_decimal(format, &nn);
c = format[nn++];
}
/* parse precision */
if (c == '.') {
prec = (int)parse_decimal(format, &nn);
c = format[nn++];
}
/* length modifier */
switch (c) {
case 'h':
bytelen = sizeof(short);
if (format[nn] == 'h') {
bytelen = sizeof(char);
nn += 1;
}
c = format[nn++];
break;
case 'l':
bytelen = sizeof(long);
if (format[nn] == 'l') {
bytelen = sizeof(long long);
nn += 1;
}
c = format[nn++];
break;
case 'z':
bytelen = sizeof(size_t);
c = format[nn++];
break;
case 't':
bytelen = sizeof(ptrdiff_t);
c = format[nn++];
break;
case 'p':
bytelen = sizeof(void*);
c = format[nn++];
default:
;
}
/* conversion specifier */
if (c == 's') {
/* string */
str = va_arg(args, const char*);
} else if (c == 'c') {
/* character */
/* NOTE: char is promoted to int when passed through the stack */
buffer[0] = (char) va_arg(args, int);
buffer[1] = '\0';
str = buffer;
} else if (c == 'p') {
uint64_t value = (uint64_t)(ptrdiff_t) va_arg(args, void*);
buffer[0] = '0';
buffer[1] = 'x';
format_hex(buffer + 2, sizeof buffer-2, value, 0);
str = buffer;
} else {
/* integers - first read value from stack */
uint64_t value;
int isSigned = (c == 'd' || c == 'i' || c == 'o');
/* NOTE: int8_t and int16_t are promoted to int when passed
* through the stack
*/
switch (bytelen) {
case 1: value = (uint8_t) va_arg(args, int); break;
case 2: value = (uint16_t) va_arg(args, int); break;
case 4: value = va_arg(args, uint32_t); break;
case 8: value = va_arg(args, uint64_t); break;
default: return; /* should not happen */
}
/* sign extension, if needed */
if (isSigned) {
int shift = 64 - 8*bytelen;
value = (uint64_t)(((int64_t)(value << shift)) >> shift);
}
/* format the number properly into our buffer */
switch (c) {
case 'i': case 'd':
format_integer(buffer, sizeof buffer, value, 10, isSigned);
break;
case 'o':
format_integer(buffer, sizeof buffer, value, 8, isSigned);
break;
case 'x': case 'X':
format_hex(buffer, sizeof buffer, value, (c == 'X'));
break;
default:
buffer[0] = '\0';
}
/* then point to it */
str = buffer;
}
/* if we are here, 'str' points to the content that must be
* outputted. handle padding and alignment now */
slen = strlen(str);
if (slen < width && !padLeft) {
char padChar = padZero ? '0' : ' ';
out_send_repeat(o, padChar, width - slen);
}
out_send(o, str, slen);
if (slen < width && padLeft) {
char padChar = padZero ? '0' : ' ';
out_send_repeat(o, padChar, width - slen);
}
}
}
#ifdef UNIT_TESTS
#include <stdio.h>
static int gFails = 0;
#define MARGIN 40
#define UTEST_CHECK(condition,message) \
printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
if (!(condition)) { \
printf("KO\n"); \
gFails += 1; \
} else { \
printf("ok\n"); \
}
static void
utest_BufOut(void)
{
char buffer[16];
BufOut bo[1];
Out* out;
int ret;
buffer[0] = '1';
out = buf_out_init(bo, buffer, sizeof buffer);
UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
out_send(out, "abc", 3);
UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
out_send_repeat(out, 'X', 4);
UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
buffer[sizeof buffer-1] = 'x';
out_send_repeat(out, 'Y', 2*sizeof(buffer));
UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
out = buf_out_init(bo, buffer, sizeof buffer);
out_send_repeat(out, 'X', 2*sizeof(buffer));
ret = buf_out_length(bo);
UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
}
static void
utest_expect(const char* result, const char* format, ...)
{
va_list args;
BufOut bo[1];
char buffer[256];
Out* out = buf_out_init(bo, buffer, sizeof buffer);
printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
va_start(args, format);
out_vformat(out, format, args);
va_end(args);
if (strcmp(result, buffer)) {
printf("KO. got '%s' expecting '%s'\n", buffer, result);
gFails += 1;
} else {
printf("ok. got '%s'\n", result);
}
}
int main(void)
{
utest_BufOut();
utest_expect("", "");
utest_expect("a", "a");
utest_expect("01234", "01234", "");
utest_expect("01234", "%s", "01234");
utest_expect("aabbcc", "aa%scc", "bb");
utest_expect("a", "%c", 'a');
utest_expect("1234", "%d", 1234);
utest_expect("-8123", "%d", -8123);
utest_expect("16", "%hd", 0x7fff0010);
utest_expect("16", "%hhd", 0x7fffff10);
utest_expect("68719476736", "%lld", 0x1000000000);
utest_expect("70000", "%ld", 70000);
utest_expect("0xb0001234", "%p", (void*)0xb0001234);
utest_expect("12ab", "%x", 0x12ab);
utest_expect("12AB", "%X", 0x12ab);
utest_expect("00123456", "%08x", 0x123456);
utest_expect("01234", "0%d", 1234);
utest_expect(" 1234", "%5d", 1234);
utest_expect("01234", "%05d", 1234);
utest_expect(" 1234", "%8d", 1234);
utest_expect("1234 ", "%-8d", 1234);
utest_expect("abcdef ", "%-11s", "abcdef");
utest_expect("something:1234", "%s:%d", "something", 1234);
return gFails != 0;
}
#endif /* UNIT_TESTS */

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LINKER_FORMAT_H
#define _LINKER_FORMAT_H
#include <stdarg.h>
#include <stddef.h>
/* Formatting routines for the dynamic linker's debug traces */
/* We want to avoid dragging the whole C library fprintf() */
/* implementation into the dynamic linker since this creates */
/* issues (it uses malloc()/free()) and increases code size */
int format_buffer(char *buffer, size_t bufsize, const char *format, ...);
#endif /* _LINKER_FORMAT_H */

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* This function is an empty stub where GDB locates a breakpoint to get notified
* about linker activity.
*/
void __attribute__((noinline)) rtld_db_dlactivity(void)
{
}