2019-08-30 16:26:37 +03:00
# include "dso.h"
2012-08-06 08:41:21 +04:00
# include "symbol.h"
2019-08-30 16:26:37 +03:00
# include "symsrc.h"
2012-08-06 08:41:21 +04:00
2017-04-18 16:46:11 +03:00
# include <errno.h>
2019-01-22 16:14:55 +03:00
# include <unistd.h>
2012-08-06 08:41:22 +04:00
# include <stdio.h>
# include <fcntl.h>
# include <string.h>
2019-07-04 17:21:24 +03:00
# include <stdlib.h>
2012-08-06 08:41:22 +04:00
# include <byteswap.h>
# include <sys/stat.h>
2019-07-04 17:32:27 +03:00
# include <linux/zalloc.h>
2019-09-03 16:56:06 +03:00
# include <internal/lib.h>
2012-08-06 08:41:22 +04:00
static bool check_need_swap ( int file_endian )
2012-08-06 08:41:21 +04:00
{
2012-08-06 08:41:22 +04:00
const int data = 1 ;
u8 * check = ( u8 * ) & data ;
int host_endian ;
if ( check [ 0 ] = = 1 )
host_endian = ELFDATA2LSB ;
else
host_endian = ELFDATA2MSB ;
return host_endian ! = file_endian ;
2012-08-06 08:41:21 +04:00
}
2012-08-06 08:41:22 +04:00
# define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
# define NT_GNU_BUILD_ID 3
static int read_build_id ( void * note_data , size_t note_len , void * bf ,
size_t size , bool need_swap )
2012-08-06 08:41:21 +04:00
{
2012-08-06 08:41:22 +04:00
struct {
u32 n_namesz ;
u32 n_descsz ;
u32 n_type ;
} * nhdr ;
void * ptr ;
ptr = note_data ;
while ( ptr < ( note_data + note_len ) ) {
const char * name ;
size_t namesz , descsz ;
nhdr = ptr ;
if ( need_swap ) {
nhdr - > n_namesz = bswap_32 ( nhdr - > n_namesz ) ;
nhdr - > n_descsz = bswap_32 ( nhdr - > n_descsz ) ;
nhdr - > n_type = bswap_32 ( nhdr - > n_type ) ;
}
namesz = NOTE_ALIGN ( nhdr - > n_namesz ) ;
descsz = NOTE_ALIGN ( nhdr - > n_descsz ) ;
ptr + = sizeof ( * nhdr ) ;
name = ptr ;
ptr + = namesz ;
if ( nhdr - > n_type = = NT_GNU_BUILD_ID & &
nhdr - > n_namesz = = sizeof ( " GNU " ) ) {
if ( memcmp ( name , " GNU " , sizeof ( " GNU " ) ) = = 0 ) {
size_t sz = min ( size , descsz ) ;
memcpy ( bf , ptr , sz ) ;
memset ( bf + sz , 0 , size - sz ) ;
return 0 ;
}
}
ptr + = descsz ;
}
2012-08-06 08:41:21 +04:00
return - 1 ;
}
2012-09-11 02:15:03 +04:00
int filename__read_debuglink ( const char * filename __maybe_unused ,
char * debuglink __maybe_unused ,
size_t size __maybe_unused )
2012-08-06 08:41:21 +04:00
{
return - 1 ;
}
2012-08-06 08:41:22 +04:00
/*
* Just try PT_NOTE header otherwise fails
*/
int filename__read_build_id ( const char * filename , void * bf , size_t size )
{
FILE * fp ;
int ret = - 1 ;
bool need_swap = false ;
u8 e_ident [ EI_NIDENT ] ;
size_t buf_size ;
void * buf ;
int i ;
fp = fopen ( filename , " r " ) ;
if ( fp = = NULL )
return - 1 ;
if ( fread ( e_ident , sizeof ( e_ident ) , 1 , fp ) ! = 1 )
goto out ;
if ( memcmp ( e_ident , ELFMAG , SELFMAG ) | |
e_ident [ EI_VERSION ] ! = EV_CURRENT )
goto out ;
need_swap = check_need_swap ( e_ident [ EI_DATA ] ) ;
/* for simplicity */
fseek ( fp , 0 , SEEK_SET ) ;
if ( e_ident [ EI_CLASS ] = = ELFCLASS32 ) {
Elf32_Ehdr ehdr ;
Elf32_Phdr * phdr ;
if ( fread ( & ehdr , sizeof ( ehdr ) , 1 , fp ) ! = 1 )
goto out ;
if ( need_swap ) {
ehdr . e_phoff = bswap_32 ( ehdr . e_phoff ) ;
ehdr . e_phentsize = bswap_16 ( ehdr . e_phentsize ) ;
ehdr . e_phnum = bswap_16 ( ehdr . e_phnum ) ;
}
buf_size = ehdr . e_phentsize * ehdr . e_phnum ;
buf = malloc ( buf_size ) ;
if ( buf = = NULL )
goto out ;
fseek ( fp , ehdr . e_phoff , SEEK_SET ) ;
if ( fread ( buf , buf_size , 1 , fp ) ! = 1 )
goto out_free ;
for ( i = 0 , phdr = buf ; i < ehdr . e_phnum ; i + + , phdr + + ) {
void * tmp ;
2014-12-16 05:16:12 +03:00
long offset ;
2012-08-06 08:41:22 +04:00
if ( need_swap ) {
phdr - > p_type = bswap_32 ( phdr - > p_type ) ;
phdr - > p_offset = bswap_32 ( phdr - > p_offset ) ;
phdr - > p_filesz = bswap_32 ( phdr - > p_filesz ) ;
}
if ( phdr - > p_type ! = PT_NOTE )
continue ;
buf_size = phdr - > p_filesz ;
2014-12-16 05:16:12 +03:00
offset = phdr - > p_offset ;
2012-08-06 08:41:22 +04:00
tmp = realloc ( buf , buf_size ) ;
if ( tmp = = NULL )
goto out_free ;
buf = tmp ;
2014-12-16 05:16:12 +03:00
fseek ( fp , offset , SEEK_SET ) ;
2012-08-06 08:41:22 +04:00
if ( fread ( buf , buf_size , 1 , fp ) ! = 1 )
goto out_free ;
ret = read_build_id ( buf , buf_size , bf , size , need_swap ) ;
if ( ret = = 0 )
ret = size ;
break ;
}
} else {
Elf64_Ehdr ehdr ;
Elf64_Phdr * phdr ;
if ( fread ( & ehdr , sizeof ( ehdr ) , 1 , fp ) ! = 1 )
goto out ;
if ( need_swap ) {
ehdr . e_phoff = bswap_64 ( ehdr . e_phoff ) ;
ehdr . e_phentsize = bswap_16 ( ehdr . e_phentsize ) ;
ehdr . e_phnum = bswap_16 ( ehdr . e_phnum ) ;
}
buf_size = ehdr . e_phentsize * ehdr . e_phnum ;
buf = malloc ( buf_size ) ;
if ( buf = = NULL )
goto out ;
fseek ( fp , ehdr . e_phoff , SEEK_SET ) ;
if ( fread ( buf , buf_size , 1 , fp ) ! = 1 )
goto out_free ;
for ( i = 0 , phdr = buf ; i < ehdr . e_phnum ; i + + , phdr + + ) {
void * tmp ;
2014-12-16 05:16:12 +03:00
long offset ;
2012-08-06 08:41:22 +04:00
if ( need_swap ) {
phdr - > p_type = bswap_32 ( phdr - > p_type ) ;
phdr - > p_offset = bswap_64 ( phdr - > p_offset ) ;
phdr - > p_filesz = bswap_64 ( phdr - > p_filesz ) ;
}
if ( phdr - > p_type ! = PT_NOTE )
continue ;
buf_size = phdr - > p_filesz ;
2014-12-16 05:16:12 +03:00
offset = phdr - > p_offset ;
2012-08-06 08:41:22 +04:00
tmp = realloc ( buf , buf_size ) ;
if ( tmp = = NULL )
goto out_free ;
buf = tmp ;
2014-12-16 05:16:12 +03:00
fseek ( fp , offset , SEEK_SET ) ;
2012-08-06 08:41:22 +04:00
if ( fread ( buf , buf_size , 1 , fp ) ! = 1 )
goto out_free ;
ret = read_build_id ( buf , buf_size , bf , size , need_swap ) ;
if ( ret = = 0 )
ret = size ;
break ;
}
}
out_free :
free ( buf ) ;
out :
fclose ( fp ) ;
return ret ;
}
int sysfs__read_build_id ( const char * filename , void * build_id , size_t size )
{
int fd ;
int ret = - 1 ;
struct stat stbuf ;
size_t buf_size ;
void * buf ;
fd = open ( filename , O_RDONLY ) ;
if ( fd < 0 )
return - 1 ;
if ( fstat ( fd , & stbuf ) < 0 )
goto out ;
buf_size = stbuf . st_size ;
buf = malloc ( buf_size ) ;
if ( buf = = NULL )
goto out ;
if ( read ( fd , buf , buf_size ) ! = ( ssize_t ) buf_size )
goto out_free ;
ret = read_build_id ( buf , buf_size , build_id , size , false ) ;
out_free :
free ( buf ) ;
out :
close ( fd ) ;
return ret ;
}
2015-03-24 17:49:02 +03:00
int symsrc__init ( struct symsrc * ss , struct dso * dso , const char * name ,
2012-08-11 02:22:57 +04:00
enum dso_binary_type type )
{
int fd = open ( name , O_RDONLY ) ;
if ( fd < 0 )
2015-03-24 17:49:02 +03:00
goto out_errno ;
2012-08-11 02:22:57 +04:00
ss - > name = strdup ( name ) ;
if ( ! ss - > name )
goto out_close ;
2013-12-04 18:23:01 +04:00
ss - > fd = fd ;
2012-08-11 02:22:57 +04:00
ss - > type = type ;
return 0 ;
out_close :
close ( fd ) ;
2015-03-24 17:49:02 +03:00
out_errno :
dso - > load_errno = errno ;
2012-08-11 02:22:57 +04:00
return - 1 ;
}
2012-09-11 02:15:03 +04:00
bool symsrc__possibly_runtime ( struct symsrc * ss __maybe_unused )
2012-08-11 02:23:02 +04:00
{
/* Assume all sym sources could be a runtime image. */
return true ;
}
2012-09-11 02:15:03 +04:00
bool symsrc__has_symtab ( struct symsrc * ss __maybe_unused )
2012-08-11 02:23:00 +04:00
{
return false ;
}
2012-08-11 02:22:57 +04:00
void symsrc__destroy ( struct symsrc * ss )
{
2013-12-27 23:55:14 +04:00
zfree ( & ss - > name ) ;
2012-08-11 02:22:57 +04:00
close ( ss - > fd ) ;
}
2012-09-11 02:15:03 +04:00
int dso__synthesize_plt_symbols ( struct dso * dso __maybe_unused ,
2018-04-26 22:52:34 +03:00
struct symsrc * ss __maybe_unused )
2012-08-06 08:41:21 +04:00
{
return 0 ;
}
2014-07-14 14:02:41 +04:00
static int fd__is_64_bit ( int fd )
{
u8 e_ident [ EI_NIDENT ] ;
if ( lseek ( fd , 0 , SEEK_SET ) )
return - 1 ;
if ( readn ( fd , e_ident , sizeof ( e_ident ) ) ! = sizeof ( e_ident ) )
return - 1 ;
if ( memcmp ( e_ident , ELFMAG , SELFMAG ) | |
e_ident [ EI_VERSION ] ! = EV_CURRENT )
return - 1 ;
return e_ident [ EI_CLASS ] = = ELFCLASS64 ;
}
2014-07-22 17:17:59 +04:00
enum dso_type dso__type_fd ( int fd )
{
Elf64_Ehdr ehdr ;
int ret ;
ret = fd__is_64_bit ( fd ) ;
if ( ret < 0 )
return DSO__TYPE_UNKNOWN ;
if ( ret )
return DSO__TYPE_64BIT ;
if ( readn ( fd , & ehdr , sizeof ( ehdr ) ) ! = sizeof ( ehdr ) )
return DSO__TYPE_UNKNOWN ;
if ( ehdr . e_machine = = EM_X86_64 )
return DSO__TYPE_X32BIT ;
return DSO__TYPE_32BIT ;
}
2012-09-11 02:15:03 +04:00
int dso__load_sym ( struct dso * dso , struct map * map __maybe_unused ,
struct symsrc * ss ,
struct symsrc * runtime_ss __maybe_unused ,
int kmodule __maybe_unused )
2012-08-06 08:41:21 +04:00
{
2015-09-08 03:30:28 +03:00
unsigned char build_id [ BUILD_ID_SIZE ] ;
2014-07-14 14:02:41 +04:00
int ret ;
ret = fd__is_64_bit ( ss - > fd ) ;
if ( ret > = 0 )
dso - > is_64_bit = ret ;
2012-08-06 08:41:22 +04:00
2012-08-11 02:22:57 +04:00
if ( filename__read_build_id ( ss - > name , build_id , BUILD_ID_SIZE ) > 0 ) {
2012-08-06 08:41:22 +04:00
dso__set_build_id ( dso , build_id ) ;
}
2012-08-06 08:41:21 +04:00
return 0 ;
}
2013-08-07 15:38:51 +04:00
int file__read_maps ( int fd __maybe_unused , bool exe __maybe_unused ,
mapfn_t mapfn __maybe_unused , void * data __maybe_unused ,
bool * is_64_bit __maybe_unused )
{
return - 1 ;
}
2013-10-09 16:01:12 +04:00
int kcore_extract__create ( struct kcore_extract * kce __maybe_unused )
{
return - 1 ;
}
void kcore_extract__delete ( struct kcore_extract * kce __maybe_unused )
{
}
2013-10-14 17:57:29 +04:00
int kcore_copy ( const char * from_dir __maybe_unused ,
const char * to_dir __maybe_unused )
{
return - 1 ;
}
2012-08-06 08:41:21 +04:00
void symbol__elf_init ( void )
{
}
2017-03-25 23:34:26 +03:00
char * dso__demangle_sym ( struct dso * dso __maybe_unused ,
int kmodule __maybe_unused ,
2017-08-07 00:24:34 +03:00
const char * elf_name __maybe_unused )
2017-03-25 23:34:26 +03:00
{
return NULL ;
}