Fix site logfile flushing on startup; #if 0 doomed libbfd-based version of dladdr.

git-svn-id: svn://10.0.0.236/trunk@68025 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
brendan%mozilla.org 2000-05-03 03:07:20 +00:00
parent a81f90bc08
commit 72282ad97a
2 changed files with 274 additions and 38 deletions

View File

@ -32,13 +32,12 @@
* the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*/
#if defined NS_TRACE_MALLOC
#ifdef NS_TRACE_MALLOC
/*
* TODO:
* - #ifdef __linux__/x86 and port to other platforms
* - unify calltree with gc/boehm somehow (common utility libs)
* - provide NS_DumpTraceMallocStats() and hook up to some xul kbd event
* - provide NS_TraceMallocTimestamp() or do it internally
*/
#include <stdlib.h>
@ -52,9 +51,6 @@
#include "prprf.h"
#include "nsTraceMalloc.h"
#define __USE_GNU 1
#include <dlfcn.h>
/* From libiberty, why isn't this in <libiberty.h> ? */
extern char *cplus_demangle(const char *, int);
@ -63,6 +59,127 @@ extern __ptr_t __libc_calloc(size_t, size_t);
extern __ptr_t __libc_realloc(__ptr_t, size_t);
extern void __libc_free(__ptr_t);
/* XXX I wish dladdr could find local text symbols (static functions). */
#define __USE_GNU 1
#include <dlfcn.h>
#if 1
#define my_dladdr dladdr
#else
/* XXX this version, which uses libbfd, runs mozilla clean out of memory! */
#include <bfd.h>
#include <elf.h> /* damn dladdr ignores local symbols! */
#include <link.h>
extern struct link_map *_dl_loaded;
static int my_dladdr(const void *address, Dl_info *info)
{
const ElfW(Addr) addr = (ElfW(Addr)) address;
struct link_map *lib, *matchlib;
unsigned int n, size;
bfd *abfd;
PTR minisyms;
long nsyms;
bfd_byte *mini, *endmini;
asymbol *sym, *storage;
bfd_vma target, symaddr;
static const char *sname;
/* Find the highest-addressed object not greater than address. */
matchlib = NULL;
for (lib = _dl_loaded; lib; lib = lib->l_next) {
if (lib->l_addr != 0 && /* 0 means map not set up yet? */
lib->l_addr <= addr &&
(!matchlib || matchlib->l_addr < lib->l_addr)) {
matchlib = lib;
}
}
if (!matchlib)
return 0;
/*
* We know the address lies within matchlib, if it's in any shared object.
* Make sure it isn't past the end of matchlib's segments.
*/
n = (size_t) matchlib->l_phnum;
if (n > 0) {
do {
--n;
} while (matchlib->l_phdr[n].p_type != PT_LOAD);
if (addr >= (matchlib->l_addr +
matchlib->l_phdr[n].p_vaddr +
matchlib->l_phdr[n].p_memsz)) {
/* Off the end of the highest-addressed shared object. */
return 0;
}
}
/*
* Now we know what object the address lies in. Set up info for a file
* match, then find the greatest info->dli_saddr <= addr.
*/
info->dli_fname = matchlib->l_name;
info->dli_fbase = (void*) matchlib->l_addr;
info->dli_sname = NULL;
info->dli_saddr = NULL;
/* Ah, the joys of libbfd.... */
abfd = bfd_openr(matchlib->l_name, "elf32-i386");
if (!abfd)
return 0;
if (!bfd_check_format(abfd, bfd_object)) {
printf("%s is not an object file, according to libbfd.\n",
matchlib->l_name);
return 0;
}
nsyms = bfd_read_minisymbols(abfd, 0, &minisyms, &size);
if (nsyms < 0) {
bfd_close(abfd);
return 0;
}
if (nsyms > 0) {
storage = bfd_make_empty_symbol(abfd);
if (!storage) {
bfd_close(abfd);
return 0;
}
target = (bfd_vma) addr - (bfd_vma) matchlib->l_addr;
endmini = (bfd_byte*) minisyms + nsyms * size;
for (mini = (bfd_byte*) minisyms; mini < endmini; mini += size) {
sym = bfd_minisymbol_to_symbol(abfd, 0, (const PTR)mini, storage);
if (!sym) {
bfd_close(abfd);
return 0;
}
if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK)) {
symaddr = sym->value + sym->section->vma;
if (symaddr == 0 || symaddr > target)
continue;
if (!info->dli_sname || info->dli_saddr < (void*) symaddr) {
info->dli_sname = sym->name;
info->dli_saddr = (void*) symaddr;
}
}
}
/* Emulate dladdr by allocating and owning info->dli_sname's storage. */
if (info->dli_sname) {
if (sname)
__libc_free((void*) sname);
sname = strdup(info->dli_sname);
if (!sname)
return 0;
info->dli_sname = sname;
}
}
bfd_close(abfd);
return 1;
}
#endif /* 0 */
typedef struct logfile logfile;
struct logfile {
@ -334,7 +451,7 @@ static callsite *calltree(uint32 *bp)
/* Not in tree, let's find our symbolic callsite info. */
info.dli_fname = info.dli_sname = NULL;
ok = dladdr((void*) pc, &info);
ok = my_dladdr((void*) pc, &info);
if (ok < 0) {
tmstats.dladdr_failures++;
return NULL;
@ -757,22 +874,23 @@ PR_IMPLEMENT(void) NS_TraceMallocStartup(int logfd, int sitefd)
if (logfd >= 0)
logfp->fd = logfd;
/* If sitefd is open, give it to logfile1, else alias sitefp to logfile0. */
if (sitefd >= 0)
/* If sitefd is open, log callsite info to it, else alias it to logfp. */
if (sitefd >= 0 && sitefd != logfd) {
/* Flush site traces first, then if logfd is open, any malloc traces. */
sitefp->fd = sitefd;
else if (logfd >= 0)
sitefp = logfp;
/* Now flush any buffered sites, methods, and libraries. */
if (sitefp->fd >= 0) {
(void) write(sitefp->fd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
(void) write(sitefd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
flush_logfile(sitefp);
}
/* And flush any malloc traces, if we're logging them at this point. */
if (logfp != sitefp && logfd >= 0) {
if (logfd >= 0) {
(void) write(logfd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
flush_logfile(logfp);
}
} else if (logfd >= 0) {
/* No site file, flush site traces to a common site/malloc log file. */
sitefp->fd = logfd;
(void) write(logfd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
flush_logfile(logfp);
flush_logfile(sitefp);
sitefp->fd = -1;
sitefp = logfp;
}
atexit(NS_TraceMallocShutdown);

View File

@ -32,13 +32,12 @@
* the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*/
#if defined NS_TRACE_MALLOC
#ifdef NS_TRACE_MALLOC
/*
* TODO:
* - #ifdef __linux__/x86 and port to other platforms
* - unify calltree with gc/boehm somehow (common utility libs)
* - provide NS_DumpTraceMallocStats() and hook up to some xul kbd event
* - provide NS_TraceMallocTimestamp() or do it internally
*/
#include <stdlib.h>
@ -52,9 +51,6 @@
#include "prprf.h"
#include "nsTraceMalloc.h"
#define __USE_GNU 1
#include <dlfcn.h>
/* From libiberty, why isn't this in <libiberty.h> ? */
extern char *cplus_demangle(const char *, int);
@ -63,6 +59,127 @@ extern __ptr_t __libc_calloc(size_t, size_t);
extern __ptr_t __libc_realloc(__ptr_t, size_t);
extern void __libc_free(__ptr_t);
/* XXX I wish dladdr could find local text symbols (static functions). */
#define __USE_GNU 1
#include <dlfcn.h>
#if 1
#define my_dladdr dladdr
#else
/* XXX this version, which uses libbfd, runs mozilla clean out of memory! */
#include <bfd.h>
#include <elf.h> /* damn dladdr ignores local symbols! */
#include <link.h>
extern struct link_map *_dl_loaded;
static int my_dladdr(const void *address, Dl_info *info)
{
const ElfW(Addr) addr = (ElfW(Addr)) address;
struct link_map *lib, *matchlib;
unsigned int n, size;
bfd *abfd;
PTR minisyms;
long nsyms;
bfd_byte *mini, *endmini;
asymbol *sym, *storage;
bfd_vma target, symaddr;
static const char *sname;
/* Find the highest-addressed object not greater than address. */
matchlib = NULL;
for (lib = _dl_loaded; lib; lib = lib->l_next) {
if (lib->l_addr != 0 && /* 0 means map not set up yet? */
lib->l_addr <= addr &&
(!matchlib || matchlib->l_addr < lib->l_addr)) {
matchlib = lib;
}
}
if (!matchlib)
return 0;
/*
* We know the address lies within matchlib, if it's in any shared object.
* Make sure it isn't past the end of matchlib's segments.
*/
n = (size_t) matchlib->l_phnum;
if (n > 0) {
do {
--n;
} while (matchlib->l_phdr[n].p_type != PT_LOAD);
if (addr >= (matchlib->l_addr +
matchlib->l_phdr[n].p_vaddr +
matchlib->l_phdr[n].p_memsz)) {
/* Off the end of the highest-addressed shared object. */
return 0;
}
}
/*
* Now we know what object the address lies in. Set up info for a file
* match, then find the greatest info->dli_saddr <= addr.
*/
info->dli_fname = matchlib->l_name;
info->dli_fbase = (void*) matchlib->l_addr;
info->dli_sname = NULL;
info->dli_saddr = NULL;
/* Ah, the joys of libbfd.... */
abfd = bfd_openr(matchlib->l_name, "elf32-i386");
if (!abfd)
return 0;
if (!bfd_check_format(abfd, bfd_object)) {
printf("%s is not an object file, according to libbfd.\n",
matchlib->l_name);
return 0;
}
nsyms = bfd_read_minisymbols(abfd, 0, &minisyms, &size);
if (nsyms < 0) {
bfd_close(abfd);
return 0;
}
if (nsyms > 0) {
storage = bfd_make_empty_symbol(abfd);
if (!storage) {
bfd_close(abfd);
return 0;
}
target = (bfd_vma) addr - (bfd_vma) matchlib->l_addr;
endmini = (bfd_byte*) minisyms + nsyms * size;
for (mini = (bfd_byte*) minisyms; mini < endmini; mini += size) {
sym = bfd_minisymbol_to_symbol(abfd, 0, (const PTR)mini, storage);
if (!sym) {
bfd_close(abfd);
return 0;
}
if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK)) {
symaddr = sym->value + sym->section->vma;
if (symaddr == 0 || symaddr > target)
continue;
if (!info->dli_sname || info->dli_saddr < (void*) symaddr) {
info->dli_sname = sym->name;
info->dli_saddr = (void*) symaddr;
}
}
}
/* Emulate dladdr by allocating and owning info->dli_sname's storage. */
if (info->dli_sname) {
if (sname)
__libc_free((void*) sname);
sname = strdup(info->dli_sname);
if (!sname)
return 0;
info->dli_sname = sname;
}
}
bfd_close(abfd);
return 1;
}
#endif /* 0 */
typedef struct logfile logfile;
struct logfile {
@ -334,7 +451,7 @@ static callsite *calltree(uint32 *bp)
/* Not in tree, let's find our symbolic callsite info. */
info.dli_fname = info.dli_sname = NULL;
ok = dladdr((void*) pc, &info);
ok = my_dladdr((void*) pc, &info);
if (ok < 0) {
tmstats.dladdr_failures++;
return NULL;
@ -757,22 +874,23 @@ PR_IMPLEMENT(void) NS_TraceMallocStartup(int logfd, int sitefd)
if (logfd >= 0)
logfp->fd = logfd;
/* If sitefd is open, give it to logfile1, else alias sitefp to logfile0. */
if (sitefd >= 0)
/* If sitefd is open, log callsite info to it, else alias it to logfp. */
if (sitefd >= 0 && sitefd != logfd) {
/* Flush site traces first, then if logfd is open, any malloc traces. */
sitefp->fd = sitefd;
else if (logfd >= 0)
sitefp = logfp;
/* Now flush any buffered sites, methods, and libraries. */
if (sitefp->fd >= 0) {
(void) write(sitefp->fd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
(void) write(sitefd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
flush_logfile(sitefp);
}
/* And flush any malloc traces, if we're logging them at this point. */
if (logfp != sitefp && logfd >= 0) {
if (logfd >= 0) {
(void) write(logfd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
flush_logfile(logfp);
}
} else if (logfd >= 0) {
/* No site file, flush site traces to a common site/malloc log file. */
sitefp->fd = logfd;
(void) write(logfd, magic, NS_TRACE_MALLOC_MAGIC_SIZE);
flush_logfile(logfp);
flush_logfile(sitefp);
sitefp->fd = -1;
sitefp = logfp;
}
atexit(NS_TraceMallocShutdown);