mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-07 13:33:06 +00:00
1139 lines
28 KiB
C++
1139 lines
28 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <unistd.h>
|
|
|
|
#include "util.h"
|
|
#include "bfd.h"
|
|
#include "elf-bfd.h"
|
|
#include "Elf.h"
|
|
#include "Map.h"
|
|
#include "StringBuilder.h"
|
|
#include "DbeFile.h"
|
|
|
|
typedef uint32_t Elf32_Word;
|
|
typedef uint32_t Elf64_Word;
|
|
typedef uint32_t Elf32_Addr;
|
|
typedef uint64_t Elf64_Addr;
|
|
typedef uint64_t Elf64_Xword;
|
|
typedef int32_t Elf32_Sword;
|
|
typedef int64_t Elf64_Sxword;
|
|
typedef uint16_t Elf32_Half;
|
|
typedef uint16_t Elf64_Half;
|
|
|
|
// Ancillary entry
|
|
typedef struct
|
|
{
|
|
Elf32_Word a_tag; /* how to interpret value */
|
|
union
|
|
{
|
|
Elf32_Word a_val;
|
|
Elf32_Addr a_ptr;
|
|
} a_un;
|
|
} Elf32_Ancillary;
|
|
|
|
struct S_Elf64_Ancillary
|
|
{
|
|
Elf64_Xword a_tag; /* how to interpret value */
|
|
union
|
|
{
|
|
Elf64_Xword a_val;
|
|
Elf64_Addr a_ptr;
|
|
} a_un;
|
|
};
|
|
|
|
/* Dynamic section entry. */
|
|
typedef struct
|
|
{
|
|
Elf32_Sword d_tag; /* Dynamic entry type */
|
|
|
|
union
|
|
{
|
|
Elf32_Word d_val; /* Integer value */
|
|
Elf32_Addr d_ptr; /* Address value */
|
|
} d_un;
|
|
} Elf32_Dyn;
|
|
|
|
struct S_Elf64_Dyn
|
|
{
|
|
Elf64_Sxword d_tag; /* Dynamic entry type */
|
|
|
|
union
|
|
{
|
|
Elf64_Xword d_val; /* Integer value */
|
|
Elf64_Addr d_ptr; /* Address value */
|
|
} d_un;
|
|
};
|
|
|
|
|
|
// 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;
|
|
|
|
typedef struct
|
|
{
|
|
Elf64_Addr r_offset;
|
|
Elf64_Xword r_info; /* sym, type: ELF64_R_... */
|
|
Elf64_Sxword r_addend;
|
|
} Elf64_Rela;
|
|
|
|
int Elf::bfd_status = -1;
|
|
|
|
void
|
|
Elf::elf_init ()
|
|
{
|
|
if (bfd_status == -1)
|
|
bfd_status = bfd_init ();
|
|
}
|
|
|
|
Elf::Elf (char *filename) : DbeMessages (), Data_window (filename)
|
|
{
|
|
ehdrp = NULL;
|
|
data = NULL;
|
|
ancillary_files = NULL;
|
|
elfSymbols = NULL;
|
|
gnu_debug_file = NULL;
|
|
dbeFile = NULL;
|
|
abfd = NULL;
|
|
if (bfd_status != BFD_INIT_MAGIC)
|
|
{
|
|
status = ELF_ERR_CANT_OPEN_FILE;
|
|
return;
|
|
}
|
|
abfd = bfd_openr (filename, NULL);
|
|
if (abfd == NULL)
|
|
{
|
|
status = ELF_ERR_CANT_OPEN_FILE;
|
|
return;
|
|
}
|
|
if (!bfd_check_format (abfd, bfd_object))
|
|
{
|
|
bfd_close (abfd);
|
|
abfd = NULL;
|
|
status = ELF_ERR_CANT_OPEN_FILE;
|
|
return;
|
|
}
|
|
ehdrp = elf_getehdr ();
|
|
if (ehdrp == NULL)
|
|
{
|
|
bfd_close (abfd);
|
|
abfd = NULL;
|
|
status = ELF_ERR_BAD_ELF_FORMAT;
|
|
return;
|
|
}
|
|
elf_class = ehdrp->e_ident[EI_CLASS];
|
|
elf_datatype = ehdrp->e_ident[EI_DATA];
|
|
|
|
if (not_opened ())
|
|
{
|
|
status = ELF_ERR_CANT_OPEN_FILE;
|
|
return;
|
|
}
|
|
status = ELF_ERR_NONE;
|
|
|
|
#if ARCH(SPARC)
|
|
need_swap_endian = is_Intel ();
|
|
#else
|
|
need_swap_endian = !is_Intel ();
|
|
#endif
|
|
|
|
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;
|
|
|
|
for (unsigned int sec = 1; sec < elf_getehdr ()->e_shnum; sec++)
|
|
{
|
|
char *name = get_sec_name (sec);
|
|
if (name == NULL)
|
|
continue;
|
|
if (streq (name, NTXT (".stab")))
|
|
stab = sec;
|
|
else if (streq (name, NTXT (".stabstr")))
|
|
stabStr = sec;
|
|
else if (streq (name, NTXT (".stab.index")))
|
|
stabIndex = sec;
|
|
else if (streq (name, NTXT (".stab.indexstr")))
|
|
stabIndexStr = sec;
|
|
else if (streq (name, NTXT (".stab.excl")))
|
|
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;
|
|
}
|
|
if (fd != -1)
|
|
{
|
|
close (fd);
|
|
fd = -1;
|
|
}
|
|
}
|
|
|
|
Elf::~Elf ()
|
|
{
|
|
if (data)
|
|
{
|
|
for (int i = 0; i < (int) ehdrp->e_shnum; i++)
|
|
{
|
|
Elf_Data *p = data[i];
|
|
if (p && !mmap_on_file && (p->d_flags & SHF_SUNW_ABSENT) == 0)
|
|
free (p->d_buf);
|
|
delete p;
|
|
}
|
|
free (data);
|
|
}
|
|
if (ancillary_files)
|
|
{
|
|
ancillary_files->destroy ();
|
|
delete ancillary_files;
|
|
}
|
|
delete elfSymbols;
|
|
delete gnu_debug_file;
|
|
delete dbeFile;
|
|
if (abfd)
|
|
bfd_close (abfd);
|
|
}
|
|
|
|
Elf_Internal_Ehdr *
|
|
Elf::elf_getehdr ()
|
|
{
|
|
if (ehdrp == NULL && abfd)
|
|
ehdrp = elf_elfheader (abfd);
|
|
return ehdrp;
|
|
}
|
|
|
|
Elf_Internal_Phdr *
|
|
Elf::get_phdr (unsigned int ndx)
|
|
{
|
|
if (ehdrp == NULL || ndx >= ehdrp->e_phnum)
|
|
return NULL;
|
|
return &(elf_tdata (abfd)->phdr[ndx]);
|
|
}
|
|
|
|
Elf_Internal_Shdr *
|
|
Elf::get_shdr (unsigned int ndx)
|
|
{
|
|
if (ehdrp == NULL || ndx >= ehdrp->e_shnum)
|
|
return NULL;
|
|
return elf_elfsections (abfd)[ndx];
|
|
}
|
|
|
|
Elf64_Dyn *
|
|
Elf::elf_getdyn (Elf_Internal_Phdr *phdr, unsigned int ndx, Elf64_Dyn *pdyn)
|
|
{
|
|
if (elf_getclass () == ELFCLASS32)
|
|
{
|
|
if (ndx * sizeof (Elf32_Dyn) >= phdr->p_filesz)
|
|
return NULL;
|
|
Elf32_Dyn *hdr = (Elf32_Dyn*) bind (phdr->p_offset + ndx * sizeof (Elf32_Dyn),
|
|
sizeof (Elf32_Dyn));
|
|
if (hdr == NULL)
|
|
return NULL;
|
|
pdyn->d_tag = decode (hdr->d_tag);
|
|
pdyn->d_un.d_val = decode (hdr->d_un.d_val);
|
|
}
|
|
else
|
|
{
|
|
if (ndx * sizeof (Elf64_Dyn) >= phdr->p_filesz)
|
|
return NULL;
|
|
Elf64_Dyn *hdr = (Elf64_Dyn*) bind (phdr->p_offset + ndx * sizeof (Elf64_Dyn),
|
|
sizeof (Elf64_Dyn));
|
|
if (hdr == NULL)
|
|
return NULL;
|
|
pdyn->d_tag = decode (hdr->d_tag);
|
|
pdyn->d_un.d_val = decode (hdr->d_un.d_val);
|
|
}
|
|
return pdyn;
|
|
}
|
|
|
|
unsigned
|
|
Elf::elf_version (unsigned ver)
|
|
{
|
|
// We compile locally, no need to check the version
|
|
return ver;
|
|
}
|
|
|
|
Elf *
|
|
Elf::elf_begin (char *fname, Elf_status *stp)
|
|
{
|
|
if (fname == NULL)
|
|
{
|
|
if (stp)
|
|
*stp = ELF_ERR_CANT_OPEN_FILE;
|
|
return NULL;
|
|
}
|
|
Elf *elf = new Elf (fname);
|
|
if (stp)
|
|
*stp = elf->status;
|
|
if (elf->status != ELF_ERR_NONE)
|
|
{
|
|
delete elf;
|
|
return NULL;
|
|
}
|
|
#if DEBUG
|
|
if (DUMP_ELF_SEC)
|
|
{
|
|
char *str = elf->dump ();
|
|
fprintf (stderr, NTXT ("%s\n\n"), str);
|
|
free (str);
|
|
}
|
|
#endif /* DEBUG */
|
|
return elf;
|
|
}
|
|
|
|
unsigned int
|
|
Elf::elf_get_sec_num (const char *name)
|
|
{
|
|
if (name == NULL || ehdrp == NULL)
|
|
return 0;
|
|
for (unsigned int sec = 1; sec < ehdrp->e_shnum; sec++)
|
|
{
|
|
Elf_Internal_Shdr *shdr = get_shdr (sec);
|
|
if (shdr == NULL)
|
|
continue;
|
|
char *sname = elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
|
|
if (sname != NULL && strcmp (name, sname) == 0)
|
|
return sec;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *
|
|
Elf::get_sec_name (unsigned int sec)
|
|
{
|
|
Elf_Internal_Shdr *shdr = get_shdr (sec);
|
|
if (ehdrp == NULL || shdr == NULL)
|
|
return NULL;
|
|
return elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
|
|
}
|
|
|
|
Elf_Data *
|
|
Elf::elf_getdata (unsigned int sec)
|
|
{
|
|
if (data == NULL)
|
|
{
|
|
data = (Elf_Data **) malloc (ehdrp->e_shnum * sizeof (Elf_Data *));
|
|
for (int i = 0; i < (int) ehdrp->e_shnum; i++)
|
|
data[i] = NULL;
|
|
}
|
|
Elf_Data *edta = data[sec];
|
|
if (edta == NULL)
|
|
{
|
|
Elf_Internal_Shdr *shdr = get_shdr (sec);
|
|
if (shdr == NULL)
|
|
return NULL;
|
|
edta = new Elf_Data;
|
|
data[sec] = edta;
|
|
if ((shdr->sh_flags & SHF_SUNW_ABSENT) != 0)
|
|
{
|
|
char *sname = get_sec_name (sec);
|
|
for (int i = 0, sz = VecSize(ancillary_files); i < sz; i++)
|
|
{
|
|
Elf *ancElf = ancillary_files->fetch (i);
|
|
int secNum = sec;
|
|
if (dbe_strcmp (sname, ancElf->get_sec_name (sec)) != 0)
|
|
{
|
|
append_msg (CMSG_WARN,
|
|
"Warning: the section #%d (%s) is mismatch in ancillary file '%s')\n",
|
|
sec, STR (sname), STR (ancElf->fname));
|
|
secNum = ancElf->elf_get_sec_num (sname);
|
|
}
|
|
if (secNum > 0)
|
|
{
|
|
Elf_Data *ed = ancElf->elf_getdata (secNum);
|
|
if (ed && ed->d_buf)
|
|
{
|
|
*edta = *ed;
|
|
edta->d_flags |= SHF_SUNW_ABSENT;
|
|
return edta;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
edta->d_buf = get_data (shdr->sh_offset, (size_t) shdr->sh_size, NULL);
|
|
edta->d_flags = shdr->sh_flags;
|
|
edta->d_size = ((edta->d_buf == NULL) || (shdr->sh_type == SHT_NOBITS)) ? 0 : shdr->sh_size;
|
|
edta->d_off = shdr->sh_offset;
|
|
edta->d_align = shdr->sh_addralign;
|
|
}
|
|
return edta;
|
|
}
|
|
|
|
int64_t
|
|
Elf::elf_checksum ()
|
|
{
|
|
if (ehdrp == NULL)
|
|
return 0;
|
|
int64_t chk = 0;
|
|
for (unsigned int ndx = 0; ndx < ehdrp->e_phnum; ndx++)
|
|
{
|
|
Elf_Internal_Phdr *phdr = get_phdr (ndx);
|
|
if (phdr == NULL)
|
|
continue;
|
|
if (phdr->p_type == PT_DYNAMIC)
|
|
{
|
|
Elf64_Dyn edyn;
|
|
for (unsigned int i = 0; elf_getdyn (phdr, i, &edyn) != NULL; i++)
|
|
{
|
|
if (!edyn.d_tag)
|
|
break;
|
|
if (edyn.d_tag == DT_CHECKSUM)
|
|
{
|
|
chk = edyn.d_un.d_val;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return normalize_checksum (chk);
|
|
}
|
|
|
|
uint64_t
|
|
Elf::get_baseAddr ()
|
|
{
|
|
uint64_t addr = 0;
|
|
for (unsigned int pnum = 0; pnum < elf_getehdr ()->e_phnum; pnum++)
|
|
{
|
|
Elf_Internal_Phdr *phdr = get_phdr (pnum);
|
|
if (phdr->p_type == PT_LOAD && phdr->p_flags == (PF_R | PF_X))
|
|
{
|
|
if (addr == 0)
|
|
addr = phdr->p_vaddr;
|
|
else
|
|
{
|
|
addr = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
char *
|
|
Elf::elf_strptr (unsigned int sec, uint64_t off)
|
|
{
|
|
Elf_Data *edta = elf_getdata (sec);
|
|
if (edta && edta->d_buf && edta->d_size > off)
|
|
return ((char *) edta->d_buf) + off;
|
|
return NULL;
|
|
}
|
|
|
|
Elf_Internal_Sym *
|
|
Elf::elf_getsym (Elf_Data *edta, unsigned int ndx, Elf_Internal_Sym *dst)
|
|
{
|
|
if (dst == NULL || edta == NULL)
|
|
return NULL;
|
|
if (elf_getclass () == ELFCLASS32)
|
|
{
|
|
if (edta->d_size <= ndx * sizeof (Elf32_Sym))
|
|
return NULL;
|
|
Elf32_Sym *hdr = (Elf32_Sym*) bind (edta->d_off + ndx * sizeof (Elf32_Sym), sizeof (Elf32_Sym));
|
|
if (hdr == NULL)
|
|
return NULL;
|
|
dst->st_name = decode (hdr->st_name);
|
|
dst->st_value = decode (hdr->st_value);
|
|
dst->st_size = decode (hdr->st_size);
|
|
dst->st_info = ELF64_ST_INFO (ELF32_ST_BIND (decode (hdr->st_info)),
|
|
ELF32_ST_TYPE (decode (hdr->st_info)));
|
|
dst->st_other = decode (hdr->st_other);
|
|
dst->st_shndx = decode (hdr->st_shndx);
|
|
}
|
|
else
|
|
{
|
|
if (edta->d_size <= ndx * sizeof (Elf64_Sym))
|
|
return NULL;
|
|
Elf64_Sym *hdr = (Elf64_Sym*) bind (edta->d_off + ndx * sizeof (Elf64_Sym),
|
|
sizeof (Elf64_Sym));
|
|
if (hdr == NULL)
|
|
return NULL;
|
|
dst->st_name = decode (hdr->st_name);
|
|
dst->st_value = decode (hdr->st_value);
|
|
dst->st_size = decode (hdr->st_size);
|
|
dst->st_info = decode (hdr->st_info);
|
|
dst->st_other = decode (hdr->st_other);
|
|
dst->st_shndx = decode (hdr->st_shndx);
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (dst == NULL || edta == NULL || edta->d_buf == NULL)
|
|
return NULL;
|
|
if (elf_getclass () == ELFCLASS32)
|
|
{
|
|
Elf32_Ancillary *p = ((Elf32_Ancillary *) edta->d_buf) + ndx;
|
|
dst->a_tag = decode (p->a_tag);
|
|
dst->a_un.a_val = decode (p->a_un.a_val);
|
|
}
|
|
else
|
|
{
|
|
Elf64_Ancillary *p = ((Elf64_Ancillary *) edta->d_buf) + ndx;
|
|
dst->a_tag = decode (p->a_tag);
|
|
dst->a_un.a_val = decode (p->a_un.a_val);
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
Elf *
|
|
Elf::get_related_file (const char *lo_name, const char *nm)
|
|
{
|
|
DbeFile *df;
|
|
if (*nm == '/')
|
|
{
|
|
df = new DbeFile (nm);
|
|
df->filetype |= (DbeFile::F_FILE | DbeFile::F_DEBUG_FILE);
|
|
}
|
|
else
|
|
{
|
|
char *bname = get_basename (lo_name);
|
|
char *fnm = dbe_sprintf ("%.*s/%s", (int) (bname - lo_name), lo_name, nm);
|
|
df = new DbeFile (fnm);
|
|
df->filetype |= (DbeFile::F_FILE | DbeFile::F_DEBUG_FILE);
|
|
free (fnm);
|
|
}
|
|
Dprintf (DEBUG_STABS, "get_related_file: %s -> '%s'\n", nm, df->get_name ());
|
|
Elf_status st = ELF_ERR_CANT_OPEN_FILE;
|
|
Elf *elf = elf_begin (df->get_location (), &st);
|
|
if (elf)
|
|
{
|
|
elf->dbeFile = df;
|
|
return elf;
|
|
}
|
|
switch (st)
|
|
{
|
|
case ELF_ERR_CANT_OPEN_FILE:
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot open file `%s'"), df->get_name ());
|
|
break;
|
|
case ELF_ERR_BAD_ELF_FORMAT:
|
|
default:
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot read ELF header of `%s'"),
|
|
df->get_name ());
|
|
break;
|
|
}
|
|
delete df;
|
|
return NULL;
|
|
}
|
|
|
|
Elf *
|
|
Elf::find_ancillary_files (char *lo_name)
|
|
{
|
|
// 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)
|
|
{
|
|
Elf_Data *dp = elf_getdata (sec);
|
|
if (dp)
|
|
{
|
|
gnu_debug_file = get_related_file (lo_name, (char *) (dp->d_buf));
|
|
if (gnu_debug_file)
|
|
return gnu_debug_file;
|
|
}
|
|
}
|
|
|
|
sec = elf_get_sec_num (NTXT (".SUNW_ancillary"));
|
|
if (sec > 0)
|
|
{
|
|
Elf_Internal_Shdr *shdr = get_shdr (sec);
|
|
uint64_t check_sum = 0;
|
|
char *ancName = NULL;
|
|
if (shdr)
|
|
{
|
|
Elf_Data *dp = elf_getdata (sec);
|
|
for (int i = 0, sz = (int) (shdr->sh_size / shdr->sh_entsize);
|
|
i < sz; i++)
|
|
{
|
|
Elf64_Ancillary anc;
|
|
if (elf_getancillary (dp, i, &anc) == NULL
|
|
|| anc.a_tag == ANC_SUNW_NULL)
|
|
break;
|
|
if (anc.a_tag == ANC_SUNW_MEMBER)
|
|
ancName = elf_strptr (shdr->sh_link, anc.a_un.a_ptr);
|
|
else if (anc.a_tag == ANC_SUNW_CHECKSUM)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
check_sum = anc.a_un.a_val;
|
|
continue;
|
|
}
|
|
if (check_sum == anc.a_un.a_val)
|
|
ancName = NULL;
|
|
if (ancName)
|
|
{
|
|
Elf *ancElf = get_related_file (lo_name, ancName);
|
|
if (ancElf == NULL)
|
|
continue;
|
|
int ancSec = ancElf->elf_get_sec_num (".SUNW_ancillary");
|
|
if (ancSec > 0)
|
|
{
|
|
Elf_Internal_Shdr *ancHdr = ancElf->get_shdr (ancSec);
|
|
if (ancHdr)
|
|
{
|
|
Elf_Data *anc_dp = ancElf->elf_getdata (ancSec);
|
|
Elf64_Ancillary anc1;
|
|
if (ancElf->elf_getancillary (anc_dp, 0, &anc1)
|
|
&& (anc1.a_tag == ANC_SUNW_CHECKSUM) &&
|
|
anc1.a_un.a_val == anc.a_un.a_val)
|
|
{
|
|
if (ancillary_files == NULL)
|
|
ancillary_files = new Vector<Elf*>(2);
|
|
ancillary_files->append (ancElf);
|
|
}
|
|
else
|
|
append_msg (CMSG_WARN, GTXT ("Load Object: '%s' (checksum Ox%lld). The .anc file '%s' has checksum Ox%llx"),
|
|
STR (fname), (long long) check_sum,
|
|
STR (ancElf->dbeFile->get_location ()),
|
|
(long long) anc1.a_un.a_val);
|
|
}
|
|
}
|
|
ancName = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char*
|
|
Elf::get_location ()
|
|
{
|
|
return dbeFile ? dbeFile->get_location () : fname;
|
|
}
|
|
|
|
#define RET_S(x) if (t == x) return (char *) #x
|
|
|
|
static char *
|
|
get_elf_class_name (int t)
|
|
{
|
|
RET_S (ELFCLASSNONE);
|
|
RET_S (ELFCLASS32);
|
|
RET_S (ELFCLASS64);
|
|
return NTXT ("ELFCLASS_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_data_name (int t)
|
|
{
|
|
RET_S (ELFDATANONE);
|
|
RET_S (ELFDATA2LSB);
|
|
RET_S (ELFDATA2MSB);
|
|
return NTXT ("ELFDATA_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_osabi_name (int t)
|
|
{
|
|
RET_S (ELFOSABI_NONE);
|
|
RET_S (ELFOSABI_HPUX);
|
|
RET_S (ELFOSABI_NETBSD);
|
|
RET_S (ELFOSABI_LINUX);
|
|
RET_S (ELFOSABI_SOLARIS);
|
|
RET_S (ELFOSABI_AIX);
|
|
RET_S (ELFOSABI_IRIX);
|
|
RET_S (ELFOSABI_FREEBSD);
|
|
RET_S (ELFOSABI_TRU64);
|
|
RET_S (ELFOSABI_MODESTO);
|
|
RET_S (ELFOSABI_OPENBSD);
|
|
return NTXT ("ELFOSABI_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_etype_name (int t)
|
|
{
|
|
RET_S (ET_NONE);
|
|
RET_S (ET_REL);
|
|
RET_S (ET_EXEC);
|
|
RET_S (ET_DYN);
|
|
RET_S (ET_CORE);
|
|
RET_S (ET_LOPROC);
|
|
RET_S (ET_HIPROC);
|
|
return NTXT ("ETYPE_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_ptype_name (int t)
|
|
{
|
|
RET_S (PT_NULL);
|
|
RET_S (PT_LOAD);
|
|
RET_S (PT_DYNAMIC);
|
|
RET_S (PT_INTERP);
|
|
RET_S (PT_NOTE);
|
|
RET_S (PT_SHLIB);
|
|
RET_S (PT_PHDR);
|
|
RET_S (PT_TLS);
|
|
RET_S (PT_LOOS);
|
|
RET_S (PT_GNU_EH_FRAME);
|
|
RET_S (PT_GNU_EH_FRAME);
|
|
RET_S (PT_HIOS);
|
|
RET_S (PT_LOPROC);
|
|
RET_S (PT_HIPROC);
|
|
return NTXT ("PTYPE_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_shtype_name (unsigned int t)
|
|
{
|
|
RET_S (SHT_NULL);
|
|
RET_S (SHT_PROGBITS);
|
|
RET_S (SHT_SYMTAB);
|
|
RET_S (SHT_STRTAB);
|
|
RET_S (SHT_RELA);
|
|
RET_S (SHT_HASH);
|
|
RET_S (SHT_DYNAMIC);
|
|
RET_S (SHT_NOTE);
|
|
RET_S (SHT_NOBITS);
|
|
RET_S (SHT_REL);
|
|
RET_S (SHT_SHLIB);
|
|
RET_S (SHT_DYNSYM);
|
|
RET_S (SHT_INIT_ARRAY);
|
|
RET_S (SHT_FINI_ARRAY);
|
|
RET_S (SHT_PREINIT_ARRAY);
|
|
RET_S (SHT_GROUP);
|
|
RET_S (SHT_SYMTAB_SHNDX);
|
|
RET_S (SHT_LOOS);
|
|
RET_S (SHT_SUNW_verdef);
|
|
RET_S (SHT_SUNW_verneed);
|
|
RET_S (SHT_HIOS);
|
|
RET_S (SHT_LOPROC);
|
|
RET_S (SHT_HIPROC);
|
|
RET_S (SHT_LOUSER);
|
|
RET_S (SHT_HIUSER);
|
|
return NTXT ("SHTYPE_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_machine_name (int t)
|
|
{
|
|
RET_S (EM_NONE);
|
|
RET_S (EM_M32);
|
|
RET_S (EM_SPARC);
|
|
RET_S (EM_386);
|
|
RET_S (EM_68K);
|
|
RET_S (EM_88K);
|
|
RET_S (EM_860);
|
|
RET_S (EM_MIPS);
|
|
RET_S (EM_S370);
|
|
RET_S (EM_MIPS_RS3_LE);
|
|
RET_S (EM_SPARC32PLUS);
|
|
RET_S (EM_960);
|
|
RET_S (EM_PPC);
|
|
RET_S (EM_PPC64);
|
|
RET_S (EM_V800);
|
|
RET_S (EM_FR20);
|
|
RET_S (EM_RH32);
|
|
RET_S (EM_RCE);
|
|
RET_S (EM_ARM);
|
|
RET_S (EM_ALPHA);
|
|
RET_S (EM_SH);
|
|
RET_S (EM_SPARCV9);
|
|
RET_S (EM_TRICORE);
|
|
RET_S (EM_ARC);
|
|
RET_S (EM_H8_300);
|
|
RET_S (EM_H8_300H);
|
|
RET_S (EM_H8S);
|
|
RET_S (EM_H8_500);
|
|
RET_S (EM_IA_64);
|
|
RET_S (EM_MIPS_X);
|
|
RET_S (EM_COLDFIRE);
|
|
RET_S (EM_68HC12);
|
|
RET_S (EM_MMA);
|
|
RET_S (EM_PCP);
|
|
RET_S (EM_NCPU);
|
|
RET_S (EM_NDR1);
|
|
RET_S (EM_STARCORE);
|
|
RET_S (EM_ME16);
|
|
RET_S (EM_ST100);
|
|
RET_S (EM_TINYJ);
|
|
RET_S (EM_X86_64);
|
|
RET_S (EM_PDSP);
|
|
RET_S (EM_FX66);
|
|
RET_S (EM_ST9PLUS);
|
|
RET_S (EM_ST7);
|
|
RET_S (EM_68HC16);
|
|
RET_S (EM_68HC11);
|
|
RET_S (EM_68HC08);
|
|
RET_S (EM_68HC05);
|
|
RET_S (EM_SVX);
|
|
RET_S (EM_ST19);
|
|
RET_S (EM_VAX);
|
|
RET_S (EM_CRIS);
|
|
RET_S (EM_JAVELIN);
|
|
RET_S (EM_FIREPATH);
|
|
RET_S (EM_ZSP);
|
|
RET_S (EM_MMIX);
|
|
RET_S (EM_HUANY);
|
|
RET_S (EM_PRISM);
|
|
RET_S (EM_AVR);
|
|
RET_S (EM_FR30);
|
|
RET_S (EM_D10V);
|
|
RET_S (EM_D30V);
|
|
RET_S (EM_V850);
|
|
RET_S (EM_M32R);
|
|
RET_S (EM_MN10300);
|
|
RET_S (EM_MN10200);
|
|
RET_S (EM_PJ);
|
|
RET_S (EM_OPENRISC);
|
|
RET_S (EM_XTENSA);
|
|
return NTXT ("ELFMACHINE_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_version_name (int t)
|
|
{
|
|
RET_S (EV_NONE);
|
|
RET_S (EV_CURRENT);
|
|
return NTXT ("VERSION_UNKNOWN");
|
|
}
|
|
|
|
static char *
|
|
get_elf_ancillary_tag (int t)
|
|
{
|
|
RET_S (ANC_SUNW_NULL);
|
|
RET_S (ANC_SUNW_CHECKSUM);
|
|
RET_S (ANC_SUNW_MEMBER);
|
|
RET_S (ANC_SUNW_NUM);
|
|
return NTXT ("ANCILLARY_TAG_UNKNOWN");
|
|
}
|
|
|
|
#define ADD_S(x) if ((f & (x)) == (x)) { sb->append(' '); sb->append(#x); f &= ~(x); }
|
|
|
|
static void
|
|
dump_sh_flags (StringBuilder *sb, long long flags)
|
|
{
|
|
long long f = flags;
|
|
if (f != 0)
|
|
{
|
|
sb->append (NTXT (" ["));
|
|
ADD_S (SHF_WRITE)
|
|
ADD_S (SHF_ALLOC)
|
|
ADD_S (SHF_EXECINSTR)
|
|
ADD_S (SHF_MERGE)
|
|
ADD_S (SHF_STRINGS)
|
|
ADD_S (SHF_INFO_LINK)
|
|
ADD_S (SHF_LINK_ORDER)
|
|
ADD_S (SHF_OS_NONCONFORMING)
|
|
ADD_S (SHF_GROUP)
|
|
ADD_S (SHF_TLS)
|
|
ADD_S (SHF_SUNW_ABSENT)
|
|
ADD_S (SHF_EXCLUDE)
|
|
if (f != 0 && f != flags)
|
|
sb->appendf (NTXT (" 0x%llx"), (long long) f);
|
|
sb->append (NTXT (" ]"));
|
|
}
|
|
sb->append (NTXT ("\n"));
|
|
}
|
|
|
|
static void
|
|
dump_p_flags (StringBuilder *sb, long long flags)
|
|
{
|
|
long long f = flags;
|
|
if (f != 0)
|
|
{
|
|
sb->append (NTXT (" ["));
|
|
ADD_S (PF_X)
|
|
ADD_S (PF_W)
|
|
ADD_S (PF_R)
|
|
ADD_S (PF_MASKPROC)
|
|
if (f != 0 && f != flags)
|
|
sb->appendf (NTXT (" 0x%llx"), (long long) f);
|
|
sb->append (NTXT (" ]"));
|
|
}
|
|
sb->append (NTXT ("\n"));
|
|
}
|
|
|
|
char *
|
|
Elf::dump ()
|
|
{
|
|
StringBuilder sb;
|
|
sb.sprintf (NTXT ("ELF Header: %s\n"), fname ? fname : GTXT ("(unknown)"));
|
|
if (ehdrp == NULL)
|
|
{
|
|
sb.appendf (GTXT ("\n\n Cannot read Elf header\n"));
|
|
return sb.toString ();
|
|
}
|
|
sb.appendf (NTXT (" %-15s "), NTXT ("e_ident"));
|
|
for (int i = 0; i < EI_NIDENT; i++)
|
|
sb.appendf (NTXT ("%x"), ehdrp->e_ident[i]);
|
|
sb.append (NTXT ("\n"));
|
|
char *fmt0 = NTXT (" %-15s %10lld ( %s )\n");
|
|
char *fmt1 = NTXT (" %-15s 0x%08llx ( %lld )\n");
|
|
char *fmt2 = NTXT (" %-15s 0x%08llx");
|
|
sb.appendf (fmt0, NTXT ("EI_CLASS"), (long long) ehdrp->e_ident[EI_CLASS],
|
|
get_elf_class_name (ehdrp->e_ident[EI_CLASS]));
|
|
sb.appendf (fmt0, NTXT ("EI_DATA"), (long long) ehdrp->e_ident[EI_DATA],
|
|
get_elf_data_name (ehdrp->e_ident[EI_DATA]));
|
|
sb.appendf (fmt0, NTXT ("EI_OSABI"), (long long) ehdrp->e_ident[EI_OSABI],
|
|
get_elf_osabi_name (ehdrp->e_ident[EI_OSABI]));
|
|
sb.appendf (fmt0, NTXT ("e_type"), (long long) ehdrp->e_type,
|
|
get_elf_etype_name (ehdrp->e_type));
|
|
sb.appendf (fmt0, NTXT ("e_machine"), (long long) ehdrp->e_machine,
|
|
get_elf_machine_name (ehdrp->e_machine));
|
|
sb.appendf (fmt0, NTXT ("e_version"), (long long) ehdrp->e_version,
|
|
get_elf_version_name (ehdrp->e_version));
|
|
sb.appendf (fmt1, NTXT ("e_entry"), (long long) ehdrp->e_entry,
|
|
(long long) ehdrp->e_entry);
|
|
sb.appendf (fmt1, NTXT ("e_phoff"), (long long) ehdrp->e_phoff,
|
|
(long long) ehdrp->e_phoff);
|
|
sb.appendf (fmt1, NTXT ("e_shoff"), (long long) ehdrp->e_shoff,
|
|
(long long) ehdrp->e_shoff);
|
|
sb.appendf (fmt1, NTXT ("e_flags"), (long long) ehdrp->e_flags,
|
|
(long long) ehdrp->e_flags);
|
|
sb.appendf (fmt1, NTXT ("e_ehsize"), (long long) ehdrp->e_ehsize,
|
|
(long long) ehdrp->e_ehsize);
|
|
sb.appendf (fmt1, NTXT ("e_phentsize"), (long long) ehdrp->e_phentsize,
|
|
(long long) ehdrp->e_phentsize);
|
|
sb.appendf (fmt1, NTXT ("e_phnum"), (long long) ehdrp->e_phnum,
|
|
(long long) ehdrp->e_phnum);
|
|
sb.appendf (fmt1, NTXT ("e_shentsize"), (long long) ehdrp->e_shentsize,
|
|
(long long) ehdrp->e_shentsize);
|
|
sb.appendf (fmt1, NTXT ("e_shnum"), (long long) ehdrp->e_shnum,
|
|
(long long) ehdrp->e_shnum);
|
|
sb.appendf (fmt1, NTXT ("e_shstrndx"), (long long) ehdrp->e_shstrndx,
|
|
(long long) ehdrp->e_shstrndx);
|
|
|
|
for (unsigned int i = 0; i < ehdrp->e_phnum; i++)
|
|
{
|
|
sb.appendf (NTXT ("\nProgram Header[%d]:\n"), i);
|
|
Elf_Internal_Phdr *phdr = get_phdr (i);
|
|
if (phdr == NULL)
|
|
{
|
|
sb.appendf (NTXT (" ERROR: get_phdr(%d) failed\n"), i);
|
|
continue;
|
|
}
|
|
sb.appendf (fmt0, "p_type", (long long) phdr->p_type,
|
|
get_elf_ptype_name (phdr->p_type));
|
|
sb.appendf (fmt2, "p_flags", (long long) phdr->p_flags);
|
|
dump_p_flags (&sb, phdr->p_flags);
|
|
sb.appendf (fmt1, "p_offset", (long long) phdr->p_offset,
|
|
(long long) phdr->p_offset);
|
|
sb.appendf (fmt1, "p_vaddr", (long long) phdr->p_vaddr,
|
|
(long long) phdr->p_vaddr);
|
|
sb.appendf (fmt1, "p_paddr", (long long) phdr->p_paddr,
|
|
(long long) phdr->p_paddr);
|
|
sb.appendf (fmt1, "p_filesz", (long long) phdr->p_filesz,
|
|
(long long) phdr->p_filesz);
|
|
sb.appendf (fmt1, "p_memsz", (long long) phdr->p_memsz,
|
|
(long long) phdr->p_memsz);
|
|
sb.appendf (fmt1, "p_align", (long long) phdr->p_align,
|
|
(long long) phdr->p_align);
|
|
}
|
|
|
|
for (unsigned int i = 1; i < ehdrp->e_shnum; i++)
|
|
{
|
|
sb.appendf (NTXT ("\nSection Header[%d]:\n"), i);
|
|
Elf_Internal_Shdr *shdr = get_shdr (i);
|
|
if (shdr == NULL)
|
|
{
|
|
sb.appendf (NTXT (" ERROR: get_shdr(%d) failed\n"), i);
|
|
continue;
|
|
}
|
|
char *s = get_sec_name (i);
|
|
sb.appendf (fmt0, "sh_name", (long long) shdr->sh_name,
|
|
s ? s : NTXT ("NULL"));
|
|
sb.appendf (fmt0, "sh_type", (long long) shdr->sh_type,
|
|
get_elf_shtype_name (shdr->sh_type));
|
|
sb.appendf (fmt2, "sh_flags", (long long) shdr->sh_flags);
|
|
dump_sh_flags (&sb, shdr->sh_flags);
|
|
sb.appendf (fmt1, "sh_addr", (long long) shdr->sh_addr,
|
|
(long long) shdr->sh_addr);
|
|
sb.appendf (fmt1, "sh_offset", (long long) shdr->sh_offset,
|
|
(long long) shdr->sh_offset);
|
|
sb.appendf (fmt1, "sh_size", (long long) shdr->sh_size,
|
|
(long long) shdr->sh_size);
|
|
sb.appendf (fmt1, "sh_link", (long long) shdr->sh_link,
|
|
(long long) shdr->sh_link);
|
|
sb.appendf (fmt1, "sh_info", (long long) shdr->sh_info,
|
|
(long long) shdr->sh_info);
|
|
sb.appendf (fmt1, "sh_addralign", (long long) shdr->sh_addralign,
|
|
(long long) shdr->sh_addralign);
|
|
sb.appendf (fmt1, "sh_entsize", (long long) shdr->sh_entsize,
|
|
(long long) shdr->sh_entsize);
|
|
}
|
|
|
|
for (unsigned int i = 1; i < ehdrp->e_shnum; i++)
|
|
{
|
|
Elf_Internal_Shdr *shdr = get_shdr (i);
|
|
if (shdr == NULL)
|
|
continue;
|
|
char *secName = get_sec_name (i);
|
|
if (secName == NULL)
|
|
continue;
|
|
if (strcmp (NTXT (".SUNW_ancillary"), secName) == 0)
|
|
{
|
|
sb.appendf (NTXT ("\nSection[%d]: %s\n"), i, secName);
|
|
Elf_Data *dp = elf_getdata (i);
|
|
for (int j = 0, cnt = (int) (shdr->sh_size / shdr->sh_entsize);
|
|
j < cnt; j++)
|
|
{
|
|
Elf64_Ancillary anc;
|
|
if (elf_getancillary (dp, j, &anc) == NULL)
|
|
break;
|
|
sb.appendf (NTXT ("%10d %-20s 0x%08llx %6lld"), j,
|
|
get_elf_ancillary_tag ((int) anc.a_tag),
|
|
(long long) anc.a_un.a_ptr, (long long) anc.a_un.a_ptr);
|
|
if (anc.a_tag == ANC_SUNW_MEMBER)
|
|
sb.appendf (NTXT (" %s\n"), STR (elf_strptr (shdr->sh_link, anc.a_un.a_ptr)));
|
|
else
|
|
sb.append (NTXT ("\n"));
|
|
}
|
|
}
|
|
}
|
|
return sb.toString ();
|
|
}
|
|
|
|
void
|
|
Elf::dump_elf_sec ()
|
|
{
|
|
if (!DUMP_ELF_SEC)
|
|
return;
|
|
if (ehdrp == NULL)
|
|
return;
|
|
Dprintf (DUMP_ELF_SEC, "======= DwarfLib::dump_elf_sec\n"
|
|
" N |type|flags| sh_addr | sh_offset | sh_size | sh_link |"
|
|
" sh_info | sh_addralign | sh_entsize | sh_name | name\n");
|
|
for (unsigned int sec = 1; sec < ehdrp->e_shnum; sec++)
|
|
{
|
|
Elf_Internal_Shdr *shdr = get_shdr (sec);
|
|
if (shdr == NULL)
|
|
continue;
|
|
char *name = elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
|
|
Dprintf (DUMP_ELF_SEC, "%3d:%3d |%4d |%9lld | %9lld |%8lld |%8lld |"
|
|
"%8lld |%14d |%11lld | %6lld %s\n",
|
|
sec, (int) shdr->sh_type, (int) shdr->sh_flags,
|
|
(long long) shdr->sh_addr, (long long) shdr->sh_offset,
|
|
(long long) shdr->sh_size, (long long) shdr->sh_link,
|
|
(long long) shdr->sh_info,
|
|
(int) shdr->sh_addralign, (long long) shdr->sh_entsize,
|
|
(long long) shdr->sh_name, name ? name : NTXT ("NULL"));
|
|
}
|
|
Dprintf (DUMP_ELF_SEC, NTXT ("\n"));
|
|
}
|