diff options
Diffstat (limited to 'gprofng/src/Elf.cc')
-rw-r--r-- | gprofng/src/Elf.cc | 225 |
1 files changed, 103 insertions, 122 deletions
diff --git a/gprofng/src/Elf.cc b/gprofng/src/Elf.cc index f0fd121..e63e3c3 100644 --- a/gprofng/src/Elf.cc +++ b/gprofng/src/Elf.cc @@ -28,6 +28,8 @@ #include "Map.h" #include "StringBuilder.h" #include "DbeFile.h" +#include "DbeSession.h" +#include "Dwarf.h" typedef uint32_t Elf32_Word; typedef uint32_t Elf64_Word; @@ -83,55 +85,30 @@ struct S_Elf64_Dyn } d_un; }; +#ifndef DEBUGDIR +#define DEBUGDIR "/lib/debug" +#endif +#ifndef EXTRA_DEBUG_ROOT1 +#define EXTRA_DEBUG_ROOT1 "/usr/lib/debug" +#endif +#ifndef EXTRA_DEBUG_ROOT2 +#define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr" +#endif -// Symbol table -typedef struct -{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; /* bind, type: ELF_32_ST_... */ - unsigned char st_other; - Elf32_Half st_shndx; /* SHN_... */ -} Elf32_Sym; - -typedef struct -{ - Elf64_Word st_name; - unsigned char st_info; /* bind, type: ELF_64_ST_... */ - unsigned char st_other; - Elf64_Half st_shndx; /* SHN_... */ - Elf64_Addr st_value; - Elf64_Xword st_size; -} Elf64_Sym; - - -// Relocation -typedef struct -{ - Elf32_Addr r_offset; - Elf32_Word r_info; /* sym, type: ELF32_R_... */ -} Elf32_Rel; - -typedef struct -{ - Elf32_Addr r_offset; - Elf32_Word r_info; /* sym, type: ELF32_R_... */ - Elf32_Sword r_addend; -} Elf32_Rela; - -typedef struct -{ - Elf64_Addr r_offset; - Elf64_Xword r_info; /* sym, type: ELF64_R_... */ -} Elf64_Rel; +static const char *debug_dirs[] = { + DEBUGDIR, EXTRA_DEBUG_ROOT1, EXTRA_DEBUG_ROOT2, "." +}; -typedef struct +template<> void Vector<asymbol *>::dump (const char *msg) { - Elf64_Addr r_offset; - Elf64_Xword r_info; /* sym, type: ELF64_R_... */ - Elf64_Sxword r_addend; -} Elf64_Rela; + Dprintf (1, NTXT ("\nFile: %s Vector<asymbol *> [%ld]\n"), + msg ? msg : "NULL", (long) size ()); + for (long i = 0, sz = size (); i < sz; i++) + { + asymbol *sym = get (i); + Dprintf (1, " %3ld %s\n", i, sym->name); + } +} int Elf::bfd_status = -1; @@ -149,6 +126,8 @@ Elf::Elf (char *filename) : DbeMessages (), Data_window (filename) ancillary_files = NULL; elfSymbols = NULL; gnu_debug_file = NULL; + gnu_debugalt_file = NULL; + sections = NULL; dbeFile = NULL; abfd = NULL; bfd_symcnt = -1; @@ -196,23 +175,13 @@ Elf::Elf (char *filename) : DbeMessages (), Data_window (filename) } status = ELF_ERR_NONE; -#if ARCH(SPARC) - need_swap_endian = is_Intel (); -#else - need_swap_endian = !is_Intel (); -#endif - + need_swap_endian = DbeSession::is_bigendian () != bfd_big_endian (abfd); analyzerInfo = 0; - SUNW_ldynsym = 0; - gnuLink = 0; stab = 0; - stabStr = 0; stabIndex = 0; stabIndexStr = 0; stabExcl = 0; stabExclStr = 0; - symtab = 0; - dynsym = 0; info = 0; plt = 0; dwarf = false; @@ -234,20 +203,12 @@ Elf::Elf (char *filename) : DbeMessages (), Data_window (filename) stabExcl = sec; else if (streq (name, NTXT (".stab.exclstr"))) stabExclStr = sec; - else if (streq (name, NTXT (".gnu_debuglink"))) - gnuLink = sec; else if (streq (name, NTXT (".__analyzer_info"))) analyzerInfo = sec; else if (streq (name, NTXT (".info"))) info = true; else if (streq (name, NTXT (".plt"))) plt = sec; - else if (streq (name, NTXT (".SUNW_ldynsym"))) - SUNW_ldynsym = sec; - else if (streq (name, NTXT (".dynsym"))) - dynsym = sec; - else if (streq (name, NTXT (".symtab"))) - symtab = sec; else if (strncmp (name, NTXT (".debug"), 6) == 0) dwarf = true; } @@ -276,6 +237,12 @@ Elf::~Elf () } free (data); } + if (sections) + { + for (int i = 0; i < (int) ehdrp->e_shnum; i++) + delete sections[i]; + free (sections); + } if (ancillary_files) { ancillary_files->destroy (); @@ -283,6 +250,7 @@ Elf::~Elf () } delete elfSymbols; delete gnu_debug_file; + delete gnu_debugalt_file; delete dbeFile; delete synthsym; free (bfd_sym); @@ -405,9 +373,36 @@ Elf::get_sec_name (unsigned int sec) return elf_strptr (ehdrp->e_shstrndx, shdr->sh_name); } +DwrSec * +Elf::get_dwr_section (const char *sec_name) +{ + int sec_num = elf_get_sec_num (sec_name); + if (sec_num > 0) + { + if (sections == NULL) + { + sections = (DwrSec **) xmalloc (ehdrp->e_shnum * sizeof (DwrSec *)); + for (int i = 0; i < (int) ehdrp->e_shnum; i++) + sections[i] = NULL; + } + if (sections[sec_num] == NULL) + { + Elf_Data *elfData = elf_getdata (sec_num); + if (elfData) + sections[sec_num] = new DwrSec ((unsigned char *) elfData->d_buf, + elfData->d_size, need_swap_endian, + elf_getclass () == ELFCLASS32); + } + return sections[sec_num]; + } + return NULL; +} + Elf_Data * Elf::elf_getdata (unsigned int sec) { + if (sec == 0) + return NULL; if (data == NULL) { data = (Elf_Data **) xmalloc (ehdrp->e_shnum * sizeof (Elf_Data *)); @@ -572,50 +567,6 @@ Elf::elf_getsym (unsigned int ndx, Elf_Internal_Sym *dst, bool is_dynamic) return asym; } -Elf_Internal_Rela * -Elf::elf_getrel (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst) -{ - if (dst == NULL || edta == NULL || edta->d_buf == NULL) - return NULL; - if (elf_getclass () == ELFCLASS32) - { - Elf32_Rel *rel = ((Elf32_Rel *) edta->d_buf) + ndx; - dst->r_offset = decode (rel->r_offset); - dst->r_info = ELF64_R_INFO (ELF32_R_SYM (decode (rel->r_info)), - ELF32_R_TYPE (decode (rel->r_info))); - } - else - { - Elf64_Rel *rel = ((Elf64_Rel *) edta->d_buf) + ndx; - dst->r_offset = decode (rel->r_offset); - dst->r_info = decode (rel->r_info); - } - return dst; -} - -Elf_Internal_Rela * -Elf::elf_getrela (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst) -{ - if (dst == NULL || edta == NULL || edta->d_buf == NULL) - return NULL; - if (elf_getclass () == ELFCLASS32) - { - Elf32_Rela *rela = ((Elf32_Rela *) edta->d_buf) + ndx; - dst->r_offset = decode (rela->r_offset); - dst->r_addend = decode (rela->r_addend); - dst->r_info = ELF64_R_INFO (ELF32_R_SYM (decode (rela->r_info)), - ELF32_R_TYPE (decode (rela->r_info))); - } - else - { - Elf64_Rela *rela = ((Elf64_Rela *) edta->d_buf) + ndx; - dst->r_offset = decode (rela->r_offset); - dst->r_addend = decode (rela->r_addend); - dst->r_info = decode (rela->r_info); - } - return dst; -} - Elf64_Ancillary * Elf::elf_getancillary (Elf_Data *edta, unsigned int ndx, Elf64_Ancillary *dst) { @@ -676,25 +627,54 @@ Elf::get_related_file (const char *lo_name, const char *nm) return NULL; } -Elf * -Elf::find_ancillary_files (char *lo_name) +static char * +find_file (char *(bfd_func) (bfd *, const char *), bfd *abfd) { - // read the .gnu_debuglink and .SUNW_ancillary seections - if (gnu_debug_file) - return gnu_debug_file; - unsigned int sec = elf_get_sec_num (NTXT (".gnu_debuglink")); - if (sec > 0) + char *fnm = NULL; + for (size_t i = 0; i < ARR_SIZE (debug_dirs); i++) + { + fnm = bfd_func (abfd, debug_dirs[i]); + if (fnm) + break; + } + Dprintf (DUMP_DWARFLIB, "FOUND: gnu_debug_file: %s --> %s\n", + abfd->filename, fnm); + return fnm; +} + +void +Elf::find_gnu_debug_files () +{ + char *fnm; + if (gnu_debug_file == NULL) { - Elf_Data *dp = elf_getdata (sec); - if (dp) + fnm = find_file (bfd_follow_gnu_debuglink, abfd); + if (fnm) { - gnu_debug_file = get_related_file (lo_name, (char *) (dp->d_buf)); + gnu_debug_file = Elf::elf_begin (fnm); + free (fnm); if (gnu_debug_file) - return gnu_debug_file; + gnu_debug_file->find_gnu_debug_files (); + } + } + if (gnu_debugalt_file == NULL) + { + fnm = find_file (bfd_follow_gnu_debugaltlink, abfd); + if (fnm) + { + gnu_debugalt_file = Elf::elf_begin (fnm); + free (fnm); } } +} - sec = elf_get_sec_num (NTXT (".SUNW_ancillary")); +void +Elf::find_ancillary_files (const char *lo_name) +{ + // read the .SUNW_ancillary section + if (ancillary_files != NULL) + return; + unsigned int sec = elf_get_sec_num (".SUNW_ancillary"); if (sec > 0) { Elf_Internal_Shdr *shdr = get_shdr (sec); @@ -755,7 +735,6 @@ Elf::find_ancillary_files (char *lo_name) } } } - return NULL; } void @@ -828,6 +807,8 @@ Elf::get_funcname_in_plt (uint64_t pc) for (long i = 0; i < bfd_synthcnt; i++) synthsym->append (bfd_synthsym + i); synthsym->sort (cmp_sym_addr); + if (DUMP_ELF_SYM) + synthsym->dump (get_location ()); } asymbol sym, *symp = &sym; |