Merge commit 'remotes/korg/cupcake' into cupcake_to_master

This commit is contained in:
Jean-Baptiste Queru 2009-03-18 16:57:15 -07:00
commit 0b251a1b9c
54 changed files with 3609 additions and 921 deletions

View File

@ -66,6 +66,7 @@ libc_common_src_files := \
unistd/usleep.c \
unistd/wait.c \
stdio/asprintf.c \
stdio/clrerr.c \
stdio/fclose.c \
stdio/fdopen.c \
stdio/feof.c \
@ -179,6 +180,7 @@ libc_common_src_files := \
string/strcat.c \
string/strchr.c \
string/strcmp.c \
string/strcoll.c \
string/strcpy.c \
string/strcspn.c \
string/strdup.c \
@ -198,6 +200,7 @@ libc_common_src_files := \
string/strstr.c \
string/strtok.c \
string/strtotimeval.c \
string/strxfrm.c \
inet/bindresvport.c \
inet/inet_addr.c \
inet/inet_aton.c \
@ -234,6 +237,7 @@ libc_common_src_files := \
bionic/ssp.c \
bionic/stubs.c \
bionic/system_properties.c \
bionic/time64.c \
bionic/thread_atexit.c \
bionic/utime.c \
bionic/utmp.c \

View File

@ -216,22 +216,6 @@ int sched_get_priority_max(int policy) 159
int sched_get_priority_min(int policy) 160
int sched_rr_get_interval(pid_t pid, struct timespec *interval) 161
# system-V inter-process communication
# TODO: implement x86 stubs for these functions when needed (when ?)
#
int semctl(int semid, int semnum, int cmd, ...) 300,-1
int semget(key_t key, int nsems, int semflg) 299,-1
int semop(int semid, struct sembuf* sops, size_t nsops) 298,-1
void* shmat(int shmid, const void* shmaddr, int shmflg) 305,-1
int shmctl(int shmid, int cmd, struct shmid_ds* buf) 308,-1
int shmdt(const void* shmaddr) 306,-1
int shmget(key_t key, size_t size, int shmflg) 307,-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf) 304,-1
int msgget(key_t key, int msgflg) 303,-1
int msgrcv(int msqid, void* msgp, size_t msgsz, long int msgtyp, int msgflg) 302,-1
int msgsnd(int msqid, const void* msgp, size_t msgsz, int msgflg) 301,-1
# other
int uname(struct utsname *) 122
pid_t __wait4:wait4(pid_t pid, int *status, int options, struct rusage *rusage) 114

View File

