op_bfd.cpp

Go to the documentation of this file.
00001 
00012 #include "op_file.h"
00013 #include "op_config.h"
00014 #include "config.h"
00015 
00016 #include <fcntl.h>
00017 #include <cstring>
00018 
00019 #include <sys/stat.h>
00020 
00021 #include <cstdlib>
00022 
00023 #include <algorithm>
00024 #include <iostream>
00025 #include <iomanip>
00026 #include <sstream>
00027 
00028 #include "op_bfd.h"
00029 #include "locate_images.h"
00030 #include "string_filter.h"
00031 #include "stream_util.h"
00032 #include "cverb.h"
00033 
00034 using namespace std;
00035 
00036 
00037 verbose vbfd("bfd");
00038 
00039 
00040 namespace {
00041 
00043 struct remove_filter {
00044     remove_filter(string_filter const & filter)
00045         : filter_(filter) {}
00046 
00047     bool operator()(op_bfd_symbol const & symbol) {
00048         return !filter_.match(symbol.name());
00049     }
00050 
00051     string_filter filter_;
00052 };
00053 
00054 
00055 } // namespace anon
00056 
00057 
00058 op_bfd_symbol::op_bfd_symbol(asymbol const * a)
00059     : bfd_symbol(a), symb_value(a->value),
00060       section_filepos(a->section->filepos),
00061       section_vma(a->section->vma),
00062       symb_size(0), symb_hidden(false), symb_weak(false),
00063       symb_artificial(false)
00064 {
00065     // Some sections have unnamed symbols in them. If
00066     // we just ignore them then we end up sticking
00067     // things like .plt hits inside of _init. So instead
00068     // we name the symbol after the section.
00069     if (a->name && a->name[0] != '\0') {
00070         symb_name = a->name;
00071         symb_weak = a->flags & BSF_WEAK;
00072         symb_hidden = (a->flags & BSF_LOCAL)
00073             && !(a->flags & BSF_GLOBAL);
00074     } else {
00075         symb_name = string("??") + a->section->name;
00076     }
00077 }
00078 
00079 
00080 op_bfd_symbol::op_bfd_symbol(bfd_vma vma, size_t size, string const & name)
00081     : bfd_symbol(0), symb_value(vma),
00082       section_filepos(0), section_vma(0),
00083       symb_size(size), symb_name(name),
00084       symb_artificial(true)
00085 {
00086 }
00087 
00088 
00089 bool op_bfd_symbol::operator<(op_bfd_symbol const & rhs) const
00090 {
00091     return filepos() < rhs.filepos();
00092 }
00093 
00094 unsigned long op_bfd_symbol::symbol_endpos(void) const
00095 {
00096     return bfd_symbol->section->filepos + bfd_symbol->section->size;
00097 }
00098 
00099 
00100 op_bfd::op_bfd(string const & fname, string_filter const & symbol_filter,
00101            extra_images const & extra_images, bool & ok)
00102     :
00103     filename(fname),
00104     archive_path(extra_images.get_archive_path()),
00105     extra_found_images(extra_images),
00106     file_size(-1),
00107     anon_obj(false)
00108 {
00109     int fd;
00110     struct stat st;
00111     // after creating all symbol it's convenient for user code to access
00112     // symbols through a vector. We use an intermediate list to avoid a
00113     // O(Nē) behavior when we will filter vector element below
00114     symbols_found_t symbols;
00115     asection const * sect;
00116     string suf = ".jo";
00117 
00118     image_error img_ok;
00119     string const image_path =
00120         extra_images.find_image_path(filename, img_ok, true);
00121 
00122     cverb << vbfd << "op_bfd ctor for " << image_path << endl;
00123 
00124     // if there's a problem already, don't try to open it
00125     if (!ok || img_ok != image_ok) {
00126         cverb << vbfd << "can't locate " << image_path << endl;
00127         goto out_fail;
00128     }
00129 
00130     fd = open(image_path.c_str(), O_RDONLY);
00131     if (fd == -1) {
00132         cverb << vbfd << "open failed for " << image_path << endl;
00133         ok = false;
00134         goto out_fail;
00135     }
00136 
00137     if (fstat(fd, &st)) {
00138         cverb << vbfd << "stat failed for " << image_path << endl;
00139         ok = false;
00140         goto out_fail;
00141     }
00142 
00143     file_size = st.st_size;
00144 
00145     ibfd.abfd = fdopen_bfd(image_path, fd);
00146 
00147     if (!ibfd.valid()) {
00148         cverb << vbfd << "fdopen_bfd failed for " << image_path << endl;
00149         ok = false;
00150         goto out_fail;
00151     }
00152 
00153     string::size_type pos;
00154     pos = filename.rfind(suf);
00155     if (pos != string::npos && pos == filename.size() - suf.size())
00156         anon_obj = true;
00157 
00158 
00159     // find .text and use it
00160     for (sect = ibfd.abfd->sections; sect; sect = sect->next) {
00161         if (sect->flags & SEC_CODE) {
00162             if (filepos_map[sect->name] != 0) {
00163                 cerr << "Found section \"" << sect->name
00164                      << "\" twice for " << get_filename()
00165                      << endl;
00166                 abort();
00167             }
00168 
00169             filepos_map[sect->name] = sect->filepos;
00170 
00171             if (sect->vma == 0 && strcmp(sect->name, ".text"))
00172                 filtered_section.push_back(sect);
00173         }
00174     }
00175 
00176     get_symbols(symbols);
00177 
00178 out:
00179     add_symbols(symbols, symbol_filter);
00180     return;
00181 out_fail:
00182     ibfd.close();
00183     dbfd.close();
00184     // make the fake symbol fit within the fake file
00185     file_size = -1;
00186     goto out;
00187 }
00188 
00189 
00190 op_bfd::~op_bfd()
00191 {
00192 }
00193 
00194 
00195 unsigned long op_bfd::get_start_offset(bfd_vma vma) const
00196 {
00197     if (!vma || !ibfd.valid()) {
00198         filepos_map_t::const_iterator it = filepos_map.find(".text");
00199         if (it != filepos_map.end())
00200             return it->second;
00201         return 0;
00202     }
00203 
00204     return 0;
00205 }
00206 
00207 
00208 void op_bfd::get_symbols(op_bfd::symbols_found_t & symbols)
00209 {
00210     ibfd.get_symbols();
00211 
00212     // On separate debug file systems, the main bfd has no symbols,
00213     // so even for non -g reports, we want to process the dbfd.
00214     // This hurts us pretty badly (the CRC), but we really don't
00215     // have much choice at the moment.
00216     has_debug_info();
00217 
00218     dbfd.set_image_bfd_info(&ibfd);
00219     dbfd.get_symbols();
00220     if (dbfd.valid() && !ibfd.nr_syms)
00221         vma_adj = ibfd.abfd->start_address - dbfd.abfd->start_address;
00222     else
00223     vma_adj= 0;
00224 
00225     size_t i;
00226     for (i = 0; i < ibfd.nr_syms; ++i) {
00227         if (!interesting_symbol(ibfd.syms[i]))
00228             continue;
00229         if (find(filtered_section.begin(), filtered_section.end(),
00230              ibfd.syms[i]->section) != filtered_section.end())
00231             continue;
00232         symbols.push_back(op_bfd_symbol(ibfd.syms[i]));
00233     }
00234 
00235     for (i = 0; i < dbfd.nr_syms; ++i) {
00236         if (!interesting_symbol(dbfd.syms[i]))
00237             continue;
00238 
00239         // need to use filepos of original file's section for
00240         // debug file symbols. We probably need to be more
00241         // careful for special symbols which have ->section from
00242         // .rodata like *ABS*
00243         u32 filepos = filepos_map[dbfd.syms[i]->section->name];
00244         if (filepos != 0)
00245             dbfd.syms[i]->section->filepos = filepos;
00246         symbols.push_back(op_bfd_symbol(dbfd.syms[i]));
00247     }
00248 
00249     symbols.sort();
00250 
00251     symbols_found_t::iterator it = symbols.begin();
00252 
00253     // we need to ensure than for a given vma only one symbol exist else
00254     // we read more than one time some samples. Fix #526098
00255     while (it != symbols.end()) {
00256         symbols_found_t::iterator temp = it;
00257         ++temp;
00258         if (temp != symbols.end() && (it->vma() == temp->vma()) &&
00259             (it->filepos() == temp->filepos())) {
00260             if (boring_symbol(*it, *temp)) {
00261                 it = symbols.erase(it);
00262             } else {
00263                 symbols.erase(temp);
00264             }
00265         } else {
00266             ++it;
00267         }
00268     }
00269 
00270     // now we can calculate the symbol size, we can't first include/exclude
00271     // symbols because the size of symbol is calculated from the difference
00272     // between the vma of a symbol and the next one.
00273     for (it = symbols.begin() ; it != symbols.end(); ++it) {
00274         op_bfd_symbol const * next = 0;
00275         symbols_found_t::iterator temp = it;
00276         ++temp;
00277         if (temp != symbols.end())
00278             next = &*temp;
00279         it->size(symbol_size(*it, next));
00280     }
00281 }
00282 
00283 
00284 void op_bfd::add_symbols(op_bfd::symbols_found_t & symbols,
00285                          string_filter const & symbol_filter)
00286 {
00287     // images with no symbols debug info available get a placeholder symbol
00288     if (symbols.empty())
00289         symbols.push_back(create_artificial_symbol());
00290 
00291     cverb << vbfd << "number of symbols before filtering "
00292           << dec << symbols.size() << hex << endl;
00293 
00294     symbols_found_t::iterator it;
00295     it = remove_if(symbols.begin(), symbols.end(),
00296                    remove_filter(symbol_filter));
00297 
00298     copy(symbols.begin(), it, back_inserter(syms));
00299 
00300     cverb << vbfd << "number of symbols now "
00301           << dec << syms.size() << hex << endl;
00302 }
00303 
00304 
00305 bfd_vma op_bfd::offset_to_pc(bfd_vma offset) const
00306 {
00307     asection const * sect = ibfd.abfd->sections;
00308 
00309     for (; sect; sect = sect->next) {
00310         if (offset >= bfd_vma(sect->filepos) &&
00311             (!sect->next || offset < bfd_vma(sect->next->filepos))) {
00312             return sect->vma + (offset - sect->filepos);
00313         }
00314     }
00315 
00316     return 0;
00317 }
00318 
00319 bool op_bfd::
00320 symbol_has_contents(symbol_index_t sym_idx)
00321 {
00322     op_bfd_symbol const & bfd_sym = syms[sym_idx];
00323     string const name = bfd_sym.name();
00324     if (name.size() == 0 || bfd_sym.artificial() || !ibfd.valid())
00325         return false;
00326     else
00327         return true;
00328 }
00329 
00330 bool op_bfd::
00331 get_symbol_contents(symbol_index_t sym_index, unsigned char * contents) const
00332 {
00333     op_bfd_symbol const & bfd_sym = syms[sym_index];
00334     size_t size = bfd_sym.size();
00335 
00336     if (!bfd_get_section_contents(ibfd.abfd, bfd_sym.symbol()->section, 
00337                  contents, 
00338                  static_cast<file_ptr>(bfd_sym.value()), size)) {
00339         return false;
00340     }
00341     return true;
00342 }
00343 
00344 bool op_bfd::has_debug_info() const
00345 {
00346     if (debug_info.cached())
00347         return debug_info.get();
00348 
00349     if (!ibfd.valid())
00350         return debug_info.reset(false);
00351 
00352     if (ibfd.has_debug_info())
00353         return debug_info.reset(true);
00354 
00355     // check to see if there is an .debug file
00356 
00357     if (find_separate_debug_file(ibfd.abfd, filename, debug_filename, extra_found_images)) {
00358         cverb << vbfd << "now loading: " << debug_filename << endl;
00359         dbfd.abfd = open_bfd(debug_filename);
00360         if (dbfd.has_debug_info())
00361             return debug_info.reset(true);
00362     }
00363 
00364     // .debug is optional, so will not fail if there's a problem
00365     cverb << vbfd << "failed to process separate debug file "
00366           << debug_filename << endl;
00367 
00368     return debug_info.reset(false);
00369 }
00370 
00371 
00372 bool op_bfd::get_linenr(symbol_index_t sym_idx, bfd_vma offset,
00373             string & source_filename, unsigned int & linenr) const
00374 {
00375     if (!has_debug_info())
00376         return false;
00377 
00378     bfd_info const & b = dbfd.valid() ? dbfd : ibfd;
00379     op_bfd_symbol const & sym = syms[sym_idx];
00380 
00381     linenr_info const info = find_nearest_line(b, sym, offset, anon_obj);
00382 
00383     if (!info.found)
00384         return false;
00385 
00386     source_filename = info.filename;
00387     linenr = info.line;
00388     return true;
00389 }
00390 
00391 
00392 size_t op_bfd::symbol_size(op_bfd_symbol const & sym,
00393                op_bfd_symbol const * next) const
00394 {
00395     unsigned long long start = sym.filepos();
00396     unsigned long long end;
00397 
00398     if (next && (sym.section() != next->section()))
00399         end = sym.symbol_endpos();
00400     else
00401         end = next ? next->filepos() : sym.section()->filepos + file_size;
00402 
00403     if (start > end)
00404         return 0;
00405 
00406     return end - start;
00407 }
00408 
00409 
00410 void op_bfd::get_symbol_range(symbol_index_t sym_idx,
00411                   unsigned long long & start, unsigned long long & end) const
00412 {
00413     op_bfd_symbol const & sym = syms[sym_idx];
00414 
00415     bool const verbose = cverb << (vbfd & vlevel1);
00416 
00417     if (anon_obj)
00418         start = sym.vma();
00419     else
00420         start = sym.filepos();
00421     end = start + sym.size();
00422 
00423     if (!verbose)
00424         return;
00425 
00426     io_state state(cverb << (vbfd & vlevel1));
00427 
00428     cverb << (vbfd & vlevel1) << "symbol " << sym.name()
00429           << ", value " << hex << sym.value() << endl;
00430     cverb << (vbfd & vlevel1)
00431           << "start " << hex << start << ", end " << end << endl;
00432 
00433     if (sym.symbol()) {
00434         cverb << (vbfd & vlevel1) << "in section "
00435               << sym.symbol()->section->name << ", filepos "
00436               << hex << sym.symbol()->section->filepos << endl;
00437     }
00438 }
00439 
00440 
00441 void op_bfd::get_vma_range(bfd_vma & start, bfd_vma & end) const
00442 {
00443     if (!syms.empty()) {
00444         // syms are sorted by vma so vma of the first symbol and vma +
00445         // size of the last symbol give the vma range for gprof output
00446         op_bfd_symbol const & last_symb = syms[syms.size() - 1];
00447         start = syms[0].vma();
00448         // end is excluded from range so + 1 *if* last_symb.size() != 0
00449         end = last_symb.vma() + last_symb.size() + (last_symb.size() != 0);
00450     } else {
00451         start = 0;
00452         end = file_size;
00453     }
00454 }
00455 
00456 
00457 op_bfd_symbol const op_bfd::create_artificial_symbol()
00458 {
00459 
00460     bfd_vma start, end;
00461     get_vma_range(start, end);
00462     return op_bfd_symbol(start, end - start, get_filename());
00463 }
00464 
00465 
00466 string op_bfd::get_filename() const
00467 {
00468     return filename;
00469 }
00470 
00471 
00472 size_t op_bfd::bfd_arch_bits_per_address() const
00473 {
00474     if (ibfd.valid())
00475         return ::bfd_arch_bits_per_address(ibfd.abfd);
00476     // FIXME: this function should be called only if the underlined ibfd
00477     // is ok, must we throw ?
00478     return sizeof(bfd_vma);
00479 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1