2012-04-20 01:59:55 +04:00
/*
* sortextable . h
*
2012-04-24 22:23:14 +04:00
* Copyright 2011 - 2012 Cavium , Inc .
2012-04-20 01:59:55 +04:00
*
* Some of this code was taken out of recordmcount . h written by :
*
* Copyright 2009 John F . Reiser < jreiser @ BitWagon . com > . All rights reserved .
* Copyright 2010 Steven Rostedt < srostedt @ redhat . com > , Red Hat Inc .
*
*
* Licensed under the GNU General Public License , version 2 ( GPLv2 ) .
*/
# undef extable_ent_size
# undef compare_extable
# undef do_func
# undef Elf_Addr
# undef Elf_Ehdr
# undef Elf_Shdr
# undef Elf_Rel
# undef Elf_Rela
# undef Elf_Sym
# undef ELF_R_SYM
# undef Elf_r_sym
# undef ELF_R_INFO
# undef Elf_r_info
# undef ELF_ST_BIND
# undef ELF_ST_TYPE
# undef fn_ELF_R_SYM
# undef fn_ELF_R_INFO
# undef uint_t
2012-04-24 22:23:14 +04:00
# undef _r
2012-04-20 01:59:55 +04:00
# undef _w
# ifdef SORTEXTABLE_64
# define extable_ent_size 16
# define compare_extable compare_extable_64
# define do_func do64
# define Elf_Addr Elf64_Addr
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
# define Elf_Rel Elf64_Rel
# define Elf_Rela Elf64_Rela
# define Elf_Sym Elf64_Sym
# define ELF_R_SYM ELF64_R_SYM
# define Elf_r_sym Elf64_r_sym
# define ELF_R_INFO ELF64_R_INFO
# define Elf_r_info Elf64_r_info
# define ELF_ST_BIND ELF64_ST_BIND
# define ELF_ST_TYPE ELF64_ST_TYPE
# define fn_ELF_R_SYM fn_ELF64_R_SYM
# define fn_ELF_R_INFO fn_ELF64_R_INFO
# define uint_t uint64_t
2012-04-24 22:23:14 +04:00
# define _r r8
2012-04-20 01:59:55 +04:00
# define _w w8
# else
# define extable_ent_size 8
# define compare_extable compare_extable_32
# define do_func do32
# define Elf_Addr Elf32_Addr
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
# define Elf_Rel Elf32_Rel
# define Elf_Rela Elf32_Rela
# define Elf_Sym Elf32_Sym
# define ELF_R_SYM ELF32_R_SYM
# define Elf_r_sym Elf32_r_sym
# define ELF_R_INFO ELF32_R_INFO
# define Elf_r_info Elf32_r_info
# define ELF_ST_BIND ELF32_ST_BIND
# define ELF_ST_TYPE ELF32_ST_TYPE
# define fn_ELF_R_SYM fn_ELF32_R_SYM
# define fn_ELF_R_INFO fn_ELF32_R_INFO
# define uint_t uint32_t
2012-04-24 22:23:14 +04:00
# define _r r
2012-04-20 01:59:55 +04:00
# define _w w
# endif
static int compare_extable ( const void * a , const void * b )
{
2012-04-24 22:23:14 +04:00
Elf_Addr av = _r ( a ) ;
Elf_Addr bv = _r ( b ) ;
2012-04-20 01:59:55 +04:00
2012-04-24 22:23:14 +04:00
if ( av < bv )
2012-04-20 01:59:55 +04:00
return - 1 ;
2012-04-24 22:23:14 +04:00
if ( av > bv )
2012-04-20 01:59:55 +04:00
return 1 ;
return 0 ;
}
static void
2012-04-24 22:23:14 +04:00
do_func ( Elf_Ehdr * ehdr , char const * const fname , table_sort_t custom_sort )
2012-04-20 01:59:55 +04:00
{
Elf_Shdr * shdr ;
Elf_Shdr * shstrtab_sec ;
Elf_Shdr * strtab_sec = NULL ;
Elf_Shdr * symtab_sec = NULL ;
Elf_Shdr * extab_sec = NULL ;
Elf_Sym * sym ;
Elf_Sym * sort_needed_sym ;
Elf_Shdr * sort_needed_sec ;
2012-04-24 22:23:14 +04:00
Elf_Rel * relocs = NULL ;
int relocs_size ;
2012-04-20 01:59:55 +04:00
uint32_t * sort_done_location ;
const char * secstrtab ;
const char * strtab ;
2012-04-24 22:23:14 +04:00
char * extab_image ;
int extab_index = 0 ;
2012-04-20 01:59:55 +04:00
int i ;
int idx ;
2012-04-24 22:23:14 +04:00
shdr = ( Elf_Shdr * ) ( ( char * ) ehdr + _r ( & ehdr - > e_shoff ) ) ;
shstrtab_sec = shdr + r2 ( & ehdr - > e_shstrndx ) ;
secstrtab = ( const char * ) ehdr + _r ( & shstrtab_sec - > sh_offset ) ;
for ( i = 0 ; i < r2 ( & ehdr - > e_shnum ) ; i + + ) {
idx = r ( & shdr [ i ] . sh_name ) ;
if ( strcmp ( secstrtab + idx , " __ex_table " ) = = 0 ) {
2012-04-20 01:59:55 +04:00
extab_sec = shdr + i ;
2012-04-24 22:23:14 +04:00
extab_index = i ;
}
if ( ( r ( & shdr [ i ] . sh_type ) = = SHT_REL | |
r ( & shdr [ i ] . sh_type ) = = SHT_RELA ) & &
r ( & shdr [ i ] . sh_info ) = = extab_index ) {
relocs = ( void * ) ehdr + _r ( & shdr [ i ] . sh_offset ) ;
relocs_size = _r ( & shdr [ i ] . sh_size ) ;
}
2012-04-20 01:59:55 +04:00
if ( strcmp ( secstrtab + idx , " .symtab " ) = = 0 )
symtab_sec = shdr + i ;
if ( strcmp ( secstrtab + idx , " .strtab " ) = = 0 )
strtab_sec = shdr + i ;
}
if ( strtab_sec = = NULL ) {
fprintf ( stderr , " no .strtab in file: %s \n " , fname ) ;
fail_file ( ) ;
}
if ( symtab_sec = = NULL ) {
fprintf ( stderr , " no .symtab in file: %s \n " , fname ) ;
fail_file ( ) ;
}
if ( extab_sec = = NULL ) {
fprintf ( stderr , " no __ex_table in file: %s \n " , fname ) ;
fail_file ( ) ;
}
2012-04-24 22:23:14 +04:00
strtab = ( const char * ) ehdr + _r ( & strtab_sec - > sh_offset ) ;
2012-04-20 01:59:55 +04:00
2012-04-24 22:23:14 +04:00
extab_image = ( void * ) ehdr + _r ( & extab_sec - > sh_offset ) ;
if ( custom_sort ) {
custom_sort ( extab_image , _r ( & extab_sec - > sh_size ) ) ;
} else {
int num_entries = _r ( & extab_sec - > sh_size ) / extable_ent_size ;
qsort ( extab_image , num_entries ,
extable_ent_size , compare_extable ) ;
}
/* If there were relocations, we no longer need them. */
if ( relocs )
memset ( relocs , 0 , relocs_size ) ;
2012-04-20 01:59:55 +04:00
/* find main_extable_sort_needed */
sort_needed_sym = NULL ;
2012-04-24 22:23:14 +04:00
for ( i = 0 ; i < _r ( & symtab_sec - > sh_size ) / sizeof ( Elf_Sym ) ; i + + ) {
sym = ( void * ) ehdr + _r ( & symtab_sec - > sh_offset ) ;
2012-04-20 01:59:55 +04:00
sym + = i ;
if ( ELF_ST_TYPE ( sym - > st_info ) ! = STT_OBJECT )
continue ;
2012-04-24 22:23:14 +04:00
idx = r ( & sym - > st_name ) ;
2012-04-20 01:59:55 +04:00
if ( strcmp ( strtab + idx , " main_extable_sort_needed " ) = = 0 ) {
sort_needed_sym = sym ;
break ;
}
}
if ( sort_needed_sym = = NULL ) {
fprintf ( stderr ,
" no main_extable_sort_needed symbol in file: %s \n " ,
fname ) ;
fail_file ( ) ;
}
2012-04-24 22:23:14 +04:00
sort_needed_sec = & shdr [ r2 ( & sort_needed_sym - > st_shndx ) ] ;
2012-04-20 01:59:55 +04:00
sort_done_location = ( void * ) ehdr +
2012-04-24 22:23:14 +04:00
_r ( & sort_needed_sec - > sh_offset ) +
_r ( & sort_needed_sym - > st_value ) -
_r ( & sort_needed_sec - > sh_addr ) ;
2012-04-20 01:59:55 +04:00
2012-11-27 13:18:00 +04:00
#if 0
2012-04-20 01:59:55 +04:00
printf ( " sort done marker at %lx \n " ,
2012-04-24 22:23:14 +04:00
( unsigned long ) ( ( char * ) sort_done_location - ( char * ) ehdr ) ) ;
# endif
2012-04-20 01:59:55 +04:00
/* We sorted it, clear the flag. */
2012-04-24 22:23:14 +04:00
w ( 0 , sort_done_location ) ;
2012-04-20 01:59:55 +04:00
}