@ -150,17 +150,6 @@ syscall_src += arch-arm/syscalls/sched_getparam.S
syscall_src += arch-arm/syscalls/sched_get_priority_max.S
syscall_src += arch-arm/syscalls/sched_get_priority_min.S
syscall_src += arch-arm/syscalls/sched_rr_get_interval.S
syscall_src += arch-arm/syscalls/semctl.S
syscall_src += arch-arm/syscalls/semget.S
syscall_src += arch-arm/syscalls/semop.S
syscall_src += arch-arm/syscalls/shmat.S
syscall_src += arch-arm/syscalls/shmctl.S
syscall_src += arch-arm/syscalls/shmdt.S
syscall_src += arch-arm/syscalls/shmget.S
syscall_src += arch-arm/syscalls/msgctl.S
syscall_src += arch-arm/syscalls/msgget.S
syscall_src += arch-arm/syscalls/msgrcv.S
syscall_src += arch-arm/syscalls/msgsnd.S
syscall_src += arch-arm/syscalls/uname.S
syscall_src += arch-arm/syscalls/__wait4.S
syscall_src += arch-arm/syscalls/umask.S

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type msgctl, #function
.globl msgctl
.align 4
.fnstart
msgctl:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_msgctl
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type msgget, #function
.globl msgget
.align 4
.fnstart
msgget:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_msgget
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,21 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type msgrcv, #function
.globl msgrcv
.align 4
.fnstart
msgrcv:
mov ip, sp
.save {r4, r5, r6, r7}
stmfd sp!, {r4, r5, r6, r7}
ldmfd ip, {r4, r5, r6}
ldr r7, =__NR_msgrcv
swi #0
ldmfd sp!, {r4, r5, r6, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type msgsnd, #function
.globl msgsnd
.align 4
.fnstart
msgsnd:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_msgsnd
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type semctl, #function
.globl semctl
.align 4
.fnstart
semctl:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_semctl
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type semget, #function
.globl semget
.align 4
.fnstart
semget:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_semget
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type semop, #function
.globl semop
.align 4
.fnstart
semop:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_semop
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type shmat, #function
.globl shmat
.align 4
.fnstart
shmat:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_shmat
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type shmctl, #function
.globl shmctl
.align 4
.fnstart
shmctl:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_shmctl
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type shmdt, #function
.globl shmdt
.align 4
.fnstart
shmdt:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_shmdt
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -1,19 +0,0 @@
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type shmget, #function
.globl shmget
.align 4
.fnstart
shmget:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_shmget
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend

View File

@ -30,7 +30,10 @@
void* __dso_handle = 0;
int __aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle)
/* Make this a weak symbol to avoid a multiple definition error when linking
* with libstdc++-v3. */
int __attribute__((weak))
__aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle)
{
//return __cxa_atexit(destructor, object, dso_handle);
return 0;

View File

@ -38,7 +38,7 @@
#include <stdarg.h>
#include <fcntl.h>
#include <utils/logger.h>
#include <cutils/logger.h>
#include "logd.h"
#include <pthread.h>

View File

@ -58,6 +58,8 @@
#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
#define SIZE_FLAG_MASK (SIZE_FLAG_ZYGOTE_CHILD)
#define MAX_SIZE_T (~(size_t)0)
/*
* In a VM process, this is set to 1 after fork()ing out of zygote.
*/
@ -608,8 +610,16 @@ void chk_free(void* mem)
void* chk_calloc(size_t n_elements, size_t elem_size)
{
size_t size = n_elements * elem_size;
void* ptr = chk_malloc(size);
size_t size;
void* ptr;
/* Fail on overflow - just to be safe even though this code runs only
* within the debugging C library, not the production one */
if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
return NULL;
}
size = n_elements * elem_size;
ptr = chk_malloc(size);
if (ptr != NULL) {
memset(ptr, 0, size);
}
@ -763,8 +773,16 @@ void leak_free(void* mem)
void* leak_calloc(size_t n_elements, size_t elem_size)
{
size_t size = n_elements * elem_size;
void* ptr = leak_malloc(size);
size_t size;
void* ptr;
/* Fail on overflow - just to be safe even though this code runs only
* within the debugging C library, not the production one */
if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
return NULL;
}
size = n_elements * elem_size;
ptr = leak_malloc(size);
if (ptr != NULL) {
memset(ptr, 0, size);
}

View File

@ -469,7 +469,7 @@ timer_settime( timer_t id,
}
if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) {
return __timer_gettime( id, ospec );
return __timer_settime( id, flags, spec, ospec );
} else {
thr_timer_t* timer = thr_timer_from_id(id);
struct timespec expires, now;
@ -485,16 +485,19 @@ timer_settime( timer_t id,
timer_gettime_internal(timer, ospec );
}
/* compute next expiration time */
/* compute next expiration time. note that if the
* new it_interval is 0, we should disarm the timer
*/
expires = spec->it_value;
clock_gettime( timer->clock, &now );
if (!(flags & TIMER_ABSTIME)) {
timespec_add(&expires, &now);
} else {
if (timespec_cmp(&expires, &now) < 0)
expires = now;
if (!timespec_is_zero(&expires)) {
clock_gettime( timer->clock, &now );
if (!(flags & TIMER_ABSTIME)) {
timespec_add(&expires, &now);
} else {
if (timespec_cmp(&expires, &now) < 0)
expires = now;
}
}
timer->expires = expires;
timer->period = spec->it_interval;
thr_timer_unlock( timer );
@ -560,11 +563,11 @@ timer_thread_start( void* _arg )
if (timespec_cmp( &expires, &now ) > 0)
{
/* cool, there was no overrun, so compute the
* relative timeout as 'now - expires', then wait
* relative timeout as 'expires - now', then wait
*/
int ret;
struct timespec diff = now;
timespec_sub( &diff, &expires );
struct timespec diff = expires;
timespec_sub( &diff, &now );
ret = __pthread_cond_timedwait_relative(
&timer->cond, &timer->mutex, &diff);

View File

@ -488,6 +488,21 @@ int pthread_getattr_np(pthread_t thid, pthread_attr_t * attr)
return 0;
}
int pthread_attr_setscope(pthread_attr_t *attr, int scope)
{
if (scope == PTHREAD_SCOPE_SYSTEM)
return 0;
if (scope == PTHREAD_SCOPE_PROCESS)
return ENOTSUP;
return EINVAL;
}
int pthread_attr_getscope(pthread_attr_t const *attr)
{
return PTHREAD_SCOPE_SYSTEM;
}
/* CAVEAT: our implementation of pthread_cleanup_push/pop doesn't support C++ exceptions
* and thread cancelation

View File

@ -35,6 +35,7 @@
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
/** Thread-specific state for the stubs functions
**/
@ -95,8 +96,9 @@ __stubs_state(void)
return s;
}
static struct passwd *android_iinfo_to_passwd(
struct passwd *pw, struct android_id_info *iinfo)
static struct passwd*
android_iinfo_to_passwd( struct passwd *pw,
struct android_id_info *iinfo )
{
pw->pw_name = (char*)iinfo->name;
pw->pw_uid = iinfo->aid;
@ -106,8 +108,9 @@ static struct passwd *android_iinfo_to_passwd(
return pw;
}
static struct group *android_iinfo_to_group(
struct group *gr, struct android_id_info *iinfo)
static struct group*
android_iinfo_to_group( struct group *gr,
struct android_id_info *iinfo )
{
gr->gr_name = (char*) iinfo->name;
gr->gr_gid = iinfo->aid;
@ -116,8 +119,8 @@ static struct group *android_iinfo_to_group(
return gr;
}
static struct passwd *android_id_to_passwd(
struct passwd *pw, unsigned id)
static struct passwd *
android_id_to_passwd( struct passwd *pw, unsigned id)
{
struct android_id_info *iinfo = android_ids;
unsigned n;
@ -126,11 +129,11 @@ static struct passwd *android_id_to_passwd(
return android_iinfo_to_passwd(pw, iinfo + n);
}
}
return 0;
return NULL;
}
static struct passwd *android_name_to_passwd(
struct passwd *pw, const char *name)
static struct passwd*
android_name_to_passwd(struct passwd *pw, const char *name)
{
struct android_id_info *iinfo = android_ids;
unsigned n;
@ -139,11 +142,11 @@ static struct passwd *android_name_to_passwd(
return android_iinfo_to_passwd(pw, iinfo + n);
}
}
return 0;
return NULL;
}
static struct group *android_id_to_group(
struct group *gr, unsigned id)
static struct group*
android_id_to_group( struct group *gr, unsigned id )
{
struct android_id_info *iinfo = android_ids;
unsigned n;
@ -152,11 +155,11 @@ static struct group *android_id_to_group(
return android_iinfo_to_group(gr, iinfo + n);
}
}
return 0;
return NULL;
}
static struct group *android_name_to_group(
struct group *gr, const char *name)
static struct group*
android_name_to_group( struct group *gr, const char *name )
{
struct android_id_info *iinfo = android_ids;
unsigned n;
@ -165,10 +168,92 @@ static struct group *android_name_to_group(
return android_iinfo_to_group(gr, iinfo + n);
}
}
return NULL;
}
/* translate a user/group name like app_1234 into the
* corresponding user/group id (AID_APP + 1234)
* returns 0 and sets errno to ENOENT in case of error
*/
static unsigned
app_id_from_name( const char* name )
{
unsigned long id;
char* end;
if (memcmp(name, "app_", 4) != 0 || !isdigit(name[4]))
goto FAIL;
id = strtoul(name+4, &end, 10);
if (id == 0 || *end != '\0')
goto FAIL;
id += AID_APP;
/* check for overflow and that the value can be
* stored in our 32-bit uid_t/gid_t */
if (id < AID_APP || (unsigned)id != id)
goto FAIL;
return (unsigned)id;
FAIL:
errno = ENOENT;
return 0;
}
struct passwd* getpwuid(uid_t uid)
/* translate a uid into the corresponding app_<uid>
* passwd structure (sets errno to ENOENT on failure)
*/
static struct passwd*
app_id_to_passwd(uid_t uid, stubs_state_t* state)
{
struct passwd* pw = &state->passwd;
if (uid < AID_APP) {
errno = ENOENT;
return NULL;
}
snprintf( state->app_name_buffer, sizeof state->app_name_buffer,
"app_%u", uid - AID_APP );
pw->pw_name = state->app_name_buffer;
pw->pw_dir = "/data";
pw->pw_shell = "/system/bin/sh";
pw->pw_uid = uid;
pw->pw_gid = uid;
return pw;
}
/* translate a gid into the corresponding app_<gid>
* group structure (sets errno to ENOENT on failure)
*/
static struct group*
app_id_to_group(gid_t gid, stubs_state_t* state)
{
struct group* gr = &state->group;
if (gid < AID_APP) {
errno = ENOENT;
return NULL;
}
snprintf(state->group_name_buffer, sizeof state->group_name_buffer,
"app_%u", gid - AID_APP);
gr->gr_name = state->group_name_buffer;
gr->gr_gid = gid;
gr->gr_mem[0] = gr->gr_name;
gr->gr_mem[1] = NULL;
return gr;
}
struct passwd*
getpwuid(uid_t uid)
{
stubs_state_t* state = __stubs_state();
struct passwd* pw;
@ -181,35 +266,27 @@ struct passwd* getpwuid(uid_t uid)
if ( android_id_to_passwd(pw, uid) != NULL )
return pw;
if (uid < AID_APP) {
errno = ENOENT;
return NULL;
}
snprintf( state->app_name_buffer, sizeof state->app_name_buffer,
"app_%d", uid - AID_APP );
pw->pw_name = state->app_name_buffer;
pw->pw_dir = "/data";
pw->pw_shell = "/system/bin/sh";
pw->pw_uid = uid;
pw->pw_gid = uid;
return pw;
return app_id_to_passwd(uid, state);
}
struct passwd* getpwnam(const char *login)
struct passwd*
getpwnam(const char *login)
{
stubs_state_t* state = __stubs_state();
if (state == NULL)
return NULL;
return android_name_to_passwd(&state->passwd, login);
if (android_name_to_passwd(&state->passwd, login) != NULL)
return &state->passwd;
return app_id_to_passwd( app_id_from_name(login), state );
}
int getgrouplist (const char *user, gid_t group,
gid_t *groups, int *ngroups) {
int
getgrouplist (const char *user, gid_t group,
gid_t *groups, int *ngroups)
{
if (*ngroups < 1) {
*ngroups = 1;
return -1;
@ -218,18 +295,20 @@ int getgrouplist (const char *user, gid_t group,
return (*ngroups = 1);
}
char* getlogin(void)
char*
getlogin(void)
{
struct passwd *pw = getpwuid(getuid());
if(pw) {
return pw->pw_name;
} else {
return 0;
return NULL;
}
}
struct group* getgrgid(gid_t gid)
struct group*
getgrgid(gid_t gid)
{
stubs_state_t* state = __stubs_state();
struct group* gr;
@ -241,34 +320,25 @@ struct group* getgrgid(gid_t gid)
if (gr != NULL)
return gr;
if (gid < AID_APP) {
errno = ENOENT;
return NULL;
}
snprintf(state->group_name_buffer, sizeof state->group_name_buffer,
"app_%d", gid - AID_APP);
gr = &state->group;
gr->gr_name = state->group_name_buffer;
gr->gr_gid = gid;
gr->gr_mem[0] = gr->gr_name;
gr->gr_mem[1] = NULL;
return gr;
return app_id_to_group(gid, state);
}
struct group* getgrnam(const char *name)
struct group*
getgrnam(const char *name)
{
stubs_state_t* state = __stubs_state();
unsigned id;
if (state == NULL)
return NULL;
return android_name_to_group(&state->group, name);
if (android_name_to_group(&state->group, name) != 0)
return &state->group;
return app_id_to_group( app_id_from_name(name), state );
}
struct netent* getnetbyname(const char *name)
{
fprintf(stderr, "FIX ME! implement getgrnam() %s:%d\n", __FILE__, __LINE__);
@ -308,5 +378,3 @@ struct protoent *getprotobynumber(int proto)
fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
return NULL;
}

793
libc/bionic/time64.c Normal file
View File

@ -0,0 +1,793 @@
/*
Copyright (c) 2007-2008 Michael G Schwern
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
The MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* See http://code.google.com/p/y2038 for this code's origin */
/*
Programmers who have available to them 64-bit time values as a 'long
long' type can use localtime64_r() and gmtime64_r() which correctly
converts the time even on 32-bit systems. Whether you have 64-bit time
values will depend on the operating system.
localtime64_r() is a 64-bit equivalent of localtime_r().
gmtime64_r() is a 64-bit equivalent of gmtime_r().
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "time64.h"
/* BIONIC_BEGIN */
/* the following are here to avoid exposing time64_config.h and
* other types in our public time64.h header
*/
#include "time64_config.h"
/* Not everyone has gm/localtime_r(), provide a replacement */
#ifdef HAS_LOCALTIME_R
# define LOCALTIME_R(clock, result) localtime_r(clock, result)
#else
# define LOCALTIME_R(clock, result) fake_localtime_r(clock, result)
#endif
#ifdef HAS_GMTIME_R
# define GMTIME_R(clock, result) gmtime_r(clock, result)
#else
# define GMTIME_R(clock, result) fake_gmtime_r(clock, result)
#endif
typedef int64_t Int64;
typedef time64_t Time64_T;
typedef int64_t Year;
#define TM tm
/* BIONIC_END */
/* Spec says except for stftime() and the _r() functions, these
all return static memory. Stabbings! */
static struct TM Static_Return_Date;
static char Static_Return_String[35];
static const int days_in_month[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};
static const int julian_days_by_month[2][12] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
};
static char const wday_name[7][3] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static char const mon_name[12][3] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const int length_of_year[2] = { 365, 366 };
/* Some numbers relating to the gregorian cycle */
static const Year years_in_gregorian_cycle = 400;
#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
static const Time64_T seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL;
/* Year range we can trust the time funcitons with */
#define MAX_SAFE_YEAR 2037
#define MIN_SAFE_YEAR 1971
/* 28 year Julian calendar cycle */
#define SOLAR_CYCLE_LENGTH 28
/* Year cycle from MAX_SAFE_YEAR down. */
static const int safe_years_high[SOLAR_CYCLE_LENGTH] = {
2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023,
2024, 2025, 2026, 2027,
2028, 2029, 2030, 2031,
2032, 2033, 2034, 2035,
2036, 2037, 2010, 2011,
2012, 2013, 2014, 2015
};
/* Year cycle from MIN_SAFE_YEAR up */
static const int safe_years_low[SOLAR_CYCLE_LENGTH] = {
1996, 1997, 1998, 1971,
1972, 1973, 1974, 1975,
1976, 1977, 1978, 1979,
1980, 1981, 1982, 1983,
1984, 1985, 1986, 1987,
1988, 1989, 1990, 1991,
1992, 1993, 1994, 1995,
};
/* This isn't used, but it's handy to look at */
static const int dow_year_start[SOLAR_CYCLE_LENGTH] = {
5, 0, 1, 2, /* 0 2016 - 2019 */
3, 5, 6, 0, /* 4 */
1, 3, 4, 5, /* 8 1996 - 1998, 1971*/
6, 1, 2, 3, /* 12 1972 - 1975 */
4, 6, 0, 1, /* 16 */
2, 4, 5, 6, /* 20 2036, 2037, 2010, 2011 */
0, 2, 3, 4 /* 24 2012, 2013, 2014, 2015 */
};
/* Let's assume people are going to be looking for dates in the future.
Let's provide some cheats so you can skip ahead.
This has a 4x speed boost when near 2008.
*/
/* Number of days since epoch on Jan 1st, 2008 GMT */
#define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
#define CHEAT_YEARS 108
#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
#define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
#ifdef USE_SYSTEM_LOCALTIME
# define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \
(a) <= SYSTEM_LOCALTIME_MAX && \
(a) >= SYSTEM_LOCALTIME_MIN \
)
#else
# define SHOULD_USE_SYSTEM_LOCALTIME(a) (0)
#endif
#ifdef USE_SYSTEM_GMTIME
# define SHOULD_USE_SYSTEM_GMTIME(a) ( \
(a) <= SYSTEM_GMTIME_MAX && \
(a) >= SYSTEM_GMTIME_MIN \
)
#else
# define SHOULD_USE_SYSTEM_GMTIME(a) (0)
#endif
/* Multi varadic macros are a C99 thing, alas */
#ifdef TIME_64_DEBUG
# define TRACE(format) (fprintf(stderr, format))
# define TRACE1(format, var1) (fprintf(stderr, format, var1))
# define TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2))
# define TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3))
#else
# define TRACE(format) ((void)0)
# define TRACE1(format, var1) ((void)0)
# define TRACE2(format, var1, var2) ((void)0)
# define TRACE3(format, var1, var2, var3) ((void)0)
#endif
static int is_exception_century(Year year)
{
int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no");
return(is_exception);
}
/* timegm() is not in the C or POSIX spec, but it is such a useful
extension I would be remiss in leaving it out. Also I need it
for localtime64()
*/
Time64_T timegm64(const struct TM *date) {
Time64_T days = 0;
Time64_T seconds = 0;
Year year;
Year orig_year = (Year)date->tm_year;
int cycles = 0;
if( orig_year > 100 ) {
cycles = (orig_year - 100) / 400;
orig_year -= cycles * 400;
days += (Time64_T)cycles * days_in_gregorian_cycle;
}
else if( orig_year < -300 ) {
cycles = (orig_year - 100) / 400;
orig_year -= cycles * 400;
days += (Time64_T)cycles * days_in_gregorian_cycle;
}
TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year);
if( orig_year > 70 ) {
year = 70;
while( year < orig_year ) {
days += length_of_year[IS_LEAP(year)];
year++;
}
}
else if ( orig_year < 70 ) {
year = 69;
do {
days -= length_of_year[IS_LEAP(year)];
year--;
} while( year >= orig_year );
}
days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
days += date->tm_mday - 1;
seconds = days * 60 * 60 * 24;
seconds += date->tm_hour * 60 * 60;
seconds += date->tm_min * 60;
seconds += date->tm_sec;
return(seconds);
}
static int check_tm(struct TM *tm)
{
/* Don't forget leap seconds */
assert(tm->tm_sec >= 0);
assert(tm->tm_sec <= 61);
assert(tm->tm_min >= 0);
assert(tm->tm_min <= 59);
assert(tm->tm_hour >= 0);
assert(tm->tm_hour <= 23);
assert(tm->tm_mday >= 1);
assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);
assert(tm->tm_mon >= 0);
assert(tm->tm_mon <= 11);
assert(tm->tm_wday >= 0);
assert(tm->tm_wday <= 6);
assert(tm->tm_yday >= 0);
assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);
#ifdef HAS_TM_TM_GMTOFF
assert(tm->tm_gmtoff >= -24 * 60 * 60);
assert(tm->tm_gmtoff <= 24 * 60 * 60);
#endif
return 1;
}
/* The exceptional centuries without leap years cause the cycle to
shift by 16
*/
static Year cycle_offset(Year year)
{
const Year start_year = 2000;
Year year_diff = year - start_year;
Year exceptions;
if( year > start_year )
year_diff--;
exceptions = year_diff / 100;
exceptions -= year_diff / 400;
TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n",
year, exceptions, year_diff);
return exceptions * 16;
}
/* For a given year after 2038, pick the latest possible matching
year in the 28 year calendar cycle.
A matching year...
1) Starts on the same day of the week.
2) Has the same leap year status.
This is so the calendars match up.
Also the previous year must match. When doing Jan 1st you might
wind up on Dec 31st the previous year when doing a -UTC time zone.
Finally, the next year must have the same start day of week. This
is for Dec 31st with a +UTC time zone.
It doesn't need the same leap year status since we only care about
January 1st.
*/
static int safe_year(const Year year)
{
int safe_year = 0;
Year year_cycle;
if( year >= MIN_SAFE_YEAR && year <= MAX_SAFE_YEAR ) {
return (int)year;
}
year_cycle = year + cycle_offset(year);
/* safe_years_low is off from safe_years_high by 8 years */
if( year < MIN_SAFE_YEAR )
year_cycle -= 8;
/* Change non-leap xx00 years to an equivalent */
if( is_exception_century(year) )
year_cycle += 11;
/* Also xx01 years, since the previous year will be wrong */
if( is_exception_century(year - 1) )
year_cycle += 17;
year_cycle %= SOLAR_CYCLE_LENGTH;
if( year_cycle < 0 )
year_cycle = SOLAR_CYCLE_LENGTH + year_cycle;
assert( year_cycle >= 0 );
assert( year_cycle < SOLAR_CYCLE_LENGTH );
if( year < MIN_SAFE_YEAR )
safe_year = safe_years_low[year_cycle];
else if( year > MAX_SAFE_YEAR )
safe_year = safe_years_high[year_cycle];
else
assert(0);
TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n",
year, year_cycle, safe_year);
assert(safe_year <= MAX_SAFE_YEAR && safe_year >= MIN_SAFE_YEAR);
return safe_year;
}
void copy_tm_to_TM(const struct tm *src, struct TM *dest) {
if( src == NULL ) {
memset(dest, 0, sizeof(*dest));
}
else {
# ifdef USE_TM64
dest->tm_sec = src->tm_sec;
dest->tm_min = src->tm_min;
dest->tm_hour = src->tm_hour;
dest->tm_mday = src->tm_mday;
dest->tm_mon = src->tm_mon;
dest->tm_year = (Year)src->tm_year;
dest->tm_wday = src->tm_wday;
dest->tm_yday = src->tm_yday;
dest->tm_isdst = src->tm_isdst;
# ifdef HAS_TM_TM_GMTOFF
dest->tm_gmtoff = src->tm_gmtoff;
# endif
# ifdef HAS_TM_TM_ZONE
dest->tm_zone = src->tm_zone;
# endif
# else
/* They're the same type */
memcpy(dest, src, sizeof(*dest));
# endif
}
}
void copy_TM_to_tm(const struct TM *src, struct tm *dest) {
if( src == NULL ) {
memset(dest, 0, sizeof(*dest));
}
else {
# ifdef USE_TM64
dest->tm_sec = src->tm_sec;
dest->tm_min = src->tm_min;
dest->tm_hour = src->tm_hour;
dest->tm_mday = src->tm_mday;
dest->tm_mon = src->tm_mon;
dest->tm_year = (int)src->tm_year;
dest->tm_wday = src->tm_wday;
dest->tm_yday = src->tm_yday;
dest->tm_isdst = src->tm_isdst;
# ifdef HAS_TM_TM_GMTOFF
dest->tm_gmtoff = src->tm_gmtoff;
# endif
# ifdef HAS_TM_TM_ZONE
dest->tm_zone = src->tm_zone;
# endif
# else
/* They're the same type */
memcpy(dest, src, sizeof(*dest));
# endif
}
}
/* Simulate localtime_r() to the best of our ability */
struct tm * fake_localtime_r(const time_t *clock, struct tm *result) {
const struct tm *static_result = localtime(clock);
assert(result != NULL);
if( static_result == NULL ) {
memset(result, 0, sizeof(*result));
return NULL;
}
else {
memcpy(result, static_result, sizeof(*result));
return result;
}
}
/* Simulate gmtime_r() to the best of our ability */
struct tm * fake_gmtime_r(const time_t *clock, struct tm *result) {
const struct tm *static_result = gmtime(clock);
assert(result != NULL);
if( static_result == NULL ) {
memset(result, 0, sizeof(*result));
return NULL;
}
else {
memcpy(result, static_result, sizeof(*result));
return result;
}
}
static Time64_T seconds_between_years(Year left_year, Year right_year) {
int increment = (left_year > right_year) ? 1 : -1;
Time64_T seconds = 0;
int cycles;
if( left_year > 2400 ) {
cycles = (left_year - 2400) / 400;
left_year -= cycles * 400;
seconds += cycles * seconds_in_gregorian_cycle;
}
else if( left_year < 1600 ) {
cycles = (left_year - 1600) / 400;
left_year += cycles * 400;
seconds += cycles * seconds_in_gregorian_cycle;
}
while( left_year != right_year ) {
seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24;
right_year += increment;
}
return seconds * increment;
}
Time64_T mktime64(const struct TM *input_date) {
struct tm safe_date;
struct TM date;
Time64_T time;
Year year = input_date->tm_year + 1900;
if( MIN_SAFE_YEAR <= year && year <= MAX_SAFE_YEAR ) {
copy_TM_to_tm(input_date, &safe_date);
return (Time64_T)mktime(&safe_date);
}
/* Have to make the year safe in date else it won't fit in safe_date */
date = *input_date;
date.tm_year = safe_year(year) - 1900;
copy_TM_to_tm(&date, &safe_date);
time = (Time64_T)mktime(&safe_date);
time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900));
return time;
}
/* Because I think mktime() is a crappy name */
Time64_T timelocal64(const struct TM *date) {
return mktime64(date);
}
struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
{
int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
Time64_T v_tm_tday;
int leap;
Time64_T m;
Time64_T time = *in_time;
Year year = 70;
int cycles = 0;
assert(p != NULL);
/* Use the system gmtime() if time_t is small enough */
if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
time_t safe_time = *in_time;
struct tm safe_date;
GMTIME_R(&safe_time, &safe_date);
copy_tm_to_TM(&safe_date, p);
assert(check_tm(p));
return p;
}
#ifdef HAS_TM_TM_GMTOFF
p->tm_gmtoff = 0;
#endif
p->tm_isdst = 0;
#ifdef HAS_TM_TM_ZONE
p->tm_zone = "UTC";
#endif
v_tm_sec = (int)(time % 60);
time /= 60;
v_tm_min = (int)(time % 60);
time /= 60;
v_tm_hour = (int)(time % 24);
time /= 24;
v_tm_tday = time;
WRAP (v_tm_sec, v_tm_min, 60);
WRAP (v_tm_min, v_tm_hour, 60);
WRAP (v_tm_hour, v_tm_tday, 24);
v_tm_wday = (int)((v_tm_tday + 4) % 7);
if (v_tm_wday < 0)
v_tm_wday += 7;
m = v_tm_tday;
if (m >= CHEAT_DAYS) {
year = CHEAT_YEARS;
m -= CHEAT_DAYS;
}
if (m >= 0) {
/* Gregorian cycles, this is huge optimization for distant times */
cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
if( cycles ) {
m -= (cycles * (Time64_T) days_in_gregorian_cycle);
year += (cycles * years_in_gregorian_cycle);
}
/* Years */
leap = IS_LEAP (year);
while (m >= (Time64_T) length_of_year[leap]) {
m -= (Time64_T) length_of_year[leap];
year++;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 0;
while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
m -= (Time64_T) days_in_month[leap][v_tm_mon];
v_tm_mon++;
}
} else {
year--;
/* Gregorian cycles */
cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
if( cycles ) {
m -= (cycles * (Time64_T) days_in_gregorian_cycle);
year += (cycles * years_in_gregorian_cycle);
}
/* Years */
leap = IS_LEAP (year);
while (m < (Time64_T) -length_of_year[leap]) {
m += (Time64_T) length_of_year[leap];
year--;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 11;
while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
m += (Time64_T) days_in_month[leap][v_tm_mon];
v_tm_mon--;
}
m += (Time64_T) days_in_month[leap][v_tm_mon];
}
p->tm_year = year;
if( p->tm_year != year ) {
#ifdef EOVERFLOW
errno = EOVERFLOW;
#endif
return NULL;
}
/* At this point m is less than a year so casting to an int is safe */
p->tm_mday = (int) m + 1;
p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
p->tm_sec = v_tm_sec;
p->tm_min = v_tm_min;
p->tm_hour = v_tm_hour;
p->tm_mon = v_tm_mon;
p->tm_wday = v_tm_wday;
assert(check_tm(p));
return p;
}
struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
{
time_t safe_time;
struct tm safe_date;
struct TM gm_tm;
Year orig_year;
int month_diff;
assert(local_tm != NULL);
/* Use the system localtime() if time_t is small enough */
if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
safe_time = *time;
TRACE1("Using system localtime for %lld\n", *time);
LOCALTIME_R(&safe_time, &safe_date);
copy_tm_to_TM(&safe_date, local_tm);
assert(check_tm(local_tm));
return local_tm;
}
if( gmtime64_r(time, &gm_tm) == NULL ) {
TRACE1("gmtime64_r returned null for %lld\n", *time);
return NULL;
}
orig_year = gm_tm.tm_year;
if (gm_tm.tm_year > (2037 - 1900) ||
gm_tm.tm_year < (1970 - 1900)
)
{
TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
}
safe_time = timegm64(&gm_tm);
if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
return NULL;
}
copy_tm_to_TM(&safe_date, local_tm);
local_tm->tm_year = orig_year;
if( local_tm->tm_year != orig_year ) {
TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
(Year)local_tm->tm_year, (Year)orig_year);
#ifdef EOVERFLOW
errno = EOVERFLOW;
#endif
return NULL;
}
month_diff = local_tm->tm_mon - gm_tm.tm_mon;
/* When localtime is Dec 31st previous year and
gmtime is Jan 1st next year.
*/
if( month_diff == 11 ) {
local_tm->tm_year--;
}
/* When localtime is Jan 1st, next year and
gmtime is Dec 31st, previous year.
*/
if( month_diff == -11 ) {
local_tm->tm_year++;
}
/* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
in a non-leap xx00. There is one point in the cycle
we can't account for which the safe xx00 year is a leap
year. So we need to correct for Dec 31st comming out as
the 366th day of the year.
*/
if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
local_tm->tm_yday--;
assert(check_tm(local_tm));
return local_tm;
}
int valid_tm_wday( const struct TM* date ) {
if( 0 <= date->tm_wday && date->tm_wday <= 6 )
return 1;
else
return 0;
}
int valid_tm_mon( const struct TM* date ) {
if( 0 <= date->tm_mon && date->tm_mon <= 11 )
return 1;
else
return 0;
}
char *asctime64_r( const struct TM* date, char *result ) {
/* I figure everything else can be displayed, even hour 25, but if
these are out of range we walk off the name arrays */
if( !valid_tm_wday(date) || !valid_tm_mon(date) )
return NULL;
sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
wday_name[date->tm_wday],
mon_name[date->tm_mon],
date->tm_mday, date->tm_hour,
date->tm_min, date->tm_sec,
1900 + date->tm_year);
return result;
}
char *ctime64_r( const Time64_T* time, char* result ) {
struct TM date;
localtime64_r( time, &date );
return asctime64_r( &date, result );
}
/* Non-thread safe versions of the above */
struct TM *localtime64(const Time64_T *time) {
return localtime64_r(time, &Static_Return_Date);
}
struct TM *gmtime64(const Time64_T *time) {
return gmtime64_r(time, &Static_Return_Date);
}
char *asctime64( const struct TM* date ) {
return asctime64_r( date, Static_Return_String );
}
char *ctime64( const Time64_T* time ) {
return asctime64(localtime64(time));
}

View File

@ -0,0 +1,75 @@
/* Debugging
TIME_64_DEBUG
Define if you want debugging messages
*/
/* #define TIME_64_DEBUG */
/* INT_64_T
A 64 bit integer type to use to store time and others.
Must be defined.
*/
#define INT_64_T long long
/* USE_TM64
Should we use a 64 bit safe replacement for tm? This will
let you go past year 2 billion but the struct will be incompatible
with tm. Conversion functions will be provided.
*/
/* #define USE_TM64 */
/* Availability of system functions.
HAS_GMTIME_R
Define if your system has gmtime_r()
HAS_LOCALTIME_R
Define if your system has localtime_r()
HAS_TIMEGM
Define if your system has timegm(), a GNU extension.
*/
#define HAS_GMTIME_R
#define HAS_LOCALTIME_R
/*#define HAS_TIMEGM */
/* Details of non-standard tm struct elements.
HAS_TM_TM_GMTOFF
True if your tm struct has a "tm_gmtoff" element.
A BSD extension.
HAS_TM_TM_ZONE
True if your tm struct has a "tm_zone" element.
A BSD extension.
*/
#define HAS_TM_TM_GMTOFF
#define HAS_TM_TM_ZONE
/* USE_SYSTEM_LOCALTIME
USE_SYSTEM_GMTIME
Should we use the system functions if the time is inside their range?
Your system localtime() is probably more accurate, but our gmtime() is
fast and safe.
*/
#define USE_SYSTEM_LOCALTIME
/* #define USE_SYSTEM_GMTIME */
/* SYSTEM_LOCALTIME_MAX
SYSTEM_LOCALTIME_MIN
SYSTEM_GMTIME_MAX
SYSTEM_GMTIME_MIN
Maximum and minimum values your system's gmtime() and localtime()
can handle. We will use your system functions if the time falls
inside these ranges.
*/
#define SYSTEM_LOCALTIME_MAX 2147483647
#define SYSTEM_LOCALTIME_MIN -2147483647
#define SYSTEM_GMTIME_MAX 2147483647
#define SYSTEM_GMTIME_MIN -2147483647

388
libc/docs/OVERVIEW.TXT Normal file
View File

@ -0,0 +1,388 @@
Bionic C Library Overview:
==========================
Introduction:
Core Philosophy:
The core idea behind Bionic's design is: KEEP IT REALLY SIMPLE.
This implies that the C library should only provide lightweight wrappers
around kernel facilities and not try to be too smart to deal with edge cases.
The name "Bionic" comes from the fact that it is part-BSD and part-Linux:
its source code consists in a mix of BSD C library pieces with custom
Linux-specific bits used to deal with threads, processes, signals and a few
others things.
All original BSD pieces carry the BSD copyright disclaimer. Bionic-specific
bits carry the Android Open Source Project copyright disclaimer. And
everything is released under the BSD license.
Architectures:
Bionic currently supports the ARM and x86 instruction sets. In theory, it
should be possible to support more, but this may require a little work (e.g.
adding system call IDs to SYSCALLS.TXT, described below, or modifying the
dynamic linker).
The ARM-specific code is under arch-arm/ and the x86-specific one is under
arch-x86/
Note that the x86 version is only meant to run on an x86 Android device. We
make absolutely no claim that you could build and use Bionic on a stock x86
Linux distribution (though that would be cool, so patches are welcomed :-))
Syscall stubs:
Each system call function is implemented by a tiny assembler source fragment
(called a "syscall stub"), which is generated automatically by
tools/gensyscalls.py which reads the SYSCALLS.TXT file for input.
SYSCALLS.TXT contains the list of all syscall stubs to generate, along with
the corresponding syscall numeric identifier (which may differ between ARM
and x86), and its signature
If you modify this file, you may want to use tools/checksyscalls.py which
checks its content against official Linux kernel header files, and will
report errors when invalid syscall ids are used.
Sometimes, the C library function is really a wrapper that calls the
corresponding syscall with another name. For example, the exit() function
is provided by the C library and calls the _exit() syscall stub.
See SYSCALLS.TXT for documentation and details.
time_t:
time_t is 32-bit as defined by the kernel on 32-bit CPUs. A 64-bit version
would be preferrable to avoid the Y2038 bug, but the kernel maintainers
consider that this is not needed at the moment.
Instead, Bionic provides a <time64.h> header that defines a time64_t type,
and related functions like mktime64(), localtime64(), etc...
Timezone management:
The name of the current timezone is taken from the TZ environment variable,
if defined. Otherwise, the system property named 'persist.sys.timezone' is
checked instead.
The zoneinfo timezone database and index files are located under directory
/system/usr/share/zoneinfo, instead of the more Posix-compliant path of
/usr/share/zoneinfo
off_t:
For similar reasons, off_t is 32-bit. We define loff_t as the 64-bit variant
due to BSD inheritance, but off64_t should be available as a typedef to ease
porting of current Linux-specific code.
Linux kernel headers:
Bionic comes with its own set of "clean" Linux kernel headers to allow
user-space code to use kernel-specific declarations (e.g. IOCTLs, structure
declarations, constants, etc...). They are located in:
./kernel/common,
./kernel/arch-arm
./kernel/arch-x86
These headers have been generated by a tool (kernel/tools/update-all.py) to
only include the public definitions from the original Linux kernel headers.
If you want to know why and how this is done, read kernel/README.TXT to get
all the (gory) details.
PThread implementation:
Bionic's C library comes with its own pthread implementation bundled in.
This is different from other historical C libraries which:
- place it in an external library (-lpthread)
- play linker tricks with weak symbols at dynamic link time
The support for real-time features (a.k.a. -lrt) is also bundled in the
C library.
The implementation is based on futexes and strives to provide *very* short
code paths for common operations. Notable features are the following:
- pthread_mutex_t, pthread_cond_t are only 4 bytes each.
- Normal, recursive and error-check mutexes are supported, and the code
path is heavily optimized for the normal case, which is used most of
the time.
- Process-shared mutexes and condition variables are not supported.
Their implementation requires far more complexity and was absolutely
not needed for Android (which uses other inter-process synchronization
capabilities).
Note that they could be added in the future without breaking the ABI
by specifying more sophisticated code paths (which may make the common
paths slightly slower though).
- There is currently no support for read/write locks, priority-ceiling in
mutexes and other more advanced features. Again, the main idea being
that this was not needed for Android at all but could be added in the
future.
pthread_cancel():
pthread_cancel() will *not* be supported in Bionic, because doing this would
involve making the C library significantly bigger for very little benefit.
Consider that:
- A proper implementation must insert pthread cancellation checks in a lot
of different places of the C library. And conformance is very difficult
to test properly.
- A proper implementation must also clean up resources, like releasing
memory, or unlocking mutexes, properly if the cancellation happens in a
complex function (e.g. inside gethostbyname() or fprintf() + complex
formatting rules). This tends to slow down the path of many functions.
- pthread cancellation cannot stop all threads: e.g. it can't do anything
against an infinite loop
- pthread cancellation itself has short-comings and isn't very portable
(see http://advogato.org/person/slamb/diary.html?start=49 for example).
All of this is contrary to the Bionic design goals. If your code depends on
thread cancellation, please consider alternatives.
Note however that Bionic does implement pthread_cleanup_push() and
pthread_cleanup_pop(), which can be used to handle cleanups that happen when
a thread voluntarily exits through pthread_exit() or returning from its
main function.
pthread_once():
Do not call fork() within a callback provided to pthread_once(). Doing this
may result in a deadlock in the child process the next time it calls
pthread_once().
Also, you can't throw a C++ Exception from the callback (see C++ Exception
Support below).
The current implementation of pthread_once() lacks the necessary support of
multi-core-safe double-checked-locking (read and write barriers).
Thread-specific data
The thread-specific storage only provides for a bit less than 64
pthread_key_t objects to each process. The implementation provides 64 real
slots but also uses about 5 of them (exact number may depend on
implementation) for its own use (e.g. two slots are pre-allocated by the C
library to speed-up the Android OpenGL sub-system).
Note that Posix mandates a minimum of 128 slots, but we do not claim to be
Posix-compliant.
Except for the main thread, the TLS area is stored at the top of the stack.
See comments in bionic/libc/bionic/pthread.c for details.
At the moment, thread-local storage defined through the __thread compiler
keyword is not supported by the Bionic C library and dynamic linker.
Multi-core support
At the moment, Bionic does not provide or use read/write memory barriers.
This means that using it on certain multi-core systems might not be
supported, depending on its exact CPU architecture.
Android-specific features:
Bionic provides a small number of Android-specific features to its clients:
- access to system properties:
Android provides a simple shared value/key space to all processes on the
system. It stores a liberal number of 'properties', each of them being a
simple size-limited string that can be associated to a size-limited
string value.
The header <sys/system_properties.h> can be used to read system
properties and also defines the maximum size of keys and values.
- Android-specific user/group management:
There is no /etc/passwd or /etc/groups in Android. By design, it is
meant to be used by a single handset user. On the other hand, Android
uses the Linux user/group management features extensively to secure
process permissions, like access to various filesystem directories.
In the Android scheme, each installed application gets its own
uid_t/gid_t starting from 10000; lower numerical ids are reserved for
system daemons.
getpwnam() recognizes some hard-coded subsystems names (e.g. "radio")
and will translate them to their low-user-id values. It also recognizes
"app_1234" as the synthetic name of the application that was installed
with uid 10000 + 1234, which is 11234. getgrnam() works similarly
getgrouplist() will always return a single group for any user name,
which is the one passed as an input parameter.
getgrgid() will similarly only return a structure that contains a
single-element members list, corresponding to the user with the same
numerical value than the group.
See bionic/libc/bionic/stubs.c for more details.
- getservent()
There is no /etc/services on Android. Instead the C library embeds a
constant list of services in its executable, which is parsed on demand
by the various functions that depend on it. See
bionic/libc/netbsd/net/getservent.c and
bionic/libc/netbsd/net/services.h
The list of services defined internally might change liberally in the
future. This feature is mostly historically and is very rarely used.
The getservent() returns thread-local data. getservbyport() and
getservbyname() are also implemented in a similar fashion.
- getprotoent()
There is no /etc/protocol on Android. Bionic does not currently
implement getprotoent() and related functions. If added, it will
likely be done in a way similar to getservent()
DNS resolver:
Bionic uses a NetBSD-derived resolver library which has been modified in
the following ways:
- don't implement the name-server-switch feature (a.k.a. <nsswitch.h>)
- read /system/etc/resolv.conf instead of /etc/resolv.conf
- read the list of servers from system properties. the code looks for
'net.dns1', 'net.dns2', etc.. Each property should contain the IP
address of a DNS server.
these properties are set/modified by other parts of the Android system
(e.g. the dhcpd daemon).
the implementation also supports per-process DNS server list, using the
properties 'net.dns1.<pid>', 'net.dns2.<pid>', etc... Where <pid> stands
for the numerical ID of the current process.
- when performing a query, use a properly randomized Query ID (instead of
a incremented one), for increased security.
- when performing a query, bind the local client socket to a random port
for increased security.
- get rid of *many* unfortunate thread-safety issues in the original code
Bionic does *not* expose implementation details of its DNS resolver; the
content of <arpa/nameser.h> is intentionally blank. The resolver
implementation might change completely in the future.
PThread Real-Time Timers:
timer_create(), timer_gettime(), timer_settime() and timer_getoverrun() are
supported.
Bionic also now supports SIGEV_THREAD real-time timers (see timer_create()).
The implementation simply uses a single thread per timer, unlike GLibc which
uses complex heuristics to try to use the less threads possible when several
timers with compatible properties are used.
This means that if your code uses a lot of SIGEV_THREAD timers, your program
may consume a lot of memory. However, if your program needs many of these
timers, it'd better handle timeout events directly instead.
Other timers (e.g. SIGEV_SIGNAL) are handled by the kernel and use much less
system resources.
Binary Compatibility:
Bionic is *not* in any way binary-compatible with the GNU C Library, ucLibc
or any known Linux C library. This means several things:
- You cannot expect to build something against the GNU C Library headers and
have it dynamically link properly to Bionic later.
- You should *really* use the Android toolchain to build your program against
Bionic. The toolchain deals with many important details that are crucial
to get something working properly.
Failure to do so will usually result in the inability to run or link your
program, or even runtime crashes. Several random web pages on the Internet
describe how you can succesfully write a "hello-world" program with the
ARM GNU toolchain. These examples usually work by chance, if anything else,
and you should not follow these instructions unless you want to waste a lot
of your time in the process.
Note however that you *can* generate a binary that is built against the
GNU C Library headers and then statically linked to it. The corresponding
executable should be able to run (if it doesn't use dlopen()/dlsym())
Dynamic Linker:
Bionic comes with its own dynamic linker (just like ld.so on Linux really
comes from GLibc). This linker does not support all the relocations
generated by other GCC ARM toolchains.
C++ Exceptions Support:
At the moment, Bionic doesn't support C++ exceptions, what this really means
is the following:
- If pthread_once() is called with a C++ callback that throws an exception,
then the C library will keep the corresponding pthread_once_t mutex
locked. Any further call to pthread_once() will result in a deadlock.
A proper implementation should be able to register a C++ exception
cleanup handler before the callback to properly unlock the
pthread_once_t. Unfortunately this requires tricky assembly code that
is highly dependent on the compiler.
This feature is not planned to be supported anytime soon.
- The same problem may arise if you throw an exception within a callback
called from the C library. Fortunately, these cases are very rare in the
real-world, but any callback you provide to the C library should *not*
throw an exception.
- Bionic lacks a few support functions to have exception support work
properly.
System V IPCs:
Bionic intentionally does not provide support for System-V IPCs mechanisms,
like the ones provided by semget(), shmget(), msgget(). The reason for this
is to avoid denial-of-service. For a detailed rationale about this, please
read the file docs/SYSV-IPCS.TXT.
Include Paths:
The Android build system should automatically provide the necessary include
paths required to build against the C library headers. However, if you want
to do that yourself, you will need to add:
libc/arch-$ARCH/include
libc/include
libc/kernel/common
libc/kernel/arch-$ARCH
to your C include path.

103
libc/docs/SYSV-IPC.TXT Normal file
View File

@ -0,0 +1,103 @@
Android does not support System V IPCs, i.e. the facilities provided by the
following standard Posix headers:
<sys/sem.h> /* SysV semaphores */
<sys/shm.h> /* SysV shared memory segments */
<sys/msg.h> /* SysV message queues */
<sys/ipc.h> /* General IPC definitions */
The reason for this is due to the fact that, by design, they lead to global
kernel resource leakage.
For example, there is no way to automatically release a SysV semaphore
allocated in the kernel when:
- a buggy or malicious process exits
- a non-buggy and non-malicious process crashes or is explicitely killed.
Killing processes automatically to make room for new ones is an
important part of Android's application lifecycle implementation. This means
that, even assuming only non-buggy and non-malicious code, it is very likely
that over time, the kernel global tables used to implement SysV IPCs will fill
up.
At that point, strange failures are likely to occur and prevent programs that
use them to run properly until the next reboot of the system.
And we can't ignore potential malicious applications. As a proof of concept
here is a simple exploit that you can run on a standard Linux box today:
--------------- cut here ------------------------
#include <sys/sem.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define NUM_SEMAPHORES 32
#define MAX_FAILS 10
int main(void)
{
int counter = 0;
int fails = 0;
if (counter == IPC_PRIVATE)
counter++;
printf( "%d (NUM_SEMAPHORES=%d)\n", counter, NUM_SEMAPHORES);
for (;;) {
int ret = fork();
int status;
if (ret < 0) {
perror("fork:");
break;
}
if (ret == 0) {
/* in the child */
ret = semget( (key_t)counter, NUM_SEMAPHORES, IPC_CREAT );
if (ret < 0) {
return errno;
}
return 0;
}
else {
/* in the parent */
ret = wait(&status);
if (ret < 0) {
perror("waitpid:");
break;
}
if (status != 0) {
status = WEXITSTATUS(status);
fprintf(stderr, "child %d FAIL at counter=%d: %d\n", ret,
counter, status);
if (++fails >= MAX_FAILS)
break;
}
}
counter++;
if ((counter % 1000) == 0) {
printf("%d\n", counter);
}
if (counter == IPC_PRIVATE)
counter++;
}
return 0;
}
--------------- cut here ------------------------
If you run it on a typical Linux distribution today, you'll discover that it
will quickly fill up the kernel's table of unique key_t values, and that
strange things will happen in some parts of the system, but not all.
(You can use the "ipcs -u" command to get a summary describing the kernel
tables and their allocations)
For example, in our experience, anything program launched after that that
calls strerror() will simply crash. The USB sub-system starts spoutting weird
errors to the system console, etc...

View File

@ -97,6 +97,9 @@ typedef volatile int pthread_once_t;
#define PTHREAD_PROCESS_PRIVATE 0
#define PTHREAD_PROCESS_SHARED 1
#define PTHREAD_SCOPE_SYSTEM 0
#define PTHREAD_SCOPE_PROCESS 1
/*
* Prototypes
*/
@ -128,6 +131,9 @@ int pthread_attr_getstack(pthread_attr_t const * attr, void ** stackaddr, size_t
int pthread_attr_setguardsize(pthread_attr_t * attr, size_t guard_size);
int pthread_attr_getguardsize(pthread_attr_t const * attr, size_t * guard_size);
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(pthread_attr_t const *attr);
int pthread_getattr_np(pthread_t thid, pthread_attr_t * attr);
int pthread_create(pthread_t *thread, pthread_attr_t const * attr,

View File

@ -82,9 +82,8 @@ extern size_t strspn(const char *, const char *);
extern char* strsignal(int sig);
/* Just declared to make libstdc++-v3 happy. */
extern int strcoll (const char *, const char *);
extern size_t strxfrm (char *, const char *, size_t);
extern int strcoll(const char *, const char *);
extern size_t strxfrm(char *, const char *, size_t);
__END_DECLS

View File

@ -170,17 +170,6 @@
#define __NR_getsockopt (__NR_SYSCALL_BASE + 295)
#define __NR_sendmsg (__NR_SYSCALL_BASE + 296)
#define __NR_recvmsg (__NR_SYSCALL_BASE + 297)
#define __NR_semctl (__NR_SYSCALL_BASE + 300)
#define __NR_semget (__NR_SYSCALL_BASE + 299)
#define __NR_semop (__NR_SYSCALL_BASE + 298)
#define __NR_shmat (__NR_SYSCALL_BASE + 305)
#define __NR_shmctl (__NR_SYSCALL_BASE + 308)
#define __NR_shmdt (__NR_SYSCALL_BASE + 306)
#define __NR_shmget (__NR_SYSCALL_BASE + 307)
#define __NR_msgctl (__NR_SYSCALL_BASE + 304)
#define __NR_msgget (__NR_SYSCALL_BASE + 303)
#define __NR_msgrcv (__NR_SYSCALL_BASE + 302)
#define __NR_msgsnd (__NR_SYSCALL_BASE + 301)
#define __NR_epoll_create (__NR_SYSCALL_BASE + 250)
#define __NR_epoll_ctl (__NR_SYSCALL_BASE + 251)
#define __NR_epoll_wait (__NR_SYSCALL_BASE + 252)

View File

@ -179,17 +179,6 @@ int sched_getparam (pid_t pid, struct sched_param *param);
int sched_get_priority_max (int policy);
int sched_get_priority_min (int policy);
int sched_rr_get_interval (pid_t pid, struct timespec *interval);
int semctl (int semid, int semnum, int cmd, ...);
int semget (key_t key, int nsems, int semflg);
int semop (int semid, struct sembuf* sops, size_t nsops);
void* shmat (int shmid, const void* shmaddr, int shmflg);
int shmctl (int shmid, int cmd, struct shmid_ds* buf);
int shmdt (const void* shmaddr);
int shmget (key_t key, size_t size, int shmflg);
int msgctl (int msqid, int cmd, struct msqid_ds *buf);
int msgget (key_t key, int msgflg);
int msgrcv (int msqid, void* msgp, size_t msgsz, long int msgtyp, int msgflg);
int msgsnd (int msqid, const void* msgp, size_t msgsz, int msgflg);
int uname (struct utsname *);
pid_t __wait4 (pid_t pid, int *status, int options, struct rusage *rusage);
mode_t umask (mode_t);

View File

@ -71,6 +71,10 @@ struct stat {
unsigned long long st_ino;
};
extern int chmod(const char *, mode_t);
extern int fchmod(int, mode_t);
extern int mkdir(const char *, mode_t);
extern int stat(const char *, struct stat *);
extern int fstat(int, struct stat *);
extern int lstat(const char *, struct stat *);

View File

@ -56,7 +56,7 @@ extern int utimes(const char *, const struct timeval *);
#define timeradd(a, b, res) \
do { \
(res)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
(res)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
if ((res)->tv_usec >= 1000000) { \
(res)->tv_usec -= 1000000; \
(res)->tv_sec += 1; \

View File

@ -65,6 +65,7 @@ typedef __kernel_nlink_t nlink_t;
#define _OFF_T_DEFINED_
typedef __kernel_off_t off_t;
typedef __kernel_loff_t loff_t;
typedef loff_t off64_t; /* GLibc-specific */
typedef __kernel_pid_t pid_t;

54
libc/include/time64.h Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright (c) 2007-2008 Michael G Schwern
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
The MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Origin: http://code.google.com/p/y2038
Modified for Bionic by the Android Open Source Project
*/
#ifndef TIME64_H
#define TIME64_H
#include <time.h>
#include <stdint.h>
typedef int64_t time64_t;
struct tm *gmtime64_r (const time64_t *, struct tm *);
struct tm *localtime64_r (const time64_t *, struct tm *);
struct tm *gmtime64 (const time64_t *);
struct tm *localtime64 (const time64_t *);
char *asctime64 (const struct tm *);
char *asctime64_r (const struct tm *, char *);
char *ctime64 (const time64_t*);
char *ctime64_r (const time64_t*, char*);
time64_t timegm64 (const struct tm *);
time64_t mktime64 (const struct tm *);
time64_t timelocal64 (const struct tm *);
#endif /* TIME64_H */

View File

@ -34,6 +34,7 @@
#include <sys/select.h>
#include <sys/sysconf.h>
#include <linux/capability.h>
#include <pathconf.h>
__BEGIN_DECLS
@ -111,9 +112,6 @@ extern int link(const char *, const char *);
extern int unlink(const char *);
extern int chdir(const char *);
extern int fchdir(int);
extern int chmod(const char *, mode_t);
extern int fchmod(int, mode_t);
extern int mkdir(const char *, mode_t);
extern int rmdir(const char *);
extern int pipe(int *);
extern int chroot(const char *);

View File

@ -29,6 +29,10 @@
#define AUDIO_SET_EQ _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned)
#define AUDIO_SET_RX_IIR _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned)
#define AUDIO_SET_VOLUME _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned)
#define AUDIO_ENABLE_AUDPRE _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned)
#define AUDIO_SET_AGC _IOW(AUDIO_IOCTL_MAGIC, 12, unsigned)
#define AUDIO_SET_NS _IOW(AUDIO_IOCTL_MAGIC, 13, unsigned)
#define AUDIO_SET_TX_IIR _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned)
struct msm_audio_config {
uint32_t buffer_size;

View File

@ -626,37 +626,12 @@ gethostbyname_internal(const char *name, int af, res_state res)
break;
}
#ifdef ANDROID_CHANGES
cache = __get_res_cache();
if (cache != NULL) {
hp = _resolv_cache_lookup( cache, name, af );
if (hp == _RESOLV_HOSTENT_NONE) {
h_errno = HOST_NOT_FOUND;
return NULL;
}
if (hp != NULL) {
h_errno = NETDB_SUCCESS;
return hp;
}
}
#endif
hp = NULL;
h_errno = NETDB_INTERNAL;
if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
#ifdef ANDROID_CHANGES
/* cache negative DNS entry */
if (h_errno == HOST_NOT_FOUND && cache != NULL)
_resolv_cache_add( cache, name, af, _RESOLV_HOSTENT_NONE );
#endif
return NULL;
}
#ifdef ANDROID_CHANGES
if (cache != NULL) {
_resolv_cache_add( cache, name, af, hp );
}
#endif
h_errno = NETDB_SUCCESS;
return hp;
}

File diff suppressed because it is too large Load Diff

View File

@ -81,6 +81,9 @@ __RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
/* set to 1 to use our small/simple/limited DNS cache */
#define USE_RESOLV_CACHE 1
/*
* Send query to name server and wait for reply.
*/
@ -111,6 +114,10 @@ __RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $");
#include <isc/eventlib.h>
#if USE_RESOLV_CACHE
# include <resolv_cache.h>
#endif
#ifndef DE_CONST
#define DE_CONST(c,v) v = ((c) ? \
strchr((const void *)(c), *(const char *)(const void *)(c)) : NULL)
@ -344,12 +351,17 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1,
return (1);
}
int
res_nsend(res_state statp,
const u_char *buf, int buflen, u_char *ans, int anssiz)
{
int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
char abuf[NI_MAXHOST];
#if USE_RESOLV_CACHE
struct resolv_cache* cache;
ResolvCacheStatus cache_status = RESOLV_CACHE_UNSUPPORTED;
#endif
if (statp->nscount == 0) {
errno = ESRCH;
@ -365,6 +377,20 @@ res_nsend(res_state statp,
gotsomewhere = 0;
terrno = ETIMEDOUT;
#if USE_RESOLV_CACHE
cache = __get_res_cache();
if (cache != NULL) {
int anslen = 0;
cache_status = _resolv_cache_lookup(
cache, buf, buflen,
ans, anssiz, &anslen);
if (cache_status == RESOLV_CACHE_FOUND) {
return anslen;
}
}
#endif
/*
* If the ns_addr_list in the resolver context has changed, then
* invalidate our cached copy and the associated timing data.
@ -534,6 +560,12 @@ res_nsend(res_state statp,
(stdout, "%s", ""),
ans, (resplen > anssiz) ? anssiz : resplen);
#if USE_RESOLV_CACHE
if (cache_status == RESOLV_CACHE_NOTFOUND) {
_resolv_cache_add(cache, buf, buflen,
ans, resplen);
}
#endif
/*
* If we have temporarily opened a virtual circuit,
* or if we haven't been asked to keep a socket open,

View File

@ -46,7 +46,6 @@ typedef struct {
struct __res_state _nres[1];
unsigned _serial;
struct prop_info* _pi;
struct hostent* _hostent;
struct res_static _rstatic[1];
} _res_thread;
@ -66,9 +65,9 @@ _res_thread_alloc(void)
if ( res_ninit( rt->_nres ) < 0 ) {
free(rt);
rt = NULL;
} else {
memset(rt->_rstatic, 0, sizeof rt->_rstatic);
}
rt->_hostent = NULL;
memset(rt->_rstatic, 0, sizeof rt->_rstatic);
}
return rt;
}
@ -93,7 +92,6 @@ _res_thread_free( void* _rt )
_res_thread* rt = _rt;
_res_static_done(rt->_rstatic);
_resolv_hostent_free(rt->_hostent);
res_ndestroy(rt->_nres);
free(rt);
}
@ -132,6 +130,7 @@ _res_thread_get(void)
rt = NULL;
pthread_setspecific( _res_key, rt );
}
_resolv_cache_reset(rt->_serial);
return rt;
}
@ -177,14 +176,6 @@ __res_put_state(res_state res)
res=res;
}
struct hostent**
__get_res_cache_hostent_p(void)
{
_res_thread* rt = _res_thread_get();
return rt ? &rt->_hostent : NULL;
}
res_static
__res_get_static(void)
{

View File

@ -28,31 +28,39 @@
#ifndef _RESOLV_CACHE_H_
#define _RESOLV_CACHE_H_
#include <netdb.h>
const struct hostent _resolv_hostent_none;
#define _RESOLV_HOSTENT_NONE ((struct hostent*)&_resolv_hostent_none)
struct resolv_cache; /* forward */
/* get cache instance, can be NULL if cache is disabled
* (e.g. through an environment variable) */
extern struct resolv_cache* __get_res_cache(void);
extern struct hostent** __get_res_cache_hostent_p(void);
extern struct resolv_cache* _resolv_cache_get( void );
/* this gets called everytime we detect some changes in the DNS configuration
* and will flush the cache */
extern void _resolv_cache_reset( unsigned generation );
extern struct resolv_cache* _resolv_cache_create( void );
typedef enum {
RESOLV_CACHE_UNSUPPORTED, /* the cache can't handle that kind of queries */
/* or the answer buffer is too small */
RESOLV_CACHE_NOTFOUND, /* the cache doesn't know about this query */
RESOLV_CACHE_FOUND /* the cache found the answer */
} ResolvCacheStatus;
extern void _resolv_cache_destroy( struct resolv_cache* cache );
extern ResolvCacheStatus
_resolv_cache_lookup( struct resolv_cache* cache,
const void* query,
int querylen,
void* answer,
int answersize,
int *answerlen );
extern struct hostent* _resolv_cache_lookup( struct resolv_cache* cache,
const char* name,
int af );
extern void _resolv_cache_add( struct resolv_cache* cache,
const char* name,
int af,
struct hostent* hp );
extern struct hostent* _resolv_hostent_copy( struct hostent* hp );
extern void _resolv_hostent_free( struct hostent* hp );
/* add a (query,answer) to the cache, only call if _resolv_cache_lookup
* did return RESOLV_CACHE_NOTFOUND
*/
extern void
_resolv_cache_add( struct resolv_cache* cache,
const void* query,
int querylen,
const void* answer,
int answerlen );
#endif /* _RESOLV_CACHE_H_ */

29
libc/include/sys/msg.h → libc/string/strcoll.c Normal file → Executable file
View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2009 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -25,19 +25,16 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SYS_MSG_H
#define _SYS_MSG_H
#include <string.h>
#include <sys/ipc.h>
#include <linux/msg.h>
__BEGIN_DECLS
extern int msgctl(int msqid, int cmd, struct msqid_ds *buf);
extern int msgget(key_t key, int msgflg);
extern int msgrcv(int msqid, void* msgp, size_t msgsz, long int msgtyp, int msgflg);
extern int msgsnd(int msqid, const void* msgp, size_t msgsz, int msgflg);
__END_DECLS
#endif /* _SYS_MSG_H */
/*
* Compare strings using the current locale. Since Bionic really does not
* support locales, we assume we always use the C locale and call strcmp.
*
* This function is provided to make libstdc++-v3 usable.
*/
int
strcoll(const char *s1, const char *s2)
{
return strcmp (s1, s2);
}

47
libc/string/strxfrm.c Executable file
View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2009 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 <string.h>
/*
* Transform string s2 to string s1 using the current locale so that
* strcmp of transformed strings yields the same result as strcoll.
* Since Bionic really does not support locales, we assume we always use
* the C locale.
*
* This function is provided to make libstdc++-v3 usable.
*/
size_t
strxfrm(char *s1, const char *s2, size_t n)
{
size_t len = strlen(s2) + 1;
if (len < n)
n = len;
memcpy(s1, s2, n);
return len;
}

View File

@ -34,6 +34,11 @@
#include "thread_private.h"
#include "atexit.h"
/* temporary, for bug hunting */
#include "logd.h"
#define debug_log(format, ...) \
__libc_android_log_print(ANDROID_LOG_DEBUG, "libc-abort", (format), ##__VA_ARGS__ )
void
abort(void)
{
@ -48,6 +53,9 @@ abort(void)
* any errors -- X311J doesn't allow abort to return anyway.
*/
sigdelset(&mask, SIGABRT);
/* temporary, so deliberate seg fault can be caught by debuggerd */
sigdelset(&mask, SIGSEGV);
/* -- */
(void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
/*
@ -64,6 +72,13 @@ abort(void)
}
}
/* temporary, for bug hunting */
debug_log("abort() called in pid %d\n", getpid());
/* seg fault seems to produce better debuggerd results than SIGABRT */
*((char*)0xdeadbaad) = 39;
debug_log("somehow we're not dead?\n");
/* -- */
(void)kill(getpid(), SIGABRT);
/*

View File

@ -1,119 +1,147 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <dlfcn.h>
extern char *optarg;
extern int optind, opterr, optopt;
static struct option long_options[] = {
{"library", required_argument, 0, 'l'},
{"symbol", required_argument, 0, 's'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0},
};
/* This array must parallel long_options[] */
static const char *descriptions[] = {
"specify a library path to look up symbol",
"specify symbol to look up",
"print this help screen",
};
void print_help(const char *name) {
fprintf(stdout,
"invokation:\n"
"\t%s [-l <libname>] -s <symbol name>\n"
"\t%s -h\n\n", name, name);
fprintf(stdout, "options:\n");
struct option *opt = long_options;
const char **desc = descriptions;
while (opt->name) {
fprintf(stdout, "\t-%c/--%s%s: %s\n",
opt->val,
opt->name,
(opt->has_arg ? " (argument)" : ""),
*desc);
opt++;
desc++;
}
}
int get_options(int argc, char **argv, char **lib, char **sym)
{
int c;
*lib = 0;
*sym = 0;
while (1) {
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long (argc, argv,
"l:s:h",
long_options,
&option_index);
/* Detect the end of the options. */
if (c == -1) break;
switch (c) {
case 'l':
*lib = strdup(optarg);
break;
case 's':
*sym = strdup(optarg);
break;
case 'h': print_help(argv[0]); exit(EXIT_FAILURE); break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
fprintf(stderr, "Unknown option");
exit(EXIT_FAILURE);
}
}
return optind;
}
int main(int argc, char **argv)
{
char *libname, *symname, *prog = *argv;
get_options(argc, argv, &libname, &symname);
if (symname == NULL) {
fprintf(stderr, "You must specify a symbol!\n");
print_help(prog);
exit(EXIT_FAILURE);
}
{
const char *dlerr;
void *handle, *symbol;
printf("opening library [%s]\n", libname);
dlerr = dlerror();
handle = libname ? dlopen(libname, RTLD_NOW) : RTLD_DEFAULT;
dlerr = dlerror();
if (dlerr != NULL) fprintf(stderr, "dlopen() error: %s\n", dlerr);
printf("opening symbol [%s]\n", symname);
symbol = dlsym(handle, symname);
dlerr = dlerror();
if (dlerr != NULL) fprintf(stderr, "dlsym() error: %s\n", dlerr);
printf("closing library [%s]\n", libname);
dlclose(handle);
dlerr = dlerror();
if (dlerr != NULL) fprintf(stderr, "dlclose() error: %s\n", dlerr);
else printf("successfully opened symbol\n");
}
if (libname != NULL) free(libname);
if (symname != NULL) free(symname);
return 0;
}
/*
* 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 <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <dlfcn.h>
extern char *optarg;
extern int optind, opterr, optopt;
static struct option long_options[] = {
{"library", required_argument, 0, 'l'},
{"symbol", required_argument, 0, 's'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0},
};
/* This array must parallel long_options[] */
static const char *descriptions[] = {
"specify a library path to look up symbol",
"specify symbol to look up",
"print this help screen",
};
void print_help(const char *name) {
fprintf(stdout,
"invokation:\n"
"\t%s [-l <libname>] -s <symbol name>\n"
"\t%s -h\n\n", name, name);
fprintf(stdout, "options:\n");
struct option *opt = long_options;
const char **desc = descriptions;
while (opt->name) {
fprintf(stdout, "\t-%c/--%s%s: %s\n",
opt->val,
opt->name,
(opt->has_arg ? " (argument)" : ""),
*desc);
opt++;
desc++;
}
}
int get_options(int argc, char **argv, char **lib, char **sym)
{
int c;
*lib = 0;
*sym = 0;
while (1) {
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long (argc, argv,
"l:s:h",
long_options,
&option_index);
/* Detect the end of the options. */
if (c == -1) break;
switch (c) {
case 'l':
*lib = strdup(optarg);
break;
case 's':
*sym = strdup(optarg);
break;
case 'h': print_help(argv[0]); exit(EXIT_FAILURE); break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
fprintf(stderr, "Unknown option");
exit(EXIT_FAILURE);
}
}
return optind;
}
int main(int argc, char **argv)
{
char *libname, *symname, *prog = *argv;
get_options(argc, argv, &libname, &symname);
if (symname == NULL) {
fprintf(stderr, "You must specify a symbol!\n");
print_help(prog);
exit(EXIT_FAILURE);
}
{
const char *dlerr;
void *handle, *symbol;
printf("opening library [%s]\n", libname);
dlerr = dlerror();
handle = libname ? dlopen(libname, RTLD_NOW) : RTLD_DEFAULT;
dlerr = dlerror();
if (dlerr != NULL) fprintf(stderr, "dlopen() error: %s\n", dlerr);
printf("opening symbol [%s]\n", symname);
symbol = dlsym(handle, symname);
dlerr = dlerror();
if (dlerr != NULL) fprintf(stderr, "dlsym() error: %s\n", dlerr);
printf("closing library [%s]\n", libname);
dlclose(handle);
dlerr = dlerror();
if (dlerr != NULL) fprintf(stderr, "dlclose() error: %s\n", dlerr);
else printf("successfully opened symbol\n");
}
if (libname != NULL) free(libname);
if (symname != NULL) free(symname);
return 0;
}

View File

@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
linker.c \
rt.c \
dlfcn.c \
debugger.c
debugger.c \
ba.c
LINKER_TEXT_BASE := 0xB0000100
@ -16,7 +17,9 @@ LINKER_AREA_SIZE := 0x01000000
LOCAL_LDFLAGS := -Wl,-Ttext,$(LINKER_TEXT_BASE)
LOCAL_CFLAGS += -DPRELINK -DLINKER_TEXT_BASE=$(LINKER_TEXT_BASE) -DLINKER_AREA_SIZE=$(LINKER_AREA_SIZE)
LOCAL_CFLAGS += -DPRELINK
LOCAL_CFLAGS += -DLINKER_TEXT_BASE=$(LINKER_TEXT_BASE)
LOCAL_CFLAGS += -DLINKER_AREA_SIZE=$(LINKER_AREA_SIZE)
# we need to access the Bionic private header <bionic_tls.h>
# in the linker

View File

@ -1,3 +1,31 @@
/*
* 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.
*/
.text
.align 4
.type _start,#function

View File

@ -1,3 +1,31 @@
/*
* 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.
*/
.text
.align 4
.type _start, @function
@ -21,3 +49,4 @@ _start:
__CTOR_LIST__:
.long -1

180
linker/ba.c Normal file
View File

@ -0,0 +1,180 @@
/*
* 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"
struct ba_bits {
unsigned allocated:1; /* 1 if allocated, 0 if free */
unsigned order:7; /* size of the region in ba space */
};
struct ba_info {
/* start address of the ba space */
unsigned long base;
/* total size of the ba space */
unsigned long size;
/* 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;
};
#undef min
#define min(a,b) ((a)<(b)?(a):(b))
#define BA_MIN_ALLOC LIBINC
#define BA_MAX_ORDER 128
#define BA_START LIBBASE
#define BA_SIZE (LIBLAST - LIBBASE)
#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 struct ba_bits ba_bitmap[BA_SIZE / BA_MIN_ALLOC];
static struct ba_info ba = {
.base = BA_START,
.size = BA_SIZE,
.bitmap = ba_bitmap,
.num_entries = sizeof(ba_bitmap)/sizeof(ba_bitmap[0]),
};
void ba_init(void)
{
int i, index = 0;
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(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(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(unsigned long len)
{
int curr = 0;
int end = ba.num_entries;
int best_fit = -1;
unsigned long order = ba_order(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(int index)
{
return BA_START_ADDR(index);
}
unsigned long ba_len(int index)
{
return BA_LEN(index);
}

View File

@ -25,19 +25,14 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SYS_SHM_H
#define _SYS_SHM_H
#include <sys/ipc.h>
#include <linux/shm.h>
#ifndef __LINKER_BA_H
#define __LINKER_BA_H
__BEGIN_DECLS
extern void ba_init(void);
extern int ba_allocate(unsigned long len);
extern int ba_free(int index);
extern unsigned long ba_start_addr(int index);
extern unsigned long ba_len(int index);
extern void* shmat(int shmid, const void* shmaddr, int shmflg);
extern int shmctl(int shmid, int cmd, struct shmid_ds* buf);
extern int shmdt(const void* shmaddr);
extern int shmget(key_t key, size_t size, int shmflg);
__END_DECLS
#endif /* _SYS_SHM_H */
#endif

View File

@ -1,3 +1,31 @@
/*
* 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>
@ -21,7 +49,7 @@ void debugger_signal_handler(int n)
signal(SIGUSR1, SIG_IGN);
tid = gettid();
s = socket_local_client("android:debuggerd",
s = socket_local_client("android:debuggerd",
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if(s >= 0) {
@ -49,4 +77,5 @@ void debugger_init()
signal(SIGFPE, debugger_signal_handler);
signal(SIGSEGV, debugger_signal_handler);
signal(SIGSTKFLT, debugger_signal_handler);
signal(SIGPIPE, debugger_signal_handler);
}

View File

@ -1,3 +1,31 @@
/*
* 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 <linux/auxvec.h>
#include <stdio.h>
@ -21,6 +49,8 @@
#include "linker.h"
#include "linker_debug.h"
#include "ba.h"
#define SO_MAX 64
/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
@ -82,7 +112,8 @@ extern void __attribute__((noinline)) rtld_db_dlactivity(void);
extern void sched_yield(void);
static struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity, RT_CONSISTENT, 0};
static struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
RT_CONSISTENT, 0};
static struct link_map *r_debug_tail = 0;
//static pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER;
@ -179,6 +210,7 @@ static soinfo *alloc_info(const char *name)
memset(si, 0, sizeof(soinfo));
strcpy((char*) si->name, name);
sonext->next = si;
si->ba_index = -1; /* by default, prelinked */
si->next = NULL;
si->refcount = 0;
sonext = si;
@ -450,8 +482,6 @@ static int open_library(const char *name)
return -1;
}
static unsigned libbase = LIBBASE;
/* temporary space for holding the first page of the shared lib
* which contains the elf header (with the pht). */
static unsigned char __header[PAGE_SIZE];
@ -597,64 +627,67 @@ get_lib_extents(int fd, const char *name, void *__hdr, unsigned *total_sz)
* segments into the correct locations within this memory range.
*
* Args:
* req_base: The requested base of the allocation. If 0, a sane one will be
* si->base: The requested base of the allocation. If 0, a sane one will be
* chosen in the range LIBBASE <= base < LIBLAST.
* sz: The size of the allocation.
* si->size: The size of the allocation.
*
* Returns:
* NULL on failure, and non-NULL pointer to memory region on success.
* -1 on failure, and 0 on success. On success, si->base will contain
* the virtual address at which the library will be mapped.
*/
static void *
alloc_mem_region(const char *name, unsigned req_base, unsigned sz)
static int reserve_mem_region(soinfo *si)
{
void *base;
void *base = mmap((void *)si->base, si->size, PROT_READ | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (base == MAP_FAILED) {
ERROR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x "
"as requested, will try general pool: %d (%s)\n",
pid, (si->base ? "" : "non-"), si->name, si->base,
errno, strerror(errno));
return -1;
} else if (base != (void *)si->base) {
ERROR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, "
"not at 0x%08x\n", pid, (si->base ? "" : "non-"),
si->name, (unsigned)base, si->base);
munmap(base, si->size);
return -1;
}
return 0;
}
if (req_base) {
/* we should probably map it as PROT_NONE, but the init code needs
* to read the phdr, so mark everything as readable. */
base = mmap((void *)req_base, sz, PROT_READ | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (base == MAP_FAILED) {
WARN("%5d can NOT map (prelinked) library '%s' at 0x%08x "
"as requested, will try general pool: %d (%s)\n",
pid, name, req_base, errno, strerror(errno));
} else if (base != (void *)req_base) {
ERROR("OOPS: %5d prelinked library '%s' mapped at 0x%08x, "
"not at 0x%08x\n", pid, name, (unsigned)base, req_base);
munmap(base, sz);
return NULL;
}
/* Here we know that we got a valid allocation. Hooray! */
return base;
static int
alloc_mem_region(soinfo *si)
{
if (si->base) {
/* Attempt to mmap a prelinked library. */
si->ba_index = -1;
return reserve_mem_region(si);
}
/* We either did not request a specific base address to map at
* (i.e. not-prelinked) OR we could not map at the requested address.
* Try to find a memory range in our "reserved" area that can be mapped.
*/
while(libbase < LIBLAST) {
base = mmap((void*) libbase, sz, PROT_READ | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(((unsigned)base) == libbase) {
/* success -- got the address we wanted */
return base;
/* This is not a prelinked library, so we attempt to allocate space
for it from the buddy allocator, which manages the area between
LIBBASE and LIBLAST.
*/
si->ba_index = ba_allocate(si->size);
if(si->ba_index >= 0) {
si->base = ba_start_addr(si->ba_index);
PRINT("%5d mapping library '%s' at %08x (index %d) " \
"through buddy allocator.\n",
pid, si->name, si->base, si->ba_index);
if (reserve_mem_region(si) < 0) {
ba_free(si->ba_index);
si->ba_index = -1;
si->base = 0;
goto err;
}
/* If we got a different address than requested (rather than
* just a failure), we need to unmap the mismapped library
* before trying again
*/
if(base != MAP_FAILED)
munmap(base, sz);
libbase += LIBINC;
return 0;
}
err:
ERROR("OOPS: %5d cannot map library '%s'. no vspace available.\n",
pid, name);
return NULL;
pid, si->name);
return -1;
}
#define MAYBE_MAP_FLAG(x,from,to) (((x) & (from)) ? (to) : 0)
@ -884,8 +917,7 @@ load_library(const char *name)
int cnt;
unsigned ext_sz;
unsigned req_base;
void *base;
soinfo *si;
soinfo *si = NULL;
Elf32_Ehdr *hdr;
if(fd == -1)
@ -911,14 +943,6 @@ load_library(const char *name)
TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
(req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
/* Carve out a chunk of memory where we will map in the individual
* segments */
base = alloc_mem_region(name, req_base, ext_sz);
if (base == NULL)
goto fail;
TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
pid, name, base, (unsigned) ext_sz);
/* Now configure the soinfo struct where we'll store all of our data
* for the ELF object. If the loading fails, we waste the entry, but
* same thing would happen if we failed during linking. Configuring the
@ -928,19 +952,31 @@ load_library(const char *name)
if (si == NULL)
goto fail;
si->base = (unsigned)base;
/* Carve out a chunk of memory where we will map in the individual
* segments */
si->base = req_base;
si->size = ext_sz;
si->flags = 0;
si->entry = 0;
si->dynamic = (unsigned *)-1;
if (alloc_mem_region(si) < 0)
goto fail;
TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
pid, name, (void *)si->base, (unsigned) ext_sz);
/* Now actually load the library's segments into right places in memory */
if (load_segments(fd, &__header[0], si) < 0)
if (load_segments(fd, &__header[0], si) < 0) {
if (si->ba_index >= 0) {
ba_free(si->ba_index);
si->ba_index = -1;
}
goto fail;
}
/* this might not be right. Technically, we don't even need this info
* once we go through 'load_segments'. */
hdr = (Elf32_Ehdr *)base;
hdr = (Elf32_Ehdr *)si->base;
si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
si->phnum = hdr->e_phnum;
/**/
@ -949,6 +985,7 @@ load_library(const char *name)
return si;
fail:
if (si) free_info(si);
close(fd);
return NULL;
}
@ -957,8 +994,6 @@ static soinfo *
init_library(soinfo *si)
{
unsigned wr_offset = 0xffffffff;
unsigned libbase_before = 0;
unsigned libbase_after = 0;
/* At this point we know that whatever is loaded @ base is a valid ELF
* shared library whose segments are properly mapped in. */
@ -968,24 +1003,10 @@ init_library(soinfo *si)
if (si->base < LIBBASE || si->base >= LIBLAST)
si->flags |= FLAG_PRELINKED;
/* Adjust libbase for the size of this library, rounded up to
** LIBINC alignment. Make note of the previous and current
** value of libbase to allow us to roll back in the event of
** a link failure.
*/
if (!(si->flags & FLAG_PRELINKED)) {
libbase_before = libbase;
libbase += (si->size + (LIBINC - 1)) & (~(LIBINC - 1));
libbase_after = libbase;
}
if(link_image(si, wr_offset)) {
/* We failed to link. However, we can only restore libbase
** if no additional libraries have moved it since we updated it.
*/
if(!(si->flags & FLAG_PRELINKED) && (libbase == libbase_after)) {
libbase = libbase_before;
}
munmap((void *)si->base, si->size);
return NULL;
}
@ -1039,6 +1060,12 @@ unsigned unload_library(soinfo *si)
}
munmap((char *)si->base, si->size);
if (si->ba_index >= 0) {
PRINT("%5d releasing library '%s' address space at %08x "\
"through buddy allocator.\n",
pid, si->name, si->base);
ba_free(si->ba_index);
}
free_info(si);
si->refcount = 0;
}
@ -1105,13 +1132,25 @@ static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
switch(type){
#if defined(ANDROID_ARM_LINKER)
case R_ARM_JUMP_SLOT:
COUNT_RELOC(RELOC_ABSOLUTE);
MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr;
break;
case R_ARM_GLOB_DAT:
COUNT_RELOC(RELOC_ABSOLUTE);
MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr;
break;
case R_ARM_ABS32:
COUNT_RELOC(RELOC_ABSOLUTE);
MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid,
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr;
*((unsigned*)reloc) += sym_addr;
break;
#elif defined(ANDROID_X86_LINKER)
case R_386_JUMP_SLOT:
@ -1563,13 +1602,13 @@ static int link_image(soinfo *si, unsigned wr_offset)
}
#endif
/* If this is a SETUID programme, dup /dev/null to openned stdin,
/* If this is a SET?ID program, dup /dev/null to opened stdin,
stdout and stderr to close a security hole described in:
ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
*/
if (getuid() != geteuid())
if (getuid() != geteuid() || getgid() != getegid())
nullify_closed_stdio ();
call_constructors(si);
notify_gdb_of_load(si);
@ -1668,6 +1707,8 @@ unsigned __linker_init(unsigned **elfdata)
vecs += 2;
}
ba_init();
si->base = 0;
si->dynamic = (unsigned *)-1;
si->wrprotect_start = 0xffffffff;

View File

@ -1,3 +1,31 @@
/*
* 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_
@ -67,6 +95,8 @@ struct soinfo
unsigned entry;
unsigned base;
unsigned size;
// buddy-allocator index, negative for prelinked libraries
int ba_index;
unsigned *dynamic;

View File

@ -1,3 +1,31 @@
/*
* 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_DEBUG_H_
#define _LINKER_DEBUG_H_
@ -7,8 +35,8 @@
* this on when submitting back to repository */
#define LINKER_DEBUG 0
#define TRACE_DEBUG 0
#define DO_TRACE_LOOKUP 1
#define DO_TRACE_RELO 1
#define DO_TRACE_LOOKUP 0
#define DO_TRACE_RELO 0
#define TIMING 0
#define STATS 0
#define COUNT_PAGES 0

View File

@ -1,3 +1,31 @@
/*
* 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.