(bfd_elf_hash): Optimize the hash function a bit.

This commit is contained in:
Ulrich Drepper
1998-10-27 00:00:50 +00:00
parent e841d72322
commit eaa57a10aa

465
bfd/elf.c
View File

@ -199,8 +199,7 @@ _bfd_elf_swap_versym_out (abfd, src, dst)
}
/* Standard ELF hash function. Do not change this function; you will
cause invalid hash tables to be generated. (Well, you would if this
were being used yet.) */
cause invalid hash tables to be generated. */
unsigned long
bfd_elf_hash (name)
CONST unsigned char *name;
@ -215,7 +214,9 @@ bfd_elf_hash (name)
if ((g = (h & 0xf0000000)) != 0)
{
h ^= g >> 24;
h &= ~g;
/* The ELF ABI says `h &= ~g', but this is equivalent in
this case and on some machines one insn instead of two. */
h ^= g;
}
}
return h;
@ -3916,7 +3917,8 @@ swap_out_syms (abfd, sttp, relocatable_p)
type_ptr = elf_symbol_from (abfd, syms[idx]);
if (bfd_is_com_section (syms[idx]->section))
if ((flags & BSF_SECTION_SYM) == 0
&& bfd_is_com_section (syms[idx]->section))
{
/* ELF common symbols put the alignment into the `value' field,
and the size into the `size' field. This is backwards from
@ -4006,17 +4008,17 @@ swap_out_syms (abfd, sttp, relocatable_p)
/* Processor-specific types */
if (bed->elf_backend_get_symbol_type)
type = (*bed->elf_backend_get_symbol_type) (&type_ptr->internal_elf_sym);
type = (*bed->elf_backend_get_symbol_type) (&type_ptr->internal_elf_sym, type);
if (bfd_is_com_section (syms[idx]->section))
if (flags & BSF_SECTION_SYM)
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
else if (bfd_is_com_section (syms[idx]->section))
sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
else if (bfd_is_und_section (syms[idx]->section))
sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
? STB_WEAK
: STB_GLOBAL),
type);
else if (flags & BSF_SECTION_SYM)
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
else if (flags & BSF_FILE)
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
else
@ -4517,6 +4519,11 @@ _bfd_elf_find_nearest_line (abfd,
bfd_vma low_func;
asymbol **p;
if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset,
filename_ptr, functionname_ptr,
line_ptr))
return true;
if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
filename_ptr, functionname_ptr,
line_ptr))
@ -4761,3 +4768,445 @@ _bfd_elf_rel_vtable_reloc_fn (abfd, re, symbol, data, is, obfd, errmsg)
{
return bfd_reloc_ok;
}
/* Elf core file support. Much of this only works on native
toolchains, since we rely on knowing the
machine-dependent procfs structure in order to pick
out details about the corefile. */
#ifdef HAVE_SYS_PROCFS_H
# include <sys/procfs.h>
#endif
/* Define offsetof for those systems which lack it. */
#ifndef offsetof
# define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
#endif
/* FIXME: this is kinda wrong, but it's what gdb wants. */
static int
elfcore_make_pid (abfd)
bfd* abfd;
{
return ((elf_tdata (abfd)->core_lwpid << 16)
+ (elf_tdata (abfd)->core_pid));
}
/* If there isn't a section called NAME, make one, using
data from SECT. Note, this function will generate a
reference to NAME, so you shouldn't deallocate or
overwrite it. */
static boolean
elfcore_maybe_make_sect (abfd, name, sect)
bfd* abfd;
char* name;
asection* sect;
{
asection* sect2;
if (bfd_get_section_by_name (abfd, name) != NULL)
return true;
sect2 = bfd_make_section (abfd, name);
if (sect2 == NULL)
return false;
sect2->_raw_size = sect->_raw_size;
sect2->filepos = sect->filepos;
sect2->flags = sect->flags;
sect2->alignment_power = sect->alignment_power;
return true;
}
/* prstatus_t exists on:
solaris 2.[567]
linux 2.[01] + glibc
unixware 4.2
*/
#if defined (HAVE_PRSTATUS_T)
static boolean
elfcore_grok_prstatus (abfd, note)
bfd* abfd;
Elf_Internal_Note* note;
{
prstatus_t prstat;
char buf[100];
char* name;
asection* sect;
if (note->descsz != sizeof (prstat))
return true;
memcpy (&prstat, note->descdata, sizeof (prstat));
elf_tdata (abfd)->core_signal = prstat.pr_cursig;
elf_tdata (abfd)->core_pid = prstat.pr_pid;
/* pr_who exists on:
solaris 2.[567]
unixware 4.2
pr_who doesn't exist on:
linux 2.[01]
*/
#if defined (HAVE_PRSTATUS_T_PR_WHO)
elf_tdata (abfd)->core_lwpid = prstat.pr_who;
#endif
/* Make a ".reg/999" section. */
sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
name = bfd_alloc (abfd, strlen (buf) + 1);
if (name == NULL)
return false;
strcpy (name, buf);
sect = bfd_make_section (abfd, name);
if (sect == NULL)
return false;
sect->_raw_size = sizeof (prstat.pr_reg);
sect->filepos = note->descpos + offsetof (prstatus_t, pr_reg);
sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
if (! elfcore_maybe_make_sect (abfd, ".reg", sect))
return false;
return true;
}
#endif /* defined (HAVE_PRSTATUS_T) */
/* There isn't a consistent prfpregset_t across platforms,
but it doesn't matter, because we don't have to pick this
data structure apart. */
static boolean
elfcore_grok_prfpreg (abfd, note)
bfd* abfd;
Elf_Internal_Note* note;
{
char buf[100];
char* name;
asection* sect;
/* Make a ".reg2/999" section. */
sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
name = bfd_alloc (abfd, strlen (buf) + 1);
if (name == NULL)
return false;
strcpy (name, buf);
sect = bfd_make_section (abfd, name);
if (sect == NULL)
return false;
sect->_raw_size = note->descsz;
sect->filepos = note->descpos;
sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
if (! elfcore_maybe_make_sect (abfd, ".reg2", sect))
return false;
return true;
}
/* return a malloc'ed copy of a string at START which is at
most MAX bytes long, possibly without a terminating '\0'.
the copy will always have a terminating '\0'. */
static char*
elfcore_strndup (abfd, start, max)
bfd* abfd;
char* start;
int max;
{
char* dup;
char* end = memchr (start, '\0', max);
int len;
if (end == NULL)
len = max;
else
len = end - start;
dup = bfd_alloc (abfd, len + 1);
if (dup == NULL)
return NULL;
memcpy (dup, start, len);
dup[len] = '\0';
return dup;
}
#if defined (HAVE_PRPSINFO_T)
# define elfcore_psinfo_t prpsinfo_t
#endif
#if defined (HAVE_PSINFO_T)
# define elfcore_psinfo_t psinfo_t
#endif
#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
static boolean
elfcore_grok_psinfo (abfd, note)
bfd* abfd;
Elf_Internal_Note* note;
{
elfcore_psinfo_t psinfo;
if (note->descsz != sizeof (elfcore_psinfo_t))
return true;
memcpy (&psinfo, note->descdata, note->descsz);
elf_tdata (abfd)->core_program
= elfcore_strndup (abfd, psinfo.pr_fname, sizeof (psinfo.pr_fname));
elf_tdata (abfd)->core_command
= elfcore_strndup (abfd, psinfo.pr_psargs, sizeof (psinfo.pr_psargs));
/* Note that for some reason, a spurious space is tacked
onto the end of the args in some (at least one anyway)
implementations, so strip it off if it exists. */
{
char* command = elf_tdata (abfd)->core_command;
int n = strlen (command);
if (0 < n && command[n - 1] == ' ')
command[n - 1] = '\0';
}
return true;
}
#endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */
#if defined (HAVE_PSTATUS_T)
static boolean
elfcore_grok_pstatus (abfd, note)
bfd* abfd;
Elf_Internal_Note* note;
{
pstatus_t pstat;
if (note->descsz != sizeof (pstat))
return true;
memcpy (&pstat, note->descdata, sizeof (pstat));
elf_tdata (abfd)->core_pid = pstat.pr_pid;
/* Could grab some more details from the "representative"
lwpstatus_t in pstat.pr_lwp, but we'll catch it all in an
NT_LWPSTATUS note, presumably. */
return true;
}
#endif /* defined (HAVE_PSTATUS_T) */
#if defined (HAVE_LWPSTATUS_T)
static boolean
elfcore_grok_lwpstatus (abfd, note)
bfd* abfd;
Elf_Internal_Note* note;
{
lwpstatus_t lwpstat;
char buf[100];
char* name;
asection* sect;
if (note->descsz != sizeof (lwpstat))
return true;
memcpy (&lwpstat, note->descdata, sizeof (lwpstat));
elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid;
elf_tdata (abfd)->core_signal = lwpstat.pr_cursig;
/* Make a ".reg/999" section. */
sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
name = bfd_alloc (abfd, strlen (buf) + 1);
if (name == NULL)
return false;
strcpy (name, buf);
sect = bfd_make_section (abfd, name);
if (sect == NULL)
return false;
#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
sect->filepos = note->descpos
+ offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs);
#endif
#if defined (HAVE_LWPSTATUS_T_PR_REG)
sect->_raw_size = sizeof (lwpstat.pr_reg);
sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
#endif
sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
if (!elfcore_maybe_make_sect (abfd, ".reg", sect))
return false;
/* Make a ".reg2/999" section */
sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
name = bfd_alloc (abfd, strlen (buf) + 1);
if (name == NULL)
return false;
strcpy (name, buf);
sect = bfd_make_section (abfd, name);
if (sect == NULL)
return false;
#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
sect->filepos = note->descpos
+ offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs);
#endif
#if defined (HAVE_LWPSTATUS_T_PR_FPREG)
sect->_raw_size = sizeof (lwpstat.pr_fpreg);
sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
#endif
sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
if (!elfcore_maybe_make_sect (abfd, ".reg2", sect))
return false;
return true;
}
#endif /* defined (HAVE_LWPSTATUS_T) */
static boolean
elfcore_grok_note (abfd, note)
bfd* abfd;
Elf_Internal_Note* note;
{
switch (note->type)
{
default:
return true;
#if defined (HAVE_PRSTATUS_T)
case NT_PRSTATUS:
return elfcore_grok_prstatus (abfd, note);
#endif
#if defined (HAVE_PSTATUS_T)
case NT_PSTATUS:
return elfcore_grok_pstatus (abfd, note);
#endif
#if defined (HAVE_LWPSTATUS_T)
case NT_LWPSTATUS:
return elfcore_grok_lwpstatus (abfd, note);
#endif
case NT_FPREGSET: /* FIXME: rename to NT_PRFPREG */
return elfcore_grok_prfpreg (abfd, note);
#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
case NT_PRPSINFO:
case NT_PSINFO:
return elfcore_grok_psinfo (abfd, note);
#endif
}
}
static boolean
elfcore_read_notes (abfd, offset, size)
bfd* abfd;
bfd_vma offset;
bfd_vma size;
{
char* buf;
char* p;
if (size <= 0)
return true;
if (bfd_seek (abfd, offset, SEEK_SET) == -1)
return false;
buf = bfd_malloc ((size_t) size);
if (buf == NULL)
return false;
if (bfd_read (buf, size, 1, abfd) != size)
{
error:
free (buf);
return false;
}
p = buf;
while (p < buf + size)
{
/* FIXME: bad alignment assumption. */
Elf_External_Note* xnp = (Elf_External_Note*) p;
Elf_Internal_Note in;
in.type = bfd_h_get_32 (abfd, (bfd_byte *) xnp->type);
in.namesz = bfd_h_get_32 (abfd, (bfd_byte *) xnp->namesz);
in.namedata = xnp->name;
in.descsz = bfd_h_get_32 (abfd, (bfd_byte *) xnp->descsz);
in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
in.descpos = offset + (in.descdata - buf);
if (! elfcore_grok_note (abfd, &in))
goto error;
p = in.descdata + BFD_ALIGN (in.descsz, 4);
}
free (buf);
return true;
}
boolean
_bfd_elfcore_section_from_phdr (abfd, phdr, sec_num)
bfd* abfd;
Elf_Internal_Phdr* phdr;
int sec_num;
{
if (! bfd_section_from_phdr (abfd, phdr, sec_num))
return false;
if (phdr->p_type == PT_NOTE
&& ! elfcore_read_notes (abfd, phdr->p_offset, phdr->p_filesz))
return false;
return true;
}