/**
* @file op_bfd.h
* Encapsulation of bfd objects
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Philippe Elie
* @author John Levon
*/
#ifndef OP_BFD_H
#define OP_BFD_H
#include "config.h"
#include <vector>
#include <string>
#include <list>
#include <map>
#include <set>
#include "bfd_support.h"
#include "locate_images.h"
#include "utility.h"
#include "cached_value.h"
#include "op_types.h"
class op_bfd;
class string_filter;
class extra_images;
/// all symbol vector indexing uses this type
typedef size_t symbol_index_t;
/**
* A symbol description from a bfd point of view. This duplicate
* information pointed by an asymbol, we need this duplication in case
* the symbol is an artificial symbol
*/
class op_bfd_symbol {
public:
/// ctor for real symbols
op_bfd_symbol(asymbol const * a);
/// ctor for artificial symbols
op_bfd_symbol(bfd_vma vma, size_t size, std::string const & name);
bfd_vma vma() const { return symb_value + section_vma; }
unsigned long value() const { return symb_value; }
unsigned long filepos() const { return symb_value + section_filepos; }
unsigned long symbol_endpos(void) const;
asection const * section(void) const { return bfd_symbol->section; }
std::string const & name() const { return symb_name; }
asymbol const * symbol() const { return bfd_symbol; }
size_t size() const { return symb_size; }
void size(size_t s) { symb_size = s; }
bool hidden() const { return symb_hidden; }
bool weak() const { return symb_weak; }
bool artificial() const { return symb_artificial; }
/// compare two symbols by their filepos()
bool operator<(op_bfd_symbol const & lhs) const;
private:
/// the original bfd symbol, this can be null if the symbol is an
/// artificial symbol
asymbol const * bfd_symbol;
/// the offset of this symbol relative to the begin of the section's
/// symbol
unsigned long symb_value;
/// the section filepos for this symbol
unsigned long section_filepos;
/// the section vma for this symbol
bfd_vma section_vma;
/// the size of this symbol
size_t symb_size;
/// the name of the symbol
std::string symb_name;
/// normally not externally visible symbol
bool symb_hidden;
/// whether other symbols can override it
bool symb_weak;
/// symbol is artificially created
bool symb_artificial;
/// code bytes corresponding to symbol -- used for XML generation
std::string symb_bytes;
};
/**
* Encapsulation of a bfd object. Simplifies open/close of bfd, enumerating
* symbols and retrieving informations for symbols or vma.
*
* Use of this class relies on a std::ostream cverb
*/
class op_bfd {
public:
/**
* @param filename the name of the image file
* @param symbol_filter filter to apply to symbols
* @param extra_images container where all extra candidate filenames
* are stored
* @param ok in-out parameter: on in, if not set, don't
* open the bfd (because it's not there or whatever). On out,
* it's set to false if the bfd couldn't be loaded.
*/
op_bfd(std::string const & filename,
string_filter const & symbol_filter,
extra_images const & extra_images,
bool & ok);
/**
* This constructor is used when processing an SPU profile
* where the SPU ELF is embedded within the PPE binary.
*/
op_bfd(uint64_t spu_offset,
std::string const & filename,
string_filter const & symbol_filter,
extra_images const & extra_images,
bool & ok);
std::string get_embedding_filename() const { return embedding_filename; }
/// close an opened bfd image and free all related resources
~op_bfd();
/**
* @param sym_idx index of the symbol
* @param offset fentry number
* @param filename output parameter to store filename
* @param linenr output parameter to store linenr.
*
* Retrieve the relevant finename:linenr information for the sym_idx
* at offset. If the lookup fails, return false. In some cases this
* function can retrieve the filename and return true but fail to
* retrieve the linenr and so can return zero in linenr
*/
bool get_linenr(symbol_index_t sym_idx, bfd_vma offset,
std::string & filename, unsigned int & linenr) const;
/**
* @param sym_idx symbol index
* @param start reference to start var
* @param end reference to end var
*
* Calculates the range of sample file entries covered by sym. start
* and end will be filled in appropriately. If index is the last entry
* in symbol table, all entries up to the end of the sample file will
* be used. After calculating start and end they are sanitized
*
* All errors are fatal.
*/
void get_symbol_range(symbol_index_t sym_idx,
unsigned long long & start, unsigned long long & end) const;
/**
* @param start reference to the start vma
* @param end reference to the end vma
*
* return in start, end the vma range for this binary object.
*/
void get_vma_range(bfd_vma & start, bfd_vma & end) const;
/** return the relocated PC value for the given file offset */
bfd_vma offset_to_pc(bfd_vma offset) const;
/**
* If passed 0, return the file position of the .text section.
* Otherwise, return the filepos of a section with a matching
* vma.
*/
unsigned long get_start_offset(bfd_vma vma = 0) const;
/**
* Return the image name of the underlying binary image. For an
* archive, this returns the path *within* the archive, not the
* full path of the file.
*/
std::string get_filename() const;
/// sorted vector by vma of interesting symbol.
std::vector<op_bfd_symbol> syms;
/// return in bits the bfd_vma size for this binary. This is needed
/// because gprof output depend on the bfd_vma for *this* binary
/// and do not depend on sizeof(bfd_vma)
size_t bfd_arch_bits_per_address() const;
/// return true if binary contain some debug information
bool has_debug_info() const;
/**
* @param sym_idx symbol index
*
* Return true or false, indicating whether or not the
* symbol referenced by the passed sym_idx has code available.
* Some symbols have no code associated with them; for example,
* artificial symbols created for anonymous memory samples or for
* stripped binaries with no symbol debug info. Additionally,
* if the bfd object associated with the symbol is not valid,
* this function will also return false.
*
* NOTE: This call should be made prior to invoking
* get_symbol_contents to avoid unnecessarily allocating
* memory for the symbol contents.
*/
bool symbol_has_contents(symbol_index_t sym_idx);
bool get_symbol_contents(symbol_index_t sym_index,
unsigned char * contents) const;
bool valid() const { return ibfd.valid(); }
private:
/// temporary container type for getting symbols
typedef std::list<op_bfd_symbol> symbols_found_t;
/**
* Parse and sort in ascending order all symbols
* in the file pointed to by abfd that reside in
* a %SEC_CODE section.
*
* The symbols are filtered through
* the interesting_symbol() predicate and sorted
* with op_bfd_symbol::operator<() comparator.
*/
void get_symbols(symbols_found_t & symbols);
/**
* Helper function for get_symbols.
* Populates bfd_syms and extracts the "interesting_symbol"s.
*/
void get_symbols_from_file(bfd_info & bfd, size_t start,
op_bfd::symbols_found_t & symbols,
bool debug_file);
/**
* Add the symbols in the binary, applying filtering,
* and handling artificial symbols.
*/
void add_symbols(symbols_found_t & symbols,
string_filter const & symbol_filter);
/**
* symbol_size - return the size of a symbol
* @param sym symbol to get size
* @param next next symbol in vma order if any
*/
size_t symbol_size(op_bfd_symbol const & sym,
op_bfd_symbol const * next) const;
/// create an artificial symbol for a symbolless binary
op_bfd_symbol const create_artificial_symbol();
/* Generate symbols using bfd functions for
* the image file associated with the ibfd arg.
*/
uint process_symtab(bfd_info * bfd, uint start);
/// filename we open (not including archive path)
std::string filename;
/// path to archive
std::string archive_path;
/// reference to extra_images
extra_images const & extra_found_images;
/// file size in bytes
off_t file_size;
/// corresponding debug file name
mutable std::string debug_filename;
/// true if at least one section has (flags & SEC_DEBUGGING) != 0
mutable cached_value<bool> debug_info;
/// our main bfd object: .bfd may be NULL
bfd_info ibfd;
// corresponding debug bfd object, if one is found
mutable bfd_info dbfd;
/// sections we will avoid to use symbol from, this is needed
/// because elf file allows sections with identical vma and we can't
/// allow overlapping symbols. Such elf layout is used actually by
/// kernel modules where all code section vma are set to 0.
std::vector<asection const *> filtered_section;
typedef std::map<std::string, u32> filepos_map_t;
// mapping of section names to filepos in the original binary
filepos_map_t filepos_map;
/**
* If spu_offset is non-zero, embedding_filename is the file containing
* the embedded SPU image.
*/
std::string embedding_filename;
bool anon_obj;
};
#endif /* !OP_BFD_H */