am 01271b18: Merge "Make dynamic linker debugging always available."

* commit '01271b1812f2cec8aaf3c105b9f960f027b33a95':
  Make dynamic linker debugging always available.
This commit is contained in:
Elliott Hughes 2012-11-02 13:55:59 -07:00 committed by Android Git Automerger
commit cfb47daf4e
7 changed files with 80 additions and 166 deletions

View File

@ -18,10 +18,6 @@ LOCAL_CFLAGS += -fno-stack-protector \
-fvisibility=hidden \ -fvisibility=hidden \
-Wall -Wextra -Wall -Wextra
# Set LINKER_DEBUG to either 1 or 0
#
LOCAL_CFLAGS += -DLINKER_DEBUG=0
# We need to access Bionic private headers in the linker... # We need to access Bionic private headers in the linker...
LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/ LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/

View File

@ -79,24 +79,6 @@ are in charge of calling them explicitly.
Debugging: Debugging:
---------- ----------
It is possible to enable debug output in the dynamic linker. To do so,
follow these steps:
1/ Modify the line in Android.mk that says:
LOCAL_CFLAGS += -DLINKER_DEBUG=0
Into the following:
LOCAL_CFLAGS += -DLINKER_DEBUG=1
2/ Force-rebuild the dynamic linker:
cd bionic/linker
mm -B
3/ Rebuild a new system image.
You can increase the verbosity of debug traces by defining the DEBUG You can increase the verbosity of debug traces by defining the DEBUG
environment variable to a numeric value from 0 to 2. This will only environment variable to a numeric value from 0 to 2. This will only
affect new processes being launched. affect new processes being launched.

View File

