// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: elfsym.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// The above named 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 work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// ========== Copyright Header End ============================================
///////////////////////////////////////////////////////////////
// elfsym: Extract Symbols for .text, .data and .bss
// sections of ELF file using libelf interface.
// Note: use 'Extended ELF Section indexes' if required,
// decode a corresponding SHT_SYMTAB_SHNDX
// Copyright 2006 Sun Microsystems, Inc. All rights reserved.
// Use is subject to license terms.
// only one routine in exported interface
int load_symbols ( char* elf_fname
, uint64_t text_base
, uint64_t data_base
, uint32_t context
);
// set level of debug info
// If you need to build a standalong elf_file utility
// set STANDALONG to be defined, build it with command
// CC -o <util_name> elf_file.cc
// usage: <util_name> <path/elf_file_name>
// output elf symbol info to the terminal
extern SymTable
*g_sym_table
; // symbol table
int main(int argc
, char **argv
)
ui
->output("usage: %s elf_file \n", argv
[0]);
return load_symbols(fname
,0,0,Symbol::ANY_CONTEXT
);
//////////////////////////////////////////////////////
// Extract defined symbols from
// .symtab and .dynsym sections
// get module name by stripping path from file name
char *path_name
=strtok(file
, "/");
char *module_name
= file
;
while (path_name
=strtok(NULL
, "/"))
if (gelf_getehdr(elf
, &ehdr
) == 0)
ui
->error( "%s: elf_getehdr() failed: %s\n",
char *filetype
= "Other";
filetype
= "Reallocatable";
filetype
= "Shared Object";
ui
->output("loading symbols for %s - %s file.\n", module_name
, filetype
);
if (elf_getshstrndx(elf
, &shstrndx
) == 0)
ui
->error( "%s: elf_getshstrndx() failed: %s\n",
// find .text, .data and .bss section headers
text_shdr
.sh_type
= SHT_NULL
;
data_shdr
.sh_type
= SHT_NULL
;
bss_shdr
.sh_type
= SHT_NULL
;
uint32_t text_idx
, data_idx
, bss_idx
;
while ((scn
= elf_nextscn(elf
, scn
)) != 0)
if (gelf_getshdr(scn
, &shdr
) == 0)
"%s: elf_getshdr() failed: %s\n",
char *sname
= elf_strptr(elf
, shstrndx
, shdr
.sh_name
);
if (strcmp(sname
, ".data")==0)
else if (strcmp(sname
, ".bss" )==0)
else if (strcmp(sname
, ".text")==0)
if (text_shdr
.sh_type
==SHT_NULL
)
ui
->error(" there is no text section \n");
ui
->output(".text #%d sh_addr=0x%llx, sh_size=0x%llx, sh_offset=0x%llx, sh_addralign=0x%llx \n",
text_idx
,text_shdr
.sh_addr
, text_shdr
.sh_size
, text_shdr
.sh_offset
, text_shdr
.sh_addralign
);
if (Verbose
&& data_shdr
.sh_type
!=SHT_NULL
)
ui
->output(".data #%d sh_addr=0x%llx, sh_size=0x%llx, sh_offset=0x%llx, sh_addralign=0x%llx \n",
data_idx
,data_shdr
.sh_addr
, data_shdr
.sh_size
, data_shdr
.sh_offset
, data_shdr
.sh_addralign
);
if (Verbose
&& bss_shdr
.sh_type
!=SHT_NULL
)
ui
->output(".bss #%d sh_addr=0x%llx, sh_size=0x%llx, sh_offset=0x%llx, sh_addralign=0x%llx \n",
bss_idx
,bss_shdr
.sh_addr
, bss_shdr
.sh_size
, bss_shdr
.sh_offset
, bss_shdr
.sh_addralign
);
// uninitialized data (bss) segment is located immediately
// after initialized data segment
(data_shdr
.sh_type
!=SHT_NULL
) // data section is present
&& (bss_shdr
.sh_addr
== 0) // not absolute address
bss_offset
= (bss_shdr
.sh_offset
- data_shdr
.sh_offset
) &
~(uint64_t(bss_shdr
.sh_addralign
) - 1);
ui
->output(".bss addr offset = 0x%llx \n", bss_offset
);
// find .dynsym and .symtab sections
while ((scn
= elf_nextscn(elf
, scn
)) != 0)
if (gelf_getshdr(scn
, &shdr
) == 0)
ui
->error("%s: elf_getshdr() failed: %s\n",
if ((shdr
.sh_type
!= SHT_SYMTAB
) &&
(shdr
.sh_type
!= SHT_DYNSYM
))
// Get the data associated with the Symbol
if ((symdata
= elf_getdata(scn
, 0)) == 0)
ui
->error("%s: elf_getdata() failed: %s\n",
// Print symbol table title and header for symbol display
ui
->output("\nSymTab: %s:%s\n", file
,
elf_strptr(elf
, shstrndx
, shdr
.sh_name
));
ui
->output(" index value size type "
"bind oth shndx name\n");
// iterate over the symbol table
symcnt
= shdr
.sh_size
/ shdr
.sh_entsize
;
for (ndx
= 0; ndx
< symcnt
; ndx
++)
if (gelf_getsymshndx(symdata
, shndxdata
, ndx
,
"%s: gelf_getsymshndx() failed: %s\n",
// Check to see if this symbol's st_shndx
// is using the 'Extended SHNDX table' for
// If it is - and we havn't searched before,
// go find the associated SHT_SYMTAB_SHNDX
if ((sym
.st_shndx
== SHN_XINDEX
) &&
(shndxdata
== 0) && (nosymshndx
== 0))
symscnndx
= elf_ndxscn(scn
);
while ((_scn
= elf_nextscn(elf
, _scn
)) != 0)
if (gelf_getshdr(_scn
, &_shdr
) == 0)
// We've found the Symtab SHNDX table
// if it's of type SHT_SYMTAB_SHNDX
// and it's shdr.sh_link points to the
// section index for the current symbol
(_shdr
.sh_link
== symscnndx
))
elf_getdata(_scn
, 0)) != 0)
(gelf_getsymshndx(symdata
, shndxdata
, ndx
,
"%s: gelf_getsymshndx() "
// No Symtab SHNDX table was found. We could
// give a fatal error here - instead we'll
// just mark that fact and display as much of
// the symbol table as we can. Any symbol
// displayed with a XINDX section index has
// a bogus value - skip it
// Decode the type & binding information
type
= GELF_ST_TYPE(sym
.st_info
);
bind
= GELF_ST_BIND(sym
.st_info
);
// section index to which this symbol refer to
if (sym
.st_shndx
< SHN_LORESERVE
)
else if ((sym
.st_shndx
!= SHN_XINDEX
) ||
// skip zero size symbols
uint64_t va
= sym
.st_value
;
// check if it is in text section
if ((text_shdr
.sh_type
!= SHT_NULL
) && (shndx
== text_idx
))
else if ( type
== STT_OBJECT
) //data symbol
if ((data_shdr
.sh_type
!= SHT_NULL
) && (shndx
== data_idx
))
else if ((bss_shdr
.sh_type
!= SHT_NULL
) && (shndx
== bss_idx
))
if ( bind
== STB_GLOBAL
)
else if (bind
== STB_LOCAL
)
// local uninitialized data is located at the end
va
+= (data_base
+ bss_offset
);
char *sym_name
= elf_strptr(elf
, shdr
.sh_link
, sym
.st_name
);
// check if symbol is already there
Symbol
*s
= g_sym_table
->find(sym_name
);
if (s
== NULL
|| s
->vaddr() != va
|| s
->size() != sym
.st_size
)
g_sym_table
->add(module_name
, sym_name
, va
, sym
.st_size
, context
);
const int INTSTRLEN
= 32;
char shndxbuf
[INTSTRLEN
];
static const char *symbind
[STB_NUM
] = {
static const char *symtype
[STT_NUM
] = {
/* STT_SECTION */ "SECT",
snprintf(typebuf
, INTSTRLEN
, "%d", type
);
snprintf(bindbuf
, INTSTRLEN
, "%d", bind
);
shndxstr
= (const char *)"UNDEF";
shndxstr
= (const char *)"ABS";
else if (shndx
== SHN_COMMON
)
shndxstr
= (const char *)"COMM";
else if (shndx
== SHN_XINDEX
)
shndxstr
= (const char *)"XIND";
snprintf(shndxbuf
, INTSTRLEN
, "%ld", shndx
);
(void) snprintf(shndxbuf
, INTSTRLEN
,
//char *this_sh_name = elf_strptr(elf, shstrndx, shndx);
// display the symbol entry
ui
->otput("[%3d] 0x%08llx 0x%08llx %-4s %-6s %2d %5s %s \n",
ndx
, va
/* sym.st_value */, sym
.st_size
,
typestr
, bindstr
, sym
.st_other
, shndxstr
,
//////////////////////////////////////////////////////////////////
// open an ELF file using
// elf_begin(ELF_C_READ) and examine search the ELF file
// for either a SHT_SYMTAB or SHT_DYNSYM symbol table.
// If it finds either - it will extract the contents of
get_symbols(elf
, file
, text_base
, data_base
,context
);
// Archives contain multiple ELF files, which can each
// in turn be examined with libelf.
// Iterate over each member of the
// archive and recursivly call process_elf() for processing.
while ((_elf
= elf_begin(fd
, cmd
, elf
)) != 0)
arhdr
= elf_getarhdr(_elf
);
// Build up file names based off of
// 'archivename(membername)'.
snprintf(buffer
, 1024, "%s(%s)", file
, arhdr
->ar_name
);
// recursivly process the ELF members.
process_elf(_elf
, buffer
, fd
, 1, text_base
, data_base
, context
);
ui
->error("%s: unexpected elf_kind(): 0x%x\n",
////////////////////////////////////////////////////////////////////
* Initialize the elf library, must be called before elf_begin()
if (elf_version(EV_CURRENT
) == EV_NONE
)
ui
->error( "elf_version() failed: %s\n", elf_errmsg(0));
if ((fd
= open(elf_fname
, O_RDONLY
)) == -1)
// open an Elf descriptor Read-Only
if ((elf
= elf_begin(fd
, ELF_C_READ
, 0)) == NULL
)
ui
->error( "elf_begin() failed: %s\n", elf_errmsg(0));
// Process elf descriptor
process_elf(elf
, elf_fname
, fd
, 0, text_base
, data_base
, context
);