@ -136,8 +136,9 @@ static void logSignalSummary(int signum, const siginfo_t* info) {
// "info" will be NULL if the siginfo_t information was not available. // "info" will be NULL if the siginfo_t information was not available.
if (info != NULL) { if (info != NULL) {
format_buffer(buffer, sizeof(buffer), format_buffer(buffer, sizeof(buffer),
"Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)", "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)",
signum, signame, info->si_addr, info->si_code, gettid(), threadname); signum, signame, reinterpret_cast<uintptr_t>(info->si_addr),
info->si_code, gettid(), threadname);
} else { } else {
format_buffer(buffer, sizeof(buffer), format_buffer(buffer, sizeof(buffer),
"Fatal signal %d (%s), thread %d (%s)", "Fatal signal %d (%s), thread %d (%s)",

View File

@ -104,11 +104,7 @@ static const char* gLdPreloadNames[LDPRELOAD_MAX + 1];
static soinfo *preloads[LDPRELOAD_MAX + 1]; static soinfo *preloads[LDPRELOAD_MAX + 1];
#if LINKER_DEBUG static int debug_verbosity;
int debug_verbosity;
#endif
static int pid;
enum RelocationKind { enum RelocationKind {
kRelocAbsolute = 0, kRelocAbsolute = 0,
@ -320,7 +316,7 @@ static soinfo* soinfo_alloc(const char* name) {
sonext->next = si; sonext->next = si;
sonext = si; sonext = si;
TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si); TRACE("name %s: allocated soinfo @ %p\n", name, si);
return si; return si;
} }
@ -332,7 +328,7 @@ static void soinfo_free(soinfo* si)
soinfo *prev = NULL, *trav; soinfo *prev = NULL, *trav;
TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si); TRACE("name %s: freeing soinfo @ %p\n", si->name, si);
for(trav = solist; trav != NULL; trav = trav->next){ for(trav = solist; trav != NULL; trav = trav->next){
if (trav == si) if (trav == si)
@ -412,7 +408,7 @@ static Elf32_Sym *soinfo_elf_lookup(soinfo *si, unsigned hash, const char *name)
const char *strtab = si->strtab; const char *strtab = si->strtab;
unsigned n; unsigned n;
TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid, TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %d\n",
name, si->name, si->base, hash, hash % si->nbucket); name, si->name, si->base, hash, hash % si->nbucket);
n = hash % si->nbucket; n = hash % si->nbucket;
@ -427,7 +423,7 @@ static Elf32_Sym *soinfo_elf_lookup(soinfo *si, unsigned hash, const char *name)
if(s->st_shndx == SHN_UNDEF) if(s->st_shndx == SHN_UNDEF)
continue; continue;
TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid, TRACE_TYPE(LOOKUP, "FOUND %s in %s (%08x) %d\n",
name, si->name, s->st_value, s->st_size); name, si->name, s->st_value, s->st_size);
return s; return s;
} }
@ -481,8 +477,8 @@ soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
*/ */
if (!si->has_DT_SYMBOLIC) { if (!si->has_DT_SYMBOLIC) {
DEBUG("%5d %s: looking up %s in executable %s\n", DEBUG("%s: looking up %s in executable %s\n",
pid, si->name, name, somain->name); si->name, name, somain->name);
s = soinfo_elf_lookup(somain, elf_hash, name); s = soinfo_elf_lookup(somain, elf_hash, name);
if (s != NULL) { if (s != NULL) {
*lsi = somain; *lsi = somain;
@ -512,8 +508,8 @@ soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
*/ */
if (si->has_DT_SYMBOLIC) { if (si->has_DT_SYMBOLIC) {
DEBUG("%5d %s: looking up %s in executable %s after local scope\n", DEBUG("%s: looking up %s in executable %s after local scope\n",
pid, si->name, name, somain->name); si->name, name, somain->name);
s = soinfo_elf_lookup(somain, elf_hash, name); s = soinfo_elf_lookup(somain, elf_hash, name);
if (s != NULL) { if (s != NULL) {
*lsi = somain; *lsi = somain;
@ -533,8 +529,8 @@ soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
} }
for(i = 0; needed[i] != NULL; i++) { for(i = 0; needed[i] != NULL; i++) {
DEBUG("%5d %s: looking up %s in %s\n", DEBUG("%s: looking up %s in %s\n",
pid, si->name, name, needed[i]->name); si->name, name, needed[i]->name);
s = soinfo_elf_lookup(needed[i], elf_hash, name); s = soinfo_elf_lookup(needed[i], elf_hash, name);
if (s != NULL) { if (s != NULL) {
*lsi = needed[i]; *lsi = needed[i];
@ -544,9 +540,9 @@ soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
done: done:
if(s != NULL) { if(s != NULL) {
TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, " TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = 0x%08x, "
"found in %s, base = 0x%08x, load bias = 0x%08x\n", "found in %s, base = 0x%08x, load bias = 0x%08x\n",
pid, si->name, name, s->st_value, si->name, name, s->st_value,
(*lsi)->name, (*lsi)->base, (*lsi)->load_bias); (*lsi)->name, (*lsi)->base, (*lsi)->load_bias);
return s; return s;
} }
@ -586,8 +582,8 @@ Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
} }
if(s != NULL) { if(s != NULL) {
TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, " TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, si->base = 0x%08x\n",
"si->base = 0x%08x\n", pid, name, s->st_value, si->base); name, s->st_value, si->base);
return s; return s;
} }
@ -635,7 +631,7 @@ static void dump(soinfo *si)
unsigned n; unsigned n;
for(n = 0; n < si->nchain; n++) { for(n = 0; n < si->nchain; n++) {
TRACE("%5d %04d> %08x: %02x %04x %08x %08x %s\n", pid, n, s, TRACE("%04d> %08x: %02x %04x %08x %08x %s\n", n, s,
s->st_info, s->st_shndx, s->st_value, s->st_size, s->st_info, s->st_shndx, s->st_value, s->st_size,
si->strtab + s->st_name); si->strtab + s->st_name);
s++; s++;
@ -660,7 +656,7 @@ static int open_library_on_path(const char* name, const char* const paths[]) {
} }
static int open_library(const char* name) { static int open_library(const char* name) {
TRACE("[ %5d opening %s ]\n", pid, name); TRACE("[ opening %s ]\n", name);
// If the name contains a slash, we should attempt to open it directly and not search the paths. // If the name contains a slash, we should attempt to open it directly and not search the paths.
if (strchr(name, '/') != NULL) { if (strchr(name, '/') != NULL) {
@ -697,7 +693,7 @@ static bool is_prelinked(int fd, const char* name)
prelink_info_t info; prelink_info_t info;
int rc = TEMP_FAILURE_RETRY(read(fd, &info, sizeof(info))); int rc = TEMP_FAILURE_RETRY(read(fd, &info, sizeof(info)));
if (rc != sizeof(info)) { if (rc != sizeof(info)) {
DL_ERR("could not read prelink_info_t structure for \"%s\":", name, strerror(errno)); DL_ERR("could not read prelink_info_t structure for \"%s\": %s", name, strerror(errno));
return true; return true;
} }
@ -812,7 +808,7 @@ static soinfo* load_library(const char* name) {
// Get the load extents. // Get the load extents.
Elf32_Addr ext_sz = phdr_table_get_load_size(phdr_table, phdr_count); Elf32_Addr ext_sz = phdr_table_get_load_size(phdr_table, phdr_count);
TRACE("[ %5d - '%s' wants sz=0x%08x ]\n", pid, name, ext_sz); TRACE("[ '%s' wants sz=0x%08x ]\n", name, ext_sz);
if (ext_sz == 0) { if (ext_sz == 0) {
DL_ERR("no loadable segments in file: %s", name); DL_ERR("no loadable segments in file: %s", name);
return NULL; return NULL;
@ -838,8 +834,7 @@ static soinfo* load_library(const char* name) {
return NULL; return NULL;
} }
TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n", TRACE("[ allocated memory for %s @ %p (0x%08x) ]\n", name, load_start, load_size);
pid, name, load_start, load_size);
/* Map all the segments in our address space with default protections */ /* Map all the segments in our address space with default protections */
ret = phdr_table_load_segments(phdr_table, ret = phdr_table_load_segments(phdr_table,
@ -876,8 +871,8 @@ static soinfo* load_library(const char* name) {
static soinfo* init_library(soinfo* si) { static soinfo* init_library(soinfo* si) {
// At this point we know that whatever is loaded @ base is a valid ELF // At this point we know that whatever is loaded @ base is a valid ELF
// shared library whose segments are properly mapped in. // shared library whose segments are properly mapped in.
TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n", TRACE("[ init_library base=0x%08x sz=0x%08x name='%s') ]\n",
pid, si->base, si->size, si->name); si->base, si->size, si->name);
if (!soinfo_link_image(si)) { if (!soinfo_link_image(si)) {
munmap((void *)si->base, si->size); munmap((void *)si->base, si->size);
@ -924,7 +919,7 @@ static soinfo* find_library_internal(const char* name) {
return NULL; return NULL;
} }
TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name); TRACE("[ '%s' has not been loaded yet. Locating...]\n", name);
si = load_library(name); si = load_library(name);
if (si != NULL) { if (si != NULL) {
si = init_library(si); si = init_library(si);
@ -943,14 +938,14 @@ static soinfo* find_library(const char* name) {
static int soinfo_unload(soinfo* si) { static int soinfo_unload(soinfo* si) {
if (si->refcount == 1) { if (si->refcount == 1) {
TRACE("%5d unloading '%s'\n", pid, si->name); TRACE("unloading '%s'\n", si->name);
si->CallDestructors(); si->CallDestructors();
for (unsigned* d = si->dynamic; *d; d += 2) { for (unsigned* d = si->dynamic; *d; d += 2) {
if (d[0] == DT_NEEDED) { if (d[0] == DT_NEEDED) {
soinfo* lsi = find_loaded_library(si->strtab + d[1]); soinfo* lsi = find_loaded_library(si->strtab + d[1]);
if (lsi != NULL) { if (lsi != NULL) {
TRACE("%5d %s needs to unload %s\n", pid, si->name, lsi->name); TRACE("%s needs to unload %s\n", si->name, lsi->name);
soinfo_unload(lsi); soinfo_unload(lsi);
} else { } else {
// TODO: should we return -1 in this case? // TODO: should we return -1 in this case?
@ -965,8 +960,7 @@ static int soinfo_unload(soinfo* si) {
si->refcount = 0; si->refcount = 0;
} else { } else {
si->refcount--; si->refcount--;
PRINT("%5d not unloading '%s', decrementing refcount to %d\n", PRINT("not unloading '%s', decrementing refcount to %d\n", si->name, si->refcount);
pid, si->name, si->refcount);
} }
return 0; return 0;
} }
@ -1008,8 +1002,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
unsigned sym_addr = 0; unsigned sym_addr = 0;
char *sym_name = NULL; char *sym_name = NULL;
DEBUG("%5d Processing '%s' relocation at index %d\n", pid, DEBUG("Processing '%s' relocation at index %d\n", si->name, idx);
si->name, idx);
if (type == 0) { // R_*_NONE if (type == 0) { // R_*_NONE
continue; continue;
} }
@ -1096,28 +1089,25 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
case R_ARM_JUMP_SLOT: case R_ARM_JUMP_SLOT:
count_relocation(kRelocAbsolute); count_relocation(kRelocAbsolute);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s\n", reloc, sym_addr, sym_name);
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr; *((unsigned*)reloc) = sym_addr;
break; break;
case R_ARM_GLOB_DAT: case R_ARM_GLOB_DAT:
count_relocation(kRelocAbsolute); count_relocation(kRelocAbsolute);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s\n", reloc, sym_addr, sym_name);
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr; *((unsigned*)reloc) = sym_addr;
break; break;
case R_ARM_ABS32: case R_ARM_ABS32:
count_relocation(kRelocAbsolute); count_relocation(kRelocAbsolute);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid, TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s\n", reloc, sym_addr, sym_name);
reloc, sym_addr, sym_name);
*((unsigned*)reloc) += sym_addr; *((unsigned*)reloc) += sym_addr;
break; break;
case R_ARM_REL32: case R_ARM_REL32:
count_relocation(kRelocRelative); count_relocation(kRelocRelative);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO REL32 %08x <- %08x - %08x %s\n", pid, TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s\n",
reloc, sym_addr, rel->r_offset, sym_name); reloc, sym_addr, rel->r_offset, sym_name);
*((unsigned*)reloc) += sym_addr - rel->r_offset; *((unsigned*)reloc) += sym_addr - rel->r_offset;
break; break;
@ -1125,29 +1115,26 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
case R_386_JMP_SLOT: case R_386_JMP_SLOT:
count_relocation(kRelocAbsolute); count_relocation(kRelocAbsolute);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s\n", reloc, sym_addr, sym_name);
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr; *((unsigned*)reloc) = sym_addr;
break; break;
case R_386_GLOB_DAT: case R_386_GLOB_DAT:
count_relocation(kRelocAbsolute); count_relocation(kRelocAbsolute);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s\n", reloc, sym_addr, sym_name);
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr; *((unsigned*)reloc) = sym_addr;
break; break;
#elif defined(ANDROID_MIPS_LINKER) #elif defined(ANDROID_MIPS_LINKER)
case R_MIPS_JUMP_SLOT: case R_MIPS_JUMP_SLOT:
count_relocation(kRelocAbsolute); count_relocation(kRelocAbsolute);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s\n", reloc, sym_addr, sym_name);
reloc, sym_addr, sym_name);
*((unsigned*)reloc) = sym_addr; *((unsigned*)reloc) = sym_addr;
break; break;
case R_MIPS_REL32: case R_MIPS_REL32:
count_relocation(kRelocAbsolute); count_relocation(kRelocAbsolute);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO REL32 %08x <- %08x %s\n", pid, TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x %s\n",
reloc, sym_addr, (sym_name) ? sym_name : "*SECTIONHDR*"); reloc, sym_addr, (sym_name) ? sym_name : "*SECTIONHDR*");
if (s) { if (s) {
*((unsigned*)reloc) += sym_addr; *((unsigned*)reloc) += sym_addr;
@ -1165,11 +1152,10 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
count_relocation(kRelocRelative); count_relocation(kRelocRelative);
MARK(rel->r_offset); MARK(rel->r_offset);
if (sym) { if (sym) {
DL_ERR("odd RELATIVE form...", pid); DL_ERR("odd RELATIVE form...");
return -1; return -1;
} }
TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid, TRACE_TYPE(RELO, "RELO RELATIVE %08x <- +%08x\n", reloc, si->base);
reloc, si->base);
*((unsigned*)reloc) += si->base; *((unsigned*)reloc) += si->base;
break; break;
@ -1178,17 +1164,15 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
count_relocation(kRelocRelative); count_relocation(kRelocRelative);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO R_386_32 %08x <- +%08x %s\n", pid, TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s\n", reloc, sym_addr, sym_name);
reloc, sym_addr, sym_name);
*((unsigned *)reloc) += (unsigned)sym_addr; *((unsigned *)reloc) += (unsigned)sym_addr;
break; break;
case R_386_PC32: case R_386_PC32:
count_relocation(kRelocRelative); count_relocation(kRelocRelative);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO R_386_PC32 %08x <- " TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s\n",
"+%08x (%08x - %08x) %s\n", pid, reloc, reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
(sym_addr - reloc), sym_addr, reloc, sym_name);
*((unsigned *)reloc) += (unsigned)(sym_addr - reloc); *((unsigned *)reloc) += (unsigned)(sym_addr - reloc);
break; break;
#endif /* ANDROID_X86_LINKER */ #endif /* ANDROID_X86_LINKER */
@ -1212,8 +1196,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
} }
count_relocation(kRelocCopy); count_relocation(kRelocCopy);
MARK(rel->r_offset); MARK(rel->r_offset);
TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid, TRACE_TYPE(RELO, "RELO %08x <- %d @ %08x %s\n", reloc, s->st_size, sym_addr, sym_name);
reloc, s->st_size, sym_addr, sym_name);
if (reloc == sym_addr) { if (reloc == sym_addr) {
Elf32_Sym *src = soinfo_do_lookup(NULL, sym_name, &lsi, needed); Elf32_Sym *src = soinfo_do_lookup(NULL, sym_name, &lsi, needed);
@ -1342,20 +1325,20 @@ void soinfo::CallArray(const char* array_name UNUSED, unsigned* array, int count
step = -1; step = -1;
} }
TRACE("[ %5d Calling %s @ %p [%d] for '%s' ]\n", pid, array_name, array, count, name); TRACE("[ Calling %s @ %p [%d] for '%s' ]\n", array_name, array, count, name);
for (int n = count; n > 0; n--) { for (int n = count; n > 0; n--) {
TRACE("[ %5d Looking at %s[%d] *%p == 0x%08x ]\n", pid, array_name, n, array, *array); TRACE("[ Looking at %s[%d] *%p == 0x%08x ]\n", array_name, n, array, *array);
void (*func)() = (void (*)()) *array; void (*func)() = (void (*)()) *array;
array += step; array += step;
if (((int) func == 0) || ((int) func == -1)) { if (((int) func == 0) || ((int) func == -1)) {
continue; continue;
} }
TRACE("[ %5d Calling func @ %p ]\n", pid, func); TRACE("[ Calling func @ %p ]\n", func);
func(); func();
} }
TRACE("[ %5d Done calling %s for '%s' ]\n", pid, array_name, name); TRACE("[ Done calling %s for '%s' ]\n", array_name, name);
} }
void soinfo::CallFunction(const char* function_name UNUSED, void (*function)()) { void soinfo::CallFunction(const char* function_name UNUSED, void (*function)()) {
@ -1363,9 +1346,9 @@ void soinfo::CallFunction(const char* function_name UNUSED, void (*function)())
return; return;
} }
TRACE("[ %5d Calling %s @ %p for '%s' ]\n", pid, function_name, function, name); TRACE("[ Calling %s @ %p for '%s' ]\n", function_name, function, name);
function(); function();
TRACE("[ %5d Done calling %s for '%s' ]\n", pid, function_name, name); TRACE("[ Done calling %s for '%s' ]\n", function_name, name);
} }
void soinfo::CallPreInitConstructors() { void soinfo::CallPreInitConstructors() {
@ -1427,7 +1410,7 @@ static int nullify_closed_stdio() {
DL_ERR("cannot open /dev/null: %s", strerror(errno)); DL_ERR("cannot open /dev/null: %s", strerror(errno));
return -1; return -1;
} }
TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null); TRACE("[ Opened /dev/null file-descriptor=%d]\n", dev_null);
/* If any of the stdio file descriptors is valid and not associated /* If any of the stdio file descriptors is valid and not associated
with /dev/null, dup /dev/null to it. */ with /dev/null, dup /dev/null to it. */
@ -1437,7 +1420,7 @@ static int nullify_closed_stdio() {
continue; continue;
} }
TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i); TRACE("[ Nullifying stdio file descriptor %d]\n", i);
status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL)); status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
/* If file is opened, we are good. */ /* If file is opened, we are good. */
@ -1466,7 +1449,7 @@ static int nullify_closed_stdio() {
/* If /dev/null is not one of the stdio file descriptors, close it. */ /* If /dev/null is not one of the stdio file descriptors, close it. */
if (dev_null > 2) { if (dev_null > 2) {
TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null); TRACE("[ Closing /dev/null file-descriptor=%d]\n", dev_null);
status = TEMP_FAILURE_RETRY(close(dev_null)); status = TEMP_FAILURE_RETRY(close(dev_null));
if (status == -1) { if (status == -1) {
DL_ERR("close failed: %s", strerror(errno)); DL_ERR("close failed: %s", strerror(errno));
@ -1489,9 +1472,8 @@ static bool soinfo_link_image(soinfo* si) {
/* We can't debug anything until the linker is relocated */ /* We can't debug anything until the linker is relocated */
if (!relocating_linker) { if (!relocating_linker) {
INFO("[ %5d linking %s ]\n", pid, si->name); INFO("[ linking %s ]\n", si->name);
DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid, DEBUG("si->base = 0x%08x si->flags = 0x%08x\n", si->base, si->flags);
si->base, si->flags);
} }
/* Extract dynamic section */ /* Extract dynamic section */
@ -1505,7 +1487,7 @@ static bool soinfo_link_image(soinfo* si) {
return false; return false;
} else { } else {
if (!relocating_linker) { if (!relocating_linker) {
DEBUG("%5d dynamic = %p\n", pid, si->dynamic); DEBUG("dynamic = %p\n", si->dynamic);
} }
} }
@ -1516,7 +1498,7 @@ static bool soinfo_link_image(soinfo* si) {
/* extract useful information from dynamic section */ /* extract useful information from dynamic section */
for (unsigned* d = si->dynamic; *d; ++d) { for (unsigned* d = si->dynamic; *d; ++d) {
DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]); DEBUG("d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", d, d[0], d[1]);
switch(*d++){ switch(*d++){
case DT_HASH: case DT_HASH:
si->nbucket = ((unsigned *) (base + *d))[0]; si->nbucket = ((unsigned *) (base + *d))[0];
@ -1563,34 +1545,29 @@ static bool soinfo_link_image(soinfo* si) {
return false; return false;
case DT_INIT: case DT_INIT:
si->init_func = (void (*)(void))(base + *d); si->init_func = (void (*)(void))(base + *d);
DEBUG("%5d %s constructors (init func) found at %p\n", DEBUG("%s constructors (init func) found at %p\n", si->name, si->init_func);
pid, si->name, si->init_func);
break; break;
case DT_FINI: case DT_FINI:
si->fini_func = (void (*)(void))(base + *d); si->fini_func = (void (*)(void))(base + *d);
DEBUG("%5d %s destructors (fini func) found at %p\n", DEBUG("%s destructors (fini func) found at %p\n", si->name, si->fini_func);
pid, si->name, si->fini_func);
break; break;
case DT_INIT_ARRAY: case DT_INIT_ARRAY:
si->init_array = (unsigned *)(base + *d); si->init_array = (unsigned *)(base + *d);
DEBUG("%5d %s constructors (init_array) found at %p\n", DEBUG("%s constructors (init_array) found at %p\n", si->name, si->init_array);
pid, si->name, si->init_array);
break; break;
case DT_INIT_ARRAYSZ: case DT_INIT_ARRAYSZ:
si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
break; break;
case DT_FINI_ARRAY: case DT_FINI_ARRAY:
si->fini_array = (unsigned *)(base + *d); si->fini_array = (unsigned *)(base + *d);
DEBUG("%5d %s destructors (fini_array) found at %p\n", DEBUG("%s destructors (fini_array) found at %p\n", si->name, si->fini_array);
pid, si->name, si->fini_array);
break; break;
case DT_FINI_ARRAYSZ: case DT_FINI_ARRAYSZ:
si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
break; break;
case DT_PREINIT_ARRAY: case DT_PREINIT_ARRAY:
si->preinit_array = (unsigned *)(base + *d); si->preinit_array = (unsigned *)(base + *d);
DEBUG("%5d %s constructors (preinit_array) found at %p\n", DEBUG("%s constructors (preinit_array) found at %p\n", si->name, si->preinit_array);
pid, si->name, si->preinit_array);
break; break;
case DT_PREINIT_ARRAYSZ: case DT_PREINIT_ARRAYSZ:
si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
@ -1651,15 +1628,14 @@ static bool soinfo_link_image(soinfo* si) {
break; break;
default: default:
DEBUG("%5d Unused DT entry: type 0x%08x arg 0x%08x\n", DEBUG("Unused DT entry: type 0x%08x arg 0x%08x\n", d[-1], d[0]);
pid, d[-1], d[0]);
break; break;
#endif #endif
} }
} }
DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n", DEBUG("si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
pid, si->base, si->strtab, si->symtab); si->base, si->strtab, si->symtab);
// Sanity checks. // Sanity checks.
if (si->nbucket == 0) { if (si->nbucket == 0) {
@ -1695,7 +1671,7 @@ static bool soinfo_link_image(soinfo* si) {
for (unsigned* d = si->dynamic; *d; d += 2) { for (unsigned* d = si->dynamic; *d; d += 2) {
if (d[0] == DT_NEEDED) { if (d[0] == DT_NEEDED) {
DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]); DEBUG("%s needs %s\n", si->name, si->strtab + d[1]);
soinfo* lsi = find_library(si->strtab + d[1]); soinfo* lsi = find_library(si->strtab + d[1]);
if (lsi == NULL) { if (lsi == NULL) {
strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
@ -1722,13 +1698,13 @@ static bool soinfo_link_image(soinfo* si) {
} }
if (si->plt_rel) { if (si->plt_rel) {
DEBUG("[ %5d relocating %s plt ]\n", pid, si->name ); DEBUG("[ relocating %s plt ]\n", si->name );
if(soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) { if(soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) {
return false; return false;
} }
} }
if (si->rel) { if (si->rel) {
DEBUG("[ %5d relocating %s ]\n", pid, si->name ); DEBUG("[ relocating %s ]\n", si->name );
if(soinfo_relocate(si, si->rel, si->rel_count, needed)) { if(soinfo_relocate(si, si->rel, si->rel_count, needed)) {
return false; return false;
} }
@ -1741,7 +1717,7 @@ static bool soinfo_link_image(soinfo* si) {
#endif #endif
si->flags |= FLAG_LINKED; si->flags |= FLAG_LINKED;
DEBUG("[ %5d finished linking %s ]\n", pid, si->name); DEBUG("[ finished linking %s ]\n", si->name);
if (si->has_text_relocations) { if (si->has_text_relocations) {
/* All relocations are done, we can protect our segments back to /* All relocations are done, we can protect our segments back to
@ -1830,8 +1806,6 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
*/ */
__libc_init_tls(elfdata); __libc_init_tls(elfdata);
pid = getpid();
#if TIMING #if TIMING
struct timeval t0, t1; struct timeval t0, t1;
gettimeofday(&t0, 0); gettimeofday(&t0, 0);
@ -1843,14 +1817,10 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
debugger_init(); debugger_init();
// Get a few environment variables. // Get a few environment variables.
#if LINKER_DEBUG const char* LD_DEBUG = linker_env_get("LD_DEBUG");
{ if (LD_DEBUG != NULL) {
const char* env = linker_env_get("LD_DEBUG"); debug_verbosity = atoi(LD_DEBUG);
if (env != NULL) {
debug_verbosity = atoi(env);
}
} }
#endif
// Normally, these are cleaned by linker_env_init, but the test // Normally, these are cleaned by linker_env_init, but the test
// doesn't cost us anything. // doesn't cost us anything.
@ -1862,7 +1832,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
} }
INFO("[ android linker & debugger ]\n"); INFO("[ android linker & debugger ]\n");
DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata); DEBUG("elfdata @ 0x%08x\n", (unsigned)elfdata);
soinfo* si = soinfo_alloc(argv[0]); soinfo* si = soinfo_alloc(argv[0]);
if (si == NULL) { if (si == NULL) {
@ -2001,8 +1971,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
fflush(stdout); fflush(stdout);
#endif #endif
TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name, TRACE("[ Ready to execute '%s' @ 0x%08x ]\n", si->name, si->entry);
si->entry);
return si->entry; return si->entry;
} }

View File

@ -31,10 +31,6 @@
#include <stdio.h> #include <stdio.h>
#ifndef LINKER_DEBUG
#error LINKER_DEBUG should be defined to either 1 or 0 in Android.mk
#endif
/* set LINKER_DEBUG_TO_LOG to 1 to send the logs to logcat, /* set LINKER_DEBUG_TO_LOG to 1 to send the logs to logcat,
* or 0 to use stdout instead. * or 0 to use stdout instead.
*/ */
@ -56,39 +52,27 @@
/*********************************************************************/ /*********************************************************************/
/* Only use printf() during debugging. We have seen occasional memory
* corruption when the linker uses printf().
*/
#if LINKER_DEBUG
#include "linker_format.h" #include "linker_format.h"
extern int debug_verbosity;
#if LINKER_DEBUG_TO_LOG #if LINKER_DEBUG_TO_LOG
extern int format_log(int, const char *, const char *, ...); extern int format_log(int, const char*, const char*, ...) __attribute__((__format__(printf, 3, 4)));
#define _PRINTVF(v,x...) \ #define _PRINTVF(v,x...) \
do { \ do { \
if (debug_verbosity > (v)) format_log(5-(v),"linker",x); \ if (debug_verbosity > (v)) format_log(5-(v),"linker",x); \
} while (0) } while (0)
#else /* !LINKER_DEBUG_TO_LOG */ #else /* !LINKER_DEBUG_TO_LOG */
extern int format_fd(int, const char *, ...); extern int format_fd(int, const char *, ...) __attribute__((__format__(printf, 2, 3)));
#define _PRINTVF(v,x...) \ #define _PRINTVF(v,x...) \
do { \ do { \
if (debug_verbosity > (v)) format_fd(1, x); \ if (debug_verbosity > (v)) format_fd(1, x); \
} while (0) } while (0)
#endif /* !LINKER_DEBUG_TO_LOG */ #endif /* !LINKER_DEBUG_TO_LOG */
#else /* !LINKER_DEBUG */
#define _PRINTVF(v,f,x...) do {} while(0)
#endif /* LINKER_DEBUG */
#define PRINT(x...) _PRINTVF(-1, x) #define PRINT(x...) _PRINTVF(-1, x)
#define INFO(x...) _PRINTVF(0, x) #define INFO(x...) _PRINTVF(0, x)
#define TRACE(x...) _PRINTVF(1, x) #define TRACE(x...) _PRINTVF(1, x)
#define WARN(fmt,args...) \ #define WARN(fmt,args...) _PRINTVF(-1, "%s:%d| WARNING: " fmt, __FILE__, __LINE__, ## args)
_PRINTVF(-1, "%s:%d| WARNING: " fmt, __FILE__, __LINE__, ## args) #define ERROR(fmt,args...) _PRINTVF(-1, "%s:%d| ERROR: " fmt, __FILE__, __LINE__, ## args)
#define ERROR(fmt,args...) \
_PRINTVF(-1, "%s:%d| ERROR: " fmt, __FILE__, __LINE__, ## args)
#if TRACE_DEBUG #if TRACE_DEBUG
#define DEBUG(x...) _PRINTVF(2, "DEBUG: " x) #define DEBUG(x...) _PRINTVF(2, "DEBUG: " x)
@ -96,26 +80,11 @@ extern int format_fd(int, const char *, ...);
#define DEBUG(x...) do {} while (0) #define DEBUG(x...) do {} while (0)
#endif /* TRACE_DEBUG */ #endif /* TRACE_DEBUG */
#if LINKER_DEBUG
#define TRACE_TYPE(t,x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0) #define TRACE_TYPE(t,x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0)
#else /* !LINKER_DEBUG */
#define TRACE_TYPE(t,x...) do {} while (0)
#endif /* LINKER_DEBUG */
#if TIMING #if TIMING
#undef WARN #undef WARN
#define WARN(x...) do {} while (0) #define WARN(x...) do {} while (0)
#endif /* TIMING */ #endif /* TIMING */
#define DEBUG_DUMP_PHDR(phdr, name, pid) do { \
DEBUG("%5d %s (phdr = 0x%08x)\n", (pid), (name), (unsigned)(phdr)); \
DEBUG("\t\tphdr->offset = 0x%08x\n", (unsigned)((phdr)->p_offset)); \
DEBUG("\t\tphdr->p_vaddr = 0x%08x\n", (unsigned)((phdr)->p_vaddr)); \
DEBUG("\t\tphdr->p_paddr = 0x%08x\n", (unsigned)((phdr)->p_paddr)); \
DEBUG("\t\tphdr->p_filesz = 0x%08x\n", (unsigned)((phdr)->p_filesz)); \
DEBUG("\t\tphdr->p_memsz = 0x%08x\n", (unsigned)((phdr)->p_memsz)); \
DEBUG("\t\tphdr->p_flags = 0x%08x\n", (unsigned)((phdr)->p_flags)); \
DEBUG("\t\tphdr->p_align = 0x%08x\n", (unsigned)((phdr)->p_align)); \
} while (0)
#endif /* _LINKER_DEBUG_H_ */ #endif /* _LINKER_DEBUG_H_ */

View File

@ -184,8 +184,6 @@ snprintf(char* buff, size_t bufsize, const char* format, ...)
return ret; return ret;
} }
#if LINKER_DEBUG
#if !LINKER_DEBUG_TO_LOG #if !LINKER_DEBUG_TO_LOG
/*** File descriptor output /*** File descriptor output
@ -326,8 +324,6 @@ format_log(int prio, const char *tag, const char *format, ...)
#endif /* LINKER_DEBUG_TO_LOG */ #endif /* LINKER_DEBUG_TO_LOG */
#endif /* LINKER_DEBUG */
/*** formatted output implementation /*** formatted output implementation
***/ ***/

View File

@ -36,6 +36,7 @@
// We want to avoid dragging the whole C library fprintf() // We want to avoid dragging the whole C library fprintf()
// implementation into the dynamic linker since this creates // implementation into the dynamic linker since this creates
// issues (it uses malloc()/free()) and increases code size. // issues (it uses malloc()/free()) and increases code size.
int format_buffer(char *buffer, size_t bufsize, const char *format, ...); int format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
__attribute__((__format__(printf, 3, 4)));
#endif /* _LINKER_FORMAT_H */ #endif /* _LINKER_FORMAT_